Merge "ClientModeImpl: Add more logging for stopIpClient" into rvc-dev
diff --git a/libs/WifiTrackerLib/src/com/android/wifitrackerlib/OsuWifiEntry.java b/libs/WifiTrackerLib/src/com/android/wifitrackerlib/OsuWifiEntry.java
index 16e55fb..89d780e 100644
--- a/libs/WifiTrackerLib/src/com/android/wifitrackerlib/OsuWifiEntry.java
+++ b/libs/WifiTrackerLib/src/com/android/wifitrackerlib/OsuWifiEntry.java
@@ -61,6 +61,7 @@
     @NonNull private final Context mContext;
     @NonNull private OsuProvider mOsuProvider;
     private String mOsuStatusString;
+    private boolean mIsAlreadyProvisioned = false;
 
     /**
      * Create n OsuWifiEntry with the associated OsuProvider
@@ -92,8 +93,14 @@
     @Override
     public String getSummary(boolean concise) {
         // TODO(b/70983952): Add verbose summary
-        return mOsuStatusString != null
-                ? mOsuStatusString : mContext.getString(R.string.tap_to_sign_up);
+        if (mOsuStatusString != null) {
+            return mOsuStatusString;
+        } else if (isAlreadyProvisioned()) {
+            return concise ? mContext.getString(R.string.wifi_passpoint_expired)
+                    : mContext.getString(R.string.tap_to_renew_subscription_and_connect);
+        } else {
+            return mContext.getString(R.string.tap_to_sign_up);
+        }
     }
 
     @Override
@@ -308,6 +315,14 @@
         return mOsuProvider;
     }
 
+    boolean isAlreadyProvisioned() {
+        return mIsAlreadyProvisioned;
+    }
+
+    void setAlreadyProvisioned(boolean isAlreadyProvisioned) {
+        mIsAlreadyProvisioned = isAlreadyProvisioned;
+    }
+
     class OsuWifiEntryProvisioningCallback extends ProvisioningCallback {
         @Override
         @MainThread public void onProvisioningFailure(int status) {
diff --git a/libs/WifiTrackerLib/src/com/android/wifitrackerlib/PasspointNetworkDetailsTracker.java b/libs/WifiTrackerLib/src/com/android/wifitrackerlib/PasspointNetworkDetailsTracker.java
index 00c786f..e2d7acc 100644
--- a/libs/WifiTrackerLib/src/com/android/wifitrackerlib/PasspointNetworkDetailsTracker.java
+++ b/libs/WifiTrackerLib/src/com/android/wifitrackerlib/PasspointNetworkDetailsTracker.java
@@ -20,17 +20,20 @@
 
 import static com.android.wifitrackerlib.PasspointWifiEntry.uniqueIdToPasspointWifiEntryKey;
 import static com.android.wifitrackerlib.WifiEntry.CONNECTED_STATE_CONNECTED;
+import static com.android.wifitrackerlib.WifiEntry.WIFI_LEVEL_UNREACHABLE;
 
 import android.content.Context;
 import android.content.Intent;
 import android.net.ConnectivityManager;
 import android.net.LinkProperties;
+import android.net.Network;
 import android.net.NetworkInfo;
 import android.net.NetworkScoreManager;
 import android.net.wifi.ScanResult;
 import android.net.wifi.WifiConfiguration;
 import android.net.wifi.WifiInfo;
 import android.net.wifi.WifiManager;
+import android.net.wifi.hotspot2.OsuProvider;
 import android.net.wifi.hotspot2.PasspointConfiguration;
 import android.os.Handler;
 import android.text.TextUtils;
@@ -54,6 +57,8 @@
     private static final String TAG = "PasspointNetworkDetailsTracker";
 
     private final PasspointWifiEntry mChosenEntry;
+    private OsuWifiEntry mOsuWifiEntry;
+    private NetworkInfo mCurrentNetworkInfo;
 
     PasspointNetworkDetailsTracker(@NonNull Lifecycle lifecycle,
             @NonNull Context context,
@@ -101,8 +106,9 @@
         conditionallyUpdateScanResults(true /* lastScanSucceeded */);
         conditionallyUpdateConfig();
         final WifiInfo wifiInfo = mWifiManager.getConnectionInfo();
-        final NetworkInfo networkInfo = mConnectivityManager.getActiveNetworkInfo();
-        mChosenEntry.updateConnectionInfo(wifiInfo, networkInfo);
+        final Network currentNetwork = mWifiManager.getCurrentNetwork();
+        mCurrentNetworkInfo = mConnectivityManager.getNetworkInfo(currentNetwork);
+        mChosenEntry.updateConnectionInfo(wifiInfo, mCurrentNetworkInfo);
         handleLinkPropertiesChanged(mConnectivityManager.getLinkProperties(
                 mWifiManager.getCurrentNetwork()));
     }
@@ -138,16 +144,15 @@
     @WorkerThread
     @Override
     protected void handleRssiChangedAction() {
-        mChosenEntry.updateConnectionInfo(mWifiManager.getConnectionInfo(),
-                mConnectivityManager.getActiveNetworkInfo());
+        mChosenEntry.updateConnectionInfo(mWifiManager.getConnectionInfo(), mCurrentNetworkInfo);
     }
 
     @WorkerThread
     @Override
     protected void handleNetworkStateChangedAction(@NonNull Intent intent) {
         checkNotNull(intent, "Intent cannot be null!");
-        mChosenEntry.updateConnectionInfo(mWifiManager.getConnectionInfo(),
-                (NetworkInfo) intent.getExtra(WifiManager.EXTRA_NETWORK_INFO));
+        mCurrentNetworkInfo = (NetworkInfo) intent.getExtra(WifiManager.EXTRA_NETWORK_INFO);
+        mChosenEntry.updateConnectionInfo(mWifiManager.getConnectionInfo(), mCurrentNetworkInfo);
     }
 
     @WorkerThread
@@ -187,6 +192,43 @@
                 null /* roamingScanResults */);
     }
 
+    @WorkerThread
+    private void updateOsuWifiEntryScans(@NonNull List<ScanResult> scanResults) {
+        checkNotNull(scanResults, "Scan Result list should not be null!");
+
+        Map<OsuProvider, List<ScanResult>> osuProviderToScans =
+                mWifiManager.getMatchingOsuProviders(scanResults);
+        Map<OsuProvider, PasspointConfiguration> osuProviderToPasspointConfig =
+                mWifiManager.getMatchingPasspointConfigsForOsuProviders(
+                        osuProviderToScans.keySet());
+
+        if (mOsuWifiEntry != null) {
+            mOsuWifiEntry.updateScanResultInfo(osuProviderToScans.get(
+                    mOsuWifiEntry.getOsuProvider()));
+        } else {
+            // Create a new OsuWifiEntry to link to the chosen PasspointWifiEntry
+            for (OsuProvider provider : osuProviderToScans.keySet()) {
+                PasspointConfiguration provisionedConfig =
+                        osuProviderToPasspointConfig.get(provider);
+                if (provisionedConfig != null && TextUtils.equals(mChosenEntry.getKey(),
+                        uniqueIdToPasspointWifiEntryKey(provisionedConfig.getUniqueId()))) {
+                    mOsuWifiEntry = new OsuWifiEntry(mContext, mMainHandler, provider, mWifiManager,
+                            mWifiNetworkScoreCache, false /* forSavedNetworksPage */);
+                    mOsuWifiEntry.updateScanResultInfo(osuProviderToScans.get(provider));
+                    mOsuWifiEntry.setAlreadyProvisioned(true);
+                    mChosenEntry.setOsuWifiEntry(mOsuWifiEntry);
+                    return;
+                }
+            }
+        }
+
+        // Remove mOsuWifiEntry if it is no longer reachable
+        if (mOsuWifiEntry != null && mOsuWifiEntry.getLevel() == WIFI_LEVEL_UNREACHABLE) {
+            mChosenEntry.setOsuWifiEntry(null);
+            mOsuWifiEntry = null;
+        }
+    }
+
     /**
      * Updates the tracked entry's scan results up to the max scan age (or more, if the last scan
      * was unsuccessful). If Wifi is disabled, the tracked entry's level will be cleared.
@@ -207,7 +249,9 @@
             scanAgeWindow += mScanIntervalMillis;
         }
 
-        updatePasspointWifiEntryScans(mScanResultUpdater.getScanResults(scanAgeWindow));
+        List<ScanResult> currentScans = mScanResultUpdater.getScanResults(scanAgeWindow);
+        updatePasspointWifiEntryScans(currentScans);
+        updateOsuWifiEntryScans(currentScans);
     }
 
     /**
diff --git a/libs/WifiTrackerLib/src/com/android/wifitrackerlib/PasspointWifiEntry.java b/libs/WifiTrackerLib/src/com/android/wifitrackerlib/PasspointWifiEntry.java
index ebabade..20a87e7 100644
--- a/libs/WifiTrackerLib/src/com/android/wifitrackerlib/PasspointWifiEntry.java
+++ b/libs/WifiTrackerLib/src/com/android/wifitrackerlib/PasspointWifiEntry.java
@@ -62,7 +62,7 @@
  * WifiEntry representation of a subscribed Passpoint network, uniquely identified by FQDN.
  */
 @VisibleForTesting
