Merge "ONA: Enable new UI and connection flow." into oc-mr1-dev
am: f0653448fc

Change-Id: Idf8a2e6804a64186c97dbd34cf6f416e49d52bb5
diff --git a/service/java/com/android/server/wifi/ConnectToNetworkNotificationBuilder.java b/service/java/com/android/server/wifi/ConnectToNetworkNotificationBuilder.java
index c0960d4..38c0ad0 100644
--- a/service/java/com/android/server/wifi/ConnectToNetworkNotificationBuilder.java
+++ b/service/java/com/android/server/wifi/ConnectToNetworkNotificationBuilder.java
@@ -35,10 +35,6 @@
     public static final String ACTION_USER_DISMISSED_NOTIFICATION =
             "com.android.server.wifi.ConnectToNetworkNotification.USER_DISMISSED_NOTIFICATION";
 
-    /** Intent when user tapped the "Connect to Network" notification. */
-    public static final String ACTION_USER_TAPPED_CONTENT =
-            "com.android.server.wifi.ConnectToNetworkNotification.USER_TAPPED_CONTENT";
-
     /** Intent when user tapped action button to connect to recommended network. */
     public static final String ACTION_CONNECT_TO_NETWORK =
             "com.android.server.wifi.ConnectToNetworkNotification.CONNECT_TO_NETWORK";
@@ -67,17 +63,24 @@
      * Creates the connect to network notification that alerts users of a recommended connectable
      * network.
      *
-     * @param numNetworks Number of available open networks nearby
+     * There are two actions - "Options" link to the Wi-Fi picker activity, and "Connect" prompts
+     * the connection to the recommended network.
+     *
+     * @param network The network to be recommended
      */
-    public Notification createConnectToNetworkNotification(int numNetworks) {
-
-        CharSequence title = mResources.getQuantityText(
-                com.android.internal.R.plurals.wifi_available, numNetworks);
-        CharSequence content = mResources.getQuantityText(
-                com.android.internal.R.plurals.wifi_available_detailed, numNetworks);
-
-        return createNotificationBuilder(title, content)
-                .setContentIntent(getPrivateBroadcast(ACTION_USER_TAPPED_CONTENT))
+    public Notification createConnectToNetworkNotification(ScanResult network) {
+        Notification.Action connectAction = new Notification.Action.Builder(
+                null /* icon */,
+                mResources.getText(R.string.wifi_available_action_connect),
+                getPrivateBroadcast(ACTION_CONNECT_TO_NETWORK)).build();
+        Notification.Action allNetworksAction = new Notification.Action.Builder(
+                null /* icon */,
+                mResources.getText(R.string.wifi_available_action_all_networks),
+                getPrivateBroadcast(ACTION_PICK_WIFI_NETWORK)).build();
+        return createNotificationBuilder(
+                mContext.getText(R.string.wifi_available_title), network.SSID)
+                .addAction(connectAction)
+                .addAction(allNetworksAction)
                 .build();
     }
 
@@ -116,6 +119,7 @@
                 mContext.getText(R.string.wifi_available_content_failed_to_connect))
                 .setContentIntent(
                         getPrivateBroadcast(ACTION_PICK_WIFI_NETWORK_AFTER_CONNECT_FAILURE))
+                .setAutoCancel(true)
                 .build();
     }
 
@@ -124,7 +128,6 @@
         return mFrameworkFacade.makeNotificationBuilder(mContext,
                 SystemNotificationChannels.NETWORK_AVAILABLE)
                 .setSmallIcon(R.drawable.stat_notify_wifi_in_range)
-                .setAutoCancel(true)
                 .setTicker(title)
                 .setContentTitle(title)
                 .setContentText(content)
diff --git a/service/java/com/android/server/wifi/OpenNetworkNotifier.java b/service/java/com/android/server/wifi/OpenNetworkNotifier.java
index d2d45c3..31ff44b 100644
--- a/service/java/com/android/server/wifi/OpenNetworkNotifier.java
+++ b/service/java/com/android/server/wifi/OpenNetworkNotifier.java
@@ -20,7 +20,6 @@
 import static com.android.server.wifi.ConnectToNetworkNotificationBuilder.ACTION_PICK_WIFI_NETWORK;
 import static com.android.server.wifi.ConnectToNetworkNotificationBuilder.ACTION_PICK_WIFI_NETWORK_AFTER_CONNECT_FAILURE;
 import static com.android.server.wifi.ConnectToNetworkNotificationBuilder.ACTION_USER_DISMISSED_NOTIFICATION;
