ClientModeImpl: Don't send NETWORK_STATE_CHANGED broadcast on roam

Only send out the NETWORK_STATE_CHANGED broadcast when we're in
L2ConnectingState. For any further roam events that happen while we're
in L3ConnectedState or L2ConnectedState, should not trigger a new
NETWORK_STATE_CHANGED event.

Bug: 157380666
Test: atest com.android.server.wifi
Change-Id: I7ba2cb934436481f39678af2830f5c7e4a936e20
diff --git a/service/java/com/android/server/wifi/ClientModeImpl.java b/service/java/com/android/server/wifi/ClientModeImpl.java
index 3722a6e..7b6d0ec 100644
--- a/service/java/com/android/server/wifi/ClientModeImpl.java
+++ b/service/java/com/android/server/wifi/ClientModeImpl.java
@@ -4382,7 +4382,8 @@
                     // state is DISCONNECTED, but the agent is not disconnected, we
                     // need to handle a disconnection
                     if (mVerboseLoggingEnabled) {
-                        log("ConnectingState: Supplicant State change " + stateChangeResult);
+                        log("ConnectingOrConnectedState: Supplicant State change "
+                                + stateChangeResult);
                     }
                     if (state == SupplicantState.DISCONNECTED && mNetworkAgent != null) {
                         if (mVerboseLoggingEnabled) {
@@ -4394,8 +4395,6 @@
                             transitionTo(mDisconnectedState);
                         }
                     }
-                    sendNetworkChangeBroadcast(
-                            WifiInfo.getDetailedStateOf(stateChangeResult.state));
                     if (state == SupplicantState.COMPLETED) {
                         mWifiScoreReport.noteIpCheck();
                     }
@@ -4707,6 +4706,8 @@
                             mWifiInfo.setProviderFriendlyName(config.providerFriendlyName);
                         }
                     }
+                    sendNetworkChangeBroadcast(
+                            WifiInfo.getDetailedStateOf(stateChangeResult.state));
                     // Let the parent state handle the rest of the state changed.
                     handleStatus = NOT_HANDLED;
                     break;
diff --git a/service/tests/wifitests/src/com/android/server/wifi/ClientModeImplTest.java b/service/tests/wifitests/src/com/android/server/wifi/ClientModeImplTest.java
index 3298976..aed4b3e 100644
--- a/service/tests/wifitests/src/com/android/server/wifi/ClientModeImplTest.java
+++ b/service/tests/wifitests/src/com/android/server/wifi/ClientModeImplTest.java
@@ -5204,4 +5204,29 @@
         verify(mWifiNative).disableNetwork(WIFI_IFACE_NAME);
         assertEquals("DisconnectedState", mCmi.getCurrentState().getName());
     }
+
+    @Test
+    public void testRoamAfterConnectDoesNotUpdateNetworkInfoInNetworkStateChangeBroadcast()
+            throws Exception {
+        connect();
+
+        // The last NETWORK_STATE_CHANGED_ACTION should be to mark the network connected.
+        ArgumentCaptor<Intent> intentCaptor = ArgumentCaptor.forClass(Intent.class);
+        verify(mContext, atLeastOnce()).sendStickyBroadcastAsUser(intentCaptor.capture(), any());
+        Intent intent = intentCaptor.getValue();
+        assertNotNull(intent);
+        assertEquals(WifiManager.NETWORK_STATE_CHANGED_ACTION, intent.getAction());
+        NetworkInfo networkInfo = (NetworkInfo) intent.getExtra(WifiManager.EXTRA_NETWORK_INFO);
+        assertTrue(networkInfo.isConnected());
+
+        reset(mContext);
+
+        // send roam event
+        mCmi.sendMessage(WifiMonitor.ASSOCIATED_BSSID_EVENT, 0, 0, sBSSID1);
+        mCmi.sendMessage(WifiMonitor.SUPPLICANT_STATE_CHANGE_EVENT, 0, 0,
+                new StateChangeResult(0, sWifiSsid, sBSSID1, SupplicantState.COMPLETED));
+        mLooper.dispatchAll();
+
+        verify(mContext, never()).sendStickyBroadcastAsUser(any(), any());
+    }
 }