-public class PasspointWifiEntry extends WifiEntry {
+public class PasspointWifiEntry extends WifiEntry implements WifiEntry.WifiEntryCallback {
     static final String KEY_PREFIX = "PasspointWifiEntry:";
 
     private final Object mLock = new Object();
@@ -81,6 +81,7 @@
     @Nullable private WifiConfiguration mWifiConfig;
     private @Security int mSecurity = SECURITY_EAP;
     private boolean mIsRoaming = false;
+    private OsuWifiEntry mOsuWifiEntry;
 
     protected long mSubscriptionExpirationTimeInMillis;
 
@@ -143,19 +144,33 @@
     }
 
     @Override
+    @ConnectedState
+    public int getConnectedState() {
+        if (isExpired()) {
+            if (super.getConnectedState() == CONNECTED_STATE_DISCONNECTED
+                    && mOsuWifiEntry != null) {
+                return mOsuWifiEntry.getConnectedState();
+            }
+        }
+        return super.getConnectedState();
+    }
+
+    @Override
     public String getTitle() {
         return mFriendlyName;
     }
 
     @Override
     public String getSummary(boolean concise) {
-        if (isExpired()) {
-            return mContext.getString(R.string.wifi_passpoint_expired);
-        }
-
         StringJoiner sj = new StringJoiner(mContext.getString(R.string.summary_separator));
 
-        if (getConnectedState() == CONNECTED_STATE_DISCONNECTED) {
+        if (isExpired()) {
+            if (mOsuWifiEntry != null) {
+                sj.add(mOsuWifiEntry.getSummary(concise));
+            } else {
+                sj.add(mContext.getString(R.string.wifi_passpoint_expired));
+            }
+        } else if (getConnectedState() == CONNECTED_STATE_DISCONNECTED) {
             String disconnectDescription = getDisconnectedStateDescription(mContext, this);
             if (TextUtils.isEmpty(disconnectDescription)) {
                 if (concise) {
@@ -257,7 +272,6 @@
     @Override
     @Security
     public int getSecurity() {
-        // TODO(b/70983952): Fill this method in
         return mSecurity;
     }
 
@@ -280,7 +294,6 @@
 
     @Override
     public boolean isSuggestion() {
-        // TODO(b/70983952): Fill this method in when passpoint suggestions are in
         return mWifiConfig != null && mWifiConfig.fromWifiNetworkSuggestion;
     }
 
@@ -296,12 +309,23 @@
 
     @Override
     public boolean canConnect() {
+        if (isExpired()) {
+            return mOsuWifiEntry != null && mOsuWifiEntry.canConnect();
+        }
+
         return mLevel != WIFI_LEVEL_UNREACHABLE
                 && getConnectedState() == CONNECTED_STATE_DISCONNECTED && mWifiConfig != null;
     }
 
     @Override
     public void connect(@Nullable ConnectCallback callback) {
+        if (isExpired()) {
+            if (mOsuWifiEntry != null) {
+                mOsuWifiEntry.connect(callback);
+                return;
+            }
+        }
+
         mConnectCallback = callback;
 
         if (mWifiConfig == null) {
@@ -593,4 +617,16 @@
     String getNetworkSelectionDescription() {
         return Utils.getNetworkSelectionDescription(mWifiConfig);
     }
+
+    /** Pass a reference to a matching OsuWifiEntry for expiration handling */
+    void setOsuWifiEntry(OsuWifiEntry osuWifiEntry) {
+        mOsuWifiEntry = osuWifiEntry;
+        mOsuWifiEntry.setListener(this);
+    }
+
+    /** Callback for updates to the linked OsuWifiEntry */
+    @Override
+    public void onUpdated() {
+        notifyOnUpdated();
+    }
 }
diff --git a/libs/WifiTrackerLib/src/com/android/wifitrackerlib/SavedNetworkTracker.java b/libs/WifiTrackerLib/src/com/android/wifitrackerlib/SavedNetworkTracker.java
index c6b5454..df931f8 100644
--- a/libs/WifiTrackerLib/src/com/android/wifitrackerlib/SavedNetworkTracker.java
+++ b/libs/WifiTrackerLib/src/com/android/wifitrackerlib/SavedNetworkTracker.java
@@ -143,7 +143,6 @@
     @WorkerThread
     @Override
     protected void handleScanResultsAvailableAction(@Nullable Intent intent) {
-        //TODO(b/70983952): Add PasspointWifiEntry and update their scans here.
         checkNotNull(intent, "Intent cannot be null!");
         conditionallyUpdateScanResults(intent.getBooleanExtra(WifiManager.EXTRA_RESULTS_UPDATED,
                 true /* defaultValue */));
@@ -158,7 +157,7 @@
 
         final WifiConfiguration config =
                 (WifiConfiguration) intent.getExtra(WifiManager.EXTRA_WIFI_CONFIGURATION);
-        if (config != null) {
+        if (config != null && !config.isPasspoint()) {
             updateStandardWifiEntryConfig(
                     config, (Integer) intent.getExtra(WifiManager.EXTRA_CHANGE_REASON));
         } else {
diff --git a/libs/WifiTrackerLib/src/com/android/wifitrackerlib/StandardNetworkDetailsTracker.java b/libs/WifiTrackerLib/src/com/android/wifitrackerlib/StandardNetworkDetailsTracker.java
index b89c8ab..3ef1b47 100644
--- a/libs/WifiTrackerLib/src/com/android/wifitrackerlib/StandardNetworkDetailsTracker.java
+++ b/libs/WifiTrackerLib/src/com/android/wifitrackerlib/StandardNetworkDetailsTracker.java
@@ -31,6 +31,7 @@
 import android.net.LinkProperties;
 import android.net.Network;
 import android.net.NetworkCapabilities;
+import android.net.NetworkInfo;
 import android.net.NetworkScoreManager;
 import android.net.wifi.WifiConfiguration;
 import android.net.wifi.WifiInfo;
@@ -55,6 +56,7 @@
 
     private final StandardWifiEntry mChosenEntry;
     private final boolean mIsNetworkRequest;
+    private NetworkInfo mCurrentNetworkInfo;
 
     StandardNetworkDetailsTracker(@NonNull Lifecycle lifecycle,
             @NonNull Context context,
@@ -84,8 +86,8 @@
         conditionallyUpdateConfig();
         final WifiInfo wifiInfo = mWifiManager.getConnectionInfo();
         final Network currentNetwork = mWifiManager.getCurrentNetwork();
-        mChosenEntry.updateConnectionInfo(wifiInfo, mConnectivityManager
-                .getNetworkInfo(currentNetwork));
+        mCurrentNetworkInfo = mConnectivityManager.getNetworkInfo(currentNetwork);
+        mChosenEntry.updateConnectionInfo(wifiInfo, mCurrentNetworkInfo);
         handleLinkPropertiesChanged(mConnectivityManager.getLinkProperties(currentNetwork));
     }
 
@@ -134,15 +136,14 @@
     @Override
     protected void handleNetworkStateChangedAction(@NonNull Intent intent) {
         checkNotNull(intent, "Intent cannot be null!");
-        mChosenEntry.updateConnectionInfo(mWifiManager.getConnectionInfo(),
-                mConnectivityManager.getNetworkInfo(mWifiManager.getCurrentNetwork()));
+        mCurrentNetworkInfo = (NetworkInfo) intent.getExtra(WifiManager.EXTRA_NETWORK_INFO);
+        mChosenEntry.updateConnectionInfo(mWifiManager.getConnectionInfo(), mCurrentNetworkInfo);
     }
 
     @WorkerThread
     @Override
     protected void handleRssiChangedAction() {
-        mChosenEntry.updateConnectionInfo(mWifiManager.getConnectionInfo(),
-                mConnectivityManager.getNetworkInfo(mWifiManager.getCurrentNetwork()));
+        mChosenEntry.updateConnectionInfo(mWifiManager.getConnectionInfo(), mCurrentNetworkInfo);
     }
 
     @WorkerThread
diff --git a/libs/WifiTrackerLib/src/com/android/wifitrackerlib/WifiPickerTracker.java b/libs/WifiTrackerLib/src/com/android/wifitrackerlib/WifiPickerTracker.java
index 734779a..bb3a224 100644
--- a/libs/WifiTrackerLib/src/com/android/wifitrackerlib/WifiPickerTracker.java
+++ b/libs/WifiTrackerLib/src/com/android/wifitrackerlib/WifiPickerTracker.java
@@ -96,6 +96,7 @@
     // NetworkRequestEntry representing a network that was connected through the NetworkRequest API
     private NetworkRequestEntry mNetworkRequestEntry;
 
+    private NetworkInfo mCurrentNetworkInfo;
     // Cache containing saved WifiConfigurations mapped by StandardWifiEntry key
     private final Map<String, WifiConfiguration> mWifiConfigCache = new HashMap<>();
     // Cache containing suggested WifiConfigurations mapped by StandardWifiEntry key
@@ -192,7 +193,8 @@
         conditionallyUpdateScanResults(true /* lastScanSucceeded */);
         final WifiInfo wifiInfo = mWifiManager.getConnectionInfo();
         final Network currentNetwork = mWifiManager.getCurrentNetwork();
-        updateConnectionInfo(wifiInfo, mConnectivityManager.getNetworkInfo(currentNetwork));
+        mCurrentNetworkInfo = mConnectivityManager.getNetworkInfo(currentNetwork);
+        updateConnectionInfo(wifiInfo, mCurrentNetworkInfo);
         handleLinkPropertiesChanged(mConnectivityManager.getLinkProperties(currentNetwork));
         notifyOnNumSavedNetworksChanged();
         notifyOnNumSavedSubscriptionsChanged();
@@ -218,7 +220,6 @@
     @WorkerThread
     @Override
     protected void handleConfiguredNetworksChangedAction(@NonNull Intent intent) {
-        // TODO(b/70983952): Handle Passpoint configurations here
         checkNotNull(intent, "Intent cannot be null!");
 
         final WifiConfiguration config =
@@ -246,9 +247,8 @@
     protected void handleNetworkStateChangedAction(@NonNull Intent intent) {
         checkNotNull(intent, "Intent cannot be null!");
         final WifiInfo wifiInfo = mWifiManager.getConnectionInfo();
-        final NetworkInfo networkInfo =
-                (NetworkInfo) intent.getExtra(WifiManager.EXTRA_NETWORK_INFO);
-        updateConnectionInfo(wifiInfo, networkInfo);
+        mCurrentNetworkInfo = (NetworkInfo) intent.getExtra(WifiManager.EXTRA_NETWORK_INFO);
+        updateConnectionInfo(wifiInfo, mCurrentNetworkInfo);
         updateWifiEntries();
     }
 
@@ -257,9 +257,7 @@
     protected void handleRssiChangedAction() {
         if (mConnectedWifiEntry != null) {
             final WifiInfo wifiInfo = mWifiManager.getConnectionInfo();
-            final NetworkInfo networkInfo = mConnectivityManager.getNetworkInfo(
-                    mWifiManager.getCurrentNetwork());
-            mConnectedWifiEntry.updateConnectionInfo(wifiInfo, networkInfo);
+            mConnectedWifiEntry.updateConnectionInfo(wifiInfo, mCurrentNetworkInfo);
         }
     }
 
@@ -320,13 +318,6 @@
                             || connectedState == CONNECTED_STATE_CONNECTING;
                 }).findAny().orElse(null /* other */);
             }
-            if (mConnectedWifiEntry == null) {
-                mConnectedWifiEntry = mOsuWifiEntryCache.values().stream().filter(entry -> {
-                    final @WifiEntry.ConnectedState int connectedState = entry.getConnectedState();
-                    return connectedState == CONNECTED_STATE_CONNECTED
-                            || connectedState == CONNECTED_STATE_CONNECTING;
-                }).findAny().orElse(null /* other */);
-            }
             if (mConnectedWifiEntry == null && mNetworkRequestEntry != null
                     && mNetworkRequestEntry.getConnectedState() != CONNECTED_STATE_DISCONNECTED) {
                 mConnectedWifiEntry = mNetworkRequestEntry;
@@ -356,7 +347,8 @@
             mWifiEntries.addAll(mPasspointWifiEntryCache.values().stream().filter(entry ->
                     entry.getConnectedState() == CONNECTED_STATE_DISCONNECTED).collect(toList()));
             mWifiEntries.addAll(mOsuWifiEntryCache.values().stream().filter(entry ->
-                    entry.getConnectedState() == CONNECTED_STATE_DISCONNECTED).collect(toList()));
+                    entry.getConnectedState() == CONNECTED_STATE_DISCONNECTED
+                            && !entry.isAlreadyProvisioned()).collect(toList()));
             Collections.sort(mWifiEntries);
             if (isVerboseLoggingEnabled()) {
                 Log.v(TAG, "Connected WifiEntry: " + mConnectedWifiEntry);
@@ -508,9 +500,9 @@
 
         Map<OsuProvider, List<ScanResult>> osuProviderToScans =
                 mWifiManager.getMatchingOsuProviders(scanResults);
-        Set<OsuProvider> alreadyProvisioned =
-                mWifiManager.getMatchingPasspointConfigsForOsuProviders(osuProviderToScans.keySet())
-                        .keySet();
+        Map<OsuProvider, PasspointConfiguration> osuProviderToPasspointConfig =
+                mWifiManager.getMatchingPasspointConfigsForOsuProviders(
+                        osuProviderToScans.keySet());
         // Update each OsuWifiEntry with new scans (or empty scans).
         for (OsuWifiEntry entry : mOsuWifiEntryCache.values()) {
             entry.updateScanResultInfo(osuProviderToScans.remove(entry.getOsuProvider()));
@@ -524,10 +516,27 @@
             mOsuWifiEntryCache.put(osuProviderToOsuWifiEntryKey(provider), newEntry);
         }
 
-        // Remove entries that are now unreachable or already provisioned
+        // Pass a reference of each OsuWifiEntry to any matching provisioned PasspointWifiEntries
+        // for expiration handling.
+        mOsuWifiEntryCache.values().forEach(osuEntry -> {
+            PasspointConfiguration provisionedConfig =
+                    osuProviderToPasspointConfig.get(osuEntry.getOsuProvider());
+            if (provisionedConfig == null) {
+                osuEntry.setAlreadyProvisioned(false);
+                return;
+            }
+            osuEntry.setAlreadyProvisioned(true);
+            PasspointWifiEntry provisionedEntry = mPasspointWifiEntryCache.get(
+                    uniqueIdToPasspointWifiEntryKey(provisionedConfig.getUniqueId()));
+            if (provisionedEntry == null) {
+                return;
+            }
+            provisionedEntry.setOsuWifiEntry(osuEntry);
+        });
+
+        // Remove entries that are now unreachable
         mOsuWifiEntryCache.entrySet()
-                .removeIf(entry -> entry.getValue().getLevel() == WIFI_LEVEL_UNREACHABLE
-                        || alreadyProvisioned.contains(entry.getValue().getOsuProvider()));
+                .removeIf(entry -> entry.getValue().getLevel() == WIFI_LEVEL_UNREACHABLE);
     }
 
     @WorkerThread
diff --git a/service/Android.bp b/service/Android.bp
index d7c16df..5becbe2 100644
--- a/service/Android.bp
+++ b/service/Android.bp
@@ -15,7 +15,7 @@
 //
 java_defaults {
     name: "wifi-service-common",
-    min_sdk_version: "29",
+    defaults: ["wifi-module-sdk-version-defaults"],
     errorprone: {
         javacflags: ["-Xep:CheckReturnValue:ERROR"],
     },
diff --git a/service/AndroidManifest_Resources.xml b/service/AndroidManifest_Resources.xml
index a6b2a58..6d637cb 100644
--- a/service/AndroidManifest_Resources.xml
+++ b/service/AndroidManifest_Resources.xml
@@ -19,6 +19,7 @@
 <!-- Manifest for wifi resources APK -->
 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
           package="com.android.wifi.resources"
+          coreApp="true"
           android:versionCode="1"
           android:versionName="R-initial">
     <application
diff --git a/service/java/com/android/server/wifi/ActiveModeManager.java b/service/java/com/android/server/wifi/ActiveModeManager.java
index aa0bf9f..0983e9b 100644
--- a/service/java/com/android/server/wifi/ActiveModeManager.java
+++ b/service/java/com/android/server/wifi/ActiveModeManager.java
@@ -59,6 +59,11 @@
      */
     void stop();
 
+    /**
+     * Method used to indicate if the mode manager is still stopping.
+     */
+    boolean isStopping();
+
     /** Roles assigned to each mode manager. */
     int ROLE_UNSPECIFIED = -1;
     // SoftApManager - Tethering, will respond to public APIs.
diff --git a/service/java/com/android/server/wifi/ActiveModeWarden.java b/service/java/com/android/server/wifi/ActiveModeWarden.java
index 0333458..e0a0a3d 100644
--- a/service/java/com/android/server/wifi/ActiveModeWarden.java
+++ b/service/java/com/android/server/wifi/ActiveModeWarden.java
@@ -282,6 +282,16 @@
     }
 
     /**
+     * @return true if any mode manager is stopping
+     */
+    private boolean hasAnyModeManagerStopping() {
+        for (ActiveModeManager manager : mActiveModeManagers) {
+            if (manager.isStopping()) return true;
+        }
+        return false;
+    }
+
+    /**
      * @return true if all the client mode managers are in scan only role,
      * false if there are no client mode managers present or if any of them are not in scan only
      * role.
@@ -886,8 +896,16 @@
                         if (mSettingsStore.isAirplaneModeOn()) {
                             return NOT_HANDLED;
                         } else {
-                            // when airplane mode is toggled off, but wifi is on, we can keep it on
-                            log("airplane mode toggled - and airplane mode is off. return handled");
+                            if (hasAnyModeManagerStopping()) {
+                                // previous airplane mode toggle on is being processed, defer the
+                                // message toggle off until previous processing is completed.
+                                deferMessage(msg);
+                            } else {
+                                // when airplane mode is toggled off, but wifi is on, we can keep it
+                                // on
+                                log("airplane mode toggled - and airplane mode is off. return "
+                                        + "handled");
+                            }
                             return HANDLED;
                         }
                     case CMD_AP_STOPPED:
diff --git a/service/java/com/android/server/wifi/ClientModeImpl.java b/service/java/com/android/server/wifi/ClientModeImpl.java
index 15ca3c8..6b6c39d 100644
--- a/service/java/com/android/server/wifi/ClientModeImpl.java
+++ b/service/java/com/android/server/wifi/ClientModeImpl.java
@@ -107,7 +107,6 @@
 import android.util.Pair;
 import android.util.SparseArray;
 
-import com.android.internal.annotations.GuardedBy;
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.util.AsyncChannel;
 import com.android.internal.util.MessageUtils;
@@ -445,9 +444,7 @@
 
     private WifiNetworkFactory mNetworkFactory;
     private UntrustedWifiNetworkFactory mUntrustedNetworkFactory;
-    @GuardedBy("mNetworkAgentLock")
     private WifiNetworkAgent mNetworkAgent;
-    private final Object mNetworkAgentLock = new Object();
 
     private byte[] mRssiRanges;
 
@@ -630,6 +627,9 @@
 
     /* Start connection to FILS AP*/
     static final int CMD_START_FILS_CONNECTION                          = BASE + 262;
+
+    private static final int CMD_GET_CURRENT_NETWORK                    = BASE + 263;
+
     // For message logging.
     private static final Class[] sMessageClasses = {
             AsyncChannel.class, ClientModeImpl.class };
@@ -1785,17 +1785,27 @@
     }
 
     /**
-     * Get Network object of current wifi network
+     * Should only be used internally.
+     * External callers should use {@link #syncGetCurrentNetwork(AsyncChannel)}.
+     */
+    private Network getCurrentNetwork() {
+        if (mNetworkAgent != null) {
+            return mNetworkAgent.getNetwork();
+        } else {
+            return null;
+        }
+    }
+
+    /**
+     * Get Network object of currently connected wifi network, or null if not connected.
      * @return Network object of current wifi network
      */
-    public Network getCurrentNetwork() {
-        synchronized (mNetworkAgentLock) {
-            if (mNetworkAgent != null) {
-                return mNetworkAgent.getNetwork();
-            } else {
-                return null;
-            }
-        }
+    public Network syncGetCurrentNetwork(AsyncChannel channel) {
+        Message resultMsg = channel.sendMessageSynchronously(CMD_GET_CURRENT_NETWORK);
+        if (messageIsNull(resultMsg)) return null;
+        Network network = (Network) resultMsg.obj;
+        resultMsg.recycle();
+        return network;
     }
 
     /**
@@ -2757,11 +2767,9 @@
         mIsAutoRoaming = false;
 
         sendNetworkChangeBroadcast(DetailedState.DISCONNECTED);
-        synchronized (mNetworkAgentLock) {
-            if (mNetworkAgent != null) {
-                mNetworkAgent.unregister();
-                mNetworkAgent = null;
-            }
+        if (mNetworkAgent != null) {
+            mNetworkAgent.unregister();
+            mNetworkAgent = null;
         }
 
         /* Clear network properties */
@@ -3492,7 +3500,8 @@
                     replyToMessage(message, message.what, Long.valueOf(featureSet));
                     break;
                 case CMD_GET_LINK_LAYER_STATS:
-                    // Not supported hence reply with error message
+                case CMD_GET_CURRENT_NETWORK:
+                    // Not supported hence reply with null message.obj
                     replyToMessage(message, message.what, null);
                     break;
                 case WifiP2pServiceImpl.P2P_CONNECTION_CHANGED:
@@ -3878,6 +3887,7 @@
                                         getTargetSsid(), bssid,
                                         WifiLastResortWatchdog.FAILURE_CODE_ASSOCIATION);
                     }
+                    mTargetNetworkId = WifiConfiguration.INVALID_NETWORK_ID;
                     break;
                 case WifiMonitor.AUTHENTICATION_FAILURE_EVENT:
                     stopIpClient();
@@ -4751,16 +4761,14 @@
                     .setPartialConnectivityAcceptable(config.noInternetAccessExpected)
                     .build();
             final NetworkCapabilities nc = getCapabilities(getCurrentWifiConfiguration());
-            synchronized (mNetworkAgentLock) {
-                // This should never happen.
-                if (mNetworkAgent != null) {
-                    Log.wtf(TAG, "mNetworkAgent is not null: " + mNetworkAgent);
-                    mNetworkAgent.unregister();
-                }
-                mNetworkAgent = new WifiNetworkAgent(mContext, getHandler().getLooper(),
-                        "WifiNetworkAgent", nc, mLinkProperties, 60, naConfig,
-                        mNetworkFactory.getProvider());
+            // This should never happen.
+            if (mNetworkAgent != null) {
+                Log.wtf(TAG, "mNetworkAgent is not null: " + mNetworkAgent);
+                mNetworkAgent.unregister();
             }
+            mNetworkAgent = new WifiNetworkAgent(mContext, getHandler().getLooper(),
+                    "WifiNetworkAgent", nc, mLinkProperties, 60, naConfig,
+                    mNetworkFactory.getProvider());
             mWifiScoreReport.setNetworkAgent(mNetworkAgent);
 
             // We must clear the config BSSID, as the wifi chipset may decide to roam
@@ -5316,6 +5324,9 @@
                         transitionTo(mDisconnectedState);
                     }
                     break;
+                case CMD_GET_CURRENT_NETWORK:
+                    replyToMessage(message, message.what, getCurrentNetwork());
+                    break;
                 default:
                     handleStatus = NOT_HANDLED;
                     break;
@@ -5540,6 +5551,9 @@
                     mWifiMetrics.incrementIpRenewalFailure();
                     handleStatus = NOT_HANDLED;
                     break;
+                case CMD_GET_CURRENT_NETWORK:
+                    replyToMessage(message, message.what, getCurrentNetwork());
+                    break;
                 default:
                     handleStatus = NOT_HANDLED;
                     break;
@@ -5677,6 +5691,7 @@
                                         WifiLastResortWatchdog.FAILURE_CODE_AUTHENTICATION);
                     }
                     clearNetworkCachedDataIfNeeded(getTargetWifiConfiguration(), message.arg2);
+                    mTargetNetworkId = WifiConfiguration.INVALID_NETWORK_ID;
                     break;
                 case WifiMonitor.SUPPLICANT_STATE_CHANGE_EVENT:
                     StateChangeResult stateChangeResult = (StateChangeResult) message.obj;
@@ -5850,6 +5865,9 @@
                 && mTargetWifiConfiguration.networkId
                 == requestData.networkId) {
             logd("id matches targetWifiConfiguration");
+        } else if (mLastNetworkId != WifiConfiguration.INVALID_NETWORK_ID
+                && mLastNetworkId == requestData.networkId) {
+            logd("id matches currentWifiConfiguration");
         } else {
             logd("id does not match targetWifiConfiguration");
             return;
@@ -6447,12 +6465,17 @@
 
         final boolean isUsingStaticIp =
                 (config.getIpAssignment() == IpConfiguration.IpAssignment.STATIC);
+        final boolean isUsingMacRandomization =
+                config.macRandomizationSetting
+                        == WifiConfiguration.RANDOMIZATION_PERSISTENT
+                        && isConnectedMacRandomizationEnabled();
         if (mVerboseLoggingEnabled) {
             final String key = config.getKey();
             log("startIpClient netId=" + Integer.toString(mLastNetworkId)
                     + " " + key + " "
                     + " roam=" + mIsAutoRoaming
                     + " static=" + isUsingStaticIp
+                    + " randomMac=" + isUsingMacRandomization
                     + " isFilsConnection=" + isFilsConnection);
         }
 
@@ -6471,15 +6494,18 @@
                 return false;
             }
             setConfigurationsPriorToIpClientProvisioning(config);
-            final ProvisioningConfiguration prov =
+            final ProvisioningConfiguration.Builder prov =
                     new ProvisioningConfiguration.Builder()
                     .withPreDhcpAction()
                     .withPreconnection()
                     .withApfCapabilities(
                     mWifiNative.getApfCapabilities(mInterfaceName))
-                    .withLayer2Information(layer2Info)
-                    .build();
-            mIpClient.startProvisioning(prov);
+                    .withLayer2Information(layer2Info);
+            if (isUsingMacRandomization) {
+                // Use EUI64 address generation for link-local IPv6 addresses.
+                prov.withRandomMacAddress();
+            }
+            mIpClient.startProvisioning(prov.build());
         } else {
             sendNetworkChangeBroadcast(DetailedState.OBTAINING_IPADDR);
             // We must clear the config BSSID, as the wifi chipset may decide to roam
@@ -6521,7 +6547,7 @@
                 }
             }
 
