Merge "Make wifi_item width match parent" into tm-dev
diff --git a/service/java/com/android/server/wifi/ClientModeImpl.java b/service/java/com/android/server/wifi/ClientModeImpl.java
index 4becb34..92cc9ff 100644
--- a/service/java/com/android/server/wifi/ClientModeImpl.java
+++ b/service/java/com/android/server/wifi/ClientModeImpl.java
@@ -4898,11 +4898,15 @@
                             String decoratedPseudonym = mWifiCarrierInfoManager
                                     .decoratePseudonymWith3GppRealm(config,
                                             anonymousIdentity);
-                            if (decoratedPseudonym != null) {
+                            if (decoratedPseudonym != null
+                                    && !decoratedPseudonym.equals(anonymousIdentity)) {
                                 anonymousIdentity = decoratedPseudonym;
                                 // propagate to the supplicant to avoid using
                                 // the original anonymous identity for firmware
                                 // roaming.
+                                if (mVerboseLoggingEnabled) {
+                                    log("Update decorated pseudonym: " + anonymousIdentity);
+                                }
                                 mWifiNative.setEapAnonymousIdentity(mInterfaceName,
                                         anonymousIdentity);
                             }
diff --git a/service/java/com/android/server/wifi/HalDeviceManager.java b/service/java/com/android/server/wifi/HalDeviceManager.java
index fa71055..c8ce15c 100644
--- a/service/java/com/android/server/wifi/HalDeviceManager.java
+++ b/service/java/com/android/server/wifi/HalDeviceManager.java
@@ -2247,6 +2247,7 @@
             StringBuilder sb = new StringBuilder();
             sb.append("{chipInfo=").append(chipInfo).append(", chipModeId=").append(chipModeId)
                     .append(", interfacesToBeRemovedFirst=").append(interfacesToBeRemovedFirst)
+                    .append(", interfacesToBeDowngraded=").append(interfacesToBeDowngraded)
                     .append(")");
             return sb.toString();
         }
@@ -2369,7 +2370,8 @@
      * Note: both proposals are 'acceptable' bases on priority criteria.
      *
      * Criteria:
-     * - Proposal is better if it means removing fewer high priority interfaces
+     * - Proposal is better if it means removing fewer high priority interfaces, or downgrades the
+     *   fewest interfaces.
      */
     private boolean compareIfaceCreationData(IfaceCreationData val1, IfaceCreationData val2) {
         if (VDBG) Log.d(TAG, "compareIfaceCreationData: val1=" + val1 + ", val2=" + val2);
@@ -2415,6 +2417,14 @@
             }
         }
 
+        int val1NumIFacesToBeDowngraded = val1.interfacesToBeDowngraded != null
+                ? val1.interfacesToBeDowngraded.size() : 0;
+        int val2NumIFacesToBeDowngraded = val2.interfacesToBeDowngraded != null
+                ? val2.interfacesToBeDowngraded.size() : 0;
+        if (val1NumIFacesToBeDowngraded != val2NumIFacesToBeDowngraded) {
+            return val1NumIFacesToBeDowngraded < val2NumIFacesToBeDowngraded;
+        }
+
         // arbitrary - flip a coin
         if (VDBG) Log.d(TAG, "proposals identical - flip a coin");
         return false;
diff --git a/service/java/com/android/server/wifi/WifiConfigManager.java b/service/java/com/android/server/wifi/WifiConfigManager.java
index 77c0eca..f5729dc 100644
--- a/service/java/com/android/server/wifi/WifiConfigManager.java
+++ b/service/java/com/android/server/wifi/WifiConfigManager.java
@@ -162,6 +162,15 @@
          * @param choiceKey The network profile key of the user connect choice that was removed.
          */
         default void onConnectChoiceRemoved(String choiceKey){ }
+
+        /**
+         * Invoke when security params changed, especially when NetworkTransitionDisable event
+         * received
+         * @param oldConfig The original WifiConfiguration
+         * @param securityParams the updated securityParams
+         */
+        default void onSecurityParamsUpdate(@NonNull WifiConfiguration oldConfig,
+                List<SecurityParams> securityParams) { }
     }
     /**
      * Max size of scan details to cache in {@link #mScanDetailCaches}.
@@ -3866,8 +3875,7 @@
      * @param indicationBit transition disable indication bits.
      * @return true if the network was found, false otherwise.
      */
