[NetworkSuggestion] ask user approval when first time add suggestions

Post a user approval notification when App first time add suggestions.
If user dismissal the notification, will post notification again when
suggestion matched in scan result.

Bug: 139037269
Test: atest android.net.wifi
Test: atest com.android.server.wifi
Test: acts WifiNetworkSuggestionTest
Change-Id: I72deeefb90f43af97e8574e40ebadca5e16a35f8
diff --git a/service/java/com/android/server/wifi/WifiNetworkSuggestionsManager.java b/service/java/com/android/server/wifi/WifiNetworkSuggestionsManager.java
index c30d78a..e1d2a02 100644
--- a/service/java/com/android/server/wifi/WifiNetworkSuggestionsManager.java
+++ b/service/java/com/android/server/wifi/WifiNetworkSuggestionsManager.java
@@ -570,6 +570,8 @@
             if (mWifiPermissionsUtil.checkNetworkCarrierProvisioningPermission(uid)) {
                 Log.i(TAG, "Setting the carrier provisioning app approved");
                 perAppInfo.hasUserApproved = true;
+            } else {
+                sendUserApprovalNotification(packageName, uid);
             }
         }
         Set<ExtendedWifiNetworkSuggestion> extNetworkSuggestions =
diff --git a/tests/wifitests/src/com/android/server/wifi/WifiNetworkSuggestionsManagerTest.java b/tests/wifitests/src/com/android/server/wifi/WifiNetworkSuggestionsManagerTest.java
index d0d7925..9b46268 100644
--- a/tests/wifitests/src/com/android/server/wifi/WifiNetworkSuggestionsManagerTest.java
+++ b/tests/wifitests/src/com/android/server/wifi/WifiNetworkSuggestionsManagerTest.java
@@ -837,7 +837,7 @@
         validatePostConnectionBroadcastSent(TEST_PACKAGE_1, networkSuggestion);
 
         // Verify no more broadcast were sent out.
-        verifyNoMoreInteractions(mContext);
+        mInorder.verifyNoMoreInteractions();
     }
 
     /**
@@ -866,7 +866,11 @@
         verify(mWifiMetrics).incrementNetworkSuggestionApiNumConnectFailure();
 
         // Verify no more broadcast were sent out.
-        verifyNoMoreInteractions(mContext);
+        mInorder.verify(mWifiPermissionsUtil, never()).enforceCanAccessScanResults(
+                anyString(), anyInt());
+        mInorder.verify(mContext,  never()).sendBroadcastAsUser(
+                any(), any());
+
     }
 
     /**
@@ -927,7 +931,7 @@
         }
 
         // Verify no more broadcast were sent out.
-        verifyNoMoreInteractions(mContext);
+        mInorder.verifyNoMoreInteractions();
     }
 
     /**
@@ -989,7 +993,7 @@
         }
 
         // Verify no more broadcast were sent out.
-        verifyNoMoreInteractions(mContext);
+        mInorder.verifyNoMoreInteractions();
     }
 
     /**
@@ -1052,7 +1056,7 @@
         }
 
         // Verify no more broadcast were sent out.
-        verifyNoMoreInteractions(mContext);
+        mInorder.verifyNoMoreInteractions();
     }
 
     /**
@@ -1084,7 +1088,10 @@
                 TEST_BSSID);
 
         // Verify no broadcast was sent out.
-        verifyNoMoreInteractions(mContext, mWifiPermissionsUtil);
+        mInorder.verify(mWifiPermissionsUtil, never()).enforceCanAccessScanResults(
+                anyString(), anyInt());
+        mInorder.verify(mContext,  never()).sendBroadcastAsUser(
+                any(), any());
     }
 
     /**
@@ -1115,7 +1122,10 @@
                 TEST_BSSID);
 
         // Verify no broadcast was sent out.
-        verifyNoMoreInteractions(mContext, mWifiPermissionsUtil);
+        mInorder.verify(mWifiPermissionsUtil, never()).enforceCanAccessScanResults(
+                anyString(), anyInt());
+        mInorder.verify(mContext,  never()).sendBroadcastAsUser(
+                any(), any());
     }
 
     /**
@@ -1152,7 +1162,7 @@
                 .enforceCanAccessScanResults(TEST_PACKAGE_1, TEST_UID_1);
 
         // Verify no broadcast was sent out.
-        verifyNoMoreInteractions(mContext, mWifiPermissionsUtil);
+        mInorder.verifyNoMoreInteractions();
     }
 
     /**
@@ -1842,10 +1852,11 @@
     }
 
     /**
-     * Verify handling of user dismissal of the user approval notification.
+     * Verify user dismissal notification when first time add suggestions and dismissal the user
+     * approval notification when framework gets scan results.
      */
     @Test