-            final ProvisioningConfiguration prov;
+            final ProvisioningConfiguration.Builder prov;
             ProvisioningConfiguration.ScanResultInfo scanResultInfo = null;
             if (scanResult != null) {
                 final List<ScanResultInfo.InformationElement> ies =
@@ -6542,8 +6568,7 @@
                     .withNetwork(getCurrentNetwork())
                     .withDisplayName(config.SSID)
                     .withScanResultInfo(scanResultInfo)
-                    .withLayer2Information(layer2Info)
-                    .build();
+                    .withLayer2Information(layer2Info);
             } else {
                 StaticIpConfiguration staticIpConfig = config.getStaticIpConfiguration();
                 prov = new ProvisioningConfiguration.Builder()
@@ -6551,10 +6576,13 @@
                         .withApfCapabilities(mWifiNative.getApfCapabilities(mInterfaceName))
                         .withNetwork(getCurrentNetwork())
                         .withDisplayName(config.SSID)
-                        .withLayer2Information(layer2Info)
-                        .build();
+                        .withLayer2Information(layer2Info);
             }
-            mIpClient.startProvisioning(prov);
+            if (isUsingMacRandomization) {
+                // Use EUI64 address generation for link-local IPv6 addresses.
+                prov.withRandomMacAddress();
+            }
+            mIpClient.startProvisioning(prov.build());
         }
 
         return true;
diff --git a/service/java/com/android/server/wifi/ClientModeManager.java b/service/java/com/android/server/wifi/ClientModeManager.java
index 61df519..6089339 100644
--- a/service/java/com/android/server/wifi/ClientModeManager.java
+++ b/service/java/com/android/server/wifi/ClientModeManager.java
@@ -76,9 +76,9 @@
 
     private String mClientInterfaceName;
     private boolean mIfaceIsUp = false;
-    private @Role int mRole = ROLE_UNSPECIFIED;
     private DeferStopHandler mDeferStopHandler;
-    private int mTargetRole = ROLE_UNSPECIFIED;
+    private @Role int mRole = ROLE_UNSPECIFIED;
+    private @Role int mTargetRole = ROLE_UNSPECIFIED;
     private int mActiveSubId = SubscriptionManager.INVALID_SUBSCRIPTION_ID;
 
     ClientModeManager(Context context, @NonNull Looper looper, Clock clock, WifiNative wifiNative,
@@ -122,6 +122,11 @@
         mDeferStopHandler.start(getWifiOffDeferringTimeMs());
     }
 