-    public boolean updateNetworkTransitionDisable(
-            int networkId,
+    public boolean updateNetworkTransitionDisable(int networkId,
             @WifiMonitor.TransitionDisableIndication int indicationBit) {
         localLog("updateNetworkTransitionDisable: network ID=" + networkId
                 + " indication: " + indicationBit);
@@ -3876,21 +3884,33 @@
             Log.e(TAG, "Cannot find network for " + networkId);
             return false;
         }
+        WifiConfiguration copy = new WifiConfiguration(config);
+        boolean changed = false;
         if (0 != (indicationBit & WifiMonitor.TDI_USE_WPA3_PERSONAL)
                 && config.isSecurityType(WifiConfiguration.SECURITY_TYPE_SAE)) {
             config.setSecurityParamsEnabled(WifiConfiguration.SECURITY_TYPE_PSK, false);
+            changed = true;
         }
         if (0 != (indicationBit & WifiMonitor.TDI_USE_SAE_PK)) {
             config.enableSaePkOnlyMode(true);
+            changed = true;
         }
         if (0 != (indicationBit & WifiMonitor.TDI_USE_WPA3_ENTERPRISE)
                 && config.isSecurityType(WifiConfiguration.SECURITY_TYPE_EAP_WPA3_ENTERPRISE)) {
             config.setSecurityParamsEnabled(WifiConfiguration.SECURITY_TYPE_EAP, false);
+            changed = true;
         }
         if (0 != (indicationBit & WifiMonitor.TDI_USE_ENHANCED_OPEN)
                 && config.isSecurityType(WifiConfiguration.SECURITY_TYPE_OWE)) {
             config.setSecurityParamsEnabled(WifiConfiguration.SECURITY_TYPE_OPEN, false);
+            changed = true;
         }
+        if (changed) {
+            for (OnNetworkUpdateListener listener : mListeners) {
+                listener.onSecurityParamsUpdate(copy, config.getSecurityParamsList());
+            }
+        }
+
         return true;
     }
 
diff --git a/service/java/com/android/server/wifi/WifiNetworkSuggestionsManager.java b/service/java/com/android/server/wifi/WifiNetworkSuggestionsManager.java
index 2b59658..5e27d34 100644
--- a/service/java/com/android/server/wifi/WifiNetworkSuggestionsManager.java
+++ b/service/java/com/android/server/wifi/WifiNetworkSuggestionsManager.java
@@ -39,6 +39,7 @@
 import android.net.wifi.ISuggestionConnectionStatusListener;
 import android.net.wifi.ISuggestionUserApprovalStatusListener;
 import android.net.wifi.ScanResult;
+import android.net.wifi.SecurityParams;
 import android.net.wifi.WifiConfiguration;
 import android.net.wifi.WifiContext;
 import android.net.wifi.WifiEnterpriseConfig;
@@ -172,14 +173,22 @@
 
     private class OnNetworkUpdateListener implements
             WifiConfigManager.OnNetworkUpdateListener {
+
         @Override
         public void onConnectChoiceSet(@NonNull List<WifiConfiguration> networks,
                 String choiceKey, int rssi) {
-            onUserConnectChoiceSet(networks, choiceKey, rssi);
+            onUserConnectChoiceSetForSuggestion(networks, choiceKey, rssi);
         }
+
         @Override
         public void onConnectChoiceRemoved(String choiceKey) {
-            onUserConnectChoiceRemove(choiceKey);
+            onUserConnectChoiceRemoveForSuggestion(choiceKey);
+        }
+
+        @Override
+        public void onSecurityParamsUpdate(WifiConfiguration configuration,
+                List<SecurityParams> securityParams) {
+            onSecurityParamsUpdateForSuggestion(configuration, securityParams);
         }
     }
 