-    public void testUserApprovalNotificationDismissal() {
+    public void testUserApprovalNotificationDismissalWhenGetScanResult() {
         WifiNetworkSuggestion networkSuggestion = new WifiNetworkSuggestion(
                 WifiConfigurationTestUtil.createOpenNetwork(), true, false, TEST_UID_1,
                 TEST_PACKAGE_1);
@@ -1856,6 +1867,11 @@
         assertEquals(WifiManager.STATUS_NETWORK_SUGGESTIONS_SUCCESS,
                 mWifiNetworkSuggestionsManager.add(networkSuggestionList, TEST_UID_1,
                         TEST_PACKAGE_1));
+        validateUserApprovalNotification(TEST_APP_NAME_1);
+        // Simulate user dismissal notification.
+        sendBroadcastForUserAction(
+                NOTIFICATION_USER_DISMISSED_INTENT_ACTION, TEST_PACKAGE_1, TEST_UID_1);
+        reset(mNotificationManger);
 
         // Simulate finding the network in scan results.
         mWifiNetworkSuggestionsManager.getNetworkSuggestionsForScanDetail(
@@ -1877,10 +1893,11 @@
     }
 
     /**
-     * Verify handling of user clicking allow on the user approval notification.
+     * Verify user dismissal notification when first time add suggestions and click on allow on
+     * the user approval notification when framework gets scan results.
      */
     @Test
-    public void testUserApprovalNotificationClickOnAllow() {
+    public void testUserApprovalNotificationClickOnAllowWhenGetScanResult() {
         WifiNetworkSuggestion networkSuggestion = new WifiNetworkSuggestion(
                 WifiConfigurationTestUtil.createOpenNetwork(), true, false, TEST_UID_1,
                 TEST_PACKAGE_1);
@@ -1891,6 +1908,12 @@
         assertEquals(WifiManager.STATUS_NETWORK_SUGGESTIONS_SUCCESS,
                 mWifiNetworkSuggestionsManager.add(networkSuggestionList, TEST_UID_1,
                         TEST_PACKAGE_1));
+        validateUserApprovalNotification(TEST_APP_NAME_1);
+
+        // Simulate user dismissal notification.
+        sendBroadcastForUserAction(
+                NOTIFICATION_USER_DISMISSED_INTENT_ACTION, TEST_PACKAGE_1, TEST_UID_1);
+        reset(mNotificationManger);
 
         // Simulate finding the network in scan results.
         mWifiNetworkSuggestionsManager.getNetworkSuggestionsForScanDetail(
@@ -1916,10 +1939,11 @@
     }
 
     /**
-     * Verify handling of user clicking disallow on the user approval notification.
+     * Verify user dismissal notification when first time add suggestions and click on disallow on
+     * the user approval notification when framework gets scan results.
      */
     @Test
-    public void testUserApprovalNotificationClickOnDisallow() {
+    public void testUserApprovalNotificationClickOnDisallowWhenGetScanResult() {
         WifiNetworkSuggestion networkSuggestion = new WifiNetworkSuggestion(
                 WifiConfigurationTestUtil.createOpenNetwork(), true, false, TEST_UID_1,
                 TEST_PACKAGE_1);
@@ -1932,6 +1956,12 @@
                         TEST_PACKAGE_1));
         verify(mAppOpsManager).startWatchingMode(eq(OPSTR_CHANGE_WIFI_STATE),
                 eq(TEST_PACKAGE_1), mAppOpChangedListenerCaptor.capture());
+        validateUserApprovalNotification(TEST_APP_NAME_1);
+
+        // Simulate user dismissal notification.
+        sendBroadcastForUserAction(
+                NOTIFICATION_USER_DISMISSED_INTENT_ACTION, TEST_PACKAGE_1, TEST_UID_1);
+        reset(mNotificationManger);
 
         // Simulate finding the network in scan results.
         mWifiNetworkSuggestionsManager.getNetworkSuggestionsForScanDetail(
@@ -2048,6 +2078,96 @@
     }
 
     /**
+     * Verify handling of user clicking allow on the user approval notification when first time
+     * add suggestions.
+     */
+    @Test
+    public void testUserApprovalNotificationClickOnAllowDuringAddingSuggestions() {
+        WifiNetworkSuggestion networkSuggestion = new WifiNetworkSuggestion(
+                WifiConfigurationTestUtil.createOpenNetwork(), true, false, TEST_UID_1,
+                TEST_PACKAGE_1);
+        List<WifiNetworkSuggestion> networkSuggestionList =
+                new ArrayList<WifiNetworkSuggestion>() {{
+                    add(networkSuggestion);
+                }};
+        assertEquals(WifiManager.STATUS_NETWORK_SUGGESTIONS_SUCCESS,
+                mWifiNetworkSuggestionsManager.add(networkSuggestionList, TEST_UID_1,
+                        TEST_PACKAGE_1));
+        validateUserApprovalNotification(TEST_APP_NAME_1);
+
+        // Simulate user clicking on allow in the notification.
+        sendBroadcastForUserAction(
+                NOTIFICATION_USER_ALLOWED_APP_INTENT_ACTION, TEST_PACKAGE_1, TEST_UID_1);
+        // Cancel the notification.
+        verify(mNotificationManger).cancel(SystemMessage.NOTE_NETWORK_SUGGESTION_AVAILABLE);
+
+        // Verify config store interactions.
+        verify(mWifiConfigManager, times(2)).saveToStore(true);
+        assertTrue(mDataSource.hasNewDataToSerialize());
+
+        reset(mNotificationManger);
+        // We should not resend the notification next time the network is found in scan results.
+        mWifiNetworkSuggestionsManager.getNetworkSuggestionsForScanDetail(
+                createScanDetailForNetwork(networkSuggestion.wifiConfiguration));
+        verifyNoMoreInteractions(mNotificationManger);
+    }
+
+    /**
+     * Verify handling of user clicking Disallow on the user approval notification when first time
+     * add suggestions.
+     */
+    @Test
+    public void testUserApprovalNotificationClickOnDisallowWhenAddSuggestions() {
+        WifiNetworkSuggestion networkSuggestion = new WifiNetworkSuggestion(
+                WifiConfigurationTestUtil.createOpenNetwork(), true, false, TEST_UID_1,
+                TEST_PACKAGE_1);
+        List<WifiNetworkSuggestion> networkSuggestionList =
+                new ArrayList<WifiNetworkSuggestion>() {{
+                    add(networkSuggestion);
+                }};
+        assertEquals(WifiManager.STATUS_NETWORK_SUGGESTIONS_SUCCESS,
+                mWifiNetworkSuggestionsManager.add(networkSuggestionList, TEST_UID_1,
+                        TEST_PACKAGE_1));
+        verify(mAppOpsManager).startWatchingMode(eq(OPSTR_CHANGE_WIFI_STATE),
+                eq(TEST_PACKAGE_1), mAppOpChangedListenerCaptor.capture());
+        validateUserApprovalNotification(TEST_APP_NAME_1);
+
+        // Simulate user clicking on disallow in the notification.
+        sendBroadcastForUserAction(
+                NOTIFICATION_USER_DISALLOWED_APP_INTENT_ACTION, TEST_PACKAGE_1, TEST_UID_1);
+        // Ensure we turn off CHANGE_WIFI_STATE app-ops.
+        verify(mAppOpsManager).setMode(
+                OP_CHANGE_WIFI_STATE, TEST_UID_1,
+                TEST_PACKAGE_1, MODE_IGNORED);
+        // Cancel the notification.
+        verify(mNotificationManger).cancel(SystemMessage.NOTE_NETWORK_SUGGESTION_AVAILABLE);
+
+        // Verify config store interactions.
+        verify(mWifiConfigManager, times(2)).saveToStore(true);
+        assertTrue(mDataSource.hasNewDataToSerialize());
+
+        reset(mNotificationManger);
+
+        // Now trigger the app-ops callback to ensure we remove all of their suggestions.
+        AppOpsManager.OnOpChangedListener listener = mAppOpChangedListenerCaptor.getValue();
+        assertNotNull(listener);
+        when(mAppOpsManager.unsafeCheckOpNoThrow(
+                OPSTR_CHANGE_WIFI_STATE, TEST_UID_1,
+                TEST_PACKAGE_1))
+                .thenReturn(MODE_IGNORED);
+        listener.onOpChanged(OPSTR_CHANGE_WIFI_STATE, TEST_PACKAGE_1);
+        mLooper.dispatchAll();
+        assertTrue(mWifiNetworkSuggestionsManager.getAllNetworkSuggestions().isEmpty());
+
+        // Assuming the user re-enabled the app again & added the same suggestions back.
+        assertEquals(WifiManager.STATUS_NETWORK_SUGGESTIONS_SUCCESS,
+                mWifiNetworkSuggestionsManager.add(networkSuggestionList, TEST_UID_1,
+                        TEST_PACKAGE_1));
+        validateUserApprovalNotification(TEST_APP_NAME_1);
+        verifyNoMoreInteractions(mNotificationManger);
+    }
+
+    /**
      * Creates a scan detail corresponding to the provided network values.
      */
     private ScanDetail createScanDetailForNetwork(WifiConfiguration configuration) {