-import static com.android.server.wifi.ConnectToNetworkNotificationBuilder.ACTION_USER_TAPPED_CONTENT;
 
 import android.annotation.IntDef;
 import android.annotation.NonNull;
@@ -169,7 +168,6 @@
 
         IntentFilter filter = new IntentFilter();
         filter.addAction(ACTION_USER_DISMISSED_NOTIFICATION);
-        filter.addAction(ACTION_USER_TAPPED_CONTENT);
         filter.addAction(ACTION_CONNECT_TO_NETWORK);
         filter.addAction(ACTION_PICK_WIFI_NETWORK);
         filter.addAction(ACTION_PICK_WIFI_NETWORK_AFTER_CONNECT_FAILURE);
@@ -182,9 +180,6 @@
                 @Override
                 public void onReceive(Context context, Intent intent) {
                     switch (intent.getAction()) {
-                        case ACTION_USER_TAPPED_CONTENT:
-                            handleUserClickedContentAction();
-                            break;
                         case ACTION_USER_DISMISSED_NOTIFICATION:
                             handleUserDismissedAction();
                             break;
@@ -257,18 +252,29 @@
             return;
         }
 
-        // Do not show or update the notification if screen is off. We want to avoid a race that
-        // could occur between a user picking a network in settings and a network candidate picked
-        // through network selection, which will happen because screen on triggers a new
-        // connectivity scan.
-        if (mState !=  STATE_NO_NOTIFICATION || !mScreenOn) {
+        // Not enough time has passed to show a recommendation notification again
+        if (mState == STATE_NO_NOTIFICATION
+                && mClock.getWallClockMillis() < mNotificationRepeatTime) {
             return;
         }
 
-        mRecommendedNetwork = mOpenNetworkRecommender.recommendNetwork(
-                availableNetworks, new ArraySet<>(mBlacklistedSsids));
+        // Do nothing when the screen is off and no notification is showing.
+        if (mState == STATE_NO_NOTIFICATION && !mScreenOn) {
+            return;
+        }
 
-        postInitialNotification(availableNetworks.size());
+        // Only show a new or update an existing recommendation notification.
+        if (mState == STATE_NO_NOTIFICATION
+                || mState == STATE_SHOWING_RECOMMENDATION_NOTIFICATION) {
+            ScanResult recommendation = mOpenNetworkRecommender.recommendNetwork(
+                    availableNetworks, new ArraySet<>(mBlacklistedSsids));
+
+            if (recommendation != null) {
+                postInitialNotification(recommendation);
+            } else {
+                clearPendingNotification(false /* resetRepeatTime */);
+            }
+        }
     }
 
     /** Handles screen state changes. */
@@ -321,19 +327,11 @@
         return (NotificationManager) mContext.getSystemService(Context.NOTIFICATION_SERVICE);
     }
 
-    private void postInitialNotification(int numNetworks) {
-        if (mState != STATE_NO_NOTIFICATION
-                && mState != STATE_SHOWING_RECOMMENDATION_NOTIFICATION) {
-            return;
-        }
-        // Not enough time has passed to show the notification again
-        if (mClock.getWallClockMillis() < mNotificationRepeatTime) {
-            return;
-        }
-
+    private void postInitialNotification(ScanResult recommendedNetwork) {
         postNotification(mNotificationBuilder.createConnectToNetworkNotification(
-                numNetworks));
+                recommendedNetwork));
         mState = STATE_SHOWING_RECOMMENDATION_NOTIFICATION;
+        mRecommendedNetwork = recommendedNetwork;
         mNotificationRepeatTime = mClock.getWallClockMillis() + mNotificationRepeatDelay;
     }
 
