Merge cherrypicks of [19211974] into tm-release.

Change-Id: I56b6a81fd3913341ba4abef5dc3d995066aaa725
diff --git a/service/java/com/android/server/wifi/ActiveModeWarden.java b/service/java/com/android/server/wifi/ActiveModeWarden.java
index 2e8fb31..cc6550b 100644
--- a/service/java/com/android/server/wifi/ActiveModeWarden.java
+++ b/service/java/com/android/server/wifi/ActiveModeWarden.java
@@ -857,7 +857,9 @@
      */
     private boolean hasPrimaryOrScanOnlyModeManager() {
         return getClientModeManagerInRole(ROLE_CLIENT_PRIMARY) != null
-                || getClientModeManagerInRole(ROLE_CLIENT_SCAN_ONLY) != null;
+                || getClientModeManagerInRole(ROLE_CLIENT_SCAN_ONLY) != null
+                || getClientModeManagerTransitioningIntoRole(ROLE_CLIENT_PRIMARY) != null
+                || getClientModeManagerTransitioningIntoRole(ROLE_CLIENT_SCAN_ONLY) != null;
     }
 
     /**
@@ -986,6 +988,14 @@
         return null;
     }
 
+    @Nullable
+    private ConcreteClientModeManager getClientModeManagerTransitioningIntoRole(ClientRole role) {
+        for (ConcreteClientModeManager manager : mClientModeManagers) {
+            if (manager.getTargetRole() == role) return manager;
+        }
+        return null;
+    }
+
     /** Get all client mode managers in the specified roles. */
     @NonNull
     public List<ConcreteClientModeManager> getClientModeManagersInRoles(ClientRole... roles) {
diff --git a/service/java/com/android/server/wifi/ConcreteClientModeManager.java b/service/java/com/android/server/wifi/ConcreteClientModeManager.java
index 7f2f13c..893fe57 100644
--- a/service/java/com/android/server/wifi/ConcreteClientModeManager.java
+++ b/service/java/com/android/server/wifi/ConcreteClientModeManager.java
@@ -499,6 +499,13 @@
         return mRole;
     }
 
+    /**
+     * Get the role this ClientModeManager is expected to become.
+     */
+    @Nullable public ClientRole getTargetRole() {
+        return mTargetRoleChangeInfo == null ? null : mTargetRoleChangeInfo.role;
+    }
+
     @Override
     @Nullable public ClientRole getPreviousRole() {
         return mPreviousRole;
diff --git a/service/tests/wifitests/src/com/android/server/wifi/ActiveModeWardenTest.java b/service/tests/wifitests/src/com/android/server/wifi/ActiveModeWardenTest.java
index 5bba4f6..9c6ba72 100644
--- a/service/tests/wifitests/src/com/android/server/wifi/ActiveModeWardenTest.java
+++ b/service/tests/wifitests/src/com/android/server/wifi/ActiveModeWardenTest.java
@@ -798,6 +798,40 @@
                 any(), eq(TEST_WORKSOURCE), eq(ROLE_CLIENT_PRIMARY), anyBoolean());
     }
 
+    @Test
+    public void testPrimaryNotCreatedTwice() throws Exception {
+        enterClientModeActiveState();
+        verify(mWifiInjector).makeClientModeManager(
+                any(), eq(TEST_WORKSOURCE), eq(ROLE_CLIENT_PRIMARY), anyBoolean());
+
+        // toggling wifi on again should be no-op when primary is already available
+        when(mSettingsStore.isWifiToggleEnabled()).thenReturn(true);
+        mActiveModeWarden.wifiToggled(TEST_WORKSOURCE);
+        mLooper.dispatchAll();
+
+        verify(mWifiInjector).makeClientModeManager(
+                any(), eq(TEST_WORKSOURCE), eq(ROLE_CLIENT_PRIMARY), anyBoolean());
+
+        // Simulate the primary not fully started by making the role null and targetRole primary.
+        when(mClientModeManager.getRole()).thenReturn(null);
+        when(mClientModeManager.getTargetRole()).thenReturn(ROLE_CLIENT_PRIMARY);
+
+        // Verify that there is no primary, but there is a CMM with targetRole as primary.
+        List<ClientModeManager> currentCMMs = mActiveModeWarden.getClientModeManagers();
+        assertEquals(1, currentCMMs.size());
+        ConcreteClientModeManager currentCmm = (ConcreteClientModeManager) currentCMMs.get(0);
+        assertTrue(currentCmm.getRole() == null);
+        assertTrue(currentCmm.getTargetRole() == ROLE_CLIENT_PRIMARY);
+
+        // verify wifi toggling on should not create another primary CMM.
+        when(mSettingsStore.isWifiToggleEnabled()).thenReturn(true);
+        mActiveModeWarden.wifiToggled(TEST_WORKSOURCE);
+        mLooper.dispatchAll();
+
+        verify(mWifiInjector).makeClientModeManager(
+                any(), eq(TEST_WORKSOURCE), eq(ROLE_CLIENT_PRIMARY), anyBoolean());
+    }
+
     /**
      * Reentering EnabledState should be a NOP.
      */