@@ -727,7 +736,7 @@
     }
 
     private void removeFromScanResultMatchInfoMapAndRemoveRelatedScoreCard(
-            @NonNull ExtendedWifiNetworkSuggestion extNetworkSuggestion) {
+            @NonNull ExtendedWifiNetworkSuggestion extNetworkSuggestion, boolean removeScoreCard) {
         ScanResultMatchInfo scanResultMatchInfo =
                 ScanResultMatchInfo.fromWifiConfiguration(
                         extNetworkSuggestion.wns.wifiConfiguration);
@@ -750,7 +759,9 @@
             if (extNetworkSuggestionsForScanResultMatchInfo.isEmpty()) {
                 mActiveScanResultMatchInfoWithBssid.remove(lookupPair);
                 if (!mActiveScanResultMatchInfoWithNoBssid.containsKey(scanResultMatchInfo)) {
-                    removeNetworkFromScoreCard(extNetworkSuggestion.wns.wifiConfiguration);
+                    if (removeScoreCard) {
+                        removeNetworkFromScoreCard(extNetworkSuggestion.wns.wifiConfiguration);
+                    }
                     mLruConnectionTracker.removeNetwork(
                             extNetworkSuggestion.wns.wifiConfiguration);
                 }
@@ -768,7 +779,9 @@
             // Remove the set from map if empty.
             if (extNetworkSuggestionsForScanResultMatchInfo.isEmpty()) {
                 mActiveScanResultMatchInfoWithNoBssid.remove(scanResultMatchInfo);
-                removeNetworkFromScoreCard(extNetworkSuggestion.wns.wifiConfiguration);
+                if (removeScoreCard) {
+                    removeNetworkFromScoreCard(extNetworkSuggestion.wns.wifiConfiguration);
+                }
                 mLruConnectionTracker.removeNetwork(
                         extNetworkSuggestion.wns.wifiConfiguration);
             }
@@ -1315,7 +1328,7 @@
             if (ewns.wns.wifiConfiguration.isEnterprise()) {
                 mWifiKeyStore.removeKeys(ewns.wns.wifiConfiguration.enterpriseConfig);
             }
-            removeFromScanResultMatchInfoMapAndRemoveRelatedScoreCard(ewns);
+            removeFromScanResultMatchInfoMapAndRemoveRelatedScoreCard(ewns, true);
             mWifiConfigManager.removeConnectChoiceFromAllNetworks(ewns
                     .createInternalWifiConfiguration(mWifiCarrierInfoManager)
                     .getProfileKey());
@@ -2644,8 +2657,8 @@
         return extendedWifiNetworkSuggestion.wns.wifiConfiguration.isOpenNetwork();
     }
 
-    private void onUserConnectChoiceSet(Collection<WifiConfiguration> networks, String choiceKey,
-            int rssi) {
+    private void onUserConnectChoiceSetForSuggestion(Collection<WifiConfiguration> networks,
+            String choiceKey, int rssi) {
         Set<String> networkKeys = networks.stream()
                 .filter(config -> config.fromWifiNetworkSuggestion)
                 .map(WifiConfiguration::getProfileKey)
@@ -2667,7 +2680,7 @@
         saveToStore();
     }
 
-    private void onUserConnectChoiceRemove(String choiceKey) {
+    private void onUserConnectChoiceRemoveForSuggestion(String choiceKey) {
         mActiveNetworkSuggestionsPerApp.values().stream()
                 .flatMap(e -> e.extNetworkSuggestions.values().stream())
                 .filter(ewns -> TextUtils.equals(ewns.connectChoice, choiceKey))
@@ -2743,4 +2756,22 @@
     private int getLingerDelayMs() {
         return SystemProperties.getInt(LINGER_DELAY_PROPERTY, DEFAULT_LINGER_DELAY_MS);
     }
+
+    private void onSecurityParamsUpdateForSuggestion(WifiConfiguration config,
+            List<SecurityParams> securityParams) {
+        Set<ExtendedWifiNetworkSuggestion> matchingExtendedWifiNetworkSuggestions =
+                        getNetworkSuggestionsForWifiConfiguration(config, config.BSSID);
+        if (matchingExtendedWifiNetworkSuggestions.isEmpty()) {
+            if (mVerboseLoggingEnabled) {
+                Log.w(TAG, "onSecurityParamsUpdateForSuggestion: no network matches: " + config);
+            }
+            return;
+        }
+        for (ExtendedWifiNetworkSuggestion ewns : matchingExtendedWifiNetworkSuggestions) {
+            removeFromScanResultMatchInfoMapAndRemoveRelatedScoreCard(ewns, false);
+            ewns.wns.wifiConfiguration.setSecurityParams(securityParams);
+            addToScanResultMatchInfoMap(ewns);
+        }
+        saveToStore();
+    }
 }
diff --git a/service/java/com/android/server/wifi/util/WifiPermissionsUtil.java b/service/java/com/android/server/wifi/util/WifiPermissionsUtil.java
index ae7acdc..4c0c7ef 100644
--- a/service/java/com/android/server/wifi/util/WifiPermissionsUtil.java
+++ b/service/java/com/android/server/wifi/util/WifiPermissionsUtil.java
@@ -1069,6 +1069,11 @@
             return false;
         }
         String[] packages = mContext.getPackageManager().getPackagesForUid(uid);
+        if (packages == null) {
+            Log.w(TAG, "isProfileOwnerOfOrganizationOwnedDevice(): could not find packages for uid="
+                    + uid);
+            return false;
+        }
         for (String packageName : packages) {
             if (devicePolicyManager.isProfileOwnerApp(packageName)) return true;
         }
diff --git a/service/tests/wifitests/src/com/android/server/wifi/HalDeviceManagerTest.java b/service/tests/wifitests/src/com/android/server/wifi/HalDeviceManagerTest.java
index 061bad1..f87cd1f 100644
--- a/service/tests/wifitests/src/com/android/server/wifi/HalDeviceManagerTest.java
+++ b/service/tests/wifitests/src/com/android/server/wifi/HalDeviceManagerTest.java
@@ -3264,16 +3264,68 @@
     }
 
     /**
-     * Validate creation of AP Bridge interface from blank start-up in chip V1.6
+     * Validate creation of AP Bridge interface from blank start-up in TestChipV6
      */
     @Test
-    public void testCreateApBridgeInterfaceNoInitModeTestChipV16() throws Exception {
+    public void testCreateApBridgeInterfaceNoInitModeTestChipV6() throws Exception {
         TestChipV6 testChip = new TestChipV6();
         setupWifiChipV15(testChip);
         runCreateSingleXxxInterfaceNoInitMode(testChip, HDM_CREATE_IFACE_AP_BRIDGE, "wlan0",
                 TestChipV6.CHIP_MODE_ID);
     }
 
+    /**
+     * Validate creation of STA will not downgrade an AP Bridge interface in TestChipV6, since it
+     * can support STA and AP Bridge concurrently.
+     */
+    @Test
+    public void testCreateStaDoesNotDowngradeApBridgeInterfaceTestChipV6() throws Exception {
+        mIsBridgedSoftApSupported = true;
+        mIsStaWithBridgedSoftApConcurrencySupported = false;
+        TestChipV6 chipMock = new TestChipV6();
+        setupWifiChipV15(chipMock);
+        chipMock.initialize();
+        mInOrder = inOrder(mServiceManagerMock, mWifiMock, mWifiMockV15, chipMock.chip,
+                mWifiChipV15, mManagerStatusListenerMock);
+        executeAndValidateInitializationSequence();
+        executeAndValidateStartupSequence();
+
+        InterfaceDestroyedListener idl = mock(
+                InterfaceDestroyedListener.class);
+
+        // Create the bridged AP
+        ArrayList<String> bridgedApInstances = new ArrayList<>();
+        bridgedApInstances.add("instance0");
+        bridgedApInstances.add("instance1");
+        chipMock.bridgedApInstancesByName.put("wlan0", bridgedApInstances);
+        IWifiIface iface = validateInterfaceSequence(chipMock,
+                false, // chipModeValid
+                -1000, // chipModeId (only used if chipModeValid is true)
+                HDM_CREATE_IFACE_AP_BRIDGE,
+                "wlan0",
+                TestChipV6.CHIP_MODE_ID,
+                null, // tearDownList
+                idl, // destroyedListener
+                TEST_WORKSOURCE_0 // requestorWs
+        );
+        collector.checkThat("interface was null", iface, IsNull.notNullValue());
+
+        when(mSoftApManager.getBridgedApDowngradeIfaceInstanceForRemoval()).thenReturn("instance1");
+        // Should be able to create a STA without downgrading the bridged AP
+        iface = validateInterfaceSequence(chipMock,
+                true, // chipModeValid
+                TestChipV6.CHIP_MODE_ID,
+                HDM_CREATE_IFACE_STA,
+                "wlan3",
+                TestChipV6.CHIP_MODE_ID,
+                null, // tearDownList
+                idl, // destroyedListener
+                TEST_WORKSOURCE_0 // requestorWs
+        );
+        collector.checkThat("interface was null", iface, IsNull.notNullValue());
+        assertEquals(2, bridgedApInstances.size());
+    }
+
     private IWifiIface setupDbsSupportTest(ChipMockBase testChip, int onlyChipMode,
             ImmutableList<ArrayList<Integer>> radioCombinationMatrix) throws Exception {
         WifiRadioCombinationMatrix matrix = new WifiRadioCombinationMatrix();
diff --git a/service/tests/wifitests/src/com/android/server/wifi/WifiConfigManagerTest.java b/service/tests/wifitests/src/com/android/server/wifi/WifiConfigManagerTest.java
index 4f5ac81..8d0a9f6 100644
--- a/service/tests/wifitests/src/com/android/server/wifi/WifiConfigManagerTest.java
+++ b/service/tests/wifitests/src/com/android/server/wifi/WifiConfigManagerTest.java
@@ -6766,6 +6766,7 @@
         int disabledType = testNetwork.getDefaultSecurityParams().getSecurityType();
         NetworkUpdateResult result = verifyAddNetworkToWifiConfigManager(testNetwork);
         int networkId = result.getNetworkId();
+        mWifiConfigManager.addOnNetworkUpdateListener(mListener);
 
         WifiConfiguration configBefore = mWifiConfigManager.getConfiguredNetwork(networkId);
         assertTrue(configBefore.getSecurityParams(disabledType).isEnabled());
@@ -6774,6 +6775,7 @@
 
         WifiConfiguration configAfter = mWifiConfigManager.getConfiguredNetwork(networkId);
         assertFalse(configAfter.getSecurityParams(disabledType).isEnabled());
+        verify(mListener).onSecurityParamsUpdate(any(), eq(configAfter.getSecurityParamsList()));
     }
 
     /**
diff --git a/service/tests/wifitests/src/com/android/server/wifi/WifiNetworkSuggestionsManagerTest.java b/service/tests/wifitests/src/com/android/server/wifi/WifiNetworkSuggestionsManagerTest.java
index a1afe2b..6ac3632 100644
--- a/service/tests/wifitests/src/com/android/server/wifi/WifiNetworkSuggestionsManagerTest.java
+++ b/service/tests/wifitests/src/com/android/server/wifi/WifiNetworkSuggestionsManagerTest.java
@@ -5232,4 +5232,49 @@
                 mWifiNetworkSuggestionsManager.add(List.of(networkSuggestion), TEST_UID_1,
                 TEST_PACKAGE_1, TEST_FEATURE));
     }
+
+    @Test
+    public void testOnNetworkConnectionSuccessWithMatchAndNetworkTransitionDisable()
+            throws Exception {
+        assertTrue(mWifiNetworkSuggestionsManager.registerSuggestionConnectionStatusListener(
+                mConnectionStatusListener, TEST_PACKAGE_1, TEST_UID_1));
+        WifiNetworkSuggestion networkSuggestion = createWifiNetworkSuggestion(
+                WifiConfigurationTestUtil.createPskNetwork(), null, true, false, true, true,
+                DEFAULT_PRIORITY_GROUP);
+        List<WifiNetworkSuggestion> networkSuggestionList =
+                new ArrayList<WifiNetworkSuggestion>() {{
+                    add(networkSuggestion);
+                }};
+        assertEquals(WifiManager.STATUS_NETWORK_SUGGESTIONS_SUCCESS,
+                mWifiNetworkSuggestionsManager.add(networkSuggestionList, TEST_UID_1,
+                        TEST_PACKAGE_1, TEST_FEATURE));
+        mWifiNetworkSuggestionsManager.setHasUserApprovedForApp(true, TEST_UID_1, TEST_PACKAGE_1);
+
+        // Simulate connecting to the network.
+        WifiConfiguration connectNetwork =
+                new WifiConfiguration(networkSuggestion.wifiConfiguration);
+        connectNetwork.fromWifiNetworkSuggestion = true;
+        connectNetwork.shared = false;
+        connectNetwork.ephemeral = true;
+        connectNetwork.creatorName = TEST_PACKAGE_1;
+        connectNetwork.creatorUid = TEST_UID_1;
+        WifiConfiguration updated = new WifiConfiguration(connectNetwork);
+        updated.setSecurityParamsEnabled(WifiConfiguration.SECURITY_TYPE_PSK, false);
+
+        // Update to handle Network Transition Disable
+        mNetworkListenerCaptor.getValue().onSecurityParamsUpdate(connectNetwork,
+                updated.getSecurityParamsList());
+        mWifiNetworkSuggestionsManager.handleConnectionAttemptEnded(
+                WifiMetrics.ConnectionEvent.FAILURE_NONE, updated, TEST_BSSID);
+
+        verify(mWifiMetrics).incrementNetworkSuggestionApiNumConnectSuccess();
+
+        // Verify that the correct broadcast was sent out.
+        mInorder.verify(mWifiPermissionsUtil).enforceCanAccessScanResults(eq(TEST_PACKAGE_1),
+                eq(TEST_FEATURE), eq(TEST_UID_1), nullable(String.class));
+        validatePostConnectionBroadcastSent(TEST_PACKAGE_1, networkSuggestion);
+
+        // Verify no more broadcast were sent out.
+        mInorder.verifyNoMoreInteractions();
+    }
 }
diff --git a/service/tests/wifitests/src/com/android/server/wifi/util/WifiPermissionsUtilTest.java b/service/tests/wifitests/src/com/android/server/wifi/util/WifiPermissionsUtilTest.java
index 0e1d9b1..33bedd4 100644
--- a/service/tests/wifitests/src/com/android/server/wifi/util/WifiPermissionsUtilTest.java
+++ b/service/tests/wifitests/src/com/android/server/wifi/util/WifiPermissionsUtilTest.java
@@ -1059,9 +1059,18 @@
         when(mDevicePolicyManager.isProfileOwnerApp(TEST_PACKAGE_NAME)).thenReturn(false);
         assertFalse(wifiPermissionsUtil.isProfileOwnerOfOrganizationOwnedDevice(
                 MANAGED_PROFILE_UID));
+        when(mDevicePolicyManager.isProfileOwnerApp(TEST_PACKAGE_NAME)).thenReturn(true);
+
+        // Package does not exist for uid.
+        when(mMockContext.getPackageManager().getPackagesForUid(MANAGED_PROFILE_UID))
+                .thenReturn(null);
+        assertFalse(wifiPermissionsUtil.isProfileOwnerOfOrganizationOwnedDevice(
+                MANAGED_PROFILE_UID));
+        when(mMockContext.getPackageManager().getPackagesForUid(MANAGED_PROFILE_UID))
+                .thenReturn(packageNames);
 
         // DevicePolicyManager does not exist.
-        when(mMockContext.getSystemService(Context.DEVICE_POLICY_SERVICE))
+        when(mMockContext.getSystemService(DevicePolicyManager.class))
                 .thenReturn(null);
         assertFalse(wifiPermissionsUtil.isProfileOwnerOfOrganizationOwnedDevice(
                 MANAGED_PROFILE_UID));