@@ -372,6 +370,8 @@
     }
 
     private void startWifiSettings() {
+        // Close notification drawer before opening the picker.
+        mContext.sendBroadcast(new Intent(Intent.ACTION_CLOSE_SYSTEM_DIALOGS));
         mContext.startActivity(
                 new Intent(Settings.ACTION_WIFI_SETTINGS)
                         .addFlags(Intent.FLAG_ACTIVITY_NEW_TASK));
@@ -382,11 +382,6 @@
         startWifiSettings();
     }
 
-    private void handleUserClickedContentAction() {
-        startWifiSettings();
-        resetStateAndDelayNotification();
-    }
-
     private void handleUserDismissedAction() {
         if (mState == STATE_SHOWING_RECOMMENDATION_NOTIFICATION) {
             // blacklist dismissed network
diff --git a/service/java/com/android/server/wifi/WifiConnectivityManager.java b/service/java/com/android/server/wifi/WifiConnectivityManager.java
index 1c5ac28..7e730c8 100644
--- a/service/java/com/android/server/wifi/WifiConnectivityManager.java
+++ b/service/java/com/android/server/wifi/WifiConnectivityManager.java
@@ -1073,7 +1073,7 @@
         mWifiState = state;
 
         if (mWifiState == WIFI_STATE_CONNECTED) {
-            mOpenNetworkNotifier.clearPendingNotification(false /* resetRepeatDelay */);
+            mOpenNetworkNotifier.handleWifiConnected();
         }
 
         // Reset BSSID of last connection attempt and kick off
diff --git a/tests/wifitests/src/com/android/server/wifi/OpenNetworkNotifierTest.java b/tests/wifitests/src/com/android/server/wifi/OpenNetworkNotifierTest.java
index 3af19e1..46ec159 100644
--- a/tests/wifitests/src/com/android/server/wifi/OpenNetworkNotifierTest.java
+++ b/tests/wifitests/src/com/android/server/wifi/OpenNetworkNotifierTest.java
@@ -120,7 +120,7 @@
         mNotificationController.handleScanResults(mOpenNetworks);
 
         verify(mOpenNetworkRecommender).recommendNetwork(mOpenNetworks, mBlacklistedSsids);
-        verify(mNotificationBuilder).createConnectToNetworkNotification(1);
+        verify(mNotificationBuilder).createConnectToNetworkNotification(mDummyNetwork);
         verify(mNotificationManager).notify(anyInt(), any());
     }
 
@@ -144,13 +144,32 @@
         mNotificationController.handleScanResults(mOpenNetworks);
 
         verify(mOpenNetworkRecommender).recommendNetwork(mOpenNetworks, mBlacklistedSsids);
-        verify(mNotificationBuilder).createConnectToNetworkNotification(1);
+        verify(mNotificationBuilder).createConnectToNetworkNotification(mDummyNetwork);
         verify(mNotificationManager).notify(anyInt(), any());
 
         mNotificationController.handleScanResults(new ArrayList<>());
 
         verify(mNotificationManager).cancel(anyInt());
     }
+
+    /**
+     * When a notification is showing and no recommendation is made for the new scan results, the
+     * notification is cleared.
+     */
+    @Test
+    public void handleScanResults_notificationShown_noRecommendation_notificationCleared() {
+        mNotificationController.handleScanResults(mOpenNetworks);
+
+        verify(mOpenNetworkRecommender).recommendNetwork(mOpenNetworks, mBlacklistedSsids);
+        verify(mNotificationBuilder).createConnectToNetworkNotification(mDummyNetwork);
+        verify(mNotificationManager).notify(anyInt(), any());
+
+        when(mOpenNetworkRecommender.recommendNetwork(any(), any())).thenReturn(null);
+        mNotificationController.handleScanResults(mOpenNetworks);
+
+        verify(mNotificationManager).cancel(anyInt());
+    }
+
     /**
      * When a notification is showing, screen is off, and scan results with no open networks are
      * handled, the notification is cleared.
@@ -160,7 +179,7 @@
         mNotificationController.handleScanResults(mOpenNetworks);
 
         verify(mOpenNetworkRecommender).recommendNetwork(mOpenNetworks, mBlacklistedSsids);
-        verify(mNotificationBuilder).createConnectToNetworkNotification(1);
+        verify(mNotificationBuilder).createConnectToNetworkNotification(mDummyNetwork);
         verify(mNotificationManager).notify(anyInt(), any());
 
         mNotificationController.handleScreenStateChanged(false);
@@ -170,19 +189,6 @@
     }
 
     /**
-     * If notification is showing, do not post another notification.
-     */
-    @Test
-    public void handleScanResults_notificationShowing_doesNotRepostNotification() {
-        mNotificationController.handleScanResults(mOpenNetworks);
-        mNotificationController.handleScanResults(mOpenNetworks);
-
-        verify(mOpenNetworkRecommender).recommendNetwork(mOpenNetworks, mBlacklistedSsids);
-        verify(mNotificationBuilder).createConnectToNetworkNotification(1);
-        verify(mNotificationManager).notify(anyInt(), any());
-    }
-
-    /**
      * When {@link OpenNetworkNotifier#clearPendingNotification(boolean)} is called and a
      * notification is shown, clear the notification.
      */
