[HDM] Interface availability semantics change to call on change

Modify the interface availability listener semantics:

WAS: call any time interface is available

NOW:
- Called on interface available or not available
- Only called if that specific listener was not called before
  or called with a different value

Bug: 69863101
Test: unit tests, integration time, manual test
Change-Id: I152ce8d813194f4fb178a1e9b73cf9e1b6815cb7
diff --git a/service/java/com/android/server/wifi/HalDeviceManager.java b/service/java/com/android/server/wifi/HalDeviceManager.java
index 3cc5504..facb065 100644
--- a/service/java/com/android/server/wifi/HalDeviceManager.java
+++ b/service/java/com/android/server/wifi/HalDeviceManager.java
@@ -79,10 +79,10 @@
     public HalDeviceManager(Clock clock) {
         mClock = clock;
 
-        mInterfaceAvailableForRequestListeners.put(IfaceType.STA, new HashSet<>());
-        mInterfaceAvailableForRequestListeners.put(IfaceType.AP, new HashSet<>());
-        mInterfaceAvailableForRequestListeners.put(IfaceType.P2P, new HashSet<>());
-        mInterfaceAvailableForRequestListeners.put(IfaceType.NAN, new HashSet<>());
+        mInterfaceAvailableForRequestListeners.put(IfaceType.STA, new HashMap<>());
+        mInterfaceAvailableForRequestListeners.put(IfaceType.AP, new HashMap<>());
+        mInterfaceAvailableForRequestListeners.put(IfaceType.P2P, new HashMap<>());
+        mInterfaceAvailableForRequestListeners.put(IfaceType.NAN, new HashMap<>());
     }
 
     /* package */ void enableVerboseLogging(int verbose) {
@@ -333,12 +333,22 @@
     public void registerInterfaceAvailableForRequestListener(int ifaceType,
             @NonNull InterfaceAvailableForRequestListener listener, @Nullable Handler handler) {
         if (VDBG) {
-            Log.d(TAG, "registerInterfaceAvailableForRequestListener: ifaceType=" + ifaceType);
+            Log.d(TAG, "registerInterfaceAvailableForRequestListener: ifaceType=" + ifaceType
+                    + ", listener=" + listener + ", handler=" + handler);
         }
 
         synchronized (mLock) {
-            mInterfaceAvailableForRequestListeners.get(ifaceType).add(
-                    new InterfaceAvailableForRequestListenerProxy(listener, handler));
+            InterfaceAvailableForRequestListenerProxy proxy =
+                    new InterfaceAvailableForRequestListenerProxy(listener, handler);
+            if (mInterfaceAvailableForRequestListeners.get(ifaceType).containsKey(proxy)) {
+                if (VDBG) {
+                    Log.d(TAG,
+                            "registerInterfaceAvailableForRequestListener: dup listener skipped: "
+                                    + listener);
+                }
+                return;
+            }
+            mInterfaceAvailableForRequestListeners.get(ifaceType).put(proxy, null);
         }
 
         WifiChipInfo[] chipInfos = getAllChipInfo();
@@ -362,14 +372,8 @@
         }
 
         synchronized (mLock) {
-            Iterator<InterfaceAvailableForRequestListenerProxy> it =
-                    mInterfaceAvailableForRequestListeners.get(ifaceType).iterator();
-            while (it.hasNext()) {
-                if (it.next().mListener == listener) {
-                    it.remove();
-                    return;
-                }
-            }
+            mInterfaceAvailableForRequestListeners.get(ifaceType).remove(
+                    new InterfaceAvailableForRequestListenerProxy(listener, null));
         }
     }
 
