[AWARE] React to Wi-Fi state changes: disable when Wi-Fi is off

Disable Wi-Fi Aware completely when Wi-Fi is disabled (whether or not
the chip is still on - i.e. irrespective of scanning mode).

Bug: 73348515
Test: unit tests, existing integration tests (AttachTest)
Change-Id: I92ce65c86c66dba616c9e6f84204ae2a77864e63
diff --git a/service/java/com/android/server/wifi/aware/WifiAwareStateManager.java b/service/java/com/android/server/wifi/aware/WifiAwareStateManager.java
index 40a9f51..8eb31cc 100644
--- a/service/java/com/android/server/wifi/aware/WifiAwareStateManager.java
+++ b/service/java/com/android/server/wifi/aware/WifiAwareStateManager.java
@@ -23,6 +23,7 @@
 import android.hardware.wifi.V1_0.NanStatusType;
 import android.hardware.wifi.V1_2.NanDataPathChannelInfo;
 import android.location.LocationManager;
+import android.net.wifi.WifiManager;
 import android.net.wifi.aware.Characteristics;
 import android.net.wifi.aware.ConfigRequest;
 import android.net.wifi.aware.IWifiAwareDiscoverySessionCallback;
@@ -216,6 +217,7 @@
     public WifiAwareDataPathStateManager mDataPathMgr;
     private PowerManager mPowerManager;
     private LocationManager mLocationManager;
+    private WifiManager mWifiManager;
 
     private final SparseArray<WifiAwareClientState> mClients = new SparseArray<>();
     private ConfigRequest mCurrentAwareConfiguration = null;
@@ -389,6 +391,7 @@
 
         mPowerManager = mContext.getSystemService(PowerManager.class);
         mLocationManager = (LocationManager) mContext.getSystemService(Context.LOCATION_SERVICE);
+        mWifiManager = (WifiManager) mContext.getSystemService(Context.WIFI_SERVICE);
 
         IntentFilter intentFilter = new IntentFilter();
         intentFilter.addAction(Intent.ACTION_SCREEN_ON);
@@ -431,6 +434,21 @@
                 }
             }
         }, intentFilter);