@@ -191,7 +197,7 @@
         mNotificationController.handleScanResults(mOpenNetworks);
 
         verify(mOpenNetworkRecommender).recommendNetwork(mOpenNetworks, mBlacklistedSsids);
-        verify(mNotificationBuilder).createConnectToNetworkNotification(1);
+        verify(mNotificationBuilder).createConnectToNetworkNotification(mDummyNetwork);
         verify(mNotificationManager).notify(anyInt(), any());
 
         mNotificationController.clearPendingNotification(true);
@@ -215,7 +221,7 @@
      * new scan results with open networks.
      */
     @Test
-    public void screenOff_handleScanResults_notificationNotDisplayed() {
+    public void screenOff_notificationNotShowing_handleScanResults_notificationNotDisplayed() {
         mNotificationController.handleScreenStateChanged(false);
         mNotificationController.handleScanResults(mOpenNetworks);
 
@@ -224,6 +230,28 @@
     }
 
     /**
+     * When screen is off and notification is displayed, the notification can be updated with a new
+     * recommendation.
+     */
+    @Test
+    public void screenOff_notificationShowing_handleScanResults_recommendationCanBeUpdated() {
+        mNotificationController.handleScanResults(mOpenNetworks);
+
+        verify(mOpenNetworkRecommender).recommendNetwork(mOpenNetworks, mBlacklistedSsids);
+        verify(mNotificationBuilder).createConnectToNetworkNotification(mDummyNetwork);
+        verify(mNotificationManager).notify(anyInt(), any());
+
+        mNotificationController.handleScreenStateChanged(false);
+        mNotificationController.handleScanResults(mOpenNetworks);
+
+        // Recommendation made twice
+        verify(mOpenNetworkRecommender, times(2)).recommendNetwork(
+                mOpenNetworks, mBlacklistedSsids);
+        verify(mNotificationBuilder, times(2)).createConnectToNetworkNotification(mDummyNetwork);
+        verify(mNotificationManager, times(2)).notify(anyInt(), any());
+    }
+
+    /**
      * When a notification is posted and cleared without resetting delay, the next scan with open
      * networks should not post another notification.
      */
@@ -232,19 +260,17 @@
         mNotificationController.handleScanResults(mOpenNetworks);
 
         verify(mOpenNetworkRecommender).recommendNetwork(mOpenNetworks, mBlacklistedSsids);
-        verify(mNotificationBuilder).createConnectToNetworkNotification(1);
+        verify(mNotificationBuilder).createConnectToNetworkNotification(mDummyNetwork);
         verify(mNotificationManager).notify(anyInt(), any());
 
         mNotificationController.clearPendingNotification(false);
 
+        verify(mNotificationManager).cancel(anyInt());
+
         mNotificationController.handleScanResults(mOpenNetworks);
 
-        // Recommendation made twice but no new notification posted.
-        verify(mOpenNetworkRecommender, times(2)).recommendNetwork(
-                mOpenNetworks, mBlacklistedSsids);
+        // no new notification posted
         verify(mNotificationManager).notify(anyInt(), any());
-        verify(mNotificationBuilder).createConnectToNetworkNotification(1);
-        verify(mNotificationManager).cancel(anyInt());
     }
 
     /**
@@ -256,7 +282,7 @@
         mNotificationController.handleScanResults(mOpenNetworks);
 
         verify(mOpenNetworkRecommender).recommendNetwork(mOpenNetworks, mBlacklistedSsids);
-        verify(mNotificationBuilder).createConnectToNetworkNotification(1);
+        verify(mNotificationBuilder).createConnectToNetworkNotification(mDummyNetwork);
         verify(mNotificationManager).notify(anyInt(), any());
 
         mNotificationController.clearPendingNotification(true);
@@ -265,31 +291,11 @@
 
         verify(mOpenNetworkRecommender, times(2)).recommendNetwork(
                 mOpenNetworks, mBlacklistedSsids);
-        verify(mNotificationBuilder, times(2)).createConnectToNetworkNotification(1);
+        verify(mNotificationBuilder, times(2)).createConnectToNetworkNotification(mDummyNetwork);
         verify(mNotificationManager, times(2)).notify(anyInt(), any());
     }
 
     /**
-     * When a notification is tapped, open Wi-Fi settings.
-     */
-    @Test
-    public void notificationTap_opensWifiSettings() {
-        mNotificationController.handleScanResults(mOpenNetworks);
-
-        verify(mOpenNetworkRecommender).recommendNetwork(mOpenNetworks, mBlacklistedSsids);
-        verify(mNotificationBuilder).createConnectToNetworkNotification(1);
-        verify(mNotificationManager).notify(anyInt(), any());
-
-        mBroadcastReceiver.onReceive(
-                mContext,
-                new Intent(ConnectToNetworkNotificationBuilder.ACTION_USER_TAPPED_CONTENT));
-
-        ArgumentCaptor<Intent> pickerIntentCaptor = ArgumentCaptor.forClass(Intent.class);
-        verify(mContext).startActivity(pickerIntentCaptor.capture());
-        assertEquals(pickerIntentCaptor.getValue().getAction(), Settings.ACTION_WIFI_SETTINGS);
-    }
-
-    /**
      * When user dismissed notification and there is a recommended network, network ssid should be
      * blacklisted.
      */