+    @Override
+    public boolean isStopping() {
+        return mTargetRole == ROLE_UNSPECIFIED && mRole != ROLE_UNSPECIFIED;
+    }
+
     private class DeferStopHandler extends WifiHandler {
         private boolean mIsDeferring = false;
         private ImsMmTelManager mImsMmTelManager = null;
@@ -280,11 +285,13 @@
         SubscriptionManager subscriptionManager = (SubscriptionManager) mContext.getSystemService(
                 Context.TELEPHONY_SUBSCRIPTION_SERVICE);
         if (subscriptionManager == null) {
+            Log.d(TAG, "SubscriptionManager not found");
             return 0;
         }
 
         List<SubscriptionInfo> subInfoList = subscriptionManager.getActiveSubscriptionInfoList();
         if (subInfoList == null) {
+            Log.d(TAG, "Active SubscriptionInfo list not found");
             return 0;
         }
 
@@ -302,6 +309,7 @@
 
     private int getWifiOffDeferringTimeMs(int subId) {
         if (subId == SubscriptionManager.INVALID_SUBSCRIPTION_ID) {
+            Log.d(TAG, "Invalid Subscription ID: " + subId);
             return 0;
         }
 
@@ -310,6 +318,7 @@
         if (!imsMmTelManager.isAvailable(
                     MmTelFeature.MmTelCapabilities.CAPABILITY_TYPE_VOICE,
                     ImsRegistrationImplBase.REGISTRATION_TECH_IWLAN)) {
+            Log.d(TAG, "IMS not registered over IWLAN for subId: " + subId);
             return 0;
         }
 
@@ -319,6 +328,7 @@
         // if LTE is available, no delay needed as IMS will be registered over LTE
         if (defaultVoiceTelephonyManager.getVoiceNetworkType()
                 == TelephonyManager.NETWORK_TYPE_LTE) {
+            Log.d(TAG, "LTE available and is default voice network type");
             return 0;
         }
 
diff --git a/service/java/com/android/server/wifi/DefaultModeManager.java b/service/java/com/android/server/wifi/DefaultModeManager.java
index cda4978..00b2117 100644
--- a/service/java/com/android/server/wifi/DefaultModeManager.java
+++ b/service/java/com/android/server/wifi/DefaultModeManager.java
@@ -45,6 +45,11 @@
     @Override
     public void stop() { };
 
+    @Override
+    public boolean isStopping() {
+        return false;
+    }
+
     /**
      * No role specified in default mode.
      */
diff --git a/service/java/com/android/server/wifi/FrameworkFacade.java b/service/java/com/android/server/wifi/FrameworkFacade.java
index a0b510f..875154e 100644
--- a/service/java/com/android/server/wifi/FrameworkFacade.java
+++ b/service/java/com/android/server/wifi/FrameworkFacade.java
@@ -32,6 +32,7 @@
 import android.net.Uri;
 import android.net.ip.IpClientCallbacks;
 import android.net.ip.IpClientUtil;
+import android.os.PersistableBundle;
 import android.provider.Settings;
 import android.telephony.CarrierConfigManager;
 import android.util.Log;
@@ -173,12 +174,14 @@
 
     public boolean getConfigWiFiDisableInECBM(Context context) {
         CarrierConfigManager configManager = getCarrierConfigManager(context);
-        if (configManager != null) {
-            return configManager.getConfig().getBoolean(
-                    CarrierConfigManager.KEY_CONFIG_WIFI_DISABLE_IN_ECBM);
+        if (configManager == null) {
+            return false;
         }
-        /* Default to TRUE */
-        return true;
+        PersistableBundle bundle = configManager.getConfig();
+        if (bundle == null) {
+            return false;
+        }
+        return bundle.getBoolean(CarrierConfigManager.KEY_CONFIG_WIFI_DISABLE_IN_ECBM);
     }
 
     public long getTxPackets(String iface) {
diff --git a/service/java/com/android/server/wifi/HalDeviceManager.java b/service/java/com/android/server/wifi/HalDeviceManager.java
index 783c91a..3d0c89c 100644
--- a/service/java/com/android/server/wifi/HalDeviceManager.java
+++ b/service/java/com/android/server/wifi/HalDeviceManager.java
@@ -179,7 +179,9 @@
      */
     public void stop() {
         stopWifi();
-        mWifi = null;
+        synchronized (mLock) { // prevents race condition
+            mWifi = null;
+        }
     }
 
     /**
diff --git a/service/java/com/android/server/wifi/NetworkSuggestionNominator.java b/service/java/com/android/server/wifi/NetworkSuggestionNominator.java
index fbc1f5f..b174be5 100644
--- a/service/java/com/android/server/wifi/NetworkSuggestionNominator.java
+++ b/service/java/com/android/server/wifi/NetworkSuggestionNominator.java
@@ -145,6 +145,11 @@
             }
             Set<ExtendedWifiNetworkSuggestion> autojoinEnableSuggestions = new HashSet<>();
             for (ExtendedWifiNetworkSuggestion ewns : matchingExtNetworkSuggestions) {
+                // Ignore insecure enterprise config.
+                if (ewns.wns.wifiConfiguration.isEnterprise()
+                        && ewns.wns.wifiConfiguration.enterpriseConfig.isInsecure()) {
+                    continue;
+                }
                 // If untrusted network is not allowed, ignore untrusted suggestion.
                 WifiConfiguration config = ewns.wns.wifiConfiguration;
                 if (!untrustedNetworkAllowed && !config.trusted) {
diff --git a/service/java/com/android/server/wifi/SoftApManager.java b/service/java/com/android/server/wifi/SoftApManager.java
index 3bf12ca..f972047 100644
--- a/service/java/com/android/server/wifi/SoftApManager.java
+++ b/service/java/com/android/server/wifi/SoftApManager.java
@@ -122,6 +122,7 @@
     private BaseWifiDiagnostics mWifiDiagnostics;
 
     private @Role int mRole = ROLE_UNSPECIFIED;
+    private @Role int mTargetRole = ROLE_UNSPECIFIED;
 
     private boolean mEverReportMetricsForMaxClient = false;
 
@@ -219,6 +220,7 @@
     @Override
     public void stop() {
         Log.d(TAG, " currentstate: " + getCurrentStateName());
+        mTargetRole = ROLE_UNSPECIFIED;
         if (mApInterfaceName != null) {
             if (mIfaceIsUp) {
                 updateApState(WifiManager.WIFI_AP_STATE_DISABLING,
@@ -232,6 +234,11 @@
     }
 
     @Override
+    public boolean isStopping() {
+        return mTargetRole == ROLE_UNSPECIFIED && mRole != ROLE_UNSPECIFIED;
+    }
+
+    @Override
     public @Role int getRole() {
         return mRole;
     }
@@ -241,6 +248,7 @@
         // softap does not allow in-place switching of roles.
         Preconditions.checkState(mRole == ROLE_UNSPECIFIED);
         Preconditions.checkState(SOFTAP_ROLES.contains(role));
+        mTargetRole = role;
         mRole = role;
     }
 
diff --git a/service/java/com/android/server/wifi/WifiConnectivityManager.java b/service/java/com/android/server/wifi/WifiConnectivityManager.java
index ad5a8f2..2ce0bc0 100644
--- a/service/java/com/android/server/wifi/WifiConnectivityManager.java
+++ b/service/java/com/android/server/wifi/WifiConnectivityManager.java
@@ -1847,6 +1847,7 @@
         if (!mWifiEnabled) return;
         localLog("forceConnectivityScan in request of " + workSource);
 
+        clearConnectionAttemptTimeStamps();
         mWaitForFullBandScanResults = true;
         startForcedSingleScan(true, workSource);
     }
diff --git a/service/java/com/android/server/wifi/WifiHealthMonitor.java b/service/java/com/android/server/wifi/WifiHealthMonitor.java
index 27167dc..8ab3a74 100644
--- a/service/java/com/android/server/wifi/WifiHealthMonitor.java
+++ b/service/java/com/android/server/wifi/WifiHealthMonitor.java
@@ -326,6 +326,15 @@
         pw.println("WifiHealthMonitor - Log End ----");
     }
 
+    /**
+     * Get current wifi mainline module long version code
+     * @Return a non-zero value if version code is available, 0 otherwise.
+     */
+    public long getWifiStackVersion() {
+        WifiSoftwareBuildInfo currentBuild = getWifiSystemInfoStats().getCurrSoftwareBuildInfo();
+        return (currentBuild == null) ? 0 : currentBuild.getWifiStackVersion();
+    }
+
     private synchronized void dailyDetectionHandler() {
         logd("Run daily detection");
         // Clear daily detection result
@@ -533,12 +542,12 @@
             return null;
         }
         PackageManager packageManager = mContext.getPackageManager();
-        int wifiStackVersion = 0;
+        long wifiStackVersion = 0;
         try {
             wifiStackVersion = packageManager.getPackageInfo(
-                    WIFI_APK_PACKAGE_NAME, PackageManager.MATCH_APEX).versionCode;
+                    WIFI_APK_PACKAGE_NAME, PackageManager.MATCH_APEX).getLongVersionCode();
         } catch (PackageManager.NameNotFoundException e) {
-            Log.e(TAG, " hit PackageManager nameNotFoundException");
+            Log.e(TAG, " Hit PackageManager exception", e);
         }
         String osBuildVersion = replaceNullByEmptyString(Build.DISPLAY);
         if (mWifiNative == null) {
@@ -629,10 +638,10 @@
      */
     final class WifiSoftwareBuildInfo {
         private String mOsBuildVersion;
-        private int mWifiStackVersion;
+        private long mWifiStackVersion;
         private String mWifiDriverVersion;
         private String mWifiFirmwareVersion;
-        WifiSoftwareBuildInfo(@NonNull String osBuildVersion, int wifiStackVersion,
+        WifiSoftwareBuildInfo(@NonNull String osBuildVersion, long wifiStackVersion,
                 @NonNull String wifiDriverVersion, @NonNull String wifiFirmwareVersion) {
             mOsBuildVersion = osBuildVersion;
             mWifiStackVersion = wifiStackVersion;
@@ -648,7 +657,7 @@
         String getOsBuildVersion() {
             return mOsBuildVersion;
         }
-        int getWifiStackVersion() {
+        long getWifiStackVersion() {
             return mWifiStackVersion;
         }
         String getWifiDriverVersion() {
@@ -842,7 +851,7 @@
                 @NonNull SoftwareBuildInfo softwareBuildInfo) {
             String osBuildVersion = softwareBuildInfo.hasOsBuildVersion()
                     ? softwareBuildInfo.getOsBuildVersion() : "NA";
-            int stackVersion = softwareBuildInfo.hasWifiStackVersion()
+            long stackVersion = softwareBuildInfo.hasWifiStackVersion()
                     ? softwareBuildInfo.getWifiStackVersion() : 0;
             String driverVersion = softwareBuildInfo.hasWifiDriverVersion()
                     ? softwareBuildInfo.getWifiDriverVersion() : "NA";
diff --git a/service/java/com/android/server/wifi/WifiMetrics.java b/service/java/com/android/server/wifi/WifiMetrics.java
index dbd5325..a704f10 100644
--- a/service/java/com/android/server/wifi/WifiMetrics.java
+++ b/service/java/com/android/server/wifi/WifiMetrics.java
@@ -272,10 +272,17 @@
     private final IntCounter mTxLinkSpeedCount5gLow = new IntCounter();
     private final IntCounter mTxLinkSpeedCount5gMid = new IntCounter();
     private final IntCounter mTxLinkSpeedCount5gHigh = new IntCounter();
+    private final IntCounter mTxLinkSpeedCount6gLow = new IntCounter();
+    private final IntCounter mTxLinkSpeedCount6gMid = new IntCounter();
+    private final IntCounter mTxLinkSpeedCount6gHigh = new IntCounter();
+
     private final IntCounter mRxLinkSpeedCount2g = new IntCounter();
     private final IntCounter mRxLinkSpeedCount5gLow = new IntCounter();
     private final IntCounter mRxLinkSpeedCount5gMid = new IntCounter();
     private final IntCounter mRxLinkSpeedCount5gHigh = new IntCounter();
+    private final IntCounter mRxLinkSpeedCount6gLow = new IntCounter();
+    private final IntCounter mRxLinkSpeedCount6gMid = new IntCounter();
+    private final IntCounter mRxLinkSpeedCount6gHigh = new IntCounter();
 
     /** RSSI of the scan result for the last connection event*/
     private int mScanResultRssi = 0;
@@ -2159,8 +2166,14 @@
                 mTxLinkSpeedCount5gLow.increment(txLinkSpeed);
             } else if (frequency <= KnownBandsChannelHelper.BAND_5_GHZ_MID_END_FREQ) {
                 mTxLinkSpeedCount5gMid.increment(txLinkSpeed);
-            } else {
+            } else if (frequency <= KnownBandsChannelHelper.BAND_5_GHZ_HIGH_END_FREQ) {
                 mTxLinkSpeedCount5gHigh.increment(txLinkSpeed);
+            } else if (frequency <= KnownBandsChannelHelper.BAND_6_GHZ_LOW_END_FREQ) {
+                mTxLinkSpeedCount6gLow.increment(txLinkSpeed);
+            } else if (frequency <= KnownBandsChannelHelper.BAND_6_GHZ_MID_END_FREQ) {
+                mTxLinkSpeedCount6gMid.increment(txLinkSpeed);
+            } else if (frequency <= KnownBandsChannelHelper.BAND_6_GHZ_HIGH_END_FREQ) {
+                mTxLinkSpeedCount6gHigh.increment(txLinkSpeed);
             }
         }
     }
@@ -2184,8 +2197,14 @@
                 mRxLinkSpeedCount5gLow.increment(rxLinkSpeed);
             } else if (frequency <= KnownBandsChannelHelper.BAND_5_GHZ_MID_END_FREQ) {
                 mRxLinkSpeedCount5gMid.increment(rxLinkSpeed);
-            } else {
+            } else if (frequency <= KnownBandsChannelHelper.BAND_5_GHZ_HIGH_END_FREQ) {
                 mRxLinkSpeedCount5gHigh.increment(rxLinkSpeed);
+            } else if (frequency <= KnownBandsChannelHelper.BAND_6_GHZ_LOW_END_FREQ) {
+                mRxLinkSpeedCount6gLow.increment(rxLinkSpeed);
+            } else if (frequency <= KnownBandsChannelHelper.BAND_6_GHZ_MID_END_FREQ) {
+                mRxLinkSpeedCount6gMid.increment(rxLinkSpeed);
+            } else if (frequency <= KnownBandsChannelHelper.BAND_6_GHZ_HIGH_END_FREQ) {
+                mRxLinkSpeedCount6gHigh.increment(rxLinkSpeed);
             }
         }
     }
@@ -3656,10 +3675,18 @@
                 pw.println("mWifiLogProto.txLinkSpeedCount5gLow=" + mTxLinkSpeedCount5gLow);
                 pw.println("mWifiLogProto.txLinkSpeedCount5gMid=" + mTxLinkSpeedCount5gMid);
                 pw.println("mWifiLogProto.txLinkSpeedCount5gHigh=" + mTxLinkSpeedCount5gHigh);
+                pw.println("mWifiLogProto.txLinkSpeedCount6gLow=" + mTxLinkSpeedCount6gLow);
+                pw.println("mWifiLogProto.txLinkSpeedCount6gMid=" + mTxLinkSpeedCount6gMid);
+                pw.println("mWifiLogProto.txLinkSpeedCount6gHigh=" + mTxLinkSpeedCount6gHigh);
+
                 pw.println("mWifiLogProto.rxLinkSpeedCount2g=" + mRxLinkSpeedCount2g);
                 pw.println("mWifiLogProto.rxLinkSpeedCount5gLow=" + mRxLinkSpeedCount5gLow);
                 pw.println("mWifiLogProto.rxLinkSpeedCount5gMid=" + mRxLinkSpeedCount5gMid);
                 pw.println("mWifiLogProto.rxLinkSpeedCount5gHigh=" + mRxLinkSpeedCount5gHigh);
+                pw.println("mWifiLogProto.rxLinkSpeedCount6gLow=" + mRxLinkSpeedCount6gLow);
+                pw.println("mWifiLogProto.rxLinkSpeedCount6gMid=" + mRxLinkSpeedCount6gMid);
+                pw.println("mWifiLogProto.rxLinkSpeedCount6gHigh=" + mRxLinkSpeedCount6gHigh);
+
                 pw.println("mWifiLogProto.numIpRenewalFailure="
                         + mWifiLogProto.numIpRenewalFailure);
                 pw.println("mWifiLogProto.connectionDurationStats="
@@ -4116,9 +4143,9 @@
             for (int i = 0; i < mConnectToNetworkNotificationActionCount.size(); i++) {
                 ConnectToNetworkNotificationAndActionCount keyVal =
                         new ConnectToNetworkNotificationAndActionCount();
-                int key = mConnectToNetworkNotificationActionCount.keyAt(i);
-                keyVal.notification = key / CONNECT_TO_NETWORK_NOTIFICATION_ACTION_KEY_MULTIPLIER;
-                keyVal.action = key % CONNECT_TO_NETWORK_NOTIFICATION_ACTION_KEY_MULTIPLIER;
+                int k = mConnectToNetworkNotificationActionCount.keyAt(i);
+                keyVal.notification =  k / CONNECT_TO_NETWORK_NOTIFICATION_ACTION_KEY_MULTIPLIER;
+                keyVal.action = k % CONNECT_TO_NETWORK_NOTIFICATION_ACTION_KEY_MULTIPLIER;
                 keyVal.recommender =
                         ConnectToNetworkNotificationAndActionCount.RECOMMENDER_OPEN;
                 keyVal.count = mConnectToNetworkNotificationActionCount.valueAt(i);
@@ -4319,10 +4346,18 @@
             mWifiLogProto.txLinkSpeedCount5GLow = mTxLinkSpeedCount5gLow.toProto();
             mWifiLogProto.txLinkSpeedCount5GMid = mTxLinkSpeedCount5gMid.toProto();
             mWifiLogProto.txLinkSpeedCount5GHigh = mTxLinkSpeedCount5gHigh.toProto();
+            mWifiLogProto.txLinkSpeedCount6GLow = mTxLinkSpeedCount6gLow.toProto();
+            mWifiLogProto.txLinkSpeedCount6GMid = mTxLinkSpeedCount6gMid.toProto();
+            mWifiLogProto.txLinkSpeedCount6GHigh = mTxLinkSpeedCount6gHigh.toProto();
+
             mWifiLogProto.rxLinkSpeedCount2G = mRxLinkSpeedCount2g.toProto();
             mWifiLogProto.rxLinkSpeedCount5GLow = mRxLinkSpeedCount5gLow.toProto();
             mWifiLogProto.rxLinkSpeedCount5GMid = mRxLinkSpeedCount5gMid.toProto();
             mWifiLogProto.rxLinkSpeedCount5GHigh = mRxLinkSpeedCount5gHigh.toProto();
+            mWifiLogProto.rxLinkSpeedCount6GLow = mRxLinkSpeedCount6gLow.toProto();
+            mWifiLogProto.rxLinkSpeedCount6GMid = mRxLinkSpeedCount6gMid.toProto();
+            mWifiLogProto.rxLinkSpeedCount6GHigh = mRxLinkSpeedCount6gHigh.toProto();
+
             HealthMonitorMetrics healthMonitorMetrics = mWifiHealthMonitor.buildProto();
             if (healthMonitorMetrics != null) {
                 mWifiLogProto.healthMonitorMetrics = healthMonitorMetrics;
@@ -4359,8 +4394,9 @@
             initialPartialScanStats.failedScanChannelCountHistogram =
                     mInitPartialScanFailureHistogram.toProto();
             mWifiLogProto.initPartialScanStats = initialPartialScanStats;
-
             mWifiLogProto.carrierWifiMetrics = mCarrierWifiMetrics.toProto();
+            mWifiLogProto.mainlineModuleVersion = mWifiHealthMonitor.getWifiStackVersion();
+
         }
     }
 
@@ -4467,10 +4503,16 @@
             mTxLinkSpeedCount5gLow.clear();
             mTxLinkSpeedCount5gMid.clear();
             mTxLinkSpeedCount5gHigh.clear();
+            mTxLinkSpeedCount6gLow.clear();
+            mTxLinkSpeedCount6gMid.clear();
+            mTxLinkSpeedCount6gHigh.clear();
             mRxLinkSpeedCount2g.clear();
             mRxLinkSpeedCount5gLow.clear();
             mRxLinkSpeedCount5gMid.clear();
             mRxLinkSpeedCount5gHigh.clear();
+            mRxLinkSpeedCount6gLow.clear();
+            mRxLinkSpeedCount6gMid.clear();
+            mRxLinkSpeedCount6gHigh.clear();
             mWifiAlertReasonCounts.clear();
             mWifiScoreCounts.clear();
             mWifiUsabilityScoreCounts.clear();
diff --git a/service/java/com/android/server/wifi/WifiNetworkSelector.java b/service/java/com/android/server/wifi/WifiNetworkSelector.java
index f59a50f..50078b6 100644
--- a/service/java/com/android/server/wifi/WifiNetworkSelector.java
+++ b/service/java/com/android/server/wifi/WifiNetworkSelector.java
@@ -400,9 +400,15 @@
 
             // Skip network with too weak signals.
             if (isSignalTooWeak(scanResult)) {
-                lowRssi.append(scanId).append("(")
-                        .append(scanResult.is24GHz() ? "2.4GHz" : "5GHz")
-                        .append(")").append(scanResult.level).append(" / ");
+                lowRssi.append(scanId);
+                if (scanResult.is24GHz()) {
+                    lowRssi.append("(2.4GHz)");
+                } else if (scanResult.is5GHz()) {
+                    lowRssi.append("(5GHz)");
+                } else if (scanResult.is6GHz()) {
+                    lowRssi.append("(6GHz)");
+                }
+                lowRssi.append(scanResult.level).append(" / ");
                 continue;
             }
 
diff --git a/service/java/com/android/server/wifi/WifiNetworkSuggestionsManager.java b/service/java/com/android/server/wifi/WifiNetworkSuggestionsManager.java
index 5d5a7d7..464ced0 100644
--- a/service/java/com/android/server/wifi/WifiNetworkSuggestionsManager.java
+++ b/service/java/com/android/server/wifi/WifiNetworkSuggestionsManager.java
@@ -993,6 +993,12 @@
                         WifiConfigurationUtil.VALIDATE_FOR_ADD)) {
                     return false;
                 }
+                if (wns.wifiConfiguration.isEnterprise()
+                        && wns.wifiConfiguration.enterpriseConfig.isInsecure()) {
+                    Log.e(TAG, "Insecure enterprise suggestion is invalid.");
+                    return false;
+                }
+
             } else {
                 if (!wns.passpointConfiguration.validate()) {
                     return false;
diff --git a/service/java/com/android/server/wifi/WifiServiceImpl.java b/service/java/com/android/server/wifi/WifiServiceImpl.java
index 9d12aa0..0704227 100644
--- a/service/java/com/android/server/wifi/WifiServiceImpl.java
+++ b/service/java/com/android/server/wifi/WifiServiceImpl.java
@@ -1448,12 +1448,20 @@
 
         @GuardedBy("mLocalOnlyHotspotRequests")
         private void startForFirstRequestLocked(LocalOnlyHotspotRequestInfo request) {
-            boolean is5Ghz = hasAutomotiveFeature(mContext)
-                    && mContext.getResources().getBoolean(
-                    R.bool.config_wifi_local_only_hotspot_5ghz)
-                    && is5GhzBandSupportedInternal();
+            int band = SoftApConfiguration.BAND_2GHZ;
 
-            int band = is5Ghz ? SoftApConfiguration.BAND_5GHZ : SoftApConfiguration.BAND_2GHZ;
+            // For auto only
+            if (hasAutomotiveFeature(mContext)) {
+                if (mContext.getResources().getBoolean(R.bool.config_wifiLocalOnlyHotspot6ghz)
+                        && mContext.getResources().getBoolean(R.bool.config_wifiSoftap6ghzSupported)
+                        && is6GhzBandSupportedInternal()) {
+                    band = SoftApConfiguration.BAND_6GHZ;
+                } else if (mContext.getResources().getBoolean(
+                        R.bool.config_wifi_local_only_hotspot_5ghz)
+                        && is5GhzBandSupportedInternal()) {
+                    band = SoftApConfiguration.BAND_5GHZ;
+                }
+            }
 
             SoftApConfiguration softApConfig = WifiApConfigStore.generateLocalOnlyHotspotConfig(
                     mContext, band, request.getCustomConfig());
@@ -3489,7 +3497,7 @@
         if (mVerboseLoggingEnabled) {
             mLog.info("getCurrentNetwork uid=%").c(Binder.getCallingUid()).flush();
         }
-        return mClientModeImpl.getCurrentNetwork();
+        return mClientModeImpl.syncGetCurrentNetwork(mClientModeImplChannel);
     }
 
     public static String toHexString(String s) {
diff --git a/service/java/com/android/server/wifi/WifiShellCommand.java b/service/java/com/android/server/wifi/WifiShellCommand.java
index 41933ab..a3cae77 100644
--- a/service/java/com/android/server/wifi/WifiShellCommand.java
+++ b/service/java/com/android/server/wifi/WifiShellCommand.java
@@ -712,6 +712,8 @@
                 configuration.meteredOverride = METERED_OVERRIDE_METERED;
             } else if (option.equals("-d")) {
                 configuration.allowAutojoin = false;
+            } else if (option.equals("-b")) {
+                configuration.BSSID = getNextArgRequired();
             } else {
                 pw.println("Ignoring unknown option " + option);
             }
@@ -783,6 +785,8 @@
                 suggestionBuilder.setCredentialSharedWithUser(true);
             } else if (option.equals("-d")) {
                 suggestionBuilder.setIsInitialAutojoinEnabled(false);
+            } else if (option.equals("-b")) {
+                suggestionBuilder.setBssid(MacAddress.fromString(getNextArgRequired()));
             } else {
                 pw.println("Ignoring unknown option " + option);
             }
@@ -808,19 +812,33 @@
         } else {
             throw new IllegalArgumentException("Unknown network type " + type);
         }
+        String bssid = null;
+        String option = getNextOption();
+        while (option != null) {
+            if (option.equals("-b")) {
+                bssid = getNextArgRequired();
+            } else {
+                pw.println("Ignoring unknown option " + option);
+            }
+            option = getNextOption();
+        }
+
         // Permission approval bypass is only available to requests with both ssid & bssid set.
         // So, find scan result with the best rssi level to set in the request.
-        ScanResult matchingScanResult =
-                mWifiService.getScanResults(SHELL_PACKAGE_NAME, null)
-                .stream()
-                .filter(s -> s.SSID.equals(ssid))
-                .max(Comparator.comparingInt(s -> s.level))
-                .orElse(null);
-        if (matchingScanResult != null) {
-            specifierBuilder.setBssid(MacAddress.fromString(matchingScanResult.BSSID));
-        } else {
-            pw.println("No matching bssid found, request will need UI approval");
+        if (bssid == null) {
+            ScanResult matchingScanResult =
+                    mWifiService.getScanResults(SHELL_PACKAGE_NAME, null)
+                            .stream()
+                            .filter(s -> s.SSID.equals(ssid))
+                            .max(Comparator.comparingInt(s -> s.level))
+                            .orElse(null);
+            if (matchingScanResult != null) {
+                bssid = matchingScanResult.BSSID;
+            } else {
+                pw.println("No matching bssid found, request will need UI approval");
+            }
         }
+        if (bssid != null) specifierBuilder.setBssid(MacAddress.fromString(bssid));
         return new NetworkRequest.Builder()
                 .addTransportType(TRANSPORT_WIFI)
                 .removeCapability(NET_CAPABILITY_INTERNET)
@@ -945,7 +963,8 @@
         pw.println("    Start a new scan");
         pw.println("  list-networks");
         pw.println("    Lists the saved networks");
-        pw.println("  connect-network <ssid> open|owe|wpa2|wpa3 [<passphrase>] [-m] [-d]");
+        pw.println("  connect-network <ssid> open|owe|wpa2|wpa3 [<passphrase>] [-m] [-d] "
+                + "[-b <bssid>]");
         pw.println("    Connect to a network with provided params and add to saved networks list");
         pw.println("    <ssid> - SSID of the network");
         pw.println("    open|owe|wpa2|wpa3 - Security type of the network.");
@@ -957,7 +976,9 @@
         pw.println("           - 'wpa3' - WPA-3 PSK networks");
         pw.println("    -m - Mark the network metered.");
         pw.println("    -d - Mark the network autojoin disabled.");
-        pw.println("  add-network <ssid> open|owe|wpa2|wpa3 [<passphrase>] [-m] [-d]");
+        pw.println("    -b <bssid> - Set specific BSSID.");
+        pw.println("  add-network <ssid> open|owe|wpa2|wpa3 [<passphrase>] [-m] [-d] "
+                + "[-b <bssid>]");
         pw.println("    Add/update saved network with provided params");
         pw.println("    <ssid> - SSID of the network");
         pw.println("    open|owe|wpa2|wpa3 - Security type of the network.");
@@ -969,6 +990,7 @@
         pw.println("           - 'wpa3' - WPA-3 PSK networks");
         pw.println("    -m - Mark the network metered.");
         pw.println("    -d - Mark the network autojoin disabled.");
+        pw.println("    -b <bssid> - Set specific BSSID.");
         pw.println("  forget-network <networkId>");
         pw.println("    Remove the network mentioned by <networkId>");
         pw.println("        - Use list-networks to retrieve <networkId> for the network");
@@ -976,7 +998,8 @@
         pw.println("    Current wifi status");
         pw.println("  set-verbose-logging enabled|disabled ");
         pw.println("    Set the verbose logging enabled or disabled");
-        pw.println("  add-suggestion <ssid> open|owe|wpa2|wpa3 [<passphrase>] [-u] [-m] [-s] [-d]");
+        pw.println("  add-suggestion <ssid> open|owe|wpa2|wpa3 [<passphrase>] [-u] [-m] [-s] [-d]"
+                + "[-b <bssid>]");
         pw.println("    Add a network suggestion with provided params");
         pw.println("    Use 'network-suggestions-set-user-approved " + SHELL_PACKAGE_NAME + " yes'"
                 +  " to approve suggestions added via shell (Needs root access)");
@@ -992,6 +1015,7 @@
         pw.println("    -m - Mark the suggestion metered.");
         pw.println("    -s - Share the suggestion with user.");
         pw.println("    -d - Mark the suggestion autojoin disabled.");
+        pw.println("    -b <bssid> - Set specific BSSID.");
         pw.println("  remove-suggestion <ssid>");
         pw.println("    Remove a network suggestion with provided SSID of the network");
         pw.println("  remove-all-suggestions");
@@ -1073,7 +1097,7 @@
         pw.println("    and/or 'wifi_softap_wpa3_sae_supported', each on a separate line.");
         pw.println("  settings-reset");
         pw.println("    Initiates wifi settings reset");
-        pw.println("  add-request <ssid> open|owe|wpa2|wpa3 [<passphrase>]");
+        pw.println("  add-request <ssid> open|owe|wpa2|wpa3 [<passphrase>] [-b <bssid>]");
         pw.println("    Add a network request with provided params");
         pw.println("    Use 'network-requests-set-user-approved android yes'"
                 +  " to pre-approve requests added via rooted shell (Not persisted)");
@@ -1085,6 +1109,7 @@
         pw.println("        - Use 'wpa2' or 'wpa3' for networks with passphrase");
         pw.println("           - 'wpa2' - WPA-2 PSK networks (Most prevalent)");
         pw.println("           - 'wpa3' - WPA-3 PSK networks");
+        pw.println("    -b <bssid> - Set specific BSSID.");
         pw.println("  remove-request <ssid>");
         pw.println("    Remove a network request with provided SSID of the network");
         pw.println("  remove-all-requests");
diff --git a/service/proto/src/metrics.proto b/service/proto/src/metrics.proto
index eaea734..01ad650 100644
--- a/service/proto/src/metrics.proto
+++ b/service/proto/src/metrics.proto
@@ -712,6 +712,27 @@
 
   // Metrics about carrier wifi network.
   optional CarrierWifiMetrics carrier_wifi_metrics = 200;
+
+  // Long version code of wifi mainline module, 0 means not available.
+  optional int64 mainline_module_version = 201;
+
+  // Histogram of Tx link speed at 6G low band
+  repeated Int32Count tx_link_speed_count_6g_low = 202;
+
+  // Histogram of Tx link speed at 6G middle band
+  repeated Int32Count tx_link_speed_count_6g_mid = 203;
+
+  // Histogram of Tx link speed at 6G high band
+  repeated Int32Count tx_link_speed_count_6g_high = 204;
+
+  // Histogram of Rx link speed at 6G low band
+  repeated Int32Count rx_link_speed_count_6g_low = 205;
+
+  // Histogram of Rx link speed at 6G middle band
+  repeated Int32Count rx_link_speed_count_6g_mid = 206;
+
+  // Histogram of Rx link speed at 6G high band
+  repeated Int32Count rx_link_speed_count_6g_high = 207;
 }
 
 // Information that gets logged for every WiFi connection.
diff --git a/service/proto/src/scorecard.proto b/service/proto/src/scorecard.proto
index ad5822c..d351c56 100644
--- a/service/proto/src/scorecard.proto
+++ b/service/proto/src/scorecard.proto
@@ -146,7 +146,7 @@
   // Android OS build version
   optional string os_build_version = 1;
   // WiFi stack APK version, 0 means not available.
-  optional int32 wifi_stack_version = 2;
+  optional int64 wifi_stack_version = 2;
   // WiFi driver version
   optional string wifi_driver_version = 3;
   // WiFi firmware version
diff --git a/service/res/values-fr/strings.xml b/service/res/values-fr/strings.xml
index 1aba6a1..62999cc 100644
--- a/service/res/values-fr/strings.xml
+++ b/service/res/values-fr/strings.xml
@@ -17,7 +17,7 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="wifiResourcesAppLabel" product="default" msgid="4965162975090543792">"Ressources Wi-Fi du système"</string>
-    <string name="wifi_available_title" msgid="2844963247498642107">"Se connecter pour ouvrir le réseau Wi-Fi"</string>
+    <string name="wifi_available_title" msgid="2844963247498642107">"Connexion à un réseau Wi-Fi ouvert"</string>
     <string name="wifi_available_title_connecting" msgid="4308431577637294026">"Connexion au réseau Wi-Fi"</string>
     <string name="wifi_available_title_connected" msgid="922603556292157664">"Connecté au réseau Wi-Fi"</string>
     <string name="wifi_available_title_failed_to_connect" msgid="2304443371893419545">"Impossible de se connecter au réseau Wi-Fi"</string>
diff --git a/service/res/values/config.xml b/service/res/values/config.xml
index 8813738..ad454c1 100644
--- a/service/res/values/config.xml
+++ b/service/res/values/config.xml
@@ -217,8 +217,14 @@
     <!-- Wifi driver supports 6GHz band for softap -->
     <bool translatable="false" name="config_wifiSoftap6ghzSupported">false</bool>
 
-    <!-- Indicates that local-only hotspot should be brought up at 5GHz.  This option is
-         for automotive builds only (the one that have PackageManager#FEATURE_AUTOMOTIVE) -->
+    <!-- Indicates that local-only hotspot should be brought up at 6GHz if possible.
+         This option is for automotive builds only (the one that have
+         PackageManager#FEATURE_AUTOMOTIVE) -->
+    <bool translatable="false" name="config_wifiLocalOnlyHotspot6ghz">false</bool>
+
+    <!-- Indicates that local-only hotspot should be brought up at 5GHz if 6GHz is not enabled
+         or feasible.  This option is for automotive builds only (the one that have
+         PackageManager#FEATURE_AUTOMOTIVE) -->
     <bool translatable="false" name="config_wifi_local_only_hotspot_5ghz">false</bool>
 
     <!-- Indicates that connected MAC randomization is supported on this device -->
diff --git a/service/res/values/overlayable.xml b/service/res/values/overlayable.xml
index 7b77da5..cab5bbf 100644
--- a/service/res/values/overlayable.xml
+++ b/service/res/values/overlayable.xml
@@ -81,6 +81,7 @@
           <item type="bool" name="config_wifiSoftapHeSuBeamformeeSupported" />
           <item type="bool" name="config_wifiSoftapHeMuBeamformerSupported" />
           <item type="bool" name="config_wifiSoftapHeTwtSupported" />
+          <item type="bool" name="config_wifiLocalOnlyHotspot6ghz" />
           <item type="bool" name="config_wifi_local_only_hotspot_5ghz" />
           <item type="bool" name="config_wifi_connected_mac_randomization_supported" />
           <item type="bool" name="config_wifi_p2p_mac_randomization_supported" />
diff --git a/tests/wifitests/Android.bp b/tests/wifitests/Android.bp
index 851a601..6c48c3b 100644
--- a/tests/wifitests/Android.bp
+++ b/tests/wifitests/Android.bp
@@ -17,13 +17,7 @@
 android_test {
     name: "FrameworksWifiTests",
 
-    srcs: [
-        "**/*.java",
-    	// wifi-service sources must be included here so that the latest changes
-    	// will be used when tests. Otherwise the tests would run against the installed
-    	// system.
-        ":wifi-service-srcs",
-    ],
+    srcs: [ "**/*.java" ],
 
     dxflags: ["--multi-dex"],
 
@@ -34,35 +28,14 @@
         "hamcrest-library",
         "mockito-target-extended-minus-junit4",
         "frameworks-base-testutils",
-	"truth-prebuilt",
+        "truth-prebuilt",
 
-        // Libraries needed by wifi-service
-        "android.hardware.wifi-V1.0-java",
-        "android.hardware.wifi-V1.1-java",
-        "android.hardware.wifi-V1.2-java",
-        "android.hardware.wifi-V1.3-java",
-        "android.hardware.wifi-V1.4-java",
-        "android.hardware.wifi.hostapd-V1.0-java",
-        "android.hardware.wifi.hostapd-V1.1-java",
-        "android.hardware.wifi.hostapd-V1.2-java",
-        "android.hardware.wifi.supplicant-V1.0-java",
-        "android.hardware.wifi.supplicant-V1.1-java",
-        "android.hardware.wifi.supplicant-V1.2-java",
-        "android.hardware.wifi.supplicant-V1.3-java",
-        "android.hidl.manager-V1.2-java",
-        "androidx.annotation_annotation",
-        "bouncycastle-unbundled",
-        "ksoap2",
-	// Note: libprotobuf-java-lite uses a few core platform APIs which
-	// does show up as @hide API usage. But, this can be safely ignored
-	// since the library uses reflection to ensure that the OS does provide
-	// the necessary core platform APIs.
-        "libprotobuf-java-lite",
-        "libnanohttpd",
-        "services.net-module-wifi",
-        "services.core",
-        "wifi-lite-protos",
-        "wifi-nano-protos",
+        // Statically link wifi-service-pre-jarjar since we want to test the working copy of
+        // service-wifi, not the on-device copy.
+        // Use pre-jarjar version so that we can reference symbols before they are renamed.
+        // Then, the jarjar_rules here will perform the rename for the entire APK
+        // i.e. service-wifi + test code
+        "wifi-service-pre-jarjar",
     ],
 
     jarjar_rules: ":wifi-jarjar-rules",
@@ -80,14 +53,8 @@
         "android.test.runner",
         "android.test.base",
         "android.test.mock",
-
-        // Libraries needed by wifi-service
-        "error_prone_annotations",
-        "jsr305",
-        "services",
         // load the resources from the resources APK.
         "ServiceWifiResources",
-        "unsupportedappusage",
     ],
 
     // These must be explicitly included because they are not normally accessible
diff --git a/tests/wifitests/src/com/android/server/wifi/ActiveModeWardenTest.java b/tests/wifitests/src/com/android/server/wifi/ActiveModeWardenTest.java
index db7b4e2..ceaf76d 100644
--- a/tests/wifitests/src/com/android/server/wifi/ActiveModeWardenTest.java
+++ b/tests/wifitests/src/com/android/server/wifi/ActiveModeWardenTest.java
@@ -2172,4 +2172,112 @@
         when(mWifiNative.isStaApConcurrencySupported()).thenReturn(true);
         assertTrue(mActiveModeWarden.isStaApConcurrencySupported());
     }
+
+    @Test
+    public void airplaneModeToggleOnDisablesWifi() throws Exception {
+        enterClientModeActiveState();
+        assertInEnabledState();
+
+        assertWifiShutDown(() -> {
+            when(mSettingsStore.isAirplaneModeOn()).thenReturn(true);
+            mActiveModeWarden.airplaneModeToggled();
+            mLooper.dispatchAll();
+        });
+
+        mClientListener.onStopped();
+        mLooper.dispatchAll();
+        assertInDisabledState();
+    }
+
+    @Test
+    public void airplaneModeToggleOnDisablesSoftAp() throws Exception {
+        enterSoftApActiveMode();
+        assertInEnabledState();
+
+        assertWifiShutDown(() -> {
+            when(mSettingsStore.isAirplaneModeOn()).thenReturn(true);
+            mActiveModeWarden.airplaneModeToggled();
+            mLooper.dispatchAll();
+        });
+
+        mSoftApListener.onStopped();
+        mLooper.dispatchAll();
+        assertInDisabledState();
+    }
+
+    @Test
+    public void airplaneModeToggleOffIsDeferredWhileProcessingToggleOnWithOneModeManager()
+            throws Exception {
+        enterClientModeActiveState();
+        assertInEnabledState();
+
+        // APM toggle on
+        assertWifiShutDown(() -> {
+            when(mSettingsStore.isAirplaneModeOn()).thenReturn(true);
+            mActiveModeWarden.airplaneModeToggled();
+            mLooper.dispatchAll();
+        });
+
+
+        // APM toggle off before the stop is complete.
+        assertInEnabledState();
+        when(mClientModeManager.isStopping()).thenReturn(true);
+        when(mSettingsStore.isAirplaneModeOn()).thenReturn(false);
+        mActiveModeWarden.airplaneModeToggled();
+        mLooper.dispatchAll();
+
+        mClientListener.onStopped();
+        mLooper.dispatchAll();
+
+        verify(mClientModeManager, times(2)).start();
+        verify(mClientModeManager, times(2)).setRole(ROLE_CLIENT_PRIMARY);
+
+        mClientListener.onStarted();
+        mLooper.dispatchAll();
+
+        // We should be back to enabled state.
+        assertInEnabledState();
+    }
+
+    @Test
+    public void airplaneModeToggleOffIsDeferredWhileProcessingToggleOnWithTwoModeManager()
+            throws Exception {
+        enterClientModeActiveState();
+        enterSoftApActiveMode();
+        assertInEnabledState();
+
+        // APM toggle on
+        assertWifiShutDown(() -> {
+            when(mSettingsStore.isAirplaneModeOn()).thenReturn(true);
+            mActiveModeWarden.airplaneModeToggled();
+            mLooper.dispatchAll();
+        });
+
+
+        // APM toggle off before the stop is complete.
+        assertInEnabledState();
+        when(mClientModeManager.isStopping()).thenReturn(true);
+        when(mSoftApManager.isStopping()).thenReturn(true);
+        when(mSettingsStore.isAirplaneModeOn()).thenReturn(false);
+        mActiveModeWarden.airplaneModeToggled();
+        mLooper.dispatchAll();
+
+        // AP stopped, should not process APM toggle.
+        mSoftApListener.onStopped();
+        mLooper.dispatchAll();
+        verify(mClientModeManager, times(1)).start();
+        verify(mClientModeManager, times(1)).setRole(ROLE_CLIENT_PRIMARY);
+
+        // STA also stopped, should process APM toggle.
+        mClientListener.onStopped();
+        mLooper.dispatchAll();
+        verify(mClientModeManager, times(2)).start();
+        verify(mClientModeManager, times(2)).setRole(ROLE_CLIENT_PRIMARY);
+
+        mClientListener.onStarted();
+        mLooper.dispatchAll();
+
+        // We should be back to enabled state.
+        assertInEnabledState();
+    }
 }
diff --git a/tests/wifitests/src/com/android/server/wifi/ClientModeImplTest.java b/tests/wifitests/src/com/android/server/wifi/ClientModeImplTest.java
index bc29d34..58f5b1c 100644
--- a/tests/wifitests/src/com/android/server/wifi/ClientModeImplTest.java
+++ b/tests/wifitests/src/com/android/server/wifi/ClientModeImplTest.java
@@ -421,6 +421,7 @@
     @Mock ThroughputPredictor mThroughputPredictor;
     @Mock ScanRequestProxy mScanRequestProxy;
     @Mock DeviceConfigFacade mDeviceConfigFacade;
+    @Mock Network mNetwork;
 
     final ArgumentCaptor<WifiConfigManager.OnNetworkUpdateListener> mConfigUpdateListenerCaptor =
             ArgumentCaptor.forClass(WifiConfigManager.OnNetworkUpdateListener.class);
@@ -533,10 +534,8 @@
             return null;
         }).when(mIpClient).shutdown();
         when(mConnectivityManager.registerNetworkAgent(any(), any(), any(), any(), anyInt(), any(),
-                anyInt())).thenReturn(mock(Network.class));
-        List<SubscriptionInfo> subList = new ArrayList<>() {{
-                add(mock(SubscriptionInfo.class));
-            }};
+                anyInt())).thenReturn(mNetwork);
+        List<SubscriptionInfo> subList = Arrays.asList(mock(SubscriptionInfo.class));
         when(mSubscriptionManager.getActiveSubscriptionInfoList()).thenReturn(subList);
         when(mSubscriptionManager.getActiveSubscriptionIdList())
                 .thenReturn(new int[]{DATA_SUBID});
@@ -1592,6 +1591,59 @@
     }
 
     /**
+     * If caller tries to connect to a network that previously failed connection, the connection
+     * request should succeed.
+     *
+     * Test: Create and trigger connect to a network, then fail the connection. Now try to reconnect
+     * to the same network. Verify that connection request returns with CONNECT_NETWORK_SUCCEEDED
+     * and did trigger a new * connection.
+     */
+    @Test
+    public void connectAfterAssociationRejection() throws Exception {
+        triggerConnect();
+
+        // fail the connection.
+        mCmi.sendMessage(WifiMonitor.ASSOCIATION_REJECTION_EVENT, 0,
+                ISupplicantStaIfaceCallback.StatusCode.AP_UNABLE_TO_HANDLE_NEW_STA, sBSSID);
+        mLooper.dispatchAll();
+
+        IActionListener connectActionListener = mock(IActionListener.class);
+        mCmi.connect(null, FRAMEWORK_NETWORK_ID, mock(Binder.class), connectActionListener, 0,
+                Binder.getCallingUid());
+        mLooper.dispatchAll();
+        verify(connectActionListener).onSuccess();
+
+        // Verify that we triggered a second connection.
+        verify(mWifiNative, times(2)).connectToNetwork(eq(WIFI_IFACE_NAME), any());
+    }
+
+    /**
+     * If caller tries to connect to a network that previously failed connection, the connection
+     * request should succeed.
+     *
+     * Test: Create and trigger connect to a network, then fail the connection. Now try to reconnect
+     * to the same network. Verify that connection request returns with CONNECT_NETWORK_SUCCEEDED
+     * and did trigger a new * connection.
+     */
+    @Test
+    public void connectAfterConnectionFailure() throws Exception {
+        triggerConnect();
+
+        // fail the connection.
+        mCmi.sendMessage(WifiMonitor.NETWORK_DISCONNECTION_EVENT, FRAMEWORK_NETWORK_ID, 0, sBSSID);
+        mLooper.dispatchAll();
+
+        IActionListener connectActionListener = mock(IActionListener.class);
+        mCmi.connect(null, FRAMEWORK_NETWORK_ID, mock(Binder.class), connectActionListener, 0,
+                Binder.getCallingUid());
+        mLooper.dispatchAll();
+        verify(connectActionListener).onSuccess();
+
+        // Verify that we triggered a second connection.
+        verify(mWifiNative, times(2)).connectToNetwork(eq(WIFI_IFACE_NAME), any());
+    }
+
+    /**
      * If caller tries to connect to a new network while still provisioning the current one,
      * the connection attempt should succeed.
      */
@@ -2420,18 +2472,20 @@
         assertEquals("DisconnectedState", getCurrentState().getName());
 
         // Simulate an AUTHENTICATION_FAILURE_EVENT, which should clear the ExtraFailureReason
-        reset(mWifiConfigManager);
+        mCmi.sendMessage(ClientModeImpl.CMD_START_CONNECT, 0, 0, sBSSID);
+        mLooper.dispatchAll();
         mCmi.sendMessage(WifiMonitor.AUTHENTICATION_FAILURE_EVENT, 0, 0, null);
         mLooper.dispatchAll();
-        verify(mWifiConfigManager).clearRecentFailureReason(eq(0));
-        verify(mWifiConfigManager, never()).setRecentFailureAssociationStatus(anyInt(), anyInt());
+        verify(mWifiConfigManager, times(1)).clearRecentFailureReason(eq(0));
+        verify(mWifiConfigManager, times(1)).setRecentFailureAssociationStatus(anyInt(), anyInt());
 
         // Simulate a NETWORK_CONNECTION_EVENT which should clear the ExtraFailureReason
-        reset(mWifiConfigManager);
+        mCmi.sendMessage(ClientModeImpl.CMD_START_CONNECT, 0, 0, sBSSID);
+        mLooper.dispatchAll();
         mCmi.sendMessage(WifiMonitor.NETWORK_CONNECTION_EVENT, 0, 0, null);
         mLooper.dispatchAll();
-        verify(mWifiConfigManager).clearRecentFailureReason(eq(0));
-        verify(mWifiConfigManager, never()).setRecentFailureAssociationStatus(anyInt(), anyInt());
+        verify(mWifiConfigManager, times(2)).clearRecentFailureReason(eq(0));
+        verify(mWifiConfigManager, times(1)).setRecentFailureAssociationStatus(anyInt(), anyInt());
     }
 
     private WifiConfiguration makeLastSelectedWifiConfiguration(int lastSelectedNetworkId,
@@ -4026,6 +4080,8 @@
 
         // Verifies that WifiLastResortWatchdog be notified
         // for FOURWAY_HANDSHAKE_TIMEOUT.
+        mCmi.sendMessage(ClientModeImpl.CMD_START_CONNECT, 0, 0, sBSSID);
+        mLooper.dispatchAll();
         mCmi.sendMessage(WifiMonitor.NETWORK_DISCONNECTION_EVENT, 0, 15, sBSSID);
         mLooper.dispatchAll();
 
@@ -5121,6 +5177,8 @@
         verify(mWifiNative, never()).removeNetworkCachedData(anyInt());
 
         // got 4WAY_HANDSHAKE_TIMEOUT during this connection attempt
+        mCmi.sendMessage(ClientModeImpl.CMD_START_CONNECT, 0, 0, sBSSID);
+        mLooper.dispatchAll();
         mCmi.sendMessage(WifiMonitor.NETWORK_DISCONNECTION_EVENT, 0, 15, sBSSID);
         mLooper.dispatchAll();
 
@@ -5207,4 +5265,19 @@
 
         verifyNoMoreInteractions(mNetworkAgentHandler);
     }
+
+    @Test
+    public void testSyncGetCurrentNetwork() throws Exception {
+        // syncGetCurrentNetwork() returns null when disconnected
+        mLooper.startAutoDispatch();
+        assertNull(mCmi.syncGetCurrentNetwork(mCmiAsyncChannel));
+        mLooper.stopAutoDispatch();
+
+        connect();
+
+        // syncGetCurrentNetwork() returns non-null Network when connected
+        mLooper.startAutoDispatch();
+        assertEquals(mNetwork, mCmi.syncGetCurrentNetwork(mCmiAsyncChannel));
+        mLooper.stopAutoDispatch();
+    }
 }
diff --git a/tests/wifitests/src/com/android/server/wifi/ClientModeManagerTest.java b/tests/wifitests/src/com/android/server/wifi/ClientModeManagerTest.java
index b733ec0..1102d1f 100644
--- a/tests/wifitests/src/com/android/server/wifi/ClientModeManagerTest.java
+++ b/tests/wifitests/src/com/android/server/wifi/ClientModeManagerTest.java
@@ -28,6 +28,7 @@
 import static com.android.dx.mockito.inline.extended.ExtendedMockito.mockitoSession;
 
 import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertNotNull;
 import static org.junit.Assert.assertNull;
 import static org.junit.Assert.assertTrue;
@@ -469,8 +470,10 @@
         reset(mContext, mListener);
         setUpSystemServiceForContext();
         mClientModeManager.stop();
+        assertTrue(mClientModeManager.isStopping());
         mLooper.dispatchAll();
         verify(mListener).onStopped();
+        assertFalse(mClientModeManager.isStopping());
 
         verify(mImsMmTelManager, never()).registerImsRegistrationCallback(any(), any());
         verify(mImsMmTelManager, never()).unregisterImsRegistrationCallback(any());
diff --git a/tests/wifitests/src/com/android/server/wifi/IpConfigStoreTestWriter.java b/tests/wifitests/src/com/android/server/wifi/IpConfigStoreTestWriter.java
new file mode 100644
index 0000000..f5a81bc
--- /dev/null
+++ b/tests/wifitests/src/com/android/server/wifi/IpConfigStoreTestWriter.java
@@ -0,0 +1,147 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.wifi;
+
+import android.net.IpConfiguration;
+import android.net.LinkAddress;
+import android.net.ProxyInfo;
+import android.net.StaticIpConfiguration;
+import android.util.Log;
+
+import java.io.DataOutputStream;
+import java.io.IOException;
+import java.net.InetAddress;
+
+/**
+ * Copied from frameworks/base/services/core/java/com/android/server/net/IpConfigStore.java
+ */
+public class IpConfigStoreTestWriter {
+    private static final String TAG = "IpConfigStoreTestWriter";
+
+    private static final String ID_KEY = "id";
+    private static final String IP_ASSIGNMENT_KEY = "ipAssignment";
+    private static final String LINK_ADDRESS_KEY = "linkAddress";
+    private static final String GATEWAY_KEY = "gateway";
+    private static final String DNS_KEY = "dns";
+    private static final String PROXY_SETTINGS_KEY = "proxySettings";
+    private static final String PROXY_HOST_KEY = "proxyHost";
+    private static final String PROXY_PORT_KEY = "proxyPort";
+    private static final String PROXY_PAC_FILE = "proxyPac";
+    private static final String EXCLUSION_LIST_KEY = "exclusionList";
+    private static final String EOS = "eos";
+
+    /** Serialize an IpConfiguration object */
+    public static boolean writeConfig(DataOutputStream out, String configKey,
+            IpConfiguration config, int version) throws IOException {
+        boolean written = false;
+
+        try {
+            switch (config.ipAssignment) {
+                case STATIC:
+                    out.writeUTF(IP_ASSIGNMENT_KEY);
+                    out.writeUTF(config.ipAssignment.toString());
+                    StaticIpConfiguration staticIpConfiguration = config.staticIpConfiguration;
+                    if (staticIpConfiguration != null) {
+                        if (staticIpConfiguration.ipAddress != null) {
+                            LinkAddress ipAddress = staticIpConfiguration.ipAddress;
+                            out.writeUTF(LINK_ADDRESS_KEY);
+                            out.writeUTF(ipAddress.getAddress().getHostAddress());
+                            out.writeInt(ipAddress.getPrefixLength());
+                        }
+                        if (staticIpConfiguration.gateway != null) {
+                            out.writeUTF(GATEWAY_KEY);
+                            out.writeInt(0);  // Default route.
+                            out.writeInt(1);  // Have a gateway.
+                            out.writeUTF(staticIpConfiguration.gateway.getHostAddress());
+                        }
+                        for (InetAddress inetAddr : staticIpConfiguration.dnsServers) {
+                            out.writeUTF(DNS_KEY);
+                            out.writeUTF(inetAddr.getHostAddress());
+                        }
+                    }
+                    written = true;
+                    break;
+                case DHCP:
+                    out.writeUTF(IP_ASSIGNMENT_KEY);
+                    out.writeUTF(config.ipAssignment.toString());
+                    written = true;
+                    break;
+                case UNASSIGNED:
+                    /* Ignore */
+                    break;
+                default:
+                    loge("Ignore invalid ip assignment while writing");
+                    break;
+            }
+
+            switch (config.proxySettings) {
+                case STATIC:
+                    ProxyInfo proxyProperties = config.httpProxy;
+                    String exclusionList = proxyProperties.getExclusionListAsString();
+                    out.writeUTF(PROXY_SETTINGS_KEY);
+                    out.writeUTF(config.proxySettings.toString());
+                    out.writeUTF(PROXY_HOST_KEY);
+                    out.writeUTF(proxyProperties.getHost());
+                    out.writeUTF(PROXY_PORT_KEY);
+                    out.writeInt(proxyProperties.getPort());
+                    if (exclusionList != null) {
+                        out.writeUTF(EXCLUSION_LIST_KEY);
+                        out.writeUTF(exclusionList);
+                    }
+                    written = true;
+                    break;
+                case PAC:
+                    ProxyInfo proxyPacProperties = config.httpProxy;
+                    out.writeUTF(PROXY_SETTINGS_KEY);
+                    out.writeUTF(config.proxySettings.toString());
+                    out.writeUTF(PROXY_PAC_FILE);
+                    out.writeUTF(proxyPacProperties.getPacFileUrl().toString());
+                    written = true;
+                    break;
+                case NONE:
+                    out.writeUTF(PROXY_SETTINGS_KEY);
+                    out.writeUTF(config.proxySettings.toString());
+                    written = true;
+                    break;
+                case UNASSIGNED:
+                    /* Ignore */
+                    break;
+                default:
+                    loge("Ignore invalid proxy settings while writing");
+                    break;
+            }
+
+            if (written) {
+                out.writeUTF(ID_KEY);
+                if (version < 3) {
+                    out.writeInt(Integer.valueOf(configKey));
+                } else {
+                    out.writeUTF(configKey);
+                }
+            }
+        } catch (NullPointerException e) {
+            loge("Failure in writing " + config + e);
+        }
+        out.writeUTF(EOS);
+
+        return written;
+    }
+
+    private static void loge(String s) {
+        Log.e(TAG, s);
+    }
+}
diff --git a/tests/wifitests/src/com/android/server/wifi/NetworkListStoreDataTest.java b/tests/wifitests/src/com/android/server/wifi/NetworkListStoreDataTest.java
index 80dfd7a..c59c8c4 100644
--- a/tests/wifitests/src/com/android/server/wifi/NetworkListStoreDataTest.java
+++ b/tests/wifitests/src/com/android/server/wifi/NetworkListStoreDataTest.java
@@ -183,8 +183,8 @@
                     + "<string name=\"EngineId\"></string>\n"
                     + "<string name=\"PrivateKeyId\"></string>\n"
                     + "<string name=\"AltSubjectMatch\"></string>\n"
-                    + "<string name=\"DomSuffixMatch\"></string>\n"
-                    + "<string name=\"CaPath\"></string>\n"
+                    + "<string name=\"DomSuffixMatch\">%s</string>\n"
+                    + "<string name=\"CaPath\">%s</string>\n"
                     + "<int name=\"EapMethod\" value=\"2\" />\n"
                     + "<int name=\"Phase2Method\" value=\"0\" />\n"
                     + "<string name=\"PLMN\"></string>\n"
@@ -413,7 +413,9 @@
                 eapNetwork.getKey().replaceAll("\"", "&quot;"),
                 eapNetwork.SSID.replaceAll("\"", "&quot;"),
                 eapNetwork.shared, eapNetwork.creatorUid,
-                eapNetwork.creatorName, eapNetwork.getRandomizedMacAddress());
+                eapNetwork.creatorName, eapNetwork.getRandomizedMacAddress(),
+                eapNetwork.enterpriseConfig.getDomainSuffixMatch(),
+                eapNetwork.enterpriseConfig.getCaPath());
         String saeNetworkXml = String.format(SINGLE_SAE_NETWORK_DATA_XML_STRING_FORMAT,
                 saeNetwork.getKey().replaceAll("\"", "&quot;"),
                 saeNetwork.SSID.replaceAll("\"", "&quot;"),
diff --git a/tests/wifitests/src/com/android/server/wifi/NetworkSuggestionNominatorTest.java b/tests/wifitests/src/com/android/server/wifi/NetworkSuggestionNominatorTest.java
index 94b14ec..9c56318 100644
--- a/tests/wifitests/src/com/android/server/wifi/NetworkSuggestionNominatorTest.java
+++ b/tests/wifitests/src/com/android/server/wifi/NetworkSuggestionNominatorTest.java
@@ -163,12 +163,50 @@
                     connectableNetworks.add(Pair.create(scanDetail, configuration));
                 });
 
-
         validateConnectableNetworks(connectableNetworks, scanSsids[0]);
-
         verifyAddToWifiConfigManager(suggestions[0].wns.wifiConfiguration);
     }
 
+    @Test
+    public void testSelectNetworkSuggestionForOneMatchWithInsecureEnterpriseSuggestion() {
+        String[] scanSsids = {"test1"};
+        String[] bssids = {"6c:f3:7f:ae:8c:f3"};
+        int[] freqs = {2470};
+        String[] caps = {"[WPA2-EAP-CCMP][ESS]"};
+        int[] levels = {-67};
+        String[] suggestionSsids = {"\"" + scanSsids[0] + "\""};
+        int[] securities = {SECURITY_EAP};
+        boolean[] appInteractions = {true};
+        boolean[] meteredness = {true};
+        int[] priorities = {-1};
+        int[] uids = {TEST_UID};
+        String[] packageNames = {TEST_PACKAGE};
+        boolean[] autojoin = {true};
+        boolean[] shareWithUser = {true};
+
+        ScanDetail[] scanDetails =
+                buildScanDetails(scanSsids, bssids, freqs, caps, levels, mClock);
+        ExtendedWifiNetworkSuggestion[] suggestions = buildNetworkSuggestions(suggestionSsids,
+                securities, appInteractions, meteredness, priorities, uids,
+                packageNames, autojoin, shareWithUser);
+        WifiConfiguration config = suggestions[0].wns.wifiConfiguration;
+        config.enterpriseConfig.setCaPath(null);
+        // Link the scan result with suggestions.
+        linkScanDetailsWithNetworkSuggestions(scanDetails, suggestions);
+        // setup config manager interactions.
+        setupAddToWifiConfigManager(suggestions[0].wns.wifiConfiguration);
+
+        List<Pair<ScanDetail, WifiConfiguration>> connectableNetworks = new ArrayList<>();
+        mNetworkSuggestionNominator.nominateNetworks(
+                Arrays.asList(scanDetails), null, null, true, false,
+                (ScanDetail scanDetail, WifiConfiguration configuration) -> {
+                    connectableNetworks.add(Pair.create(scanDetail, configuration));
+                });
+
+        // Verify no network is nominated.
+        assertTrue(connectableNetworks.isEmpty());
+    }
+
     /**
      * Ensure that we nominate the all network suggestion corresponding to the scan results
      * Expected connectable Networks: {suggestionSsids[0], suggestionSsids[1]}
diff --git a/tests/wifitests/src/com/android/server/wifi/SoftApManagerTest.java b/tests/wifitests/src/com/android/server/wifi/SoftApManagerTest.java
index ca7bc62..99cd2db 100644
--- a/tests/wifitests/src/com/android/server/wifi/SoftApManagerTest.java
+++ b/tests/wifitests/src/com/android/server/wifi/SoftApManagerTest.java
@@ -36,6 +36,8 @@
 import static com.google.common.truth.Truth.assertThat;
 
 import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
 import static org.mockito.Mockito.any;
 import static org.mockito.Mockito.anyInt;
 import static org.mockito.Mockito.anyLong;
@@ -676,6 +678,7 @@
         InOrder order = inOrder(mCallback, mListener, mContext);
 
         mSoftApManager.stop();
+        assertTrue(mSoftApManager.isStopping());
         mLooper.dispatchAll();
 
         ArgumentCaptor<Intent> intentCaptor = ArgumentCaptor.forClass(Intent.class);
@@ -694,6 +697,8 @@
         checkApStateChangedBroadcast(intentCaptor.getValue(), WIFI_AP_STATE_DISABLED,
                 WIFI_AP_STATE_DISABLING, HOTSPOT_NO_ERROR, TEST_INTERFACE_NAME,
                 softApModeConfig.getTargetMode());
+        order.verify(mListener).onStopped();
+        assertFalse(mSoftApManager.isStopping());
     }
 
     /**
@@ -729,6 +734,7 @@
                 WIFI_AP_STATE_DISABLING, HOTSPOT_NO_ERROR, TEST_INTERFACE_NAME,
                 softApModeConfig.getTargetMode());
         order.verify(mListener).onStopped();
+        assertFalse(mSoftApManager.isStopping());
     }
 
     /**
@@ -1784,6 +1790,7 @@
 
 
         mSoftApManager.start();
+        mSoftApManager.setRole(ActiveModeManager.ROLE_SOFTAP_TETHERED);
         mLooper.dispatchAll();
         verify(mFakeSoftApNotifier).dismissSoftApShutDownTimeoutExpiredNotification();
         order.verify(mWifiNative).setupInterfaceForSoftApMode(
diff --git a/tests/wifitests/src/com/android/server/wifi/SupplicantStaNetworkHalTest.java b/tests/wifitests/src/com/android/server/wifi/SupplicantStaNetworkHalTest.java
index 6f0de57..f7fc9c2 100644
--- a/tests/wifitests/src/com/android/server/wifi/SupplicantStaNetworkHalTest.java
+++ b/tests/wifitests/src/com/android/server/wifi/SupplicantStaNetworkHalTest.java
@@ -50,7 +50,6 @@
 import com.android.wifi.resources.R;
 
 import org.junit.Before;
-import org.junit.Ignore;
 import org.junit.Test;
 import org.mockito.Mock;
 import org.mockito.MockitoAnnotations;
@@ -249,7 +248,6 @@
     /**
      * Tests the saving/loading of WifiConfiguration to wpa_supplicant.
      */
-    @Ignore("b/148963201: flaky test")
     @Test
     public void testWepNetworkWifiConfigurationSaveLoad() throws Exception {
         WifiConfiguration config = WifiConfigurationTestUtil.createWepHiddenNetwork();
diff --git a/tests/wifitests/src/com/android/server/wifi/WifiBackupRestoreTest.java b/tests/wifitests/src/com/android/server/wifi/WifiBackupRestoreTest.java
index 6b01f8e..e640c42 100644
--- a/tests/wifitests/src/com/android/server/wifi/WifiBackupRestoreTest.java
+++ b/tests/wifitests/src/com/android/server/wifi/WifiBackupRestoreTest.java
@@ -25,7 +25,6 @@
 
 import androidx.test.filters.SmallTest;
 
-import com.android.server.net.IpConfigStore;
 import com.android.server.wifi.util.WifiPermissionsUtil;
 
 import org.junit.After;
@@ -1183,8 +1182,11 @@
             out.writeInt(configStoreVersion);
             for (WifiConfiguration configuration : configurations) {
                 // TODO: store configKey as a string instead of calculating its hash
-                IpConfigStore.writeConfig(out, String.valueOf(configuration.getKey().hashCode()),
-                        configuration.getIpConfiguration(), configStoreVersion);
+                IpConfigStoreTestWriter.writeConfig(
+                        out,
+                        String.valueOf(configuration.getKey().hashCode()),
+                        configuration.getIpConfiguration(),
+                        configStoreVersion);
             }
             out.flush();
             return bos.toByteArray();
diff --git a/tests/wifitests/src/com/android/server/wifi/WifiConfigManagerTest.java b/tests/wifitests/src/com/android/server/wifi/WifiConfigManagerTest.java
index d1e476b..dcd0fa8 100644
--- a/tests/wifitests/src/com/android/server/wifi/WifiConfigManagerTest.java
+++ b/tests/wifitests/src/com/android/server/wifi/WifiConfigManagerTest.java
@@ -1682,6 +1682,7 @@
         assertAndSetNetworkEnterprisePassword(network, "test");
 
         verifyUpdateNetworkToWifiConfigManagerWithoutIpChange(network);
+        network.enterpriseConfig.setCaPath(WifiConfigurationTestUtil.TEST_CA_CERT_PATH);
         WifiConfigurationTestUtil.assertConfigurationEqualForConfigManagerAddOrUpdate(
                 network, mWifiConfigManager.getConfiguredNetworkWithPassword(network.networkId));
 
diff --git a/tests/wifitests/src/com/android/server/wifi/WifiConfigurationTestUtil.java b/tests/wifitests/src/com/android/server/wifi/WifiConfigurationTestUtil.java
index b991104..5a03d14 100644
--- a/tests/wifitests/src/com/android/server/wifi/WifiConfigurationTestUtil.java
+++ b/tests/wifitests/src/com/android/server/wifi/WifiConfigurationTestUtil.java
@@ -86,6 +86,8 @@
     public static final String TEST_STATIC_PROXY_EXCLUSION_LIST = "";
     public static final String TEST_PAC_PROXY_LOCATION = "http://";
     public static final String TEST_CA_CERT_ALIAS = "WifiConfigurationTestUtilCaCertAlias";
+    public static final String TEST_CA_CERT_PATH = "caPath";
+    public static final String TEST_DOM_SUBJECT_MATCH = "domSubjectMatch";
 
     private static final int MAX_SSID_LENGTH = 32;
     /**
@@ -162,6 +164,8 @@
                 config.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.WPA_EAP);
                 config.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.IEEE8021X);
                 config.enterpriseConfig.setEapMethod(WifiEnterpriseConfig.Eap.TTLS);
+                config.enterpriseConfig.setCaPath(TEST_CA_CERT_PATH);
+                config.enterpriseConfig.setDomainSuffixMatch(TEST_DOM_SUBJECT_MATCH);
             }
 
             if ((security & SECURITY_EAP_SUITE_B) != 0) {
@@ -488,6 +492,7 @@
         config.setPhase2Method(WifiEnterpriseConfig.Phase2.GTC);
         config.setCaCertificateAliases(new String[] {TEST_CA_CERT_ALIAS + "PEAP"});
         config.setCaCertificates(new X509Certificate[] {FakeKeys.CA_CERT0, FakeKeys.CA_CERT1});
+        config.setDomainSuffixMatch(TEST_DOM_SUBJECT_MATCH);
         return config;
     }
 
@@ -497,6 +502,7 @@
         config.setPhase2Method(WifiEnterpriseConfig.Phase2.NONE);
         config.setCaCertificateAliases(new String[] {TEST_CA_CERT_ALIAS + "TLS"});
         config.setCaCertificates(new X509Certificate[] {FakeKeys.CA_CERT0, FakeKeys.CA_CERT1});
+        config.setDomainSuffixMatch(TEST_DOM_SUBJECT_MATCH);
         return config;
     }
 
@@ -504,6 +510,7 @@
         WifiEnterpriseConfig config = new WifiEnterpriseConfig();
         config.setEapMethod(WifiEnterpriseConfig.Eap.TLS);
         config.setPhase2Method(WifiEnterpriseConfig.Phase2.AKA);
+        config.setDomainSuffixMatch(TEST_DOM_SUBJECT_MATCH);
         return config;
     }
 
diff --git a/tests/wifitests/src/com/android/server/wifi/WifiConnectivityManagerTest.java b/tests/wifitests/src/com/android/server/wifi/WifiConnectivityManagerTest.java
index 7bf21fb..ba1c4f9 100644
--- a/tests/wifitests/src/com/android/server/wifi/WifiConnectivityManagerTest.java
+++ b/tests/wifitests/src/com/android/server/wifi/WifiConnectivityManagerTest.java
@@ -607,6 +607,50 @@
     }
 
     /**
+     * Multiple back to back connection attempts after a force connectivity scan should not be rate
+     * limited.
+     *
+     * Expected behavior: WifiConnectivityManager calls ClientModeImpl.startConnectToNetwork()
+     * with the expected candidate network ID and BSSID for only the expected number of times within
+     * the given interval.
+     */
+    @Test
+    public void connectionAttemptNotRateLimitedWhenScreenOffForceConnectivityScan() {
+        int maxAttemptRate = WifiConnectivityManager.MAX_CONNECTION_ATTEMPTS_RATE;
+        int timeInterval = WifiConnectivityManager.MAX_CONNECTION_ATTEMPTS_TIME_INTERVAL_MS;
+        int numAttempts = 0;
+        int connectionAttemptIntervals = timeInterval / maxAttemptRate;
+
+        mWifiConnectivityManager.handleScreenStateChanged(false);
+
+        // First attempt the max rate number of connections within the rate interval.
+        long currentTimeStamp = 0;
+        for (int attempt = 0; attempt < maxAttemptRate; attempt++) {
+            currentTimeStamp += connectionAttemptIntervals;
+            when(mClock.getElapsedSinceBootMillis()).thenReturn(currentTimeStamp);
+            // Set WiFi to disconnected state to trigger PNO scan
+            mWifiConnectivityManager.handleConnectionStateChanged(
+                    WifiConnectivityManager.WIFI_STATE_DISCONNECTED);
+            numAttempts++;
+        }
+
+        mWifiConnectivityManager.forceConnectivityScan(new WorkSource());
+
+        for (int attempt = 0; attempt < maxAttemptRate; attempt++) {
+            currentTimeStamp += connectionAttemptIntervals;
+            when(mClock.getElapsedSinceBootMillis()).thenReturn(currentTimeStamp);
+            // Set WiFi to disconnected state to trigger PNO scan
+            mWifiConnectivityManager.handleConnectionStateChanged(
+                    WifiConnectivityManager.WIFI_STATE_DISCONNECTED);
+            numAttempts++;
+        }
+
+        // Verify that all the connection attempts went through
+        verify(mClientModeImpl, times(numAttempts)).startConnectToNetwork(
+                CANDIDATE_NETWORK_ID, Process.WIFI_UID, CANDIDATE_BSSID);
+    }
+
+    /**
      * Multiple back to back connection attempts after a user selection should not be rate limited.
      *
      * Expected behavior: WifiConnectivityManager calls ClientModeImpl.startConnectToNetwork()
diff --git a/tests/wifitests/src/com/android/server/wifi/WifiHealthMonitorTest.java b/tests/wifitests/src/com/android/server/wifi/WifiHealthMonitorTest.java
index 4e0b5b7..264fe90 100644
--- a/tests/wifitests/src/com/android/server/wifi/WifiHealthMonitorTest.java
+++ b/tests/wifitests/src/com/android/server/wifi/WifiHealthMonitorTest.java
@@ -110,6 +110,7 @@
     private WifiConfiguration mWifiConfig;
     private String mDriverVersion;
     private String mFirmwareVersion;
+    private static final long MODULE_VERSION = 1L;
     private TestAlarmManager mAlarmManager;
     private TestLooper mLooper = new TestLooper();
     private List<WifiConfiguration> mConfiguredNetworks;
@@ -152,7 +153,7 @@
 
         mDriverVersion = "build 1.1";
         mFirmwareVersion = "HW 1.1";
-        mPackageInfo.versionCode = 1;
+        when(mPackageInfo.getLongVersionCode()).thenReturn(MODULE_VERSION);
         when(mContext.getPackageName()).thenReturn("WifiAPK");
         when(mPackageManager.getPackageInfo(anyString(), anyInt())).thenReturn(mPackageInfo);
         when(mContext.getPackageManager()).thenReturn(mPackageManager);
@@ -310,6 +311,7 @@
         // trigger extractCurrentSoftwareBuildInfo() call to update currSoftwareBuildInfo
         mWifiHealthMonitor.installMemoryStoreSetUpDetectionAlarm(mMemoryStore);
         mWifiHealthMonitor.setWifiEnabled(true);
+        assertEquals(0, mWifiHealthMonitor.getWifiStackVersion());
         millisecondsPass(5000);
         mWifiScanner.startScan(mScanSettings, mScanListener);
         mAlarmManager.dispatch(WifiHealthMonitor.POST_BOOT_DETECTION_TIMER_TAG);
@@ -365,6 +367,7 @@
                 .getWifiFirmwareVersion());
         assertEquals(mFirmwareVersion, wifiSystemInfoStats.getPrevSoftwareBuildInfo()
                 .getWifiFirmwareVersion());
+        assertEquals(MODULE_VERSION, mWifiHealthMonitor.getWifiStackVersion());
 
         // Check write
         String writtenHex = hexStringFromByteArray(mBlobs.get(mKeys.size() - 1));
@@ -395,8 +398,7 @@
         SystemInfoStats systemInfoStats = SystemInfoStats.parseFrom(serialized);
         WifiSoftwareBuildInfo currSoftwareBuildInfoFromMemory = wifiSystemInfoStats
                 .fromSoftwareBuildInfo(systemInfoStats.getCurrSoftwareBuildInfo());
-        assertEquals(mPackageInfo.versionCode,
-                currSoftwareBuildInfoFromMemory.getWifiStackVersion());
+        assertEquals(MODULE_VERSION, currSoftwareBuildInfoFromMemory.getWifiStackVersion());
         assertEquals(mDriverVersion, currSoftwareBuildInfoFromMemory.getWifiDriverVersion());
         assertEquals(mFirmwareVersion, currSoftwareBuildInfoFromMemory.getWifiFirmwareVersion());
         assertEquals(Build.DISPLAY, currSoftwareBuildInfoFromMemory.getOsBuildVersion());
diff --git a/tests/wifitests/src/com/android/server/wifi/WifiMetricsTest.java b/tests/wifitests/src/com/android/server/wifi/WifiMetricsTest.java
index fcaee05..ca5ae26 100644
--- a/tests/wifitests/src/com/android/server/wifi/WifiMetricsTest.java
+++ b/tests/wifitests/src/com/android/server/wifi/WifiMetricsTest.java
@@ -441,6 +441,7 @@
     private static final int NUM_NETWORK_SUFFICIENT_RECENT_STATS_ONLY = 4;
     private static final int NUM_NETWORK_SUFFICIENT_RECENT_PREV_STATS = 5;
     private static final int NUM_BSSID_SELECTION_DIFFERENT_BETWEEN_FRAMEWORK_FIRMWARE = 3;
+    private static final long WIFI_MAINLINE_MODULE_VERSION = 123456L;
 
     /** Number of notifications per "Connect to Network" notification type. */
     private static final int[] NUM_CONNECT_TO_NETWORK_NOTIFICATIONS = {0, 10, 20, 30, 40};
@@ -1010,6 +1011,7 @@
         metrics.numNetworkSufficientRecentStatsOnly = NUM_NETWORK_SUFFICIENT_RECENT_STATS_ONLY;
         metrics.numNetworkSufficientRecentPrevStats = NUM_NETWORK_SUFFICIENT_RECENT_PREV_STATS;
         when(mWifiHealthMonitor.buildProto()).thenReturn(metrics);
+        when(mWifiHealthMonitor.getWifiStackVersion()).thenReturn(WIFI_MAINLINE_MODULE_VERSION);
     }
 
     private void addSoftApEventsToMetrics() {
@@ -1412,6 +1414,7 @@
                 mDecodedProto.numConnectRequestWithFilsAkm);
         assertEquals(NUM_L2_CONNECTION_THROUGH_FILS_AUTHENTICATION,
                 mDecodedProto.numL2ConnectionThroughFilsAuthentication);
+        assertEquals(WIFI_MAINLINE_MODULE_VERSION, mDecodedProto.mainlineModuleVersion);
 
     }
 
diff --git a/tests/wifitests/src/com/android/server/wifi/WifiNetworkSuggestionsManagerTest.java b/tests/wifitests/src/com/android/server/wifi/WifiNetworkSuggestionsManagerTest.java
index e7e8660..38a0026 100644
--- a/tests/wifitests/src/com/android/server/wifi/WifiNetworkSuggestionsManagerTest.java
+++ b/tests/wifitests/src/com/android/server/wifi/WifiNetworkSuggestionsManagerTest.java
@@ -429,6 +429,25 @@
         verify(mLruConnectionTracker).removeNetwork(any());
     }
 
+    @Test
+    public void testAddInsecureEnterpriseNetworkSuggestion() {
+        WifiNetworkSuggestion networkSuggestion = new WifiNetworkSuggestion(
+                WifiConfigurationTestUtil.createEapNetwork(), null, false, false, true, true);
+        networkSuggestion.wifiConfiguration.enterpriseConfig.setCaPath(null);
+        List<WifiNetworkSuggestion> networkSuggestionList = Arrays.asList(networkSuggestion);
+        assertEquals(WifiManager.STATUS_NETWORK_SUGGESTIONS_ERROR_ADD_INVALID,
+                mWifiNetworkSuggestionsManager.add(networkSuggestionList, TEST_UID_1,
+                        TEST_PACKAGE_1, TEST_FEATURE));
+
+        networkSuggestion = new WifiNetworkSuggestion(
+                WifiConfigurationTestUtil.createEapNetwork(), null, false, false, true, true);
+        networkSuggestion.wifiConfiguration.enterpriseConfig.setDomainSuffixMatch("");
+        networkSuggestionList = Arrays.asList(networkSuggestion);
+        assertEquals(WifiManager.STATUS_NETWORK_SUGGESTIONS_ERROR_ADD_INVALID,
+                mWifiNetworkSuggestionsManager.add(networkSuggestionList, TEST_UID_1,
+                        TEST_PACKAGE_1, TEST_FEATURE));
+    }
+
     /**
      * Verify successful removal of all network suggestions.
      */
diff --git a/tests/wifitests/src/com/android/server/wifi/WifiServiceImplTest.java b/tests/wifitests/src/com/android/server/wifi/WifiServiceImplTest.java
index 603a4d8..6d1ae29 100644
--- a/tests/wifitests/src/com/android/server/wifi/WifiServiceImplTest.java
+++ b/tests/wifitests/src/com/android/server/wifi/WifiServiceImplTest.java
@@ -2168,18 +2168,26 @@
     @Test
     public void testStartLocalOnlyHotspotAt2Ghz() {
         registerLOHSRequestFull();
-        verifyLohsBand(WifiConfiguration.AP_BAND_2GHZ);
+        verifyLohsBand(SoftApConfiguration.BAND_2GHZ);
     }
 
     /**
-     * Verify that startLocalOnlyHotspot will start access point at 5 GHz if properly configured.
+     * Verify that startLocalOnlyHotspot will start access point at 6 GHz if properly configured
+     * and if feasible, even if the 5GHz is enabled.
      */
     @Test
-    public void testStartLocalOnlyHotspotAt5Ghz() {
+    public void testStartLocalOnlyHotspotAt6Ghz() {
         when(mResources.getBoolean(
                 eq(R.bool.config_wifi_local_only_hotspot_5ghz)))
                 .thenReturn(true);
+        when(mResources.getBoolean(
+                eq(R.bool.config_wifiLocalOnlyHotspot6ghz)))
+                .thenReturn(true);
         when(mClientModeImpl.isWifiBandSupported(WifiScanner.WIFI_BAND_5_GHZ)).thenReturn(true);
+        when(mClientModeImpl.isWifiBandSupported(WifiScanner.WIFI_BAND_6_GHZ)).thenReturn(true);
+        when(mResources.getBoolean(
+                eq(R.bool.config_wifiSoftap6ghzSupported)))
+                .thenReturn(true);
         when(mPackageManager.hasSystemFeature(PackageManager.FEATURE_AUTOMOTIVE)).thenReturn(true);
 
         verify(mAsyncChannel).connect(any(), mHandlerCaptor.capture(), any(Handler.class));
@@ -2189,15 +2197,44 @@
 
         mLooper.startAutoDispatch();
         registerLOHSRequestFull();
-        verifyLohsBand(WifiConfiguration.AP_BAND_5GHZ);
+        verifyLohsBand(SoftApConfiguration.BAND_6GHZ);
+    }
+
+    /**
+     * Verify that startLocalOnlyHotspot will start access point at 5 GHz if both 5GHz and 6GHz
+     * are enabled, but SoftAp is not supported for 6GHz.
+     */
+    @Test
+    public void testStartLocalOnlyHotspotAt5Ghz() {
+        when(mResources.getBoolean(
+                eq(R.bool.config_wifi_local_only_hotspot_5ghz)))
+                .thenReturn(true);
+        when(mResources.getBoolean(
+                eq(R.bool.config_wifiLocalOnlyHotspot6ghz)))
+                .thenReturn(true);
+        when(mClientModeImpl.isWifiBandSupported(WifiScanner.WIFI_BAND_5_GHZ)).thenReturn(true);
+        when(mClientModeImpl.isWifiBandSupported(WifiScanner.WIFI_BAND_6_GHZ)).thenReturn(true);
+        when(mResources.getBoolean(
+                eq(R.bool.config_wifiSoftap6ghzSupported)))
+                .thenReturn(false);
+        when(mPackageManager.hasSystemFeature(PackageManager.FEATURE_AUTOMOTIVE)).thenReturn(true);
+
+        verify(mAsyncChannel).connect(any(), mHandlerCaptor.capture(), any(Handler.class));
+        final Handler handler = mHandlerCaptor.getValue();
+        handler.handleMessage(handler.obtainMessage(
+                AsyncChannel.CMD_CHANNEL_HALF_CONNECTED, AsyncChannel.STATUS_SUCCESSFUL, 0));
+
+        mLooper.startAutoDispatch();
+        registerLOHSRequestFull();
+        verifyLohsBand(SoftApConfiguration.BAND_5GHZ);
     }
 
     private void verifyLohsBand(int expectedBand) {
         verify(mActiveModeWarden).startSoftAp(mSoftApModeConfigCaptor.capture());
-        final WifiConfiguration configuration =
-                mSoftApModeConfigCaptor.getValue().getSoftApConfiguration().toWifiConfiguration();
+        final SoftApConfiguration configuration =
+                mSoftApModeConfigCaptor.getValue().getSoftApConfiguration();
         assertNotNull(configuration);
-        assertEquals(expectedBand, configuration.apBand);
+        assertEquals(expectedBand, configuration.getBand());
     }
 
     private static class FakeLohsCallback extends ILocalOnlyHotspotCallback.Stub {