+
+        intentFilter = new IntentFilter();
+        intentFilter.addAction(WifiManager.WIFI_STATE_CHANGED_ACTION);
+        mContext.registerReceiver(new BroadcastReceiver() {
+            @Override
+            public void onReceive(Context context, Intent intent) {
+                boolean isEnabled = intent.getIntExtra(WifiManager.EXTRA_WIFI_STATE,
+                        WifiManager.WIFI_STATE_UNKNOWN) == WifiManager.WIFI_STATE_ENABLED;
+                if (isEnabled) {
+                    enableUsage();
+                } else {
+                    disableUsage();
+                }
+            }
+        }, intentFilter);
     }
 
     /**
@@ -670,11 +688,15 @@
     public void enableUsage() {
         if (mSettableParameters.get(PARAM_ON_IDLE_DISABLE_AWARE) != 0
                 && mPowerManager.isDeviceIdleMode()) {
-            Log.d(TAG, "enableUsage(): while device is in IDLE mode - ignoring");
+            if (mDbg) Log.d(TAG, "enableUsage(): while device is in IDLE mode - ignoring");
             return;
         }
         if (!mLocationManager.isLocationEnabled()) {
-            Log.d(TAG, "enableUsage(): while location is disabled - ignoring");
+            if (mDbg) Log.d(TAG, "enableUsage(): while location is disabled - ignoring");
+            return;
+        }
+        if (mWifiManager.getWifiState() != WifiManager.WIFI_STATE_ENABLED) {
+            if (mDbg) Log.d(TAG, "enableUsage(): while Wi-Fi is disabled - ignoring");
             return;
         }
         Message msg = mSm.obtainMessage(MESSAGE_TYPE_COMMAND);
diff --git a/service/tests/wifitests/src/com/android/server/wifi/aware/WifiAwareDataPathStateManagerTest.java b/service/tests/wifitests/src/com/android/server/wifi/aware/WifiAwareDataPathStateManagerTest.java
index dd31e76..83be557 100644
--- a/service/tests/wifitests/src/com/android/server/wifi/aware/WifiAwareDataPathStateManagerTest.java
+++ b/service/tests/wifitests/src/com/android/server/wifi/aware/WifiAwareDataPathStateManagerTest.java
@@ -45,6 +45,7 @@
 import android.net.NetworkFactory;
 import android.net.NetworkRequest;
 import android.net.NetworkSpecifier;
+import android.net.wifi.WifiManager;
 import android.net.wifi.aware.AttachCallback;
 import android.net.wifi.aware.ConfigRequest;
 import android.net.wifi.aware.DiscoverySession;
@@ -115,6 +116,7 @@
     @Mock private WifiPermissionsUtil mWifiPermissionsUtil;
     @Mock private WifiPermissionsWrapper mPermissionsWrapperMock;
     @Mock private LocationManager mLocationManagerMock;
+    @Mock private WifiManager mMockWifiManager;
     TestAlarmManager mAlarmManager;
     private PowerManager mMockPowerManager;
 
@@ -132,6 +134,9 @@
         when(mMockContext.getSystemService(Context.ALARM_SERVICE))
                 .thenReturn(mAlarmManager.getAlarmManager());
 
+        when(mMockContext.getSystemService(Context.WIFI_SERVICE)).thenReturn(mMockWifiManager);
+        when(mMockWifiManager.getWifiState()).thenReturn(WifiManager.WIFI_STATE_ENABLED);
+
         mMockLooper = new TestLooper();
         mMockLooperHandler = new Handler(mMockLooper.getLooper());
 
diff --git a/service/tests/wifitests/src/com/android/server/wifi/aware/WifiAwareStateManagerTest.java b/service/tests/wifitests/src/com/android/server/wifi/aware/WifiAwareStateManagerTest.java
index 7ada6ae..e6586e3 100644
--- a/service/tests/wifitests/src/com/android/server/wifi/aware/WifiAwareStateManagerTest.java
+++ b/service/tests/wifitests/src/com/android/server/wifi/aware/WifiAwareStateManagerTest.java
@@ -50,6 +50,7 @@
 import android.hardware.wifi.V1_0.NanStatusType;
 import android.location.LocationManager;
 import android.net.ConnectivityManager;
+import android.net.wifi.WifiManager;
 import android.net.wifi.aware.ConfigRequest;
 import android.net.wifi.aware.IWifiAwareDiscoverySessionCallback;
 import android.net.wifi.aware.IWifiAwareEventCallback;
@@ -116,8 +117,10 @@
     @Mock private LocationManager mLocationManagerMock;
     TestAlarmManager mAlarmManager;
     private PowerManager mMockPowerManager;
+    @Mock private WifiManager mMockWifiManager;
     private BroadcastReceiver mPowerBcastReceiver;
     private BroadcastReceiver mLocationModeReceiver;
+    private BroadcastReceiver mWifiStateChangedReceiver;
     @Mock private WifiAwareDataPathStateManager mMockAwareDataPathStatemanager;
 
     @Rule
@@ -136,6 +139,9 @@
         when(mMockContext.getSystemService(Context.ALARM_SERVICE))
                 .thenReturn(mAlarmManager.getAlarmManager());
 
+        when(mMockContext.getSystemService(Context.WIFI_SERVICE)).thenReturn(mMockWifiManager);
+        when(mMockWifiManager.getWifiState()).thenReturn(WifiManager.WIFI_STATE_ENABLED);
+
         mMockLooper = new TestLooper();
 
         IPowerManager powerManagerService = mock(IPowerManager.class);
@@ -170,10 +176,11 @@
                 mWifiPermissionsUtil, mPermissionsWrapperMock);
         mDut.startLate();
         mMockLooper.dispatchAll();
-        verify(mMockContext, times(2)).registerReceiver(bcastRxCaptor.capture(),
+        verify(mMockContext, times(3)).registerReceiver(bcastRxCaptor.capture(),
                 any(IntentFilter.class));
         mPowerBcastReceiver = bcastRxCaptor.getAllValues().get(0);
         mLocationModeReceiver = bcastRxCaptor.getAllValues().get(1);
+        mWifiStateChangedReceiver = bcastRxCaptor.getAllValues().get(2);
         installMocksInStateManager(mDut, mMockAwareDataPathStatemanager);
     }
 
@@ -3105,6 +3112,16 @@
         simulatePowerStateChangeInteractive(false);
         mMockLooper.dispatchAll();
 
+        // and same for other gating changes -> no changes
+        simulateLocationModeChange(false);
+        simulateWifiStateChange(false);
+        mMockLooper.dispatchAll();
+
+        // and same for other gating changes -> no changes
+        simulateLocationModeChange(true);
+        simulateWifiStateChange(true);
+        mMockLooper.dispatchAll();
+
         // (5) power state change: DOZE OFF
         simulatePowerStateChangeDoze(false);
         mMockLooper.dispatchAll();
@@ -3155,6 +3172,16 @@
         mDut.onDisableResponse(transactionId.getValue(), NanStatusType.SUCCESS);
         validateCorrectAwareStatusChangeBroadcast(inOrder, false);
 
+        // disable other gating feature -> no change
+        simulatePowerStateChangeDoze(true);
+        simulateWifiStateChange(false);
+        mMockLooper.dispatchAll();
+
+        // enable other gating feature -> no change
+        simulatePowerStateChangeDoze(false);
+        simulateWifiStateChange(true);
+        mMockLooper.dispatchAll();
+
         // (4) location mode change: enable
         simulateLocationModeChange(true);
         mMockLooper.dispatchAll();
@@ -3163,6 +3190,66 @@
         verifyNoMoreInteractions(mMockNativeManager, mMockNative, mockCallback);
     }
 
+    /**
+     * Validate aware enable/disable during Wi-Fi State transitions.
+     */
+    @Test
+    public void testEnableDisableOnWifiStateChanges() throws Exception {
+        final int clientId = 188;
+        final int uid = 1000;
+        final int pid = 2000;
+        final String callingPackage = "com.google.somePackage";
+
+        ConfigRequest configRequest = new ConfigRequest.Builder().build();
+
+        ArgumentCaptor<Short> transactionId = ArgumentCaptor.forClass(Short.class);
+        IWifiAwareEventCallback mockCallback = mock(IWifiAwareEventCallback.class);
+        InOrder inOrder = inOrder(mMockContext, mMockNativeManager, mMockNative, mockCallback);
+        inOrder.verify(mMockNativeManager).start(any(Handler.class));
+
+        mDut.enableUsage();
+        mMockLooper.dispatchAll();
+        inOrder.verify(mMockNativeManager).tryToGetAware();
+        inOrder.verify(mMockNative).getCapabilities(transactionId.capture());
+        mDut.onCapabilitiesUpdateResponse(transactionId.getValue(), getCapabilities());
+        mMockLooper.dispatchAll();
+        inOrder.verify(mMockNativeManager).releaseAware();
+
+        // (1) connect
+        mDut.connect(clientId, uid, pid, callingPackage, mockCallback, configRequest, false);
+        mMockLooper.dispatchAll();
+        inOrder.verify(mMockNativeManager).tryToGetAware();
+        inOrder.verify(mMockNative).enableAndConfigure(transactionId.capture(),
+                eq(configRequest), eq(false), eq(true), eq(true), eq(false));
+        mDut.onConfigSuccessResponse(transactionId.getValue());
+        mMockLooper.dispatchAll();
+        inOrder.verify(mockCallback).onConnectSuccess(clientId);
+
+        // (3) wifi state change: disable
+        simulateWifiStateChange(false);
+        mMockLooper.dispatchAll();
+        inOrder.verify(mMockNative).disable(transactionId.capture());
+        mDut.onDisableResponse(transactionId.getValue(), NanStatusType.SUCCESS);
+        validateCorrectAwareStatusChangeBroadcast(inOrder, false);
+
+        // disable other gating feature -> no change
+        simulatePowerStateChangeDoze(true);
+        simulateLocationModeChange(false);
+        mMockLooper.dispatchAll();
+
+        // enable other gating feature -> no change
+        simulatePowerStateChangeDoze(false);
+        simulateLocationModeChange(true);
+        mMockLooper.dispatchAll();
+
+        // (4) wifi state change: enable
+        simulateWifiStateChange(true);
+        mMockLooper.dispatchAll();
+        validateCorrectAwareStatusChangeBroadcast(inOrder, true);
+
+        verifyNoMoreInteractions(mMockNativeManager, mMockNative, mockCallback);
+    }
+
     /*
      * Tests of internal state of WifiAwareStateManager: very limited (not usually
      * a good idea). However, these test that the internal state is cleaned-up
@@ -3354,6 +3441,19 @@
         mLocationModeReceiver.onReceive(mMockContext, intent);
     }
 
+    /**
+     * Simulate Wi-Fi state change: broadcast state change and modify the API return value.
+     */
+    private void simulateWifiStateChange(boolean isWifiOn) {
+        when(mMockWifiManager.getWifiState()).thenReturn(
+                isWifiOn ? WifiManager.WIFI_STATE_ENABLED : WifiManager.WIFI_STATE_DISABLED);
+
+        Intent intent = new Intent(WifiManager.WIFI_STATE_CHANGED_ACTION);
+        intent.putExtra(WifiManager.EXTRA_WIFI_STATE,
+                isWifiOn ? WifiManager.WIFI_STATE_ENABLED : WifiManager.WIFI_STATE_DISABLED);
+        mWifiStateChangedReceiver.onReceive(mMockContext, intent);
+    }
+
     private static Capabilities getCapabilities() {
         Capabilities cap = new Capabilities();
         cap.maxConcurrentAwareClusters = 1;