@@ -298,7 +304,7 @@
         mNotificationController.handleScanResults(mOpenNetworks);
 
         verify(mOpenNetworkRecommender).recommendNetwork(mOpenNetworks, mBlacklistedSsids);
-        verify(mNotificationBuilder).createConnectToNetworkNotification(1);
+        verify(mNotificationBuilder).createConnectToNetworkNotification(mDummyNetwork);
         verify(mNotificationManager).notify(anyInt(), any());
 
         mBroadcastReceiver.onReceive(
@@ -307,7 +313,9 @@
 
         verify(mWifiConfigManager).saveToStore(false /* forceWrite */);
 
-        mNotificationController.handleScanResults(mOpenNetworks);
+        mNotificationController.clearPendingNotification(true);
+        List<ScanDetail> scanResults = mOpenNetworks;
+        mNotificationController.handleScanResults(scanResults);
 
         Set<String> expectedBlacklist = new ArraySet<>();
         expectedBlacklist.add(mDummyNetwork.SSID);
@@ -323,7 +331,7 @@
         mNotificationController.handleScanResults(mOpenNetworks);
 
         verify(mOpenNetworkRecommender).recommendNetwork(mOpenNetworks, mBlacklistedSsids);
-        verify(mNotificationBuilder).createConnectToNetworkNotification(1);
+        verify(mNotificationBuilder).createConnectToNetworkNotification(mDummyNetwork);
         verify(mNotificationManager).notify(anyInt(), any());
 
         mNotificationController.clearPendingNotification(false);
@@ -335,6 +343,7 @@
 
         verify(mOpenNetworkRecommender, times(2)).recommendNetwork(
                 mOpenNetworks, mBlacklistedSsids);
+        verify(mNotificationBuilder, times(2)).createConnectToNetworkNotification(mDummyNetwork);
         verify(mNotificationManager, times(2)).notify(anyInt(), any());
     }
 
@@ -356,7 +365,7 @@
         mNotificationController.handleScanResults(mOpenNetworks);
 
         verify(mOpenNetworkRecommender).recommendNetwork(mOpenNetworks, mBlacklistedSsids);
