Merge "Add SettingsProvider team as OWNERS of android.provider.Settings"
diff --git a/StubLibraries.bp b/StubLibraries.bp
index d4abeee..4b28352 100644
--- a/StubLibraries.bp
+++ b/StubLibraries.bp
@@ -333,20 +333,6 @@
     },
 }
 
-java_library_static {
-    name: "android_non_updatable_stubs_current",
-    srcs: [":api-stubs-docs-non-updatable"],
-    defaults: ["android_defaults_stubs_current"],
-    libs: ["sdk_system_29_android"],
-}
-
-java_library_static {
-    name: "android_system_non_updatable_stubs_current",
-    srcs: [":system-api-stubs-docs-non-updatable"],
-    defaults: ["android_defaults_stubs_current"],
-    libs: ["sdk_system_29_android"],
-}
-
 /////////////////////////////////////////////////////////////////////
 // hwbinder.stubs provides APIs required for building HIDL Java
 // libraries.
diff --git a/services/core/java/com/android/server/AlarmManagerService.java b/services/core/java/com/android/server/AlarmManagerService.java
index 651f941..d09f44f 100644
--- a/services/core/java/com/android/server/AlarmManagerService.java
+++ b/services/core/java/com/android/server/AlarmManagerService.java
@@ -3369,7 +3369,9 @@
                     if (mMaxDelayTime < thisDelayTime) {
                         mMaxDelayTime = thisDelayTime;
                     }
