Disable partial scan if firmware roaming control is enabled

We used to request partial connectivity scan instead of full
band scan when screen is on and there is traffic over wifi.

Partial scans only cover channels known for APs with the
same SSID. Since intra-SSID roaming is controlled by firmware
on some devices, we don't need these partial scans anymore.

Bug: 69321070
Test: compile, unit tests, integration test
Change-Id: I943b84e8a04ebc9ac1c47cca7cdcef2bf98f30ad
diff --git a/service/java/com/android/server/wifi/WifiConnectivityManager.java b/service/java/com/android/server/wifi/WifiConnectivityManager.java
index 458f73a..c67e7c6 100644
--- a/service/java/com/android/server/wifi/WifiConnectivityManager.java
+++ b/service/java/com/android/server/wifi/WifiConnectivityManager.java
@@ -814,24 +814,38 @@
             }
         }
 
+        boolean isScanNeeded = true;
         boolean isFullBandScan = true;
+        boolean isTrafficOverThreshold = mWifiInfo.txSuccessRate > mFullScanMaxTxRate
+                || mWifiInfo.rxSuccessRate > mFullScanMaxRxRate;
 
-        // If the WiFi traffic is heavy, only partial scan is initiated.
-        if (mWifiState == WIFI_STATE_CONNECTED
-                && (mWifiInfo.txSuccessRate > mFullScanMaxTxRate
-                    || mWifiInfo.rxSuccessRate > mFullScanMaxRxRate)) {
-            localLog("No full band scan due to ongoing traffic");
-            isFullBandScan = false;
+        // If the WiFi traffic is heavy, only partial scan is proposed.
+        if (mWifiState == WIFI_STATE_CONNECTED && isTrafficOverThreshold) {
+            // If only partial scan is proposed and firmware roaming control is supported,
+            // we will not issue any scan because firmware roaming will take care of
+            // intra-SSID roam.
+            if (mConnectivityHelper.isFirmwareRoamingSupported()) {
+                localLog("No partial scan because firmware roaming is supported.");
+                isScanNeeded = false;
+            } else {
+                localLog("No full band scan due to ongoing traffic");
+                isFullBandScan = false;
+            }
         }
 
-        mLastPeriodicSingleScanTimeStamp = currentTimeStamp;
-        startSingleScan(isFullBandScan, WIFI_WORK_SOURCE);
-        schedulePeriodicScanTimer(mPeriodicSingleScanInterval);
+        if (isScanNeeded) {
+            mLastPeriodicSingleScanTimeStamp = currentTimeStamp;
+            startSingleScan(isFullBandScan, WIFI_WORK_SOURCE);
+            schedulePeriodicScanTimer(mPeriodicSingleScanInterval);
 
-        // Set up the next scan interval in an exponential backoff fashion.
-        mPeriodicSingleScanInterval *= 2;
-        if (mPeriodicSingleScanInterval >  MAX_PERIODIC_SCAN_INTERVAL_MS) {
-            mPeriodicSingleScanInterval = MAX_PERIODIC_SCAN_INTERVAL_MS;
+            // Set up the next scan interval in an exponential backoff fashion.
+            mPeriodicSingleScanInterval *= 2;
+            if (mPeriodicSingleScanInterval >  MAX_PERIODIC_SCAN_INTERVAL_MS) {
+                mPeriodicSingleScanInterval = MAX_PERIODIC_SCAN_INTERVAL_MS;
+            }
+        } else {
+            // Since we already skipped this scan, keep the same scan interval for next scan.
+            schedulePeriodicScanTimer(mPeriodicSingleScanInterval);
         }
     }
 
diff --git a/tests/wifitests/src/com/android/server/wifi/WifiConnectivityManagerTest.java b/tests/wifitests/src/com/android/server/wifi/WifiConnectivityManagerTest.java
index 4fabd9d..30f823a 100644
--- a/tests/wifitests/src/com/android/server/wifi/WifiConnectivityManagerTest.java
+++ b/tests/wifitests/src/com/android/server/wifi/WifiConnectivityManagerTest.java
@@ -1027,11 +1027,12 @@
      * Verify that we perform partial scan when the currently connected network's tx/rx success
      * rate is high and when the currently connected network is present in scan
      * cache in WifiConfigManager.
+     * WifiConnectivityManager does partial scan only when firmware roaming is not supported.
      *
-     * Expected behavior: WifiConnectivityManager does full band scan.
+     * Expected behavior: WifiConnectivityManager does partial scan.
      */
     @Test
-    public void checkSingleScanSettingsWhenConnectedWithHighDataRate() {
+    public void checkPartialScanRequestedWithHighDataRateWithoutFwRoaming() {
         mWifiInfo.txSuccessRate = mFullScanMaxTxPacketRate * 2;
         mWifiInfo.rxSuccessRate = mFullScanMaxRxPacketRate * 2;
 
@@ -1044,6 +1045,7 @@
                 .thenReturn(new WifiConfiguration());
         when(mWifiConfigManager.fetchChannelSetForNetworkForPartialScan(anyInt(), anyLong(),
                 anyInt())).thenReturn(channelList);
+        when(mWifiConnectivityHelper.isFirmwareRoamingSupported()).thenReturn(false);
 
         doAnswer(new AnswerWithArguments() {
             public void answer(ScanSettings settings, ScanListener listener,
@@ -1066,6 +1068,52 @@
     }
 
     /**
+     * Verify that we skip the partial scan when:
+     * 1. The currently connected network's tx/rx success rate is high.
+     * 2. When the currently connected network is present in scan
+     * cache in WifiConfigManager.
+     * 3. When firmware roaming is supported.
+     * Expected behavior: WifiConnectivityManager does no scan, but periodic scans
+     * are still scheduled.
+     */
+    @Test
+    public void checkPartialScanSkippedWithHighDataRateWithFwRoaming() {
+        mWifiInfo.txSuccessRate = mFullScanMaxTxPacketRate * 2;
+        mWifiInfo.rxSuccessRate = mFullScanMaxRxPacketRate * 2;
+
+        long currentTimeStamp = CURRENT_SYSTEM_TIME_MS;
+        when(mClock.getElapsedSinceBootMillis()).thenReturn(currentTimeStamp);
+
+        final HashSet<Integer> channelList = new HashSet<>();
+        channelList.add(1);
+        channelList.add(2);
+        channelList.add(3);
+
+        when(mWifiStateMachine.getCurrentWifiConfiguration())
+                .thenReturn(new WifiConfiguration());
+        when(mWifiConfigManager.fetchChannelSetForNetworkForPartialScan(anyInt(), anyLong(),
+                anyInt())).thenReturn(channelList);
+        // No scan will be requested when firmware roaming control is not supported.
+        when(mWifiConnectivityHelper.isFirmwareRoamingSupported()).thenReturn(true);
+
+        // Set screen to ON
+        mWifiConnectivityManager.handleScreenStateChanged(true);
+
+        // Set WiFi to connected state to trigger periodic scan
+        mWifiConnectivityManager.handleConnectionStateChanged(
+                WifiConnectivityManager.WIFI_STATE_CONNECTED);
+
+        verify(mWifiScanner, never()).startScan(anyObject(), anyObject(), anyObject());
+
+        // Get the first periodic scan interval to check that we are still scheduling
+        // periodic scans.
+        long firstIntervalMs = mAlarmManager
+                .getTriggerTimeMillis(WifiConnectivityManager.PERIODIC_SCAN_TIMER_TAG)
+                - currentTimeStamp;
+        assertEquals(firstIntervalMs, WifiConnectivityManager.PERIODIC_SCAN_INTERVAL_MS);
+    }
+
+    /**
      * Verify that we fall back to full band scan when the currently connected network's tx/rx
      * success rate is high and the currently connected network is not present in scan cache in
      * WifiConfigManager. This is simulated by returning an empty hashset in |makeChannelList|.