WCM: forced connectivity scan

WCM starts a full band single scan when user forces a connectivity
scan and wait for the full band scan results to make network
selection.

Bug: 30897947
Test: unit tests and manual test
Change-Id: Ie220c25dd60a0534afbf33f62691f32515f7062b
diff --git a/service/java/com/android/server/wifi/WifiConnectivityManager.java b/service/java/com/android/server/wifi/WifiConnectivityManager.java
index 1c6ba64..49a2842 100644
--- a/service/java/com/android/server/wifi/WifiConnectivityManager.java
+++ b/service/java/com/android/server/wifi/WifiConnectivityManager.java
@@ -150,6 +150,7 @@
     private long mLastPeriodicSingleScanTimeStamp = RESET_TIME_STAMP;
     private boolean mPnoScanStarted = false;
     private boolean mPeriodicScanTimerSet = false;
+    private boolean mWaitForFullBandScanResults = false;
 
     // PNO settings
     private int mMin5GHzRssi;
@@ -325,9 +326,21 @@
         public void onResults(WifiScanner.ScanData[] results) {
             if (!mWifiEnabled || !mWifiConnectivityManagerEnabled) {
                 clearScanDetails();
+                mWaitForFullBandScanResults = false;
                 return;
             }
 
+            // Full band scan results only.
+            if (mWaitForFullBandScanResults) {
+                if (!results[0].isAllChannelsScanned()) {
+                    localLog("AllSingleScanListener waiting for full band scan results.");
+                    clearScanDetails();
+                    return;
+                } else {
+                    mWaitForFullBandScanResults = false;
+                }
+            }
+
             boolean wasConnectAttempted = handleScanResults(mScanDetails, "AllSingleScanListener");
             clearScanDetails();
 
@@ -1078,7 +1091,8 @@
     public void forceConnectivityScan() {
         Log.i(TAG, "forceConnectivityScan");
 
-        startConnectivityScan(SCAN_IMMEDIATELY);
+        mWaitForFullBandScanResults = true;
+        startSingleScan(true);
     }
 
     /**
@@ -1122,6 +1136,7 @@
             stopConnectivityScan();
             resetLastPeriodicSingleScanTimeStamp();
             mLastConnectionAttemptBssid = null;
+            mWaitForFullBandScanResults = false;
         } else if (mWifiConnectivityManagerEnabled) {
            startConnectivityScan(SCAN_IMMEDIATELY);
         }
@@ -1139,6 +1154,7 @@
             stopConnectivityScan();
             resetLastPeriodicSingleScanTimeStamp();
             mLastConnectionAttemptBssid = null;
+            mWaitForFullBandScanResults = false;
         } else if (mWifiEnabled) {
            startConnectivityScan(SCAN_IMMEDIATELY);
         }
diff --git a/service/java/com/android/server/wifi/WifiStateMachine.java b/service/java/com/android/server/wifi/WifiStateMachine.java
index 5425181..a66a68f 100644
--- a/service/java/com/android/server/wifi/WifiStateMachine.java
+++ b/service/java/com/android/server/wifi/WifiStateMachine.java
@@ -5607,8 +5607,11 @@
                             config, disableOthers, message.sendingUid);
                     if (!ok) {
                         messageHandlingStatus = MESSAGE_HANDLING_STATUS_FAIL;
-                    } else if (disableOthers) {
-                        mTargetNetworkId = netId;
+                    } else {
+                        if (disableOthers) {
+                            mTargetNetworkId = netId;
+                        }
+                        mWifiConnectivityManager.forceConnectivityScan();
                     }
 
                     replyToMessage(message, message.what, ok ? SUCCESS : FAILURE);
diff --git a/tests/wifitests/src/com/android/server/wifi/WifiConnectivityManagerTest.java b/tests/wifitests/src/com/android/server/wifi/WifiConnectivityManagerTest.java
index b1f88ec..281ffa1 100644
--- a/tests/wifitests/src/com/android/server/wifi/WifiConnectivityManagerTest.java
+++ b/tests/wifitests/src/com/android/server/wifi/WifiConnectivityManagerTest.java
@@ -33,6 +33,7 @@
 import android.net.wifi.WifiScanner;
 import android.net.wifi.WifiScanner.PnoScanListener;
 import android.net.wifi.WifiScanner.PnoSettings;
+import android.net.wifi.WifiScanner.ScanData;
 import android.net.wifi.WifiScanner.ScanListener;
 import android.net.wifi.WifiScanner.ScanSettings;
 import android.net.wifi.WifiSsid;
@@ -71,6 +72,7 @@
         mWifiStateMachine = mockWifiStateMachine();
         mWifiConfigManager = mockWifiConfigManager();
         mWifiInfo = getWifiInfo();
+        mScanData = mockScanData();
         mWifiScanner = mockWifiScanner();
         mWifiQNS = mockWifiQualifiedNetworkSelector();
         mWifiConnectivityManager = new WifiConnectivityManager(mContext, mWifiStateMachine,
@@ -96,6 +98,7 @@
     private WifiQualifiedNetworkSelector mWifiQNS;
     private WifiStateMachine mWifiStateMachine;
     private WifiScanner mWifiScanner;
+    private ScanData mScanData;
     private WifiConfigManager mWifiConfigManager;
     private WifiInfo mWifiInfo;
     private Clock mClock = mock(Clock.class);
@@ -128,6 +131,14 @@
         return context;
     }
 
+    ScanData mockScanData() {
+        ScanData scanData = mock(ScanData.class);
+
+        when(scanData.isAllChannelsScanned()).thenReturn(true);
+
+        return scanData;
+    }
+
     WifiScanner mockWifiScanner() {
         WifiScanner scanner = mock(WifiScanner.class);
         ArgumentCaptor<ScanListener> allSingleScanListenerCaptor =
@@ -135,9 +146,8 @@
 
         doNothing().when(scanner).registerScanListener(allSingleScanListenerCaptor.capture());
 
-        // dummy scan results. QNS PeriodicScanListener bulids scanDetails from
-        // the fullScanResult and doesn't really use results
-        final WifiScanner.ScanData[] scanDatas = new WifiScanner.ScanData[1];
+        ScanData[] scanDatas = new ScanData[1];
+        scanDatas[0] = mScanData;
 
         // do a synchronous answer for the ScanListener callbacks
         doAnswer(new AnswerWithArguments() {
@@ -756,8 +766,9 @@
         currentTimeStamp += 2000;
         when(mClock.elapsedRealtime()).thenReturn(currentTimeStamp);
 
-        // Force a connectivity scan
-        mWifiConnectivityManager.forceConnectivityScan();
+        // Allow untrusted networks so WifiConnectivityManager starts a periodic scan
+        // immediately.
+        mWifiConnectivityManager.setUntrustedConnectionAllowed(true);
 
         // Get the second periodic scan actual time stamp. Note, this scan is not
         // started from the AlarmManager.
@@ -944,4 +955,41 @@
         verify(mWifiStateMachine).autoConnectToNetwork(
                 CANDIDATE_NETWORK_ID, CANDIDATE_BSSID);
     }
+
+    /**
+     *  Verify that a forced connectivity scan waits for full band scan
+     *  results.
+     *
+     * Expected behavior: WifiConnectivityManager doesn't invoke
+     * WifiStateMachine.autoConnectToNetwork() when full band scan
+     * results are not available.
+     */
+    @Test
+    public void waitForFullBandScanResults() {
+        // Set WiFi to connected state.
+        mWifiConnectivityManager.handleConnectionStateChanged(
+                WifiConnectivityManager.WIFI_STATE_CONNECTED);
+
+        // Set up as partial scan results.
+        when(mScanData.isAllChannelsScanned()).thenReturn(false);
+
+        // Force a connectivity scan which enables WifiConnectivityManager
+        // to wait for full band scan results.
+        mWifiConnectivityManager.forceConnectivityScan();
+
+        // No roaming because no full band scan results.
+        verify(mWifiStateMachine, times(0)).autoConnectToNetwork(
+                CANDIDATE_NETWORK_ID, CANDIDATE_BSSID);
+
+        // Set up as full band scan results.
+        when(mScanData.isAllChannelsScanned()).thenReturn(true);
+
+        // Force a connectivity scan which enables WifiConnectivityManager
+        // to wait for full band scan results.
+        mWifiConnectivityManager.forceConnectivityScan();
+
+        // Roaming attempt because full band scan results are available.
+        verify(mWifiStateMachine).autoConnectToNetwork(
+                CANDIDATE_NETWORK_ID, CANDIDATE_BSSID);
+    }
 }