-                    deliverAlarmsLocked(mPendingNonWakeupAlarms, nowELAPSED);
+                    ArrayList<Alarm> triggerList =
+                            (ArrayList<Alarm>) mPendingNonWakeupAlarms.clone();
+                    deliverAlarmsLocked(triggerList, nowELAPSED);
                     mPendingNonWakeupAlarms.clear();
                 }
                 if (mNonInteractiveStartTime > 0) {
diff --git a/telephony/java/android/telephony/AccessNetworkUtils.java b/telephony/java/android/telephony/AccessNetworkUtils.java
index 981ed450..7661a32 100644
--- a/telephony/java/android/telephony/AccessNetworkUtils.java
+++ b/telephony/java/android/telephony/AccessNetworkUtils.java
@@ -5,8 +5,11 @@
 import static android.telephony.ServiceState.DUPLEX_MODE_UNKNOWN;
 
 import android.telephony.AccessNetworkConstants.EutranBand;
+import android.telephony.AccessNetworkConstants.GeranBand;
+import android.telephony.AccessNetworkConstants.UtranBand;
 import android.telephony.ServiceState.DuplexMode;
 
+import java.util.Arrays;
 
 /**
  * Utilities to map between radio constants.
@@ -20,6 +23,9 @@
 
     public static final int INVALID_BAND = -1;
 
+    /** ISO country code of Japan. */
+    private static final String JAPAN_ISO_COUNTRY_CODE = "jp";
+
     /**
      * Gets the duplex mode for the given EUTRAN operating band.
      *
@@ -50,7 +56,7 @@
     /**
      * Gets the EUTRAN Operating band for a given downlink EARFCN.
      *
-     * <p>See 3GPP 36.101 sec 5.7.3-1 for calculation.
+     * <p>See 3GPP TS 36.101 clause 5.7.3-1 for calculation.
      *
      * @param earfcn The downlink EARFCN
      * @return Operating band number, or {@link #INVALID_BAND} if no corresponding band exists
@@ -198,4 +204,125 @@
 
         return INVALID_BAND;
     }
+
+    /**
+     * Gets the GERAN Operating band for a given ARFCN.
+     *
+     * <p>See 3GPP TS 45.005 clause 2 for calculation.
+     *
+     * @param arfcn The ARFCN
+     * @return Operating band number, or {@link #INVALID_BAND} if no corresponding band exists
+     */
+    public static int getOperatingBandForArfcn(int arfcn) {
+        if (arfcn >= 0 && arfcn <= 124) {
+            return GeranBand.BAND_E900;
+        } else if (arfcn >= 128 && arfcn <= 251) {
+            return GeranBand.BAND_850;
+        } else if (arfcn >= 259 && arfcn <= 293) {
+            return GeranBand.BAND_450;
+        } else if (arfcn >= 306 && arfcn <= 340) {
+            return GeranBand.BAND_480;
+        } else if (arfcn >= 438 && arfcn <= 511) {
+            return GeranBand.BAND_750;
+        } else if (arfcn >= 512 && arfcn <= 885) {
+            // ARFCN between 512 and 810 are also part of BAND_PCS1900.
+            // Returning BAND_DCS1800 in both cases.
+            return GeranBand.BAND_DCS1800;
+        } else if (arfcn >= 940 && arfcn <= 974) {
+            return GeranBand.BAND_ER900;
+        } else if (arfcn >= 975 && arfcn <= 1023) {
+            return GeranBand.BAND_E900;
+        }
+        return INVALID_BAND;
+    }
+
+    /**
+     * Gets the UTRAN Operating band for a given downlink UARFCN.
+     *
+     * <p>See 3GPP TS 25.101 clause 5.4.4 for calculation.
+     *
+     * @param uarfcn The downlink UARFCN
+     * @return Operating band number, or {@link #INVALID_BAND} if no corresponding band exists
+     */
+    public static int getOperatingBandForUarfcn(int uarfcn) {
+        // List of additional bands defined in TS 25.101.
+        int[] addlBand2 = {412, 437, 462, 487, 512, 537, 562, 587, 612, 637, 662, 687};
+        int[] addlBand4 = {1887, 1912, 1937, 1962, 1987, 2012, 2037, 2062, 2087};
+        int[] addlBand5 = {1007, 1012, 1032, 1037, 1062, 1087};
+        int[] addlBand6 = {1037, 1062};
+        int[] addlBand7 =
+                {2587, 2612, 2637, 2662, 2687, 2712, 2737, 2762, 2787, 2812, 2837, 2862,
+                2887, 2912};
+        int[] addlBand10 =
+                {3412, 3437, 3462, 3487, 3512, 3537, 3562, 3587, 3612, 3637, 3662, 3687};
+        int[] addlBand12 = {3932, 3957, 3962, 3987, 3992};
+        int[] addlBand13 = {4067, 4092};
+        int[] addlBand14 = {4167, 4192};
+        int[] addlBand19 = {787, 812, 837};
+        int[] addlBand25 =
+                {6292, 6317, 6342, 6367, 6392, 6417, 6442, 6467, 6492, 6517, 6542, 6567, 6592};
+        int[] addlBand26 = {5937, 5962, 5987, 5992, 6012, 6017, 6037, 6042, 6062, 6067, 6087};
+
+        if (uarfcn >= 10562 && uarfcn <= 10838) {
+            return UtranBand.BAND_1;
+        } else if ((uarfcn >= 9662 && uarfcn <= 9938)
+                || Arrays.binarySearch(addlBand2, uarfcn) >= 0) {
+            return UtranBand.BAND_2;
+        } else if (uarfcn >= 1162 && uarfcn <= 1513) {
+            return UtranBand.BAND_3;
+        } else if ((uarfcn >= 1537 && uarfcn <= 1738)
+                || Arrays.binarySearch(addlBand4, uarfcn) >= 0) {
+            return UtranBand.BAND_4;
+        } else if (uarfcn >= 4387 && uarfcn <= 4413) {
+            // Band 6 is a subset of band 5. Only Japan uses band 6 and Japan does not have band 5.
+            String country = TelephonyManager.getDefault().getNetworkCountryIso();
+            if (JAPAN_ISO_COUNTRY_CODE.compareToIgnoreCase(country) == 0) {
+                return UtranBand.BAND_6;
+            } else {
+                return UtranBand.BAND_5;
+            }
+        } else if ((uarfcn >= 4357 && uarfcn <= 4458)
+                || Arrays.binarySearch(addlBand5, uarfcn) >= 0) {
+            return UtranBand.BAND_5;
+        } else if (Arrays.binarySearch(addlBand6, uarfcn) >= 0) {
+            return UtranBand.BAND_6;
+        } else if ((uarfcn >= 2237 && uarfcn <= 2563)
+                || Arrays.binarySearch(addlBand7, uarfcn) >= 0) {
+            return UtranBand.BAND_7;
+        } else if (uarfcn >= 2937 && uarfcn <= 3088) {
+            return UtranBand.BAND_8;
+        } else if (uarfcn >= 9237 && uarfcn <= 9387) {
+            return UtranBand.BAND_9;
+        } else if ((uarfcn >= 3112 && uarfcn <= 3388)
+                || Arrays.binarySearch(addlBand10, uarfcn) >= 0) {
+            return UtranBand.BAND_10;
+        } else if (uarfcn >= 3712 && uarfcn <= 3787) {
+            return UtranBand.BAND_11;
+        } else if ((uarfcn >= 3842 && uarfcn <= 3903)
+                || Arrays.binarySearch(addlBand12, uarfcn) >= 0) {
+            return UtranBand.BAND_12;
+        } else if ((uarfcn >= 4017 && uarfcn <= 4043)
+                || Arrays.binarySearch(addlBand13, uarfcn) >= 0) {
+            return UtranBand.BAND_13;
+        } else if ((uarfcn >= 4117 && uarfcn <= 4143)
+                || Arrays.binarySearch(addlBand14, uarfcn) >= 0) {
+            return UtranBand.BAND_14;
+        } else if ((uarfcn >= 712 && uarfcn <= 763)
+                || Arrays.binarySearch(addlBand19, uarfcn) >= 0) {
+            return UtranBand.BAND_19;
+        } else if (uarfcn >= 4512 && uarfcn <= 4638) {
+            return UtranBand.BAND_20;
+        } else if (uarfcn >= 862 && uarfcn <= 912) {
+            return UtranBand.BAND_21;
+        } else if (uarfcn >= 4662 && uarfcn <= 5038) {
+            return UtranBand.BAND_22;
+        } else if ((uarfcn >= 5112 && uarfcn <= 5413)
+                || Arrays.binarySearch(addlBand25, uarfcn) >= 0) {
+            return UtranBand.BAND_25;
+        } else if ((uarfcn >= 5762 && uarfcn <= 5913)
+                || Arrays.binarySearch(addlBand26, uarfcn) >= 0) {
+            return UtranBand.BAND_26;
+        }
+        return INVALID_BAND;
+    }
 }