-        verify(mNotificationBuilder).createConnectToNetworkNotification(1);
+        verify(mNotificationBuilder).createConnectToNetworkNotification(mDummyNetwork);
         verify(mNotificationManager).notify(anyInt(), any());
 
         when(mUserManager.hasUserRestriction(UserManager.DISALLOW_CONFIG_WIFI, UserHandle.CURRENT))
@@ -389,7 +398,7 @@
 
         verify(mOpenNetworkRecommender).recommendNetwork(mOpenNetworks, mBlacklistedSsids);
         // Initial Notification
-        verify(mNotificationBuilder).createConnectToNetworkNotification(1);
+        verify(mNotificationBuilder).createConnectToNetworkNotification(mDummyNetwork);
         verify(mNotificationManager).notify(anyInt(), any());
 
         mBroadcastReceiver.onReceive(mContext,
@@ -421,7 +430,7 @@
 
         verify(mOpenNetworkRecommender).recommendNetwork(mOpenNetworks, mBlacklistedSsids);
         // Initial Notification
-        verify(mNotificationBuilder).createConnectToNetworkNotification(1);
+        verify(mNotificationBuilder).createConnectToNetworkNotification(mDummyNetwork);
         verify(mNotificationManager).notify(anyInt(), any());
 
         mNotificationController.handleWifiConnected();
@@ -439,7 +448,7 @@
 
         verify(mOpenNetworkRecommender).recommendNetwork(mOpenNetworks, mBlacklistedSsids);
         // Initial Notification
-        verify(mNotificationBuilder).createConnectToNetworkNotification(1);
+        verify(mNotificationBuilder).createConnectToNetworkNotification(mDummyNetwork);
         verify(mNotificationManager).notify(anyInt(), any());
 
         mBroadcastReceiver.onReceive(mContext,
@@ -477,7 +486,7 @@
 
         verify(mOpenNetworkRecommender).recommendNetwork(mOpenNetworks, mBlacklistedSsids);
         // Initial Notification
-        verify(mNotificationBuilder).createConnectToNetworkNotification(1);
+        verify(mNotificationBuilder).createConnectToNetworkNotification(mDummyNetwork);
         verify(mNotificationManager).notify(anyInt(), any());
 
         mBroadcastReceiver.onReceive(mContext,
@@ -505,7 +514,7 @@
 
         verify(mOpenNetworkRecommender).recommendNetwork(mOpenNetworks, mBlacklistedSsids);
         // Initial Notification
-        verify(mNotificationBuilder).createConnectToNetworkNotification(1);
+        verify(mNotificationBuilder).createConnectToNetworkNotification(mDummyNetwork);
         verify(mNotificationManager).notify(anyInt(), any());
 
         mBroadcastReceiver.onReceive(mContext,
diff --git a/tests/wifitests/src/com/android/server/wifi/WifiConnectivityManagerTest.java b/tests/wifitests/src/com/android/server/wifi/WifiConnectivityManagerTest.java
index cb1160c..6420fac 100644
--- a/tests/wifitests/src/com/android/server/wifi/WifiConnectivityManagerTest.java
+++ b/tests/wifitests/src/com/android/server/wifi/WifiConnectivityManagerTest.java
@@ -637,18 +637,17 @@
     }
 
     /**
-     * When wifi is connected, {@link OpenNetworkNotifier} tries to clear the pending
-     * notification and does not reset notification repeat delay.
+     * When wifi is connected, {@link OpenNetworkNotifier} handles the Wi-Fi connected behavior.
      *
-     * Expected behavior: ONA clears pending notification and does not reset repeat delay.
+     * Expected behavior: ONA handles connected behavior
      */
     @Test
-    public void wifiConnected_openNetworkNotifierClearsPendingNotification() {
+    public void wifiConnected_openNetworkNotifierHandlesConnection() {
         // Set WiFi to connected state
         mWifiConnectivityManager.handleConnectionStateChanged(
                 WifiConnectivityManager.WIFI_STATE_CONNECTED);
 
-        verify(mOpenNetworkNotifier).clearPendingNotification(false /* resetRepeatDelay*/);
+        verify(mOpenNetworkNotifier).handleWifiConnected();
     }
 
     /**