@@ -415,15 +419,15 @@
     }
 
     /**
-     * Called when an interface type is possibly available for creation.
+     * Called when an interface type availability for creation is changed.
      */
     public interface InterfaceAvailableForRequestListener {
         /**
-         * Registered when an interface type could be requested. Registered with
+         * Called when an interface type availability for creation is updated. Registered with
          * registerInterfaceAvailableForRequestListener() and unregistered with
          * unregisterInterfaceAvailableForRequestListener().
          */
-        void onAvailableForRequest();
+        void onAvailabilityChanged(boolean isAvailable);
     }
 
     /**
@@ -488,7 +492,7 @@
     private IWifi mWifi;
     private final WifiEventCallback mWifiEventCallback = new WifiEventCallback();
     private final Set<ManagerStatusListenerProxy> mManagerStatusListeners = new HashSet<>();
-    private final SparseArray<Set<InterfaceAvailableForRequestListenerProxy>>
+    private final SparseArray<Map<InterfaceAvailableForRequestListenerProxy, Boolean>>
             mInterfaceAvailableForRequestListeners = new SparseArray<>();
     private final SparseArray<IWifiChipEventCallback.Stub> mDebugCallbacks = new SparseArray<>();
 
@@ -1882,21 +1886,30 @@
             WifiChipInfo[] chipInfos) {
         if (VDBG) Log.d(TAG, "dispatchAvailableForRequestListenersForType: ifaceType=" + ifaceType);
 
-        Set<InterfaceAvailableForRequestListenerProxy> listeners =
-                mInterfaceAvailableForRequestListeners.get(ifaceType);
+        synchronized (mLock) {
+            Map<InterfaceAvailableForRequestListenerProxy, Boolean> listeners =
+                    mInterfaceAvailableForRequestListeners.get(ifaceType);
 
-        if (listeners.size() == 0) {
-            return;
-        }
+            if (listeners.size() == 0) {
+                return;
+            }
 
-        if (!isItPossibleToCreateIface(chipInfos, ifaceType)) {
-            if (VDBG) Log.d(TAG, "Creating interface type isn't possible: ifaceType=" + ifaceType);
-            return;
-        }
+            boolean isAvailable = isItPossibleToCreateIface(chipInfos, ifaceType);
 
-        if (VDBG) Log.d(TAG, "It is possible to create the interface type: ifaceType=" + ifaceType);
-        for (InterfaceAvailableForRequestListenerProxy listener : listeners) {
-            listener.trigger();
+            if (VDBG) {
+                Log.d(TAG, "Interface available for: ifaceType=" + ifaceType + " = " + isAvailable);
+            }
+            for (Map.Entry<InterfaceAvailableForRequestListenerProxy, Boolean> listenerEntry :
+                    listeners.entrySet()) {
+                if (listenerEntry.getValue() == null || listenerEntry.getValue() != isAvailable) {
+                    if (VDBG) {
+                        Log.d(TAG, "Interface available listener dispatched: ifaceType=" + ifaceType
+                                + ", listener=" + listenerEntry.getKey());
+                    }
+                    listenerEntry.getKey().triggerWithArg(isAvailable);
+                }
+                listenerEntry.setValue(isAvailable);
+            }
         }
     }
 
@@ -1964,7 +1977,18 @@
             }
         }
 
-        protected abstract void action();
+        void triggerWithArg(boolean arg) {
+            if (mHandler != null) {
+                mHandler.post(() -> {
+                    actionWithArg(arg);
+                });
+            } else {
+                actionWithArg(arg);
+            }
+        }
+
+        protected void action() {}
+        protected void actionWithArg(boolean arg) {}
 
         ListenerProxy(LISTENER listener, Handler handler, String tag) {
             mListener = listener;
@@ -1996,8 +2020,8 @@
         }
 
         @Override
-        protected void action() {
-            mListener.onAvailableForRequest();
+        protected void actionWithArg(boolean isAvailable) {
+            mListener.onAvailabilityChanged(isAvailable);
         }
     }
 
diff --git a/service/java/com/android/server/wifi/aware/WifiAwareNativeManager.java b/service/java/com/android/server/wifi/aware/WifiAwareNativeManager.java
index dd19d7b..89b2417 100644
--- a/service/java/com/android/server/wifi/aware/WifiAwareNativeManager.java
+++ b/service/java/com/android/server/wifi/aware/WifiAwareNativeManager.java
@@ -161,9 +161,11 @@
     private class InterfaceAvailableForRequestListener implements
             HalDeviceManager.InterfaceAvailableForRequestListener {
         @Override
-        public void onAvailableForRequest() {
-            if (mDbg) Log.v(TAG, "Interface is possibly available");
-            tryToGetAware();
+        public void onAvailabilityChanged(boolean isAvailable) {
+            if (mDbg) Log.d(TAG, "Interface availability = " + isAvailable);
+            if (isAvailable) {
+                tryToGetAware();
+            }
         }
     }
 
diff --git a/tests/wifitests/src/com/android/server/wifi/HalDeviceManagerTest.java b/tests/wifitests/src/com/android/server/wifi/HalDeviceManagerTest.java
index f9c3c3f..3e3ce42 100644
--- a/tests/wifitests/src/com/android/server/wifi/HalDeviceManagerTest.java
+++ b/tests/wifitests/src/com/android/server/wifi/HalDeviceManagerTest.java
@@ -313,6 +313,8 @@
         HalDeviceManager.InterfaceAvailableForRequestListener nanAvailListener = mock(
                 HalDeviceManager.InterfaceAvailableForRequestListener.class);
 
+        InOrder availInOrder = inOrder(staAvailListener, nanAvailListener);
+
         // Request STA
         IWifiIface staIface = validateInterfaceSequence(chipMock,
                 false, // chipModeValid
@@ -324,6 +326,7 @@
                 staDestroyedListener, // destroyedListener
                 staAvailListener // availableListener
         );
+        availInOrder.verify(staAvailListener).onAvailabilityChanged(false);
 
         // Request NAN
         IWifiIface nanIface = validateInterfaceSequence(chipMock,
@@ -336,19 +339,25 @@
                 nanDestroyedListener, // destroyedListener
                 nanAvailListener // availableListener
         );
+        availInOrder.verify(nanAvailListener).onAvailabilityChanged(false);
 
         // fiddle with the "chip" by removing the STA
         chipMock.interfaceNames.get(IfaceType.STA).remove("wlan0");
 
         // now try to request another NAN
         IWifiIface nanIface2 = mDut.createNanIface(nanDestroyedListener, mHandler);
+        collector.checkThat("NAN can't be created", nanIface2, IsNull.nullValue());
+
         mDut.registerInterfaceAvailableForRequestListener(IfaceType.NAN, nanAvailListener,
                 mHandler);
-        collector.checkThat("NAN can't be created", nanIface2, IsNull.nullValue());
+        mTestLooper.dispatchAll();
+
+        // extra (apparently duplicate) call since everything was cleaned-up once a cache mismatch
+        // was detected - so this is a call on a new registration
+        availInOrder.verify(nanAvailListener).onAvailabilityChanged(false);
 
         // verify that Wi-Fi is shut-down: should also get all onDestroyed messages that are
         // registered (even if they seem out-of-sync to chip)
-        mTestLooper.dispatchAll();
         verify(mWifiMock, times(2)).stop();
         verify(mManagerStatusListenerMock, times(2)).onStatusChanged();
         verify(staDestroyedListener).onDestroyed(getName(staIface));
@@ -399,12 +408,14 @@
                 mHandler);
         mTestLooper.dispatchAll();
 
+        verify(staAvailListener).onAvailabilityChanged(false);
+
         // remove STA interface -> should trigger callbacks
         mDut.removeIface(staIface);
         mTestLooper.dispatchAll();
 
         // verify: only a single trigger
-        verify(staAvailListener).onAvailableForRequest();
+        verify(staAvailListener).onAvailabilityChanged(true);
 
         verifyNoMoreInteractions(staAvailListener);
     }
@@ -516,7 +527,7 @@
     @Test
     public void testCreateStaInterfaceNoInitModeTestChipV1() throws Exception {
         runCreateSingleXxxInterfaceNoInitMode(new TestChipV1(), IfaceType.STA, "wlan0",
-                TestChipV1.STA_CHIP_MODE_ID, 1);
+                TestChipV1.STA_CHIP_MODE_ID, false);
     }
 
     /**
@@ -525,7 +536,7 @@
     @Test
     public void testCreateApInterfaceNoInitModeTestChipV1() throws Exception {
         runCreateSingleXxxInterfaceNoInitMode(new TestChipV1(), IfaceType.AP, "wlan0",
-                TestChipV1.AP_CHIP_MODE_ID, 1);
+                TestChipV1.AP_CHIP_MODE_ID, false);
     }
 
     /**
@@ -534,7 +545,7 @@
     @Test
     public void testCreateP2pInterfaceNoInitModeTestChipV1() throws Exception {
         runCreateSingleXxxInterfaceNoInitMode(new TestChipV1(), IfaceType.P2P, "p2p0",
-                TestChipV1.STA_CHIP_MODE_ID, 1);
+                TestChipV1.STA_CHIP_MODE_ID, false);
     }
 
     /**
@@ -543,7 +554,7 @@
     @Test
     public void testCreateNanInterfaceNoInitModeTestChipV1() throws Exception {
         runCreateSingleXxxInterfaceNoInitMode(new TestChipV1(), IfaceType.NAN, "wlan0",
-                TestChipV1.STA_CHIP_MODE_ID, 1);
+                TestChipV1.STA_CHIP_MODE_ID, false);
     }
 
     // TestChipV2
@@ -558,7 +569,7 @@
         // and we get callback 2 after destroying the first STA (since we can create another STA -
         // as expected).
         runCreateSingleXxxInterfaceNoInitMode(new TestChipV2(), IfaceType.STA, "wlan0",
-                TestChipV2.CHIP_MODE_ID, 2);
+                TestChipV2.CHIP_MODE_ID, true);
     }
 
     /**
@@ -567,7 +578,7 @@
     @Test
     public void testCreateApInterfaceNoInitModeTestChipV2() throws Exception {
         runCreateSingleXxxInterfaceNoInitMode(new TestChipV2(), IfaceType.AP, "wlan0",
-                TestChipV2.CHIP_MODE_ID, 1);
+                TestChipV2.CHIP_MODE_ID, false);
     }
 
     /**
@@ -576,7 +587,7 @@
     @Test
     public void testCreateP2pInterfaceNoInitModeTestChipV2() throws Exception {
         runCreateSingleXxxInterfaceNoInitMode(new TestChipV2(), IfaceType.P2P, "p2p0",
-                TestChipV2.CHIP_MODE_ID, 1);
+                TestChipV2.CHIP_MODE_ID, false);
     }
 
     /**
@@ -585,7 +596,7 @@
     @Test
     public void testCreateNanInterfaceNoInitModeTestChipV2() throws Exception {
         runCreateSingleXxxInterfaceNoInitMode(new TestChipV2(), IfaceType.NAN, "wlan0",
-                TestChipV2.CHIP_MODE_ID, 1);
+                TestChipV2.CHIP_MODE_ID, false);
     }
 
     // TestChipV3
@@ -600,7 +611,7 @@
         // and we get callback 2 after destroying the first STA (since we can create another STA -
         // as expected).
         runCreateSingleXxxInterfaceNoInitMode(new TestChipV3(), IfaceType.STA, "wlan0",
-                TestChipV3.CHIP_MODE_ID, 2);
+                TestChipV3.CHIP_MODE_ID, true);
     }
 
     /**
@@ -609,7 +620,7 @@
     @Test
     public void testCreateApInterfaceNoInitModeTestChipV3() throws Exception {
         runCreateSingleXxxInterfaceNoInitMode(new TestChipV3(), IfaceType.AP, "wlan0",
-                TestChipV3.CHIP_MODE_ID, 1);
+                TestChipV3.CHIP_MODE_ID, false);
     }
 
     /**
@@ -618,7 +629,7 @@
     @Test
     public void testCreateP2pInterfaceNoInitModeTestChipV3() throws Exception {
         runCreateSingleXxxInterfaceNoInitMode(new TestChipV3(), IfaceType.P2P, "p2p0",
-                TestChipV3.CHIP_MODE_ID, 1);
+                TestChipV3.CHIP_MODE_ID, false);
     }
 
     /**
@@ -627,7 +638,7 @@
     @Test
     public void testCreateNanInterfaceNoInitModeTestChipV3() throws Exception {
         runCreateSingleXxxInterfaceNoInitMode(new TestChipV3(), IfaceType.NAN, "wlan0",
-                TestChipV3.CHIP_MODE_ID, 1);
+                TestChipV3.CHIP_MODE_ID, false);
     }
 
     //////////////////////////////////////////////////////////////////////////////////////
@@ -666,6 +677,8 @@
         );
         collector.checkThat("allocated interface", iface, IsNull.notNullValue());
 
+        verify(iafrl).onAvailabilityChanged(false);
+
         // act: stop Wi-Fi
         mDut.stop();
         mTestLooper.dispatchAll();
@@ -707,8 +720,8 @@
         mDut.registerInterfaceAvailableForRequestListener(IfaceType.STA, staIafrl, null);
         mDut.registerInterfaceAvailableForRequestListener(IfaceType.AP, apIafrl, null);
 
-        mInOrder.verify(staIafrl).onAvailableForRequest();
-        mInOrder.verify(apIafrl).onAvailableForRequest();
+        mInOrder.verify(staIafrl).onAvailabilityChanged(true);
+        mInOrder.verify(apIafrl).onAvailabilityChanged(true);
 
         // Create STA Iface first.
         IWifiStaIface staIface = mock(IWifiStaIface.class);
@@ -721,7 +734,7 @@
         assertEquals(staIface, mDut.createStaIface(staIdl, null));
 
         mInOrder.verify(chipMock.chip).configureChip(TestChipV1.STA_CHIP_MODE_ID);
-        mInOrder.verify(apIafrl).onAvailableForRequest();
+        mInOrder.verify(staIafrl).onAvailabilityChanged(false);
 
         // Now Create AP Iface.
         IWifiApIface apIface = mock(IWifiApIface.class);
@@ -736,7 +749,8 @@
         mInOrder.verify(chipMock.chip).removeStaIface(getName(staIface));
         mInOrder.verify(staIdl).onDestroyed(getName(staIface));
         mInOrder.verify(chipMock.chip).configureChip(TestChipV1.AP_CHIP_MODE_ID);
-        mInOrder.verify(staIafrl).onAvailableForRequest();
+        mInOrder.verify(apIafrl).onAvailabilityChanged(false);
+        mInOrder.verify(staIafrl).onAvailabilityChanged(true);
 
         // Stop Wi-Fi
         mDut.stop();
@@ -780,6 +794,8 @@
         );
         collector.checkThat("allocated interface", iface, IsNull.notNullValue());
 
+        verify(iafrl).onAvailabilityChanged(false);
+
         // act: stop Wi-Fi
         mDut.stop();
         mTestLooper.dispatchAll();
@@ -844,10 +860,8 @@
         HalDeviceManager.InterfaceAvailableForRequestListener nanAvailListener = mock(
                 HalDeviceManager.InterfaceAvailableForRequestListener.class);
 
-        InOrder inOrderStaAvail = inOrder(staAvailListener);
-        InOrder inOrderApAvail = inOrder(apAvailListener);
-        InOrder inOrderP2pAvail = inOrder(p2pAvailListener);
-        InOrder inOrderNanAvail = inOrder(nanAvailListener);
+        InOrder inOrderAvail = inOrder(staAvailListener, apAvailListener, p2pAvailListener,
+                nanAvailListener);
 
         // register listeners for interface availability
         mDut.registerInterfaceAvailableForRequestListener(IfaceType.STA, staAvailListener,
@@ -859,10 +873,10 @@
                 mHandler);
         mTestLooper.dispatchAll();
 
-        inOrderStaAvail.verify(staAvailListener).onAvailableForRequest();
-        inOrderApAvail.verify(apAvailListener).onAvailableForRequest();
-        inOrderP2pAvail.verify(p2pAvailListener).onAvailableForRequest();
-        inOrderNanAvail.verify(nanAvailListener).onAvailableForRequest();
+        inOrderAvail.verify(staAvailListener).onAvailabilityChanged(true);
+        inOrderAvail.verify(apAvailListener).onAvailabilityChanged(true);
+        inOrderAvail.verify(p2pAvailListener).onAvailabilityChanged(true);
+        inOrderAvail.verify(nanAvailListener).onAvailabilityChanged(true);
 
         // Request STA
         IWifiIface staIface = validateInterfaceSequence(chipMock,
@@ -877,9 +891,7 @@
         );
         collector.checkThat("allocated STA interface", staIface, IsNull.notNullValue());
 
-        inOrderApAvail.verify(apAvailListener).onAvailableForRequest();
-        inOrderP2pAvail.verify(p2pAvailListener).onAvailableForRequest();
-        inOrderNanAvail.verify(nanAvailListener).onAvailableForRequest();
+        inOrderAvail.verify(staAvailListener).onAvailabilityChanged(false);
 
         // request STA2: should fail
         IWifiIface staIface2 = mDut.createStaIface(null, null);
@@ -903,7 +915,8 @@
         );
         collector.checkThat("allocated P2P interface", p2pIface, IsNull.notNullValue());
 
-        inOrderApAvail.verify(apAvailListener).onAvailableForRequest();
+        inOrderAvail.verify(p2pAvailListener).onAvailabilityChanged(false);
+        inOrderAvail.verify(nanAvailListener).onAvailabilityChanged(false);
 
         // Request AP
         IWifiIface apIface = validateInterfaceSequence(chipMock,
@@ -925,7 +938,8 @@
         );
         collector.checkThat("allocated AP interface", apIface, IsNull.notNullValue());
 
-        inOrderStaAvail.verify(staAvailListener).onAvailableForRequest();
+        inOrderAvail.verify(apAvailListener).onAvailabilityChanged(false);
+        inOrderAvail.verify(staAvailListener).onAvailabilityChanged(true);
 
         // request AP2: should fail
         IWifiIface apIface2 = mDut.createApIface(null, null);
@@ -951,9 +965,10 @@
         );
         collector.checkThat("allocated STA interface", staIface, IsNull.notNullValue());
 
-        inOrderApAvail.verify(apAvailListener).onAvailableForRequest();
-        inOrderP2pAvail.verify(p2pAvailListener).onAvailableForRequest();
-        inOrderNanAvail.verify(nanAvailListener).onAvailableForRequest();
+        inOrderAvail.verify(apAvailListener).onAvailabilityChanged(true);
+        inOrderAvail.verify(staAvailListener).onAvailabilityChanged(false);
+        inOrderAvail.verify(p2pAvailListener).onAvailabilityChanged(true);
+        inOrderAvail.verify(nanAvailListener).onAvailabilityChanged(true);
 
         mTestLooper.dispatchAll();
         verify(apDestroyedListener).onDestroyed(getName(apIface));
@@ -970,7 +985,8 @@
                 null // availableListener
         );
 
-        inOrderApAvail.verify(apAvailListener).onAvailableForRequest();
+        inOrderAvail.verify(p2pAvailListener).onAvailabilityChanged(false);
+        inOrderAvail.verify(nanAvailListener).onAvailabilityChanged(false);
 
         // Request NAN: should fail
         IWifiIface nanIface = mDut.createNanIface(nanDestroyedListener, mHandler);
@@ -982,9 +998,8 @@
         mDut.removeIface(p2pIface);
         mTestLooper.dispatchAll();
 
-        inOrderApAvail.verify(apAvailListener).onAvailableForRequest();
-        inOrderP2pAvail.verify(p2pAvailListener).onAvailableForRequest();
-        inOrderNanAvail.verify(nanAvailListener).onAvailableForRequest();
+        inOrderAvail.verify(p2pAvailListener).onAvailabilityChanged(true);
+        inOrderAvail.verify(nanAvailListener).onAvailabilityChanged(true);
         verify(chipMock.chip, times(2)).removeP2pIface("p2p0");
         verify(p2pDestroyedListener2).onDestroyed(getName(p2pIface));
 
@@ -1001,8 +1016,7 @@
         );
         collector.checkThat("allocated NAN interface", nanIface, IsNull.notNullValue());
 
-        inOrderApAvail.verify(apAvailListener).onAvailableForRequest();
-        inOrderP2pAvail.verify(p2pAvailListener).onAvailableForRequest();
+        inOrderAvail.verify(nanAvailListener).onAvailabilityChanged(false);
 
         verifyNoMoreInteractions(mManagerStatusListenerMock, staDestroyedListener, staAvailListener,
                 staDestroyedListener2, apDestroyedListener, apAvailListener, p2pDestroyedListener,
@@ -1023,9 +1037,7 @@
      */
     @Test
     public void testP2pAndNanInteractionsTestChipV1() throws Exception {
-        // staAvailCallbacks=0: there is no second STA so will never get available callback after
-        // first is created.
-        runP2pAndNanExclusiveInteractionsTestChip(new TestChipV1(), 0, TestChipV1.STA_CHIP_MODE_ID);
+        runP2pAndNanExclusiveInteractionsTestChip(new TestChipV1(), TestChipV1.STA_CHIP_MODE_ID);
     }
 
     /**
@@ -1062,6 +1074,8 @@
         );
         collector.checkThat("STA created", staIface1, IsNull.notNullValue());
 
+        verify(staAvailListener1).onAvailabilityChanged(false);
+
         // get STA interface again
         IWifiIface staIface2 = mDut.createStaIface(staDestroyedListener2, mHandler);
         collector.checkThat("STA created", staIface2, IsNull.nullValue());
@@ -1170,10 +1184,8 @@
         HalDeviceManager.InterfaceAvailableForRequestListener nanAvailListener = mock(
                 HalDeviceManager.InterfaceAvailableForRequestListener.class);
 
-        InOrder inOrderStaAvail = inOrder(staAvailListener);
-        InOrder inOrderApAvail = inOrder(apAvailListener);
-        InOrder inOrderP2pAvail = inOrder(p2pAvailListener);
-        InOrder inOrderNanAvail = inOrder(nanAvailListener);
+        InOrder inOrderAvail = inOrder(staAvailListener, apAvailListener, p2pAvailListener,
+                nanAvailListener);
 
         // register listeners for interface availability
         mDut.registerInterfaceAvailableForRequestListener(IfaceType.STA, staAvailListener,
@@ -1185,10 +1197,10 @@
                 mHandler);
         mTestLooper.dispatchAll();
 
-        inOrderStaAvail.verify(staAvailListener).onAvailableForRequest();
-        inOrderApAvail.verify(apAvailListener).onAvailableForRequest();
-        inOrderP2pAvail.verify(p2pAvailListener).onAvailableForRequest();
-        inOrderNanAvail.verify(nanAvailListener).onAvailableForRequest();
+        inOrderAvail.verify(staAvailListener).onAvailabilityChanged(true);
+        inOrderAvail.verify(apAvailListener).onAvailabilityChanged(true);
+        inOrderAvail.verify(p2pAvailListener).onAvailabilityChanged(true);
+        inOrderAvail.verify(nanAvailListener).onAvailabilityChanged(true);
 
         // create STA
         when(mClock.getUptimeSinceBootMillis()).thenReturn(15L);
@@ -1204,11 +1216,6 @@
         );
         collector.checkThat("STA interface wasn't created", staIface, IsNull.notNullValue());
 
-        inOrderStaAvail.verify(staAvailListener).onAvailableForRequest();
-        inOrderApAvail.verify(apAvailListener).onAvailableForRequest();
-        inOrderP2pAvail.verify(p2pAvailListener).onAvailableForRequest();
-        inOrderNanAvail.verify(nanAvailListener).onAvailableForRequest();
-
         // create P2P
         IWifiIface p2pIface = validateInterfaceSequence(chipMock,
                 true, // chipModeValid
@@ -1222,8 +1229,8 @@
         );
         collector.checkThat("P2P interface wasn't created", p2pIface, IsNull.notNullValue());
 
-        inOrderStaAvail.verify(staAvailListener).onAvailableForRequest();
-        inOrderApAvail.verify(apAvailListener).onAvailableForRequest();
+        inOrderAvail.verify(p2pAvailListener).onAvailabilityChanged(false);
+        inOrderAvail.verify(nanAvailListener).onAvailabilityChanged(false);
 
         // request NAN: should fail
         IWifiIface nanIface = mDut.createNanIface(null, null);
@@ -1242,6 +1249,9 @@
         );
         collector.checkThat("AP interface wasn't created", apIface, IsNull.notNullValue());
 
+        inOrderAvail.verify(apAvailListener).onAvailabilityChanged(false);
+        inOrderAvail.verify(staAvailListener).onAvailabilityChanged(false);
+
         // request STA2: should fail
         IWifiIface staIface2 = mDut.createStaIface(null, null);
         collector.checkThat("STA2 should not be created", staIface2, IsNull.nullValue());
@@ -1254,8 +1264,8 @@
         mDut.removeIface(apIface);
         mTestLooper.dispatchAll();
 
-        inOrderStaAvail.verify(staAvailListener).onAvailableForRequest();
-        inOrderApAvail.verify(apAvailListener).onAvailableForRequest();
+        inOrderAvail.verify(apAvailListener).onAvailabilityChanged(true);
+        inOrderAvail.verify(staAvailListener).onAvailabilityChanged(true);
         verify(chipMock.chip).removeApIface("wlan1");
         verify(apDestroyedListener).onDestroyed(getName(apIface));
 
@@ -1273,7 +1283,7 @@
         );
         collector.checkThat("STA 2 interface wasn't created", staIface2, IsNull.notNullValue());
 
-        inOrderApAvail.verify(apAvailListener).onAvailableForRequest();
+        inOrderAvail.verify(staAvailListener).onAvailabilityChanged(false);
 
         // request STA3: should fail
         IWifiIface staIface3 = mDut.createStaIface(null, null);
@@ -1295,12 +1305,14 @@
         );
         collector.checkThat("AP interface wasn't created", apIface, IsNull.notNullValue());
 
+        inOrderAvail.verify(apAvailListener).onAvailabilityChanged(false);
+
         // tear down P2P
         mDut.removeIface(p2pIface);
         mTestLooper.dispatchAll();
 
-        inOrderP2pAvail.verify(p2pAvailListener).onAvailableForRequest();
-        inOrderNanAvail.verify(nanAvailListener).onAvailableForRequest();
+        inOrderAvail.verify(p2pAvailListener).onAvailabilityChanged(true);
+        inOrderAvail.verify(nanAvailListener).onAvailabilityChanged(true);
         verify(chipMock.chip).removeP2pIface("p2p0");
         verify(p2pDestroyedListener).onDestroyed(getName(p2pIface));
 
@@ -1317,7 +1329,7 @@
         );
         collector.checkThat("NAN interface wasn't created", nanIface, IsNull.notNullValue());
 
-        inOrderP2pAvail.verify(p2pAvailListener).onAvailableForRequest();
+        inOrderAvail.verify(nanAvailListener).onAvailabilityChanged(false);
 
         verifyNoMoreInteractions(mManagerStatusListenerMock, staDestroyedListener,
                 staDestroyedListener2, apDestroyedListener, p2pDestroyedListener,
@@ -1340,9 +1352,7 @@
      */
     @Test
     public void testP2pAndNanInteractionsTestChipV2() throws Exception {
-        // staAvailCallbacks=5: after every substantial change will get a callback since second
-        // STA is always available.
-        runP2pAndNanExclusiveInteractionsTestChip(new TestChipV2(), 5, TestChipV2.CHIP_MODE_ID);
+        runP2pAndNanExclusiveInteractionsTestChip(new TestChipV2(), TestChipV2.CHIP_MODE_ID);
     }
 
     /**
@@ -1445,10 +1455,8 @@
         HalDeviceManager.InterfaceAvailableForRequestListener nanAvailListener = mock(
                 HalDeviceManager.InterfaceAvailableForRequestListener.class);
 
-        InOrder inOrderStaAvail = inOrder(staAvailListener);
-        InOrder inOrderApAvail = inOrder(apAvailListener);
-        InOrder inOrderP2pAvail = inOrder(p2pAvailListener);
-        InOrder inOrderNanAvail = inOrder(nanAvailListener);
+        InOrder inOrderAvail = inOrder(staAvailListener, apAvailListener, p2pAvailListener,
+                nanAvailListener);
 
         // register listeners for interface availability
         mDut.registerInterfaceAvailableForRequestListener(IfaceType.STA, staAvailListener,
@@ -1460,10 +1468,10 @@
                 mHandler);
         mTestLooper.dispatchAll();
 
-        inOrderStaAvail.verify(staAvailListener).onAvailableForRequest();
-        inOrderApAvail.verify(apAvailListener).onAvailableForRequest();
-        inOrderP2pAvail.verify(p2pAvailListener).onAvailableForRequest();
-        inOrderNanAvail.verify(nanAvailListener).onAvailableForRequest();
+        inOrderAvail.verify(staAvailListener).onAvailabilityChanged(true);
+        inOrderAvail.verify(apAvailListener).onAvailabilityChanged(true);
+        inOrderAvail.verify(p2pAvailListener).onAvailabilityChanged(true);
+        inOrderAvail.verify(nanAvailListener).onAvailabilityChanged(true);
 
         // create STA
         when(mClock.getUptimeSinceBootMillis()).thenReturn(15L);
@@ -1479,11 +1487,6 @@
         );
         collector.checkThat("STA interface wasn't created", staIface, IsNull.notNullValue());
 
-        inOrderStaAvail.verify(staAvailListener).onAvailableForRequest();
-        inOrderApAvail.verify(apAvailListener).onAvailableForRequest();
-        inOrderP2pAvail.verify(p2pAvailListener).onAvailableForRequest();
-        inOrderNanAvail.verify(nanAvailListener).onAvailableForRequest();
-
         // create P2P
         IWifiIface p2pIface = validateInterfaceSequence(chipMock,
                 true, // chipModeValid
@@ -1497,7 +1500,9 @@
         );
         collector.checkThat("P2P interface wasn't created", p2pIface, IsNull.notNullValue());
 
-        inOrderApAvail.verify(apAvailListener).onAvailableForRequest();
+        inOrderAvail.verify(staAvailListener).onAvailabilityChanged(false);
+        inOrderAvail.verify(p2pAvailListener).onAvailabilityChanged(false);
+        inOrderAvail.verify(nanAvailListener).onAvailabilityChanged(false);
 
         // request NAN: should fail
         IWifiIface nanIface = mDut.createNanIface(null, null);
@@ -1518,6 +1523,8 @@
         collector.checkThat("AP interface wasn't created", apIface, IsNull.notNullValue());
         verify(chipMock.chip).removeP2pIface("p2p0");
 
+        inOrderAvail.verify(apAvailListener).onAvailabilityChanged(false);
+
         // request STA2: should fail
         IWifiIface staIface2 = mDut.createStaIface(null, null);
         collector.checkThat("STA2 should not be created", staIface2, IsNull.nullValue());
@@ -1534,10 +1541,10 @@
         mDut.removeIface(apIface);
         mTestLooper.dispatchAll();
 
-        inOrderStaAvail.verify(staAvailListener).onAvailableForRequest();
-        inOrderApAvail.verify(apAvailListener).onAvailableForRequest();
-        inOrderP2pAvail.verify(p2pAvailListener).onAvailableForRequest();
-        inOrderNanAvail.verify(nanAvailListener).onAvailableForRequest();
+        inOrderAvail.verify(apAvailListener).onAvailabilityChanged(true);
+        inOrderAvail.verify(staAvailListener).onAvailabilityChanged(true);
+        inOrderAvail.verify(p2pAvailListener).onAvailabilityChanged(true);
+        inOrderAvail.verify(nanAvailListener).onAvailabilityChanged(true);
         verify(chipMock.chip).removeApIface("wlan1");
         verify(apDestroyedListener).onDestroyed(getName(apIface));
 
@@ -1555,9 +1562,7 @@
         );
         collector.checkThat("STA 2 interface wasn't created", staIface2, IsNull.notNullValue());
 
-        inOrderApAvail.verify(apAvailListener).onAvailableForRequest();
-        inOrderP2pAvail.verify(p2pAvailListener).onAvailableForRequest();
-        inOrderNanAvail.verify(nanAvailListener).onAvailableForRequest();
+        inOrderAvail.verify(staAvailListener).onAvailabilityChanged(false);
 
         // request STA3: should fail
         IWifiIface staIface3 = mDut.createStaIface(null, null);
@@ -1578,8 +1583,7 @@
         );
         collector.checkThat("NAN interface wasn't created", nanIface, IsNull.notNullValue());
 
-        inOrderApAvail.verify(apAvailListener).onAvailableForRequest();
-        inOrderP2pAvail.verify(p2pAvailListener).onAvailableForRequest();
+        inOrderAvail.verify(nanAvailListener).onAvailabilityChanged(false);
         verify(chipMock.chip).removeStaIface("wlan1");
         verify(staDestroyedListener2).onDestroyed(getName(staIface2));
 
@@ -1608,8 +1612,7 @@
      */
     @Test
     public void testP2pAndNanInteractionsTestChipV3() throws Exception {
-        // staAvailCallbacks=2: only get callback (for second STA) when P2P or NAN are down.
-        runP2pAndNanExclusiveInteractionsTestChip(new TestChipV3(), 2, TestChipV3.CHIP_MODE_ID);
+        runP2pAndNanExclusiveInteractionsTestChip(new TestChipV3(), TestChipV3.CHIP_MODE_ID);
     }
 
     /**
@@ -1725,7 +1728,7 @@
     }
 
     private void runCreateSingleXxxInterfaceNoInitMode(ChipMockBase chipMock, int ifaceTypeToCreate,
-            String ifaceName, int finalChipMode, int expectedAvailableCalls) throws Exception {
+            String ifaceName, int finalChipMode, boolean multipleIfaceSupport) throws Exception {
         chipMock.initialize();
         mInOrder = inOrder(mServiceManagerMock, mWifiMock, chipMock.chip,
                 mManagerStatusListenerMock);
@@ -1737,6 +1740,8 @@
         HalDeviceManager.InterfaceAvailableForRequestListener iafrl = mock(
                 HalDeviceManager.InterfaceAvailableForRequestListener.class);
 
+        InOrder availInOrder = inOrder(iafrl);
+
         IWifiIface iface = validateInterfaceSequence(chipMock,
                 false, // chipModeValid
                 -1000, // chipModeId (only used if chipModeValid is true)
@@ -1748,6 +1753,7 @@
                 iafrl // availableListener
         );
         collector.checkThat("allocated interface", iface, IsNull.notNullValue());
+        availInOrder.verify(iafrl).onAvailabilityChanged(multipleIfaceSupport);
 
         // act: remove interface
         mDut.removeIface(iface);
@@ -1770,7 +1776,9 @@
         }
 
         verify(idl).onDestroyed(ifaceName);
-        verify(iafrl, times(expectedAvailableCalls)).onAvailableForRequest();
+        if (!multipleIfaceSupport) {
+            availInOrder.verify(iafrl).onAvailabilityChanged(true);
+        }
 
         verifyNoMoreInteractions(mManagerStatusListenerMock, idl, iafrl);
     }
@@ -1791,7 +1799,7 @@
      * line of NAN and P2P being exclusive).
      */
     public void runP2pAndNanExclusiveInteractionsTestChip(ChipMockBase chipMock,
-            int staAvailCallbacks, int onlyChipMode) throws Exception {
+            int onlyChipMode) throws Exception {
         chipMock.initialize();
         mInOrder = inOrder(mServiceManagerMock, mWifiMock, chipMock.chip,
                 mManagerStatusListenerMock);
@@ -1810,7 +1818,8 @@
 
         InterfaceDestroyedListener p2pDestroyedListener = mock(
                 InterfaceDestroyedListener.class);
-        HalDeviceManager.InterfaceAvailableForRequestListener p2pAvailListener = null;
+
+        InOrder availInOrder = inOrder(staAvailListener, nanAvailListener);
 
         // Request STA
         IWifiIface staIface = validateInterfaceSequence(chipMock,
@@ -1823,6 +1832,8 @@
                 staDestroyedListener, // destroyedListener
                 staAvailListener // availableListener
         );
+        availInOrder.verify(staAvailListener).onAvailabilityChanged(
+                chipMock.chipMockId == CHIP_MOCK_V2 || chipMock.chipMockId == CHIP_MOCK_V3);
 
         // Request NAN
         IWifiIface nanIface = validateInterfaceSequence(chipMock,
@@ -1835,6 +1846,10 @@
                 nanDestroyedListener, // destroyedListener
                 nanAvailListener // availableListener
         );
+        if (chipMock.chipMockId == CHIP_MOCK_V3) {
+            availInOrder.verify(staAvailListener).onAvailabilityChanged(false);
+        }
+        availInOrder.verify(nanAvailListener).onAvailabilityChanged(false);
 
         // Request P2P
         IWifiIface p2pIface = validateInterfaceSequence(chipMock,
@@ -1845,7 +1860,7 @@
                 onlyChipMode, // finalChipMode
                 new IWifiIface[]{nanIface}, // tearDownList
                 p2pDestroyedListener, // destroyedListener
-                p2pAvailListener, // availableListener
+                null, // availableListener
                 // destroyedInterfacesDestroyedListeners...
                 new InterfaceDestroyedListenerWithIfaceName(
                         getName(nanIface), nanDestroyedListener)
@@ -1864,7 +1879,10 @@
 
         mTestLooper.dispatchAll();
         verify(p2pDestroyedListener).onDestroyed(getName(p2pIface));
-        verify(nanAvailListener).onAvailableForRequest();
+        if (chipMock.chipMockId == CHIP_MOCK_V3) {
+            availInOrder.verify(staAvailListener).onAvailabilityChanged(true);
+        }
+        availInOrder.verify(nanAvailListener).onAvailabilityChanged(true);
 
         // Request NAN: expect success now
         nanIface = validateInterfaceSequence(chipMock,
@@ -1877,11 +1895,10 @@
                 nanDestroyedListener, // destroyedListener
                 nanAvailListener // availableListener
         );
-
-        if (staAvailCallbacks != 0) {
-            // if there are duplicate STAs then expect an available callback for each step above
-            verify(staAvailListener, times(staAvailCallbacks)).onAvailableForRequest();
+        if (chipMock.chipMockId == CHIP_MOCK_V3) {
+            availInOrder.verify(staAvailListener).onAvailabilityChanged(false);
         }
+        availInOrder.verify(nanAvailListener).onAvailabilityChanged(false);
 
         verifyNoMoreInteractions(mManagerStatusListenerMock, staDestroyedListener, staAvailListener,
                 nanDestroyedListener, nanAvailListener, p2pDestroyedListener);
@@ -2285,7 +2302,13 @@
 
     // chip configuration
 
+    private static final int CHIP_MOCK_V1 = 0;
+    private static final int CHIP_MOCK_V2 = 1;
+    private static final int CHIP_MOCK_V3 = 2;
+
     private class ChipMockBase {
+        public int chipMockId;
+
         public IWifiChip chip;
         public int chipId;
         public boolean chipModeValid = false;
@@ -2353,6 +2376,8 @@
         void initialize() throws Exception {
             super.initialize();
 
+            chipMockId = CHIP_MOCK_V1;
+
             // chip Id configuration
             ArrayList<Integer> chipIds;
             chipId = 10;
@@ -2414,6 +2439,8 @@
         void initialize() throws Exception {
             super.initialize();
 
+            chipMockId = CHIP_MOCK_V2;
+
             // chip Id configuration
             ArrayList<Integer> chipIds;
             chipId = 12;
@@ -2472,6 +2499,8 @@
         void initialize() throws Exception {
             super.initialize();
 
+            chipMockId = CHIP_MOCK_V3;
+
             // chip Id configuration
             ArrayList<Integer> chipIds;
             chipId = 15;
diff --git a/tests/wifitests/src/com/android/server/wifi/aware/WifiAwareNativeManagerTest.java b/tests/wifitests/src/com/android/server/wifi/aware/WifiAwareNativeManagerTest.java
index 122d6e6..4ff4c9e 100644
--- a/tests/wifitests/src/com/android/server/wifi/aware/WifiAwareNativeManagerTest.java
+++ b/tests/wifitests/src/com/android/server/wifi/aware/WifiAwareNativeManagerTest.java
@@ -109,7 +109,7 @@
         mManagerStatusListenerCaptor.getValue().onStatusChanged();
         mInOrder.verify(mHalDeviceManager).registerInterfaceAvailableForRequestListener(
                 eq(IfaceType.NAN), mAvailListenerCaptor.capture(), any(Handler.class));
-        mAvailListenerCaptor.getValue().onAvailableForRequest();
+        mAvailListenerCaptor.getValue().onAvailabilityChanged(true);
 
         mInOrder.verify(mHalDeviceManager).createNanIface(
                 mDestroyedListenerCaptor.capture(), any());
@@ -118,7 +118,7 @@
         // 3 & 4 onAvailableForRequest + non-null return value: validate that enables usage
         when(mHalDeviceManager.createNanIface(any(), any())).thenReturn(mWifiNanIfaceMock);
 
-        mAvailListenerCaptor.getValue().onAvailableForRequest();
+        mAvailListenerCaptor.getValue().onAvailabilityChanged(true);
 
         mInOrder.verify(mHalDeviceManager).createNanIface(
                 mDestroyedListenerCaptor.capture(), any());
@@ -140,7 +140,7 @@
         mManagerStatusListenerCaptor.getValue().onStatusChanged();
         mInOrder.verify(mHalDeviceManager).registerInterfaceAvailableForRequestListener(
                 eq(IfaceType.NAN), mAvailListenerCaptor.capture(), any(Handler.class));
-        mAvailListenerCaptor.getValue().onAvailableForRequest();
+        mAvailListenerCaptor.getValue().onAvailabilityChanged(true);
 
         mInOrder.verify(mHalDeviceManager).createNanIface(
                 mDestroyedListenerCaptor.capture(), any());