diff --git a/wifi/api/current.txt b/wifi/api/current.txt
index 53c3b33..28224cf 100644
--- a/wifi/api/current.txt
+++ b/wifi/api/current.txt
@@ -264,7 +264,7 @@
     field public static final int SIM = 5; // 0x5
   }
 
-  public class WifiInfo implements android.os.Parcelable {
+  public class WifiInfo implements android.os.Parcelable android.net.TransportInfo {
     method public int describeContents();
     method public String getBSSID();
     method public static android.net.NetworkInfo.DetailedState getDetailedStateOf(android.net.wifi.SupplicantState);
@@ -315,7 +315,7 @@
     method @Deprecated public boolean disconnect();
     method @Deprecated public boolean enableNetwork(int, boolean);
     method @Deprecated @RequiresPermission(allOf={android.Manifest.permission.ACCESS_FINE_LOCATION, android.Manifest.permission.ACCESS_WIFI_STATE}) public java.util.List<android.net.wifi.WifiConfiguration> getConfiguredNetworks();
-    method public android.net.wifi.WifiInfo getConnectionInfo();
+    method @Deprecated public android.net.wifi.WifiInfo getConnectionInfo();
     method public android.net.DhcpInfo getDhcpInfo();
     method public int getMaxNumberOfNetworkSuggestionsPerApp();
     method @IntRange(from=0) public int getMaxSignalLevel();
diff --git a/wifi/api/system-current.txt b/wifi/api/system-current.txt
index 07793c1..afc39b9 100644
--- a/wifi/api/system-current.txt
+++ b/wifi/api/system-current.txt
@@ -401,7 +401,7 @@
     method public static void registerServiceWrappers();
   }
 
-  public class WifiInfo implements android.os.Parcelable {
+  public class WifiInfo implements android.os.Parcelable android.net.TransportInfo {
     method public double getLostTxPacketsPerSecond();
     method @Nullable public String getRequestingPackageName();
     method public double getRetriedTxPacketsPerSecond();
diff --git a/wifi/java/android/net/wifi/WifiInfo.java b/wifi/java/android/net/wifi/WifiInfo.java
index 5388367..7437082 100644
--- a/wifi/java/android/net/wifi/WifiInfo.java
+++ b/wifi/java/android/net/wifi/WifiInfo.java
@@ -22,11 +22,13 @@
 import android.annotation.SystemApi;
 import android.compat.annotation.UnsupportedAppUsage;
 import android.net.NetworkInfo.DetailedState;
+import android.net.TransportInfo;
 import android.os.Build;
 import android.os.Parcel;
 import android.os.Parcelable;
 import android.text.TextUtils;
 
+import com.android.modules.utils.build.SdkLevel;
 import com.android.net.module.util.Inet4AddressUtils;
 
 import java.net.Inet4Address;
@@ -34,12 +36,21 @@
 import java.net.UnknownHostException;
 import java.util.EnumMap;
 import java.util.Locale;
+import java.util.Objects;
 
 /**
  * Describes the state of any Wi-Fi connection that is active or
  * is in the process of being set up.
+ *
+ * In the connected state, access to location sensitive fields requires
+ * the same permissions as {@link WifiManager#getScanResults}. If such access is not allowed,
+ * {@link #getSSID} will return {@link WifiManager#UNKNOWN_SSID} and
+ * {@link #getBSSID} will return {@code "02:00:00:00:00:00"}.
+ * {@link #getNetworkId()} will return {@code -1}.
+ * {@link #getPasspointFqdn()} will return null.
+ * {@link #getPasspointProviderFriendlyName()} will return null.
  */
-public class WifiInfo implements Parcelable {
+public class WifiInfo implements TransportInfo, Parcelable {
     private static final String TAG = "WifiInfo";
     /**
      * This is the map described in the Javadoc comment above. The positions
@@ -1048,4 +1059,88 @@
     public @Nullable String getPasspointUniqueId() {
         return mPasspointUniqueId;
     }
+
+    @Override
+    public boolean equals(Object that) {
+        if (this == that) return true;
+
+        // Potential API behavior change, so don't change behavior on older devices.
+        if (!SdkLevel.isAtLeastS()) return false;
+
+        if (!(that instanceof WifiInfo)) return false;
+
+        WifiInfo thatWifiInfo = (WifiInfo) that;
+        return Objects.equals(mWifiSsid, thatWifiInfo.mWifiSsid)
+                && Objects.equals(mBSSID, thatWifiInfo.mBSSID)
+                && Objects.equals(mNetworkId, thatWifiInfo.mNetworkId)
+                && Objects.equals(mRssi, thatWifiInfo.mRssi)
+                && Objects.equals(mSupplicantState, thatWifiInfo.mSupplicantState)
+                && Objects.equals(mLinkSpeed, thatWifiInfo.mLinkSpeed)
+                && Objects.equals(mTxLinkSpeed, thatWifiInfo.mTxLinkSpeed)
+                && Objects.equals(mRxLinkSpeed, thatWifiInfo.mRxLinkSpeed)
+                && Objects.equals(mFrequency, thatWifiInfo.mFrequency)
+                && Objects.equals(mIpAddress, thatWifiInfo.mIpAddress)
+                && Objects.equals(mMacAddress, thatWifiInfo.mMacAddress)
+                && Objects.equals(mMeteredHint, thatWifiInfo.mMeteredHint)
+                && Objects.equals(mEphemeral, thatWifiInfo.mEphemeral)
+                && Objects.equals(mTrusted, thatWifiInfo.mTrusted)
+                && Objects.equals(mRequestingPackageName, thatWifiInfo.mRequestingPackageName)
+                && Objects.equals(mOsuAp, thatWifiInfo.mOsuAp)
+                && Objects.equals(mFqdn, thatWifiInfo.mFqdn)
+                && Objects.equals(mProviderFriendlyName, thatWifiInfo.mProviderFriendlyName)
+                && Objects.equals(txBad, thatWifiInfo.txBad)
+                && Objects.equals(txRetries, thatWifiInfo.txRetries)
+                && Objects.equals(txSuccess, thatWifiInfo.txSuccess)
+                && Objects.equals(rxSuccess, thatWifiInfo.rxSuccess)
+                && Objects.equals(mLostTxPacketsPerSecond, thatWifiInfo.mLostTxPacketsPerSecond)
+                && Objects.equals(mTxRetriedTxPacketsPerSecond,
+                thatWifiInfo.mTxRetriedTxPacketsPerSecond)
+                && Objects.equals(mSuccessfulTxPacketsPerSecond,
+                thatWifiInfo.mSuccessfulTxPacketsPerSecond)
+                && Objects.equals(mSuccessfulRxPacketsPerSecond,
+                thatWifiInfo.mSuccessfulRxPacketsPerSecond)
+                && Objects.equals(score, thatWifiInfo.score)
+                && Objects.equals(mWifiStandard, thatWifiInfo.mWifiStandard)
+                && Objects.equals(mMaxSupportedTxLinkSpeed, thatWifiInfo.mMaxSupportedTxLinkSpeed)
+                && Objects.equals(mMaxSupportedRxLinkSpeed, thatWifiInfo.mMaxSupportedRxLinkSpeed)
+                && Objects.equals(mPasspointUniqueId, thatWifiInfo.mPasspointUniqueId);
+    }
+
+    @Override
+    public int hashCode() {
+        // Potential API behavior change, so don't change behavior on older devices.
+        if (!SdkLevel.isAtLeastS()) return System.identityHashCode(this);
+
+        return Objects.hash(mWifiSsid,
+                mBSSID,
+                mNetworkId,
+                mRssi,
+                mSupplicantState,
+                mLinkSpeed,
+                mTxLinkSpeed,
+                mRxLinkSpeed,
+                mFrequency,
+                mIpAddress,
+                mMacAddress,
+                mMeteredHint,
+                mEphemeral,
+                mTrusted,
+                mRequestingPackageName,
+                mOsuAp,
+                mFqdn,
+                mProviderFriendlyName,
+                txBad,
+                txRetries,
+                txSuccess,
+                rxSuccess,
+                mLostTxPacketsPerSecond,
+                mTxRetriedTxPacketsPerSecond,
+                mSuccessfulTxPacketsPerSecond,
+                mSuccessfulRxPacketsPerSecond,
+                score,
+                mWifiStandard,
+                mMaxSupportedTxLinkSpeed,
+                mMaxSupportedRxLinkSpeed,
+                mPasspointUniqueId);
+    }
 }
diff --git a/wifi/java/android/net/wifi/WifiManager.java b/wifi/java/android/net/wifi/WifiManager.java
index ccf8a80..3ae2520 100644
--- a/wifi/java/android/net/wifi/WifiManager.java
+++ b/wifi/java/android/net/wifi/WifiManager.java
@@ -36,9 +36,11 @@
 import android.content.Context;
 import android.content.pm.ParceledListSlice;
 import android.net.ConnectivityManager;
+import android.net.ConnectivityManager.NetworkCallback;
 import android.net.DhcpInfo;
 import android.net.MacAddress;
 import android.net.Network;
+import android.net.NetworkCapabilities;
 import android.net.NetworkStack;
 import android.net.wifi.hotspot2.IProvisioningCallback;
 import android.net.wifi.hotspot2.OsuProvider;
@@ -2744,15 +2746,46 @@
     /**
      * Return dynamic information about the current Wi-Fi connection, if any is active.
      * <p>
-     * In the connected state, access to the SSID and BSSID requires
-     * the same permissions as {@link #getScanResults}. If such access is not allowed,
-     * {@link WifiInfo#getSSID} will return {@link #UNKNOWN_SSID} and
-     * {@link WifiInfo#getBSSID} will return {@code "02:00:00:00:00:00"}.
-     * {@link WifiInfo#getPasspointFqdn()} will return null.
-     * {@link WifiInfo#getPasspointProviderFriendlyName()} will return null.
      *
      * @return the Wi-Fi information, contained in {@link WifiInfo}.
+     *
+     * @deprecated Starting with {@link Build.VERSION_CODES#S}, WifiInfo retrieval is moved to
+     * {@link ConnectivityManager} API surface. WifiInfo is attached in
+     * {@link NetworkCapabilities#getTransportInfo()} which is available via callback in
+     * {@link NetworkCallback#onCapabilitiesChanged(Network, NetworkCapabilities)} or on-demand from
+     * {@link ConnectivityManager#getNetworkCapabilities(Network)}.
+     *
+     *</p>
+     * Usage example:
+     * <pre>{@code
+     * final NetworkRequest request =
+     *      new NetworkRequest.Builder()
+     *      .addTransportType(NetworkCapabilities.TRANSPORT_WIFI)
+     *      .build();
+     * final ConnectivityManager connectivityManager =
+     *      context.getSystemService(ConnectivityManager.class);
+     * final NetworkCallback networkCallback = new NetworkCallback() {
+     *      ...
+     *      {@literal @}Override
+     *      void onAvailable(Network network) {}
+     *
+     *      {@literal @}Override
+     *      void onCapabilitiesChanged(Network network, NetworkCapabilities networkCapabilities) {
+     *          WifiInfo wifiInfo = (WifiInfo) networkCapabilities.getTransportInfo();
+     *      }
+     *      // etc.
+     * };
+     * connectivityManager.requestNetwork(request, networkCallback); // For request
+     * connectivityManager.registerNetworkCallback(request, networkCallback); // For listen
+     * }</pre>
+     * <p>
+     * <b>Compatibility Note:</b>
+     * <li>Apps can continue using this API, however newer features
+     * such as ability to mask out location sensitive data in WifiInfo will not be supported
+     * via this API. </li>
+     * </p>
      */
+    @Deprecated
     public WifiInfo getConnectionInfo() {
         try {
             return mService.getConnectionInfo(mContext.getOpPackageName(),
diff --git a/wifi/tests/src/android/net/wifi/WifiInfoTest.java b/wifi/tests/src/android/net/wifi/WifiInfoTest.java
index 311bbc4..9787cc0 100644
--- a/wifi/tests/src/android/net/wifi/WifiInfoTest.java
+++ b/wifi/tests/src/android/net/wifi/WifiInfoTest.java
@@ -17,6 +17,7 @@
 package android.net.wifi;
 
 import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotEquals;
 import static org.junit.Assert.assertNotNull;
 import static org.junit.Assert.assertNotSame;
 import static org.junit.Assert.assertTrue;
@@ -25,6 +26,8 @@
 
 import androidx.test.filters.SmallTest;
 
+import com.android.modules.utils.build.SdkLevel;
+
 import org.junit.Test;
 
 import java.nio.charset.StandardCharsets;
@@ -148,4 +151,82 @@
         assertEquals(TEST_RSSI, info2.getRssi());
         assertEquals(TEST_NETWORK_ID2, info2.getNetworkId());
     }
+
+    @Test
+    public void testWifiInfoEquals() throws Exception {
+        WifiInfo.Builder builder = new WifiInfo.Builder()
+                .setSsid(TEST_SSID.getBytes(StandardCharsets.UTF_8))
+                .setBssid(TEST_BSSID)
+                .setRssi(TEST_RSSI)
+                .setNetworkId(TEST_NETWORK_ID);
+
+        WifiInfo info1 = builder.build();
+        WifiInfo info2 = builder.build();
+        if (SdkLevel.isAtLeastS()) {
+            assertEquals(info1, info2);
+        } else {
+            assertNotEquals(info1, info2);
+        }
+
+        info1.setTrusted(false);
+        // Same behavior pre-S & post-S.
+        assertNotEquals(info1, info2);
+
+        info2.setTrusted(false);
+        if (SdkLevel.isAtLeastS()) {
+            assertEquals(info1, info2);
+        } else {
+            assertNotEquals(info1, info2);
+        }
+
+        info1.setSSID(WifiSsid.createFromHex(null));
+        // Same behavior pre-S & post-S.
+        assertNotEquals(info1, info2);
+
+        info2.setSSID(WifiSsid.createFromHex(null));
+        if (SdkLevel.isAtLeastS()) {
+            assertEquals(info1, info2);
+        } else {
+            assertNotEquals(info1, info2);
+        }
+    }
+
+    @Test
+    public void testWifiInfoHashcode() throws Exception {
+        WifiInfo.Builder builder = new WifiInfo.Builder()
+                .setSsid(TEST_SSID.getBytes(StandardCharsets.UTF_8))
+                .setBssid(TEST_BSSID)
+                .setRssi(TEST_RSSI)
+                .setNetworkId(TEST_NETWORK_ID);
+
+        WifiInfo info1 = builder.build();
+        WifiInfo info2 = builder.build();
+        if (SdkLevel.isAtLeastS()) {
+            assertEquals(info1.hashCode(), info2.hashCode());
+        } else {
+            assertNotEquals(info1.hashCode(), info2.hashCode());
+        }
+
+        info1.setTrusted(false);
+        // Same behavior pre-S & post-S.
+        assertNotEquals(info1.hashCode(), info2.hashCode());
+
+        info2.setTrusted(false);
+        if (SdkLevel.isAtLeastS()) {
+            assertEquals(info1.hashCode(), info2.hashCode());
+        } else {
+            assertNotEquals(info1.hashCode(), info2.hashCode());
+        }
+
+        info1.setSSID(WifiSsid.createFromHex(null));
+        // Same behavior pre-S & post-S.
+        assertNotEquals(info1.hashCode(), info2.hashCode());
+
+        info2.setSSID(WifiSsid.createFromHex(null));
+        if (SdkLevel.isAtLeastS()) {
+            assertEquals(info1.hashCode(), info2.hashCode());
+        } else {
+            assertNotEquals(info1.hashCode(), info2.hashCode());
+        }
+    }
 }