Expose WifiConfiguration @hide APIs as @SystemApi

These APIs are mostly used by Settings.

Bug: 143892601
Bug: 129482052
Bug: 115717178
Test: atest FrameworksWifiApiTests
Change-Id: Ie801fdc6ed716007802fe77b8db3decd37813c58
diff --git a/api/system-current.txt b/api/system-current.txt
index 7f8c57b..5447b67 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -5140,19 +5140,46 @@
   }
 
   @Deprecated public class WifiConfiguration implements android.os.Parcelable {
+    method @Deprecated public int getAuthType();
+    method @Deprecated @NonNull public android.net.IpConfiguration.IpAssignment getIpAssignment();
+    method @Deprecated @NonNull public android.net.wifi.WifiConfiguration.NetworkSelectionStatus getNetworkSelectionStatus();
+    method @Deprecated @NonNull public String getPrintableSsid();
+    method @Deprecated @NonNull public android.net.IpConfiguration.ProxySettings getProxySettings();
+    method @Deprecated @Nullable public android.net.StaticIpConfiguration getStaticIpConfiguration();
     method @Deprecated public boolean hasNoInternetAccess();
     method @Deprecated public boolean isEphemeral();
+    method @Deprecated public static boolean isMetered(@Nullable android.net.wifi.WifiConfiguration, @Nullable android.net.wifi.WifiInfo);
     method @Deprecated public boolean isNoInternetAccessExpected();
+    method @Deprecated public void setIpConfiguration(@Nullable android.net.IpConfiguration);
+    method @Deprecated public void setProxy(@NonNull android.net.IpConfiguration.ProxySettings, @NonNull android.net.ProxyInfo);
+    field @Deprecated public static final int AP_BAND_2GHZ = 0; // 0x0
+    field @Deprecated public static final int AP_BAND_5GHZ = 1; // 0x1
+    field @Deprecated public static final int AP_BAND_ANY = -1; // 0xffffffff
+    field @Deprecated public static final int INVALID_NETWORK_ID = -1; // 0xffffffff
+    field @Deprecated public static final int METERED_OVERRIDE_METERED = 1; // 0x1
+    field @Deprecated public static final int METERED_OVERRIDE_NONE = 0; // 0x0
+    field @Deprecated public static final int METERED_OVERRIDE_NOT_METERED = 2; // 0x2
+    field @Deprecated public static final int RANDOMIZATION_NONE = 0; // 0x0
+    field @Deprecated public static final int RANDOMIZATION_PERSISTENT = 1; // 0x1
     field @Deprecated public boolean allowAutojoin;
+    field @Deprecated public int apBand;
     field @Deprecated public int carrierId;
     field @Deprecated public String creatorName;
     field @Deprecated public int creatorUid;
+    field @Deprecated public boolean fromWifiNetworkSpecifier;
+    field @Deprecated public boolean fromWifiNetworkSuggestion;
     field @Deprecated public String lastUpdateName;
     field @Deprecated public int lastUpdateUid;
+    field @Deprecated public int macRandomizationSetting;
     field @Deprecated public boolean meteredHint;
+    field @Deprecated public int meteredOverride;
     field @Deprecated public int numAssociation;
     field @Deprecated public int numScorerOverride;
     field @Deprecated public int numScorerOverrideAndSwitchedNetwork;
+    field @Deprecated @NonNull public final android.net.wifi.WifiConfiguration.RecentFailure recentFailure;
+    field @Deprecated public boolean requirePMF;
+    field @Deprecated @Nullable public String saePasswordId;
+    field @Deprecated public boolean shared;
     field @Deprecated public boolean useExternalScores;
   }
 
@@ -5160,6 +5187,49 @@
     field @Deprecated public static final int WPA2_PSK = 4; // 0x4
   }
 
+  @Deprecated public static class WifiConfiguration.NetworkSelectionStatus {
+    method @Deprecated public int getDisableReasonCounter(int);
+    method @Deprecated public long getDisableTime();
+    method @Deprecated public boolean getHasEverConnected();
+    method @Deprecated @Nullable public static String getNetworkDisableReasonString(int);
+    method @Deprecated public int getNetworkSelectionDisableReason();
+    method @Deprecated @NonNull public String getNetworkStatusString();
+    method @Deprecated public boolean isNetworkEnabled();
+    method @Deprecated public boolean isNetworkPermanentlyDisabled();
+    field @Deprecated public static final int DISABLED_ASSOCIATION_REJECTION = 1; // 0x1
+    field @Deprecated public static final int DISABLED_AUTHENTICATION_FAILURE = 2; // 0x2
+    field @Deprecated public static final int DISABLED_AUTHENTICATION_NO_CREDENTIALS = 5; // 0x5
+    field @Deprecated public static final int DISABLED_AUTHENTICATION_NO_SUBSCRIPTION = 9; // 0x9
+    field @Deprecated public static final int DISABLED_BY_WIFI_MANAGER = 7; // 0x7
+    field @Deprecated public static final int DISABLED_BY_WRONG_PASSWORD = 8; // 0x8
+    field @Deprecated public static final int DISABLED_DHCP_FAILURE = 3; // 0x3
+    field @Deprecated public static final int DISABLED_NO_INTERNET_PERMANENT = 6; // 0x6
+    field @Deprecated public static final int DISABLED_NO_INTERNET_TEMPORARY = 4; // 0x4
+    field @Deprecated public static final int NETWORK_SELECTION_DISABLED_MAX = 10; // 0xa
+    field @Deprecated public static final int NETWORK_SELECTION_ENABLE = 0; // 0x0
+  }
+
+  @Deprecated public static class WifiConfiguration.RecentFailure {
+    method @Deprecated public int getAssociationStatus();
+    field @Deprecated public static final int NONE = 0; // 0x0
+    field @Deprecated public static final int STATUS_AP_UNABLE_TO_HANDLE_NEW_STA = 17; // 0x11
+  }
+
+  public class WifiEnterpriseConfig implements android.os.Parcelable {
+    method @Nullable public String[] getCaCertificateAliases();
+    method @NonNull public String getCaPath();
+    method @NonNull public String getClientCertificateAlias();
+    method public int getOcsp();
+    method public void setCaCertificateAliases(@Nullable String[]);
+    method public void setCaPath(@Nullable String);
+    method public void setClientCertificateAlias(@Nullable String);
+    method public void setOcsp(int);
+    field public static final int OCSP_NONE = 0; // 0x0
+    field public static final int OCSP_REQUEST_CERT_STATUS = 1; // 0x1
+    field public static final int OCSP_REQUIRE_ALL_NON_TRUSTED_CERTS_STATUS = 3; // 0x3
+    field public static final int OCSP_REQUIRE_CERT_STATUS = 2; // 0x2
+  }
+
   public class WifiFrameworkInitializer {
     method public static void registerServiceWrappers();
   }
diff --git a/api/system-lint-baseline.txt b/api/system-lint-baseline.txt
index 7eb5443..ab0f0f9 100644
--- a/api/system-lint-baseline.txt
+++ b/api/system-lint-baseline.txt
@@ -152,10 +152,35 @@
     
 
 
+
+MutableBareField: android.net.IpConfiguration#httpProxy:
+    Bare field httpProxy must be marked final, or moved behind accessors if mutable
+MutableBareField: android.net.IpConfiguration#ipAssignment:
+    Bare field ipAssignment must be marked final, or moved behind accessors if mutable
+MutableBareField: android.net.IpConfiguration#proxySettings:
+    Bare field proxySettings must be marked final, or moved behind accessors if mutable
+MutableBareField: android.net.IpConfiguration#staticIpConfiguration:
+    Bare field staticIpConfiguration must be marked final, or moved behind accessors if mutable
 MutableBareField: android.net.wifi.WifiConfiguration#allowAutojoin:
     
+MutableBareField: android.net.wifi.WifiConfiguration#apBand:
+    Bare field apBand must be marked final, or moved behind accessors if mutable
 MutableBareField: android.net.wifi.WifiConfiguration#carrierId:
     
+MutableBareField: android.net.wifi.WifiConfiguration#fromWifiNetworkSpecifier:
+    Bare field fromWifiNetworkSpecifier must be marked final, or moved behind accessors if mutable
+MutableBareField: android.net.wifi.WifiConfiguration#fromWifiNetworkSuggestion:
+    Bare field fromWifiNetworkSuggestion must be marked final, or moved behind accessors if mutable
+MutableBareField: android.net.wifi.WifiConfiguration#macRandomizationSetting:
+    Bare field macRandomizationSetting must be marked final, or moved behind accessors if mutable
+MutableBareField: android.net.wifi.WifiConfiguration#meteredOverride:
+    Bare field meteredOverride must be marked final, or moved behind accessors if mutable
+MutableBareField: android.net.wifi.WifiConfiguration#requirePMF:
+    Bare field requirePMF must be marked final, or moved behind accessors if mutable
+MutableBareField: android.net.wifi.WifiConfiguration#saePasswordId:
+    Bare field saePasswordId must be marked final, or moved behind accessors if mutable
+MutableBareField: android.net.wifi.WifiConfiguration#shared:
+    Bare field shared must be marked final, or moved behind accessors if mutable
 
 
 NoClone: android.service.contentcapture.ContentCaptureService#dump(java.io.FileDescriptor, java.io.PrintWriter, String[]) parameter #0:
diff --git a/packages/SettingsLib/src/com/android/settingslib/wifi/AccessPoint.java b/packages/SettingsLib/src/com/android/settingslib/wifi/AccessPoint.java
index d577b5a..f2af40e 100644
--- a/packages/SettingsLib/src/com/android/settingslib/wifi/AccessPoint.java
+++ b/packages/SettingsLib/src/com/android/settingslib/wifi/AccessPoint.java
@@ -1098,16 +1098,12 @@
                         summary.append(mContext.getString(R.string.wifi_check_password_try_again));
                         break;
                     case WifiConfiguration.NetworkSelectionStatus.DISABLED_DHCP_FAILURE:
-                    case WifiConfiguration.NetworkSelectionStatus.DISABLED_DNS_FAILURE:
                         summary.append(mContext.getString(R.string.wifi_disabled_network_failure));
                         break;
                     case WifiConfiguration.NetworkSelectionStatus.DISABLED_ASSOCIATION_REJECTION:
                         summary.append(mContext.getString(R.string.wifi_disabled_generic));
                         break;
                 }
-            } else if (mConfig != null && mConfig.getNetworkSelectionStatus().isNotRecommended()) {
-                summary.append(mContext.getString(
-                        R.string.wifi_disabled_by_recommendation_provider));
             } else if (mIsCarrierAp) {
                 summary.append(String.format(mContext.getString(
                         R.string.available_via_carrier), mCarrierName));
diff --git a/packages/SettingsLib/src/com/android/settingslib/wifi/WifiTracker.java b/packages/SettingsLib/src/com/android/settingslib/wifi/WifiTracker.java
index 97fddc0..23754c5 100644
--- a/packages/SettingsLib/src/com/android/settingslib/wifi/WifiTracker.java
+++ b/packages/SettingsLib/src/com/android/settingslib/wifi/WifiTracker.java
@@ -518,8 +518,7 @@
             int networkId, final List<WifiConfiguration> configs) {
         if (configs != null) {
             for (WifiConfiguration config : configs) {
-                if (mLastInfo != null && networkId == config.networkId &&
-                        !(config.selfAdded && config.numAssociation == 0)) {
+                if (mLastInfo != null && networkId == config.networkId) {
                     return config;
                 }
             }
diff --git a/packages/SettingsLib/src/com/android/settingslib/wifi/WifiUtils.java b/packages/SettingsLib/src/com/android/settingslib/wifi/WifiUtils.java
index ee89738..b93b000 100644
--- a/packages/SettingsLib/src/com/android/settingslib/wifi/WifiUtils.java
+++ b/packages/SettingsLib/src/com/android/settingslib/wifi/WifiUtils.java
@@ -30,6 +30,8 @@
 
 public class WifiUtils {
 
+    private static final int INVALID_RSSI = -127;
+
     public static String buildLoggingSummary(AccessPoint accessPoint, WifiConfiguration config) {
         final StringBuilder summary = new StringBuilder();
         final WifiInfo info = accessPoint.getInfo();
@@ -106,8 +108,8 @@
             visibility.append(String.format("rx=%.1f", info.getRxSuccessRate()));
         }
 
-        int maxRssi5 = WifiConfiguration.INVALID_RSSI;
-        int maxRssi24 = WifiConfiguration.INVALID_RSSI;
+        int maxRssi5 = INVALID_RSSI;
+        int maxRssi24 = INVALID_RSSI;
         final int maxDisplayedScans = 4;
         int num5 = 0; // number of scanned BSSID on 5GHz band
         int num24 = 0; // number of scanned BSSID on 2.4Ghz band
diff --git a/packages/SettingsLib/tests/integ/src/com/android/settingslib/wifi/AccessPointTest.java b/packages/SettingsLib/tests/integ/src/com/android/settingslib/wifi/AccessPointTest.java
index 7139a4f..7d06e6c 100644
--- a/packages/SettingsLib/tests/integ/src/com/android/settingslib/wifi/AccessPointTest.java
+++ b/packages/SettingsLib/tests/integ/src/com/android/settingslib/wifi/AccessPointTest.java
@@ -459,10 +459,11 @@
 
     @Test
     public void testSummaryString_showsWrongPasswordLabel() {
-        WifiConfiguration configuration = createWifiConfiguration();
-        configuration.getNetworkSelectionStatus().setNetworkSelectionStatus(
-                WifiConfiguration.NetworkSelectionStatus.NETWORK_SELECTION_PERMANENTLY_DISABLED);
-        configuration.getNetworkSelectionStatus().setNetworkSelectionDisableReason(
+        WifiConfiguration configuration = spy(createWifiConfiguration());
+        WifiConfiguration.NetworkSelectionStatus status =
+                mock(WifiConfiguration.NetworkSelectionStatus.class);
+        when(configuration.getNetworkSelectionStatus()).thenReturn(status);
+        when(status.getNetworkSelectionDisableReason()).thenReturn(
                 WifiConfiguration.NetworkSelectionStatus.DISABLED_BY_WRONG_PASSWORD);
         AccessPoint ap = new AccessPoint(mContext, configuration);
 
diff --git a/packages/SettingsLib/tests/integ/src/com/android/settingslib/wifi/WifiTrackerTest.java b/packages/SettingsLib/tests/integ/src/com/android/settingslib/wifi/WifiTrackerTest.java
index 37fdc34..94fbc54 100644
--- a/packages/SettingsLib/tests/integ/src/com/android/settingslib/wifi/WifiTrackerTest.java
+++ b/packages/SettingsLib/tests/integ/src/com/android/settingslib/wifi/WifiTrackerTest.java
@@ -494,7 +494,6 @@
 
         WifiConfiguration selfAddedNoAssociation = new WifiConfiguration();
         selfAddedNoAssociation.ephemeral = true;
-        selfAddedNoAssociation.selfAdded = true;
         selfAddedNoAssociation.numAssociation = 0;
         selfAddedNoAssociation.SSID = SSID_2;
         selfAddedNoAssociation.BSSID = BSSID_2;
diff --git a/wifi/java/android/net/wifi/WifiConfiguration.java b/wifi/java/android/net/wifi/WifiConfiguration.java
index 90343d4..dfdc075 100644
--- a/wifi/java/android/net/wifi/WifiConfiguration.java
+++ b/wifi/java/android/net/wifi/WifiConfiguration.java
@@ -38,6 +38,7 @@
 import android.text.TextUtils;
 import android.util.BackupUtils;
 import android.util.Log;
+import android.util.SparseArray;
 import android.util.TimeUtils;
 
 import java.io.ByteArrayOutputStream;
@@ -86,7 +87,12 @@
     public static final String pmfVarName = "ieee80211w";
     /** {@hide} */
     public static final String updateIdentiferVarName = "update_identifier";
-    /** {@hide} */
+    /**
+     * The network ID for an invalid network.
+     *
+     * @hide
+     */
+    @SystemApi
     public static final int INVALID_NETWORK_ID = -1;
     /** {@hide} */
     public static final int LOCAL_ONLY_NETWORK_ID = -2;
@@ -102,20 +108,41 @@
     public static class KeyMgmt {
         private KeyMgmt() { }
 
+        /** @hide */
+        @Retention(RetentionPolicy.SOURCE)
+        @IntDef(value = {
+                NONE,
+                WPA_PSK,
+                WPA_EAP,
+                IEEE8021X,
+                WPA2_PSK,
+                OSEN,
+                FT_PSK,
+                FT_EAP,
+                SAE,
+                OWE,
+                SUITE_B_192,
+                WPA_PSK_SHA256,
+                WPA_EAP_SHA256})
+        public @interface KeyMgmtScheme {}
+
         /** WPA is not used; plaintext or static WEP could be used. */
         public static final int NONE = 0;
         /** WPA pre-shared key (requires {@code preSharedKey} to be specified). */
         public static final int WPA_PSK = 1;
         /** WPA using EAP authentication. Generally used with an external authentication server. */
         public static final int WPA_EAP = 2;
-        /** IEEE 802.1X using EAP authentication and (optionally) dynamically
-         * generated WEP keys. */
+        /**
+         * IEEE 802.1X using EAP authentication and (optionally) dynamically
+         * generated WEP keys.
+         */
         public static final int IEEE8021X = 3;
 
-        /** WPA2 pre-shared key for use with soft access point
-          * (requires {@code preSharedKey} to be specified).
-          * @hide
-          */
+        /**
+         * WPA2 pre-shared key for use with soft access point
+         * (requires {@code preSharedKey} to be specified).
+         * @hide
+         */
         @SystemApi
         public static final int WPA2_PSK = 4;
         /**
@@ -462,16 +489,26 @@
      */
     public String BSSID;
 
+    /** @hide */
+    @Retention(RetentionPolicy.SOURCE)
+    @IntDef(prefix = {"AP_BAND_"}, value = {
+            AP_BAND_2GHZ,
+            AP_BAND_5GHZ,
+            AP_BAND_ANY})
+    public @interface ApBand {}
+
     /**
      * 2GHz band.
      * @hide
      */
+    @SystemApi
     public static final int AP_BAND_2GHZ = 0;
 
     /**
      * 5GHz band.
      * @hide
      */
+    @SystemApi
     public static final int AP_BAND_5GHZ = 1;
 
     /**
@@ -479,15 +516,18 @@
      * operating country code and current radio conditions.
      * @hide
      */
+    @SystemApi
     public static final int AP_BAND_ANY = -1;
 
     /**
-     * The band which AP resides on
-     * -1:Any 0:2G 1:5G
-     * By default, 2G is chosen
+     * The band which the AP resides on.
+     * One of {@link #AP_BAND_2GHZ}, {@link #AP_BAND_5GHZ}, or {@link #AP_BAND_ANY}.
+     * By default, {@link #AP_BAND_2GHZ} is chosen.
+     *
      * @hide
      */
-    @UnsupportedAppUsage
+    @SystemApi
+    @ApBand
     public int apBand = AP_BAND_2GHZ;
 
     /**
@@ -515,6 +555,7 @@
      * Optional SAE Password Id for use with WPA3-SAE. It is an ASCII string.
      * @hide
      */
+    @SystemApi
     public @Nullable String saePasswordId;
 
     /**
@@ -553,9 +594,10 @@
     public boolean hiddenSSID;
 
     /**
-     * This is a network that requries Protected Management Frames (PMF).
+     * True if the network requires Protected Management Frames (PMF), false otherwise.
      * @hide
      */
+    @SystemApi
     public boolean requirePMF;
 
     /**
@@ -643,11 +685,12 @@
     public long[] roamingConsortiumIds;
 
     /**
+     * True if this network configuration is visible to and usable by other users on the
+     * same device, false otherwise.
+     *
      * @hide
-     * This network configuration is visible to and usable by other users on the
-     * same device.
      */
-    @UnsupportedAppUsage
+    @SystemApi
     public boolean shared;
 
     /**
@@ -740,54 +783,16 @@
 
     /**
      * @hide
-     * Status of user approval for connection
-     */
-    public int userApproved = USER_UNSPECIFIED;
-
-    /**
-     * @hide
      * Auto-join is allowed by user for this network.
      * Default true.
      */
     @SystemApi
     public boolean allowAutojoin = true;
 
-    /** The Below RSSI thresholds are used to configure AutoJoin
-     *  - GOOD/LOW/BAD thresholds are used so as to calculate link score
-     *  - UNWANTED_SOFT are used by the blacklisting logic so as to handle
-     *  the unwanted network message coming from CS
-     *  - UNBLACKLIST thresholds are used so as to tweak the speed at which
-     *  the network is unblacklisted (i.e. if
-     *          it is seen with good RSSI, it is blacklisted faster)
-     *  - INITIAL_AUTOJOIN_ATTEMPT, used to determine how close from
-     *  the network we need to be before autojoin kicks in
-     */
     /** @hide **/
     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
     public static int INVALID_RSSI = -127;
 
-    // States for the userApproved field
-    /**
-     * @hide
-     * User hasn't specified if connection is okay
-     */
-    public static final int USER_UNSPECIFIED = 0;
-    /**
-     * @hide
-     * User has approved this for connection
-     */
-    public static final int USER_APPROVED = 1;
-    /**
-     * @hide
-     * User has banned this from connection
-     */
-    public static final int USER_BANNED = 2;
-    /**
-     * @hide
-     * Waiting for user input
-     */
-    public static final int USER_PENDING = 3;
-
     /**
      * @hide
      * Number of reports indicating no Internet Access
@@ -861,21 +866,13 @@
      * This boolean is cleared if we get a connect/save/ update or
      * any wifiManager command that indicate the user interacted with the configuration
      * since we will now consider that the configuration belong to him.
+     * @deprecated only kept for @UnsupportedAppUsage
      * @hide
      */
     @UnsupportedAppUsage
     public boolean selfAdded;
 
     /**
-     * Set if the configuration was self added by the framework
-     * This boolean is set once and never cleared. It is used
-     * so as we never loose track of who created the
-     * configuration in the first place.
-     * @hide
-     */
-    public boolean didSelfAdd;
-
-    /**
      * Peer WifiConfiguration this WifiConfiguration was added for
      * @hide
      */
@@ -906,44 +903,77 @@
     public boolean trusted;
 
     /**
-     * This Wifi configuration is created from a {@link WifiNetworkSuggestion}
+     * True if this Wifi configuration is created from a {@link WifiNetworkSuggestion},
+     * false otherwise.
+     *
      * @hide
      */
+    @SystemApi
     public boolean fromWifiNetworkSuggestion;
 
     /**
-     * This Wifi configuration is created from a {@link WifiNetworkSpecifier}
+     * True if this Wifi configuration is created from a {@link WifiNetworkSpecifier},
+     * false otherwise.
+     *
      * @hide
      */
+    @SystemApi
     public boolean fromWifiNetworkSpecifier;
 
     /**
-     * Indicates if the creator of this configuration has expressed that it
-     * should be considered metered.
+     * True if the creator of this configuration has expressed that it
+     * should be considered metered, false otherwise.
      *
      * @see #isMetered(WifiConfiguration, WifiInfo)
+     *
      * @hide
      */
     @SystemApi
     public boolean meteredHint;
 
-    /** {@hide} */
+    /** @hide */
+    @Retention(RetentionPolicy.SOURCE)
+    @IntDef(prefix = {"METERED_OVERRIDE_"}, value = {
+            METERED_OVERRIDE_NONE,
+            METERED_OVERRIDE_METERED,
+            METERED_OVERRIDE_NOT_METERED})
+    public @interface MeteredOverride {}
+
+    /**
+     * No metered override.
+     * @hide
+     */
+    @SystemApi
     public static final int METERED_OVERRIDE_NONE = 0;
-    /** {@hide} */
+    /**
+     * Override network to be metered.
+     * @hide
+     */
+    @SystemApi
     public static final int METERED_OVERRIDE_METERED = 1;
-    /** {@hide} */
+    /**
+     * Override network to be unmetered.
+     * @hide
+     */
+    @SystemApi
     public static final int METERED_OVERRIDE_NOT_METERED = 2;
 
     /**
      * Indicates if the end user has expressed an explicit opinion about the
      * meteredness of this network, such as through the Settings app.
+     * This value is one of {@link #METERED_OVERRIDE_NONE}, {@link #METERED_OVERRIDE_METERED},
+     * or {@link #METERED_OVERRIDE_NOT_METERED}.
      * <p>
      * This should always override any values from {@link #meteredHint} or
      * {@link WifiInfo#getMeteredHint()}.
      *
+     * By default this field is set to {@link #METERED_OVERRIDE_NONE}.
+     *
      * @see #isMetered(WifiConfiguration, WifiInfo)
      * @hide
      */
+    @SystemApi
+    @MeteredOverride
     public int meteredOverride = METERED_OVERRIDE_NONE;
 
     /**
@@ -952,7 +982,8 @@
      *
      * @hide
      */
-    public static boolean isMetered(WifiConfiguration config, WifiInfo info) {
+    @SystemApi
+    public static boolean isMetered(@Nullable WifiConfiguration config, @Nullable WifiInfo info) {
         boolean metered = false;
         if (info != null && info.getMeteredHint()) {
             metered = true;
@@ -1029,21 +1060,34 @@
     @SystemApi
     public int numAssociation;
 
+    /** @hide */
+    @Retention(RetentionPolicy.SOURCE)
+    @IntDef(prefix = {"RANDOMIZATION_"}, value = {
+            RANDOMIZATION_NONE,
+            RANDOMIZATION_PERSISTENT})
+    public @interface MacRandomizationSetting {}
+
     /**
-     * @hide
      * Use factory MAC when connecting to this network
+     * @hide
      */
+    @SystemApi
     public static final int RANDOMIZATION_NONE = 0;
     /**
-     * @hide
      * Generate a randomized MAC once and reuse it for all connections to this network
+     * @hide
      */
+    @SystemApi
     public static final int RANDOMIZATION_PERSISTENT = 1;
 
     /**
+     * Level of MAC randomization for this network.
+     * One of {@link #RANDOMIZATION_NONE} or {@link #RANDOMIZATION_PERSISTENT}.
+     * By default this field is set to {@link #RANDOMIZATION_PERSISTENT}.
      * @hide
-     * Level of MAC randomization for this network
      */
+    @SystemApi
+    @MacRandomizationSetting
     public int macRandomizationSetting = RANDOMIZATION_PERSISTENT;
 
     /**
@@ -1107,145 +1151,250 @@
     public static final int HOME_NETWORK_RSSI_BOOST = 5;
 
     /**
+     * This class is used to contain all the information and API used for quality network selection.
      * @hide
-     * This class is used to contain all the information and API used for quality network selection
      */
+    @SystemApi
     public static class NetworkSelectionStatus {
-        /**
-         * Quality Network Selection Status enable, temporary disabled, permanently disabled
-         */
+        // Quality Network Selection Status enable, temporary disabled, permanently disabled
         /**
          * This network is allowed to join Quality Network Selection
+         * @hide
          */
         public static final int NETWORK_SELECTION_ENABLED = 0;
         /**
          * network was temporary disabled. Can be re-enabled after a time period expire
+         * @hide
          */
         public static final int NETWORK_SELECTION_TEMPORARY_DISABLED  = 1;
         /**
          * network was permanently disabled.
+         * @hide
          */
         public static final int NETWORK_SELECTION_PERMANENTLY_DISABLED  = 2;
         /**
          * Maximum Network selection status
+         * @hide
          */
         public static final int NETWORK_SELECTION_STATUS_MAX = 3;
 
         /**
          * Quality network selection status String (for debug purpose). Use Quality network
          * selection status value as index to extec the corresponding debug string
+         * @hide
          */
         public static final String[] QUALITY_NETWORK_SELECTION_STATUS = {
                 "NETWORK_SELECTION_ENABLED",
                 "NETWORK_SELECTION_TEMPORARY_DISABLED",
                 "NETWORK_SELECTION_PERMANENTLY_DISABLED"};
 
-        //Quality Network disabled reasons
-        /**
-         * Default value. Means not disabled
-         */
+        /** @hide */
+        @Retention(RetentionPolicy.SOURCE)
+        @IntDef(value = {
+                NETWORK_SELECTION_ENABLE,
+                DISABLED_ASSOCIATION_REJECTION,
+                DISABLED_AUTHENTICATION_FAILURE,
+                DISABLED_DHCP_FAILURE,
+                DISABLED_NO_INTERNET_TEMPORARY,
+                DISABLED_AUTHENTICATION_NO_CREDENTIALS,
+                DISABLED_NO_INTERNET_PERMANENT,
+                DISABLED_BY_WIFI_MANAGER,
+                DISABLED_BY_WRONG_PASSWORD,
+                DISABLED_AUTHENTICATION_NO_SUBSCRIPTION})
+        public @interface NetworkSelectionDisableReason {}
+
+        // Quality Network disabled reasons
+        /** Default value. Means not disabled. */
         public static final int NETWORK_SELECTION_ENABLE = 0;
         /**
-         * The starting index for network selection disabled reasons
+         * The starting index for network selection disabled reasons.
+         * @hide
          */
         public static final int NETWORK_SELECTION_DISABLED_STARTING_INDEX = 1;
         /**
-         * @deprecated it is not used any more.
-         * This network is disabled because higher layer (>2) network is bad
+         * The starting index for network selection temporarily disabled reasons.
+         * @hide
          */
-        public static final int DISABLED_BAD_LINK = 1;
+        public static final int TEMPORARILY_DISABLED_STARTING_INDEX = 1;
+        /** This network is disabled because of multiple association rejections. */
+        public static final int DISABLED_ASSOCIATION_REJECTION = 1;
+        /** This network is disabled because of multiple authentication failure. */
+        public static final int DISABLED_AUTHENTICATION_FAILURE = 2;
+        /** This network is disabled because of multiple DHCP failure. */
+        public static final int DISABLED_DHCP_FAILURE = 3;
+        /** This network is temporarily disabled because it has no Internet access. */
+        public static final int DISABLED_NO_INTERNET_TEMPORARY = 4;
         /**
-         * This network is disabled because multiple association rejects
+         * The starting index for network selection permanently disabled reasons.
+         * @hide
          */
-        public static final int DISABLED_ASSOCIATION_REJECTION = 2;
+        public static final int PERMANENTLY_DISABLED_STARTING_INDEX = 5;
+        /** This network is disabled due to absence of user credentials */
+        public static final int DISABLED_AUTHENTICATION_NO_CREDENTIALS = 5;
         /**
-         * This network is disabled because multiple authentication failure
+         * This network is permanently disabled because it has no Internet access and the user does
+         * not want to stay connected.
          */
-        public static final int DISABLED_AUTHENTICATION_FAILURE = 3;
-        /**
-         * This network is disabled because multiple DHCP failure
-         */
-        public static final int DISABLED_DHCP_FAILURE = 4;
-        /**
-         * This network is disabled because of security network but no credentials
-         */
-        public static final int DISABLED_DNS_FAILURE = 5;
-        /**
-         * This network is temporarily disabled because it has no Internet access.
-         */
-        public static final int DISABLED_NO_INTERNET_TEMPORARY = 6;
-        /**
-         * This network is disabled because we started WPS
-         */
-        public static final int DISABLED_WPS_START = 7;
-        /**
-         * This network is disabled because EAP-TLS failure
-         */
-        public static final int DISABLED_TLS_VERSION_MISMATCH = 8;
-        // Values above are for temporary disablement; values below are for permanent disablement.
-        /**
-         * This network is disabled due to absence of user credentials
-         */
-        public static final int DISABLED_AUTHENTICATION_NO_CREDENTIALS = 9;
-        /**
-         * This network is permanently disabled because it has no Internet access and user does not
-         * want to stay connected.
-         */
-        public static final int DISABLED_NO_INTERNET_PERMANENT = 10;
-        /**
-         * This network is disabled due to WifiManager disable it explicitly
-         */
-        public static final int DISABLED_BY_WIFI_MANAGER = 11;
-        /**
-         * This network is disabled due to user switching
-         */
-        public static final int DISABLED_DUE_TO_USER_SWITCH = 12;
-        /**
-         * This network is disabled due to wrong password
-         */
-        public static final int DISABLED_BY_WRONG_PASSWORD = 13;
-        /**
-         * This network is disabled because service is not subscribed
-         */
-        public static final int DISABLED_AUTHENTICATION_NO_SUBSCRIPTION = 14;
-        /**
-         * This Maximum disable reason value
-         */
-        public static final int NETWORK_SELECTION_DISABLED_MAX = 15;
+        public static final int DISABLED_NO_INTERNET_PERMANENT = 6;
+        /** This network is disabled due to WifiManager disabling it explicitly. */
+        public static final int DISABLED_BY_WIFI_MANAGER = 7;
+        /** This network is disabled due to wrong password. */
+        public static final int DISABLED_BY_WRONG_PASSWORD = 8;
+        /** This network is disabled because service is not subscribed. */
+        public static final int DISABLED_AUTHENTICATION_NO_SUBSCRIPTION = 9;
+        /** All other disable reasons should be strictly less than this value. */
+        public static final int NETWORK_SELECTION_DISABLED_MAX = 10;
 
         /**
-         * Quality network selection disable reason String (for debug purpose)
+         * Contains info about disable reasons.
+         * @hide
          */
-        public static final String[] QUALITY_NETWORK_SELECTION_DISABLE_REASON = {
-                "NETWORK_SELECTION_ENABLE",
-                "NETWORK_SELECTION_DISABLED_BAD_LINK", // deprecated
-                "NETWORK_SELECTION_DISABLED_ASSOCIATION_REJECTION ",
-                "NETWORK_SELECTION_DISABLED_AUTHENTICATION_FAILURE",
-                "NETWORK_SELECTION_DISABLED_DHCP_FAILURE",
-                "NETWORK_SELECTION_DISABLED_DNS_FAILURE",
-                "NETWORK_SELECTION_DISABLED_NO_INTERNET_TEMPORARY",
-                "NETWORK_SELECTION_DISABLED_WPS_START",
-                "NETWORK_SELECTION_DISABLED_TLS_VERSION",
-                "NETWORK_SELECTION_DISABLED_AUTHENTICATION_NO_CREDENTIALS",
-                "NETWORK_SELECTION_DISABLED_NO_INTERNET_PERMANENT",
-                "NETWORK_SELECTION_DISABLED_BY_WIFI_MANAGER",
-                "NETWORK_SELECTION_DISABLED_BY_USER_SWITCH",
-                "NETWORK_SELECTION_DISABLED_BY_WRONG_PASSWORD",
-                "NETWORK_SELECTION_DISABLED_AUTHENTICATION_NO_SUBSCRIPTION"
-        };
+        public static final class DisableReasonInfo {
+            /**
+             * String representation for the disable reason.
+             * Note that these strings are persisted in
+             * {@link
+             * com.android.server.wifi.util.XmlUtil.NetworkSelectionStatusXmlUtil#writeToXml},
+             * so do not change the string values to maintain backwards compatibility.
+             */
+            public final String mReasonStr;
+            /**
+             * Network Selection disable reason threshold, used to debounce network failures before
+             * we disable them.
+             */
+            public final int mDisableThreshold;
+            /**
+             * Network Selection disable timeout for the error. After the timeout milliseconds,
+             * enable the network again.
+             */
+            public final int mDisableTimeoutMillis;
+
+            /**
+             * Constructor
+             * @param reasonStr string representation of the error
+             * @param disableThreshold number of failures before we disable the network
+             * @param disableTimeoutMillis the timeout, in milliseconds, before we re-enable the
+             *                             network after disabling it
+             */
+            public DisableReasonInfo(String reasonStr, int disableThreshold,
+                    int disableTimeoutMillis) {
+                mReasonStr = reasonStr;
+                mDisableThreshold = disableThreshold;
+                mDisableTimeoutMillis = disableTimeoutMillis;
+            }
+        }
+
+        /**
+         * Quality network selection disable reason infos.
+         * @hide
+         */
+        public static final SparseArray<DisableReasonInfo> DISABLE_REASON_INFOS =
+                buildDisableReasonInfos();
+
+        private static SparseArray<DisableReasonInfo> buildDisableReasonInfos() {
+            SparseArray<DisableReasonInfo> reasons = new SparseArray<>();
+
+            reasons.append(NETWORK_SELECTION_ENABLE,
+                    new DisableReasonInfo(
+                            // Note that these strings are persisted in
+                            // XmlUtil.NetworkSelectionStatusXmlUtil#writeToXml,
+                            // so do not change the string values to maintain backwards
+                            // compatibility.
+                            "NETWORK_SELECTION_ENABLE",
+                            -1,
+                            Integer.MAX_VALUE));
+
+            reasons.append(DISABLED_ASSOCIATION_REJECTION,
+                    new DisableReasonInfo(
+                            // Note that there is a space at the end of this string. Cannot fix
+                            // since this string is persisted.
+                            "NETWORK_SELECTION_DISABLED_ASSOCIATION_REJECTION ",
+                            5,
+                            5 * 60 * 1000));
+
+            reasons.append(DISABLED_AUTHENTICATION_FAILURE,
+                    new DisableReasonInfo(
+                            "NETWORK_SELECTION_DISABLED_AUTHENTICATION_FAILURE",
+                            5,
+                            5 * 60 * 1000));
+
+            reasons.append(DISABLED_DHCP_FAILURE,
+                    new DisableReasonInfo(
+                            "NETWORK_SELECTION_DISABLED_DHCP_FAILURE",
+                            5,
+                            5 * 60 * 1000));
+
+            reasons.append(DISABLED_NO_INTERNET_TEMPORARY,
+                    new DisableReasonInfo(
+                            "NETWORK_SELECTION_DISABLED_NO_INTERNET_TEMPORARY",
+                            1,
+                            10 * 60 * 1000));
+
+            reasons.append(DISABLED_AUTHENTICATION_NO_CREDENTIALS,
+                    new DisableReasonInfo(
+                            "NETWORK_SELECTION_DISABLED_AUTHENTICATION_NO_CREDENTIALS",
+                            1,
+                            Integer.MAX_VALUE));
+
+            reasons.append(DISABLED_NO_INTERNET_PERMANENT,
+                    new DisableReasonInfo(
+                            "NETWORK_SELECTION_DISABLED_NO_INTERNET_PERMANENT",
+                            1,
+                            Integer.MAX_VALUE));
+
+            reasons.append(DISABLED_BY_WIFI_MANAGER,
+                    new DisableReasonInfo(
+                            "NETWORK_SELECTION_DISABLED_BY_WIFI_MANAGER",
+                            1,
+                            Integer.MAX_VALUE));
+
+            reasons.append(DISABLED_BY_WRONG_PASSWORD,
+                    new DisableReasonInfo(
+                            "NETWORK_SELECTION_DISABLED_BY_WRONG_PASSWORD",
+                            1,
+                            Integer.MAX_VALUE));
+
+            reasons.append(DISABLED_AUTHENTICATION_NO_SUBSCRIPTION,
+                    new DisableReasonInfo(
+                            "NETWORK_SELECTION_DISABLED_AUTHENTICATION_NO_SUBSCRIPTION",
+                            1,
+                            Integer.MAX_VALUE));
+
+            return reasons;
+        }
+
+        /**
+         * Get the {@link NetworkSelectionDisableReason} int code by its string value.
+         * @return the NetworkSelectionDisableReason int code corresponding to the reason string,
+         * or -1 if the reason string is unrecognized.
+         * @hide
+         */
+        @NetworkSelectionDisableReason
+        public static int getDisableReasonByString(@NonNull String reasonString) {
+            for (int i = 0; i < DISABLE_REASON_INFOS.size(); i++) {
+                int key = DISABLE_REASON_INFOS.keyAt(i);
+                DisableReasonInfo value = DISABLE_REASON_INFOS.valueAt(i);
+                if (value != null && TextUtils.equals(reasonString, value.mReasonStr)) {
+                    return key;
+                }
+            }
+            Log.e(TAG, "Unrecognized network disable reason: " + reasonString);
+            return -1;
+        }
 
         /**
          * Invalid time stamp for network selection disable
+         * @hide
          */
         public static final long INVALID_NETWORK_SELECTION_DISABLE_TIMESTAMP = -1L;
 
         /**
-         *  This constant indicates the current configuration has connect choice set
+         * This constant indicates the current configuration has connect choice set
          */
         private static final int CONNECT_CHOICE_EXISTS = 1;
 
         /**
-         *  This constant indicates the current configuration does not have connect choice set
+         * This constant indicates the current configuration does not have connect choice set
          */
         private static final int CONNECT_CHOICE_NOT_EXISTS = -1;
 
@@ -1259,6 +1408,7 @@
         /**
          * Reason for disable this network
          */
+        @NetworkSelectionDisableReason
         private int mNetworkSelectionDisableReason;
 
         /**
@@ -1319,30 +1469,9 @@
         private boolean mHasEverConnected;
 
         /**
-         * Boolean indicating whether {@link com.android.server.wifi.RecommendedNetworkEvaluator}
-         * chose not to connect to this network in the last qualified network selection process.
-         */
-        private boolean mNotRecommended;
-
-        /**
-         * Set whether {@link com.android.server.wifi.RecommendedNetworkEvaluator} does not
-         * recommend connecting to this network.
-         */
-        public void setNotRecommended(boolean notRecommended) {
-            mNotRecommended = notRecommended;
-        }
-
-        /**
-         * Returns whether {@link com.android.server.wifi.RecommendedNetworkEvaluator} does not
-         * recommend connecting to this network.
-         */
-        public boolean isNotRecommended() {
-            return mNotRecommended;
-        }
-
-        /**
          * set whether this network is visible in latest Qualified Network Selection
          * @param seen value set to candidate
+         * @hide
          */
         public void setSeenInLastQualifiedNetworkSelection(boolean seen) {
             mSeenInLastQualifiedNetworkSelection =  seen;
@@ -1352,6 +1481,7 @@
          * get whether this network is visible in latest Qualified Network Selection
          * @return returns true -- network is visible in latest Qualified Network Selection
          *         false -- network is invisible in latest Qualified Network Selection
+         * @hide
          */
         public boolean getSeenInLastQualifiedNetworkSelection() {
             return mSeenInLastQualifiedNetworkSelection;
@@ -1359,6 +1489,7 @@
         /**
          * set the temporary candidate of current network selection procedure
          * @param scanCandidate {@link ScanResult} the candidate set to mCandidate
+         * @hide
          */
         public void setCandidate(ScanResult scanCandidate) {
             mCandidate = scanCandidate;
@@ -1368,6 +1499,7 @@
          * get the temporary candidate of current network selection procedure
          * @return  returns {@link ScanResult} temporary candidate of current network selection
          * procedure
+         * @hide
          */
         public ScanResult getCandidate() {
             return mCandidate;
@@ -1376,6 +1508,7 @@
         /**
          * set the score of the temporary candidate of current network selection procedure
          * @param score value set to mCandidateScore
+         * @hide
          */
         public void setCandidateScore(int score) {
             mCandidateScore = score;
@@ -1384,6 +1517,7 @@
         /**
          * get the score of the temporary candidate of current network selection procedure
          * @return returns score of the temporary candidate of current network selection procedure
+         * @hide
          */
         public int getCandidateScore() {
             return mCandidateScore;
@@ -1391,7 +1525,8 @@
 
         /**
          * get user preferred choice over this configuration
-         *@return returns configKey of user preferred choice over this configuration
+         * @return returns configKey of user preferred choice over this configuration
+         * @hide
          */
         public String getConnectChoice() {
             return mConnectChoice;
@@ -1400,6 +1535,7 @@
         /**
          * set user preferred choice over this configuration
          * @param newConnectChoice, the configKey of user preferred choice over this configuration
+         * @hide
          */
         public void setConnectChoice(String newConnectChoice) {
             mConnectChoice = newConnectChoice;
@@ -1408,6 +1544,7 @@
         /**
          * get the timeStamp when user select a choice over this configuration
          * @return returns when current connectChoice is set (time from System.currentTimeMillis)
+         * @hide
          */
         public long getConnectChoiceTimestamp() {
             return mConnectChoiceTimestamp;
@@ -1417,82 +1554,90 @@
          * set the timeStamp when user select a choice over this configuration
          * @param timeStamp, the timestamp set to connectChoiceTimestamp, expected timestamp should
          *        be obtained from System.currentTimeMillis
+         * @hide
          */
         public void setConnectChoiceTimestamp(long timeStamp) {
             mConnectChoiceTimestamp = timeStamp;
         }
 
-        /**
-         * get current Quality network selection status
-         * @return returns current Quality network selection status in String (for debug purpose)
-         */
+        /** Get the current Quality network selection status as a String (for debugging). */
+        @NonNull
         public String getNetworkStatusString() {
             return QUALITY_NETWORK_SELECTION_STATUS[mStatus];
         }
 
+        /** @hide */
         public void setHasEverConnected(boolean value) {
             mHasEverConnected = value;
         }
 
+        /** True if the device has ever connected to this network, false otherwise. */
         public boolean getHasEverConnected() {
             return mHasEverConnected;
         }
 
+        /** @hide */
         public NetworkSelectionStatus() {
             // previously stored configs will not have this parameter, so we default to false.
             mHasEverConnected = false;
-        };
+        }
 
         /**
-         * @param reason specific error reason
-         * @return  corresponding network disable reason String (for debug purpose)
+         * Get the network disable reason string for a reason code (for debugging).
+         * @param reason specific error reason. One of the {@link #NETWORK_SELECTION_ENABLE} or
+         *               DISABLED_* constants e.g. {@link #DISABLED_ASSOCIATION_REJECTION}.
+         * @return network disable reason string, or null if the reason is invalid.
          */
-        public static String getNetworkDisableReasonString(int reason) {
-            if (reason >= NETWORK_SELECTION_ENABLE && reason < NETWORK_SELECTION_DISABLED_MAX) {
-                return QUALITY_NETWORK_SELECTION_DISABLE_REASON[reason];
-            } else {
+        @Nullable
+        public static String getNetworkDisableReasonString(
+                @NetworkSelectionDisableReason int reason) {
+            DisableReasonInfo info = DISABLE_REASON_INFOS.get(reason);
+            if (info == null) {
                 return null;
+            } else {
+                return info.mReasonStr;
             }
         }
         /**
          * get current network disable reason
          * @return current network disable reason in String (for debug purpose)
+         * @hide
          */
         public String getNetworkDisableReasonString() {
-            return QUALITY_NETWORK_SELECTION_DISABLE_REASON[mNetworkSelectionDisableReason];
+            return getNetworkDisableReasonString(mNetworkSelectionDisableReason);
         }
 
         /**
          * get current network network selection status
          * @return return current network network selection status
+         * @hide
          */
         public int getNetworkSelectionStatus() {
             return mStatus;
         }
-        /**
-         * @return whether current network is enabled to join network selection
-         */
+
+        /** True if the current network is enabled to join network selection, false otherwise. */
         public boolean isNetworkEnabled() {
             return mStatus == NETWORK_SELECTION_ENABLED;
         }
 
         /**
          * @return whether current network is temporary disabled
+         * @hide
          */
         public boolean isNetworkTemporaryDisabled() {
             return mStatus == NETWORK_SELECTION_TEMPORARY_DISABLED;
         }
 
-        /**
-         * @return returns whether current network is permanently disabled
-         */
+        /** True if the current network is permanently disabled, false otherwise. */
         public boolean isNetworkPermanentlyDisabled() {
             return mStatus == NETWORK_SELECTION_PERMANENTLY_DISABLED;
         }
 
         /**
-         * set current networ work selection status
+         * set current network selection status
          * @param status network selection status to set
+         * @hide
          */
         public void setNetworkSelectionStatus(int status) {
             if (status >= 0 && status < NETWORK_SELECTION_STATUS_MAX) {
@@ -1501,17 +1646,21 @@
         }
 
         /**
-         * @return returns current network's disable reason
+         * Returns the current network's disable reason.
+         * One of the {@link #NETWORK_SELECTION_ENABLE} or DISABLED_* constants
+         * e.g. {@link #DISABLED_ASSOCIATION_REJECTION}.
          */
+        @NetworkSelectionDisableReason
         public int getNetworkSelectionDisableReason() {
             return mNetworkSelectionDisableReason;
         }
 
         /**
          * set Network disable reason
-         * @param  reason Network disable reason
+         * @param reason Network disable reason
+         * @hide
          */
-        public void setNetworkSelectionDisableReason(int reason) {
+        public void setNetworkSelectionDisableReason(@NetworkSelectionDisableReason int reason) {
             if (reason >= 0 && reason < NETWORK_SELECTION_DISABLED_MAX) {
                 mNetworkSelectionDisableReason = reason;
             } else {
@@ -1520,38 +1669,30 @@
         }
 
         /**
-         * check whether network is disabled by this reason
-         * @param reason a specific disable reason
-         * @return true -- network is disabled for this reason
-         *         false -- network is not disabled for this reason
-         */
-        public boolean isDisabledByReason(int reason) {
-            return mNetworkSelectionDisableReason == reason;
-        }
-
-        /**
          * @param timeStamp Set when current network is disabled in millisecond since January 1,
          * 1970 00:00:00.0 UTC
+         * @hide
          */
         public void setDisableTime(long timeStamp) {
             mTemporarilyDisabledTimestamp = timeStamp;
         }
 
         /**
-         * @return returns when current network is disabled in millisecond since January 1,
-         * 1970 00:00:00.0 UTC
+         * Returns when the current network was disabled, in milliseconds since January 1,
+         * 1970 00:00:00.0 UTC.
          */
         public long getDisableTime() {
             return mTemporarilyDisabledTimestamp;
         }
 
         /**
-         * get the disable counter of a specific reason
-         * @param  reason specific failure reason
-         * @exception throw IllegalArgumentException for illegal input
+         * Get the disable counter of a specific reason.
+         * @param reason specific failure reason. One of the {@link #NETWORK_SELECTION_ENABLE} or
+         *              DISABLED_* constants e.g. {@link #DISABLED_ASSOCIATION_REJECTION}.
+         * @exception IllegalArgumentException for invalid reason
          * @return counter number for specific error reason.
          */
-        public int getDisableReasonCounter(int reason) {
+        public int getDisableReasonCounter(@NetworkSelectionDisableReason int reason) {
             if (reason >= NETWORK_SELECTION_ENABLE && reason < NETWORK_SELECTION_DISABLED_MAX) {
                 return mNetworkSeclectionDisableCounter[reason];
             } else {
@@ -1564,6 +1705,7 @@
          * @param reason reason for disable error
          * @param value the counter value for this specific reason
          * @exception throw IllegalArgumentException for illegal input
+         * @hide
          */
         public void setDisableReasonCounter(int reason, int value) {
             if (reason >= NETWORK_SELECTION_ENABLE && reason < NETWORK_SELECTION_DISABLED_MAX) {
@@ -1577,6 +1719,7 @@
          * increment the counter of a specific failure reason
          * @param reason a specific failure reason
          * @exception throw IllegalArgumentException for illegal input
+         * @hide
          */
         public void incrementDisableReasonCounter(int reason) {
             if (reason >= NETWORK_SELECTION_ENABLE  && reason < NETWORK_SELECTION_DISABLED_MAX) {
@@ -1588,9 +1731,9 @@
 
         /**
          * clear the counter of a specific failure reason
-         * @hide
          * @param reason a specific failure reason
          * @exception throw IllegalArgumentException for illegal input
+         * @hide
          */
         public void clearDisableReasonCounter(int reason) {
             if (reason >= NETWORK_SELECTION_ENABLE && reason < NETWORK_SELECTION_DISABLED_MAX) {
@@ -1602,6 +1745,7 @@
 
         /**
          * clear all the failure reason counters
+         * @hide
          */
         public void clearDisableReasonCounter() {
             Arrays.fill(mNetworkSeclectionDisableCounter, NETWORK_SELECTION_ENABLE);
@@ -1615,6 +1759,7 @@
         /**
          * get current network Selection BSSID
          * @return current network Selection BSSID
+         * @hide
          */
         public String getNetworkSelectionBSSID() {
             return mNetworkSelectionBSSID;
@@ -1623,11 +1768,13 @@
         /**
          * set network Selection BSSID
          * @param bssid The target BSSID for assocaition
+         * @hide
          */
         public void setNetworkSelectionBSSID(String bssid) {
             mNetworkSelectionBSSID = bssid;
         }
 
+        /** @hide */
         public void copy(NetworkSelectionStatus source) {
             mStatus = source.mStatus;
             mNetworkSelectionDisableReason = source.mNetworkSelectionDisableReason;
@@ -1644,9 +1791,9 @@
             setConnectChoice(source.getConnectChoice());
             setConnectChoiceTimestamp(source.getConnectChoiceTimestamp());
             setHasEverConnected(source.getHasEverConnected());
-            setNotRecommended(source.isNotRecommended());
         }
 
+        /** @hide */
         public void writeToParcel(Parcel dest) {
             dest.writeInt(getNetworkSelectionStatus());
             dest.writeInt(getNetworkSelectionDisableReason());
@@ -1664,9 +1811,9 @@
                 dest.writeInt(CONNECT_CHOICE_NOT_EXISTS);
             }
             dest.writeInt(getHasEverConnected() ? 1 : 0);
-            dest.writeInt(isNotRecommended() ? 1 : 0);
         }
 
+        /** @hide */
         public void readFromParcel(Parcel in) {
             setNetworkSelectionStatus(in.readInt());
             setNetworkSelectionDisableReason(in.readInt());
@@ -1684,7 +1831,6 @@
                 setConnectChoiceTimestamp(INVALID_NETWORK_SELECTION_DISABLE_TIMESTAMP);
             }
             setHasEverConnected(in.readInt() != 0);
-            setNotRecommended(in.readInt() != 0);
         }
     }
 
@@ -1699,8 +1845,16 @@
      * This class is intended to store extra failure reason information for the most recent
      * connection attempt, so that it may be surfaced to the settings UI
      */
+    @SystemApi
     public static class RecentFailure {
 
+        private RecentFailure() {}
+
+        /** @hide */
+        @Retention(RetentionPolicy.SOURCE)
+        @IntDef(value = {NONE, STATUS_AP_UNABLE_TO_HANDLE_NEW_STA})
+        public @interface AssociationStatus {}
+
         /**
          * No recent failure, or no specific reason given for the recent connection failure
          */
@@ -1713,38 +1867,47 @@
         /**
          * Association Rejection Status code (NONE for success/non-association-rejection-fail)
          */
+        @AssociationStatus
         private int mAssociationStatus = NONE;
 
         /**
          * @param status the association status code for the recent failure
+         * @hide
          */
-        public void setAssociationStatus(int status) {
+        public void setAssociationStatus(@AssociationStatus int status) {
             mAssociationStatus = status;
         }
         /**
          * Sets the RecentFailure to NONE
+         * @hide
          */
         public void clear() {
             mAssociationStatus = NONE;
         }
         /**
-         * Get the recent failure code
+         * Get the recent failure code. One of {@link #NONE} or
+         * {@link #STATUS_AP_UNABLE_TO_HANDLE_NEW_STA}.
          */
+        @AssociationStatus
         public int getAssociationStatus() {
             return mAssociationStatus;
         }
     }
 
     /**
-     * @hide
      * RecentFailure member
+     * @hide
      */
-    final public RecentFailure recentFailure = new RecentFailure();
+    @NonNull
+    @SystemApi
+    public final RecentFailure recentFailure = new RecentFailure();
 
     /**
+     * Get the network selection status.
      * @hide
-     * @return network selection status
      */
+    @NonNull
+    @SystemApi
     public NetworkSelectionStatus getNetworkSelectionStatus() {
         return mNetworkSelectionStatus;
     }
@@ -1787,8 +1950,6 @@
             wepKeys[i] = null;
         }
         enterpriseConfig = new WifiEnterpriseConfig();
-        selfAdded = false;
-        didSelfAdd = false;
         ephemeral = false;
         osu = false;
         trusted = true; // Networks are considered trusted by default.
@@ -1900,8 +2061,6 @@
         if (this.creationTime != null) {
             sbuf.append(" creation ").append(this.creationTime).append("\n");
         }
-        if (this.didSelfAdd) sbuf.append(" didSelfAdd");
-        if (this.selfAdded) sbuf.append(" selfAdded");
         if (this.validatedInternetAccess) sbuf.append(" validatedInternetAccess");
         if (this.ephemeral) sbuf.append(" ephemeral");
         if (this.osu) sbuf.append(" osu");
@@ -1910,9 +2069,9 @@
         if (this.fromWifiNetworkSpecifier) sbuf.append(" fromWifiNetworkSpecifier");
         if (this.meteredHint) sbuf.append(" meteredHint");
         if (this.useExternalScores) sbuf.append(" useExternalScores");
-        if (this.didSelfAdd || this.selfAdded || this.validatedInternetAccess
-                || this.ephemeral || this.trusted || this.fromWifiNetworkSuggestion
-                || this.fromWifiNetworkSpecifier || this.meteredHint || this.useExternalScores) {
+        if (this.validatedInternetAccess || this.ephemeral || this.trusted
+                || this.fromWifiNetworkSuggestion || this.fromWifiNetworkSpecifier
+                || this.meteredHint || this.useExternalScores) {
             sbuf.append("\n");
         }
         if (this.meteredOverride != METERED_OVERRIDE_NONE) {
@@ -2040,7 +2199,6 @@
         if (lastUpdateName != null) sbuf.append(" lname=" + lastUpdateName);
         if (updateIdentifier != null) sbuf.append(" updateIdentifier=" + updateIdentifier);
         sbuf.append(" lcuid=" + lastConnectUid);
-        sbuf.append(" userApproved=" + userApprovedAsString(userApproved));
         sbuf.append(" allowAutojoin=" + allowAutojoin);
         sbuf.append(" noInternetAccessExpected=" + noInternetAccessExpected);
         sbuf.append(" ");
@@ -2062,8 +2220,13 @@
         return sbuf.toString();
     }
 
-    /** {@hide} */
-    @UnsupportedAppUsage
+    /**
+     * Get the SSID in a human-readable format, with all additional formatting removed
+     * e.g. quotation marks around the SSID, "P" prefix
+     * @hide
+     */
+    @NonNull
+    @SystemApi
     public String getPrintableSsid() {
         if (SSID == null) return "";
         final int length = SSID.length();
@@ -2071,7 +2234,7 @@
             return SSID.substring(1, length - 1);
         }
 
-        /** The ascii-encoded string format is P"<ascii-encoded-string>"
+        /* The ascii-encoded string format is P"<ascii-encoded-string>"
          * The decoding is implemented in the supplicant for a newly configured
          * network.
          */
@@ -2084,20 +2247,6 @@
         return SSID;
     }
 
-    /** @hide **/
-    public static String userApprovedAsString(int userApproved) {
-        switch (userApproved) {
-            case USER_APPROVED:
-                return "USER_APPROVED";
-            case USER_BANNED:
-                return "USER_BANNED";
-            case USER_UNSPECIFIED:
-                return "USER_UNSPECIFIED";
-            default:
-                return "INVALID";
-        }
-    }
-
     /**
      * Get an identifier for associating credentials with this config
      * @param current configuration contains values for additional fields
@@ -2166,8 +2315,13 @@
         }
     }
 
-    /** @hide */
-    @UnsupportedAppUsage
+    /**
+     * Get the authentication type of the network.
+     * @return One of the {@link KeyMgmt} constants. e.g. {@link KeyMgmt#WPA2_PSK}.
+     * @hide
+     */
+    @SystemApi
+    @KeyMgmt.KeyMgmtScheme
     public int getAuthType() {
         if (allowedKeyManagement.cardinality() > 1) {
             throw new IllegalStateException("More than one auth type set");
@@ -2256,15 +2410,25 @@
         return mIpConfiguration;
     }
 
-    /** @hide */
-    @UnsupportedAppUsage
-    public void setIpConfiguration(IpConfiguration ipConfiguration) {
+    /**
+     * Set the {@link IpConfiguration} for this network.
+     * @param ipConfiguration the {@link IpConfiguration} to set, or null to use the default
+     *                        constructor {@link IpConfiguration#IpConfiguration()}.
+     * @hide
+     */
+    @SystemApi
+    public void setIpConfiguration(@Nullable IpConfiguration ipConfiguration) {
         if (ipConfiguration == null) ipConfiguration = new IpConfiguration();
         mIpConfiguration = ipConfiguration;
     }
 
-    /** @hide */
-    @UnsupportedAppUsage
+    /**
+     * Get the {@link StaticIpConfiguration} for this network.
+     * @return the {@link StaticIpConfiguration}, or null if unset.
+     * @hide
+     */
+    @Nullable
+    @SystemApi
     public StaticIpConfiguration getStaticIpConfiguration() {
         return mIpConfiguration.getStaticIpConfiguration();
     }
@@ -2275,8 +2439,12 @@
         mIpConfiguration.setStaticIpConfiguration(staticIpConfiguration);
     }
 
-    /** @hide */
-    @UnsupportedAppUsage
+    /**
+     * Get the {@link IpConfiguration.IpAssignment} for this network.
+     * @hide
+     */
+    @NonNull
+    @SystemApi
     public IpConfiguration.IpAssignment getIpAssignment() {
         return mIpConfiguration.ipAssignment;
     }
@@ -2287,8 +2455,12 @@
         mIpConfiguration.ipAssignment = ipAssignment;
     }
 
-    /** @hide */
-    @UnsupportedAppUsage
+    /**
+     * Get the {@link IpConfiguration.ProxySettings} for this network.
+     * @hide
+     */
+    @NonNull
+    @SystemApi
     public IpConfiguration.ProxySettings getProxySettings() {
         return mIpConfiguration.proxySettings;
     }
@@ -2347,9 +2519,12 @@
         mIpConfiguration.setHttpProxy(httpProxyCopy);
     }
 
-    /** @hide */
-    @UnsupportedAppUsage
-    public void setProxy(ProxySettings settings, ProxyInfo proxy) {
+    /**
+     * Set the {@link ProxySettings} and {@link ProxyInfo} for this network.
+     * @hide
+     */
+    @SystemApi
+    public void setProxy(@NonNull ProxySettings settings, @NonNull ProxyInfo proxy) {
         mIpConfiguration.proxySettings = settings;
         mIpConfiguration.httpProxy = proxy;
     }
@@ -2415,7 +2590,6 @@
                 linkedConfigurations.putAll(source.linkedConfigurations);
             }
             mCachedConfigKey = null; //force null configKey
-            selfAdded = source.selfAdded;
             validatedInternetAccess = source.validatedInternetAccess;
             isLegacyPasspointConfig = source.isLegacyPasspointConfig;
             ephemeral = source.ephemeral;
@@ -2427,7 +2601,6 @@
             meteredOverride = source.meteredOverride;
             useExternalScores = source.useExternalScores;
 
-            didSelfAdd = source.didSelfAdd;
             lastConnectUid = source.lastConnectUid;
             lastUpdateUid = source.lastUpdateUid;
             creatorUid = source.creatorUid;
@@ -2440,7 +2613,6 @@
             numScorerOverride = source.numScorerOverride;
             numScorerOverrideAndSwitchedNetwork = source.numScorerOverrideAndSwitchedNetwork;
             numAssociation = source.numAssociation;
-            userApproved = source.userApproved;
             allowAutojoin = source.allowAutojoin;
             numNoInternetAccessReports = source.numNoInternetAccessReports;
             noInternetAccessExpected = source.noInternetAccessExpected;
@@ -2498,8 +2670,6 @@
         dest.writeParcelable(mIpConfiguration, flags);
         dest.writeString(dhcpServer);
         dest.writeString(defaultGwMacAddress);
-        dest.writeInt(selfAdded ? 1 : 0);
-        dest.writeInt(didSelfAdd ? 1 : 0);
         dest.writeInt(validatedInternetAccess ? 1 : 0);
         dest.writeInt(isLegacyPasspointConfig ? 1 : 0);
         dest.writeInt(ephemeral ? 1 : 0);
@@ -2517,7 +2687,6 @@
         dest.writeInt(numScorerOverride);
         dest.writeInt(numScorerOverrideAndSwitchedNetwork);
         dest.writeInt(numAssociation);
-        dest.writeInt(userApproved);
         dest.writeBoolean(allowAutojoin);
         dest.writeInt(numNoInternetAccessReports);
         dest.writeInt(noInternetAccessExpected ? 1 : 0);
@@ -2575,8 +2744,6 @@
                 config.setIpConfiguration(in.readParcelable(null));
                 config.dhcpServer = in.readString();
                 config.defaultGwMacAddress = in.readString();
-                config.selfAdded = in.readInt() != 0;
-                config.didSelfAdd = in.readInt() != 0;
                 config.validatedInternetAccess = in.readInt() != 0;
                 config.isLegacyPasspointConfig = in.readInt() != 0;
                 config.ephemeral = in.readInt() != 0;
@@ -2594,7 +2761,6 @@
                 config.numScorerOverride = in.readInt();
                 config.numScorerOverrideAndSwitchedNetwork = in.readInt();
                 config.numAssociation = in.readInt();
-                config.userApproved = in.readInt();
                 config.allowAutojoin = in.readBoolean();
                 config.numNoInternetAccessReports = in.readInt();
                 config.noInternetAccessExpected = in.readInt() != 0;
@@ -2615,9 +2781,11 @@
         };
 
     /**
-     * Serializes the object for backup
+     * Serialize the Soft AP configuration contained in this object for backup.
      * @hide
      */
+    @NonNull
+    // TODO(b/144368124): this method should be removed once we migrate to SoftApConfiguration
     public byte[] getBytesForBackup() throws IOException {
         ByteArrayOutputStream baos = new ByteArrayOutputStream();
         DataOutputStream out = new DataOutputStream(baos);
@@ -2633,11 +2801,16 @@
     }
 
     /**
-     * Deserializes a byte array into the WiFiConfiguration Object
+     * Deserialize a byte array containing Soft AP configuration into a WifiConfiguration object.
+     * @return The deserialized WifiConfiguration containing Soft AP configuration, or null if
+     * the version contains a bad dataset e.g. Version 1
+     * @throws BackupUtils.BadVersionException if the version is unrecognized
      * @hide
      */
-    public static WifiConfiguration getWifiConfigFromBackup(DataInputStream in) throws IOException,
-            BackupUtils.BadVersionException {
+    @Nullable
+    // TODO(b/144368124): this method should be removed once we migrate to SoftApConfiguration
+    public static WifiConfiguration getWifiConfigFromBackup(@NonNull DataInputStream in)
+            throws IOException, BackupUtils.BadVersionException {
         WifiConfiguration config = new WifiConfiguration();
         int version = in.readInt();
         if (version < 1 || version > BACKUP_VERSION) {
diff --git a/wifi/java/android/net/wifi/WifiEnterpriseConfig.java b/wifi/java/android/net/wifi/WifiEnterpriseConfig.java
index 7b99a2b..449f95e 100644
--- a/wifi/java/android/net/wifi/WifiEnterpriseConfig.java
+++ b/wifi/java/android/net/wifi/WifiEnterpriseConfig.java
@@ -16,7 +16,9 @@
 package android.net.wifi;
 
 import android.annotation.IntDef;
+import android.annotation.NonNull;
 import android.annotation.Nullable;
+import android.annotation.SystemApi;
 import android.annotation.UnsupportedAppUsage;
 import android.os.Parcel;
 import android.os.Parcelable;
@@ -118,18 +120,21 @@
      * Do not use OCSP stapling (TLS certificate status extension)
      * @hide
      */
+    @SystemApi
     public static final int OCSP_NONE = 0;
 
     /**
      * Try to use OCSP stapling, but not require response
      * @hide
      */
+    @SystemApi
     public static final int OCSP_REQUEST_CERT_STATUS = 1;
 
     /**
      * Require valid OCSP stapling response
      * @hide
      */
+    @SystemApi
     public static final int OCSP_REQUIRE_CERT_STATUS = 2;
 
     /**
@@ -137,6 +142,7 @@
      * certificate chain
      * @hide
      */
+    @SystemApi
     public static final int OCSP_REQUIRE_ALL_NON_TRUSTED_CERTS_STATUS = 3;
 
     /** @hide */
@@ -147,8 +153,7 @@
             OCSP_REQUIRE_ALL_NON_TRUSTED_CERTS_STATUS
     })
     @Retention(RetentionPolicy.SOURCE)
-    public @interface Ocsp {
-    }
+    public @interface Ocsp {}
 
     /**
      * Whether to use/require OCSP (Online Certificate Status Protocol) to check server certificate.
@@ -636,9 +641,11 @@
      * <p> See the {@link android.security.KeyChain} for details on installing or choosing
      * a certificate.
      * </p>
-     * @param aliases identifies the certificate
+     * @param aliases identifies the certificate. Can be null to indicate the absence of a
+     *                certificate.
      * @hide
      */
+    @SystemApi
     public void setCaCertificateAliases(@Nullable String[] aliases) {
         if (aliases == null) {
             setFieldValue(CA_CERT_KEY, null, CA_CERT_PREFIX);
@@ -669,11 +676,13 @@
     }
 
     /**
-     * Get CA certificate aliases
-     * @return alias to the CA certificate
+     * Get CA certificate aliases.
+     * @return alias to the CA certificate, or null if unset.
      * @hide
      */
-    @Nullable public String[] getCaCertificateAliases() {
+    @Nullable
+    @SystemApi
+    public String[] getCaCertificateAliases() {
         String value = getFieldValue(CA_CERT_KEY);
         if (value.startsWith(CA_CERT_PREFIX)) {
             // Backwards compatibility: parse the original alias prefix.
@@ -792,32 +801,36 @@
      * like /etc/ssl/certs. If configured, these certificates are added to the
      * list of trusted CAs. ca_cert may also be included in that case, but it is
      * not required.
-     * @param domain The path for CA certificate files
+     * @param path The path for CA certificate files, or null/empty string to clear.
      * @hide
      */
-    public void setCaPath(String path) {
+    @SystemApi
+    public void setCaPath(@Nullable String path) {
         setFieldValue(CA_PATH_KEY, path);
     }
 
     /**
      * Get the domain_suffix_match value. See setDomSuffixMatch.
-     * @return The path for CA certificate files.
+     * @return The path for CA certificate files, or an empty string if unset.
      * @hide
      */
+    @NonNull
+    @SystemApi
     public String getCaPath() {
         return getFieldValue(CA_PATH_KEY);
     }
 
-    /** Set Client certificate alias.
+    /**
+     * Set Client certificate alias.
      *
      * <p> See the {@link android.security.KeyChain} for details on installing or choosing
      * a certificate
      * </p>
-     * @param alias identifies the certificate
+     * @param alias identifies the certificate, or null/empty string to clear.
      * @hide
      */
-    @UnsupportedAppUsage
-    public void setClientCertificateAlias(String alias) {
+    @SystemApi
+    public void setClientCertificateAlias(@Nullable String alias) {
         setFieldValue(CLIENT_CERT_KEY, alias, CLIENT_CERT_PREFIX);
         setFieldValue(PRIVATE_KEY_ID_KEY, alias, Credentials.USER_PRIVATE_KEY);
         // Also, set engine parameters
@@ -831,11 +844,12 @@
     }
 
     /**
-     * Get client certificate alias
-     * @return alias to the client certificate
+     * Get client certificate alias.
+     * @return alias to the client certificate, or an empty string if unset.
      * @hide
      */
-    @UnsupportedAppUsage
+    @NonNull
+    @SystemApi
     public String getClientCertificateAlias() {
         return getFieldValue(CLIENT_CERT_KEY, CLIENT_CERT_PREFIX);
     }
@@ -1241,12 +1255,14 @@
     }
 
     /**
-     * Set the ocsp type.
-     * @param  ocsp is one {@link ##OCSP_NONE}, {@link #OCSP_REQUEST_CERT_STATUS},
+     * Set the OCSP type.
+     * @param ocsp is one of {@link ##OCSP_NONE}, {@link #OCSP_REQUEST_CERT_STATUS},
      *                   {@link #OCSP_REQUIRE_CERT_STATUS} or
      *                   {@link #OCSP_REQUIRE_ALL_NON_TRUSTED_CERTS_STATUS}
+     * @throws IllegalArgumentException if the OCSP type is invalid
      * @hide
      */
+    @SystemApi
     public void setOcsp(@Ocsp int ocsp) {
         if (ocsp >= OCSP_NONE && ocsp <= OCSP_REQUIRE_ALL_NON_TRUSTED_CERTS_STATUS) {
             mOcsp = ocsp;
@@ -1256,10 +1272,10 @@
     }
 
     /**
-     * Get the ocsp type.
-     * @return ocsp type
+     * Get the OCSP type.
      * @hide
      */
+    @SystemApi
     public @Ocsp int getOcsp() {
         return mOcsp;
     }
diff --git a/wifi/tests/src/android/net/wifi/WifiConfigurationTest.java b/wifi/tests/src/android/net/wifi/WifiConfigurationTest.java
index 6d7e621..7e38e14 100644
--- a/wifi/tests/src/android/net/wifi/WifiConfigurationTest.java
+++ b/wifi/tests/src/android/net/wifi/WifiConfigurationTest.java
@@ -19,6 +19,7 @@
 import static org.junit.Assert.assertArrayEquals;
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
 import static org.junit.Assert.assertTrue;
 
 import android.net.MacAddress;
@@ -90,37 +91,6 @@
     }
 
     @Test
-    public void testNetworkSelectionStatusCopy() {
-        NetworkSelectionStatus networkSelectionStatus = new NetworkSelectionStatus();
-        networkSelectionStatus.setNotRecommended(true);
-
-        NetworkSelectionStatus copy = new NetworkSelectionStatus();
-        copy.copy(networkSelectionStatus);
-
-        assertEquals(networkSelectionStatus.isNotRecommended(), copy.isNotRecommended());
-    }
-
-    @Test
-    public void testNetworkSelectionStatusParcel() {
-        NetworkSelectionStatus networkSelectionStatus = new NetworkSelectionStatus();
-        networkSelectionStatus.setNotRecommended(true);
-
-        Parcel parcelW = Parcel.obtain();
-        networkSelectionStatus.writeToParcel(parcelW);
-        byte[] bytes = parcelW.marshall();
-        parcelW.recycle();
-
-        Parcel parcelR = Parcel.obtain();
-        parcelR.unmarshall(bytes, 0, bytes.length);
-        parcelR.setDataPosition(0);
-
-        NetworkSelectionStatus copy = new NetworkSelectionStatus();
-        copy.readFromParcel(parcelR);
-
-        assertEquals(networkSelectionStatus.isNotRecommended(), copy.isNotRecommended());
-    }
-
-    @Test
     public void testIsOpenNetwork_IsOpen_NullWepKeys() {
         WifiConfiguration config = new WifiConfiguration();
         config.allowedKeyManagement.clear();
@@ -348,4 +318,18 @@
         config.allowedKeyManagement.set(KeyMgmt.NONE);
         assertEquals(mSsid + KeyMgmt.strings[KeyMgmt.NONE], config.getSsidAndSecurityTypeString());
     }
+
+    /**
+     * Ensure that the {@link NetworkSelectionStatus.DisableReasonInfo}s are populated in
+     * {@link NetworkSelectionStatus#DISABLE_REASON_INFOS} for reason codes from 0 to
+     * {@link NetworkSelectionStatus#NETWORK_SELECTION_DISABLED_MAX} - 1.
+     */
+    @Test
+    public void testNetworkSelectionDisableReasonInfosPopulated() {
+        assertEquals(NetworkSelectionStatus.NETWORK_SELECTION_DISABLED_MAX,
+                NetworkSelectionStatus.DISABLE_REASON_INFOS.size());
+        for (int i = 0; i < NetworkSelectionStatus.NETWORK_SELECTION_DISABLED_MAX; i++) {
+            assertNotNull(NetworkSelectionStatus.DISABLE_REASON_INFOS.get(i));
+        }
+    }
 }