Merge "[MS31] Fix several hidden API usages"
diff --git a/core/api/system-current.txt b/core/api/system-current.txt
index 09c58ae..6321aaa 100644
--- a/core/api/system-current.txt
+++ b/core/api/system-current.txt
@@ -9453,7 +9453,9 @@
     field public static final int MATCH_ALL_APN_SET_ID = -1; // 0xffffffff
     field public static final String MAX_CONNECTIONS = "max_conns";
     field public static final String MODEM_PERSIST = "modem_cognitive";
-    field public static final String MTU = "mtu";
+    field @Deprecated public static final String MTU = "mtu";
+    field public static final String MTU_V4 = "mtu_v4";
+    field public static final String MTU_V6 = "mtu_v6";
     field public static final int NO_APN_SET_ID = 0; // 0x0
     field public static final String TIME_LIMIT_FOR_MAX_CONNECTIONS = "max_conns_time";
     field public static final int UNEDITED = 0; // 0x0
diff --git a/core/java/android/bluetooth/BluetoothUuid.java b/core/java/android/bluetooth/BluetoothUuid.java
index 858819e..2a8ff51 100644
--- a/core/java/android/bluetooth/BluetoothUuid.java
+++ b/core/java/android/bluetooth/BluetoothUuid.java
@@ -189,7 +189,7 @@
     @NonNull
     @SystemApi
     public static final ParcelUuid CAP =
-        ParcelUuid.fromString("EEEEEEEE-EEEE-EEEE-EEEE-EEEEEEEEEEEE");
+            ParcelUuid.fromString("00001853-0000-1000-8000-00805F9B34FB");
     /** @hide */
     @NonNull
     @SystemApi
diff --git a/core/java/android/net/Ikev2VpnProfile.java b/core/java/android/net/Ikev2VpnProfile.java
index b18e9be..fab692c 100644
--- a/core/java/android/net/Ikev2VpnProfile.java
+++ b/core/java/android/net/Ikev2VpnProfile.java
@@ -142,8 +142,9 @@
             boolean isBypassable,
             boolean isMetered,
             int maxMtu,
-            boolean restrictToTestNetworks) {
-        super(type);
+            boolean restrictToTestNetworks,
+            boolean excludeLocalRoutes) {
+        super(type, excludeLocalRoutes);
 
         checkNotNull(serverAddr, MISSING_PARAM_MSG_TMPL, "Server address");
         checkNotNull(userIdentity, MISSING_PARAM_MSG_TMPL, "User Identity");
@@ -403,7 +404,8 @@
                 && mIsBypassable == other.mIsBypassable
                 && mIsMetered == other.mIsMetered
                 && mMaxMtu == other.mMaxMtu
-                && mIsRestrictedToTestNetworks == other.mIsRestrictedToTestNetworks;
+                && mIsRestrictedToTestNetworks == other.mIsRestrictedToTestNetworks
+                && mExcludeLocalRoutes == other.mExcludeLocalRoutes;
     }
 
     /**
@@ -417,7 +419,7 @@
     @NonNull
     public VpnProfile toVpnProfile() throws IOException, GeneralSecurityException {
         final VpnProfile profile = new VpnProfile("" /* Key; value unused by IKEv2VpnProfile(s) */,
-                mIsRestrictedToTestNetworks);
+                mIsRestrictedToTestNetworks, mExcludeLocalRoutes);
         profile.type = mType;
         profile.server = mServerAddr;
         profile.ipsecIdentifier = mUserIdentity;
@@ -518,6 +520,8 @@
                 throw new IllegalArgumentException("Invalid auth method set");
         }
 
+        builder.setExcludeLocalRoutes(profile.excludeLocalRoutes);
+
         return builder.build();
     }
 
@@ -657,6 +661,7 @@
         private boolean mIsMetered = true;
         private int mMaxMtu = PlatformVpnProfile.MAX_MTU_DEFAULT;
         private boolean mIsRestrictedToTestNetworks = false;
+        private boolean mExcludeLocalRoutes = false;
 
         /**
          * Creates a new builder with the basic parameters of an IKEv2/IPsec VPN.
@@ -902,6 +907,18 @@
         }
 
         /**
+         *  Sets whether the local traffic is exempted from the VPN.
+         *
+         *  @hide TODO(184750836): unhide once the implementation is completed
+         */
+        @NonNull
+        @RequiresFeature(PackageManager.FEATURE_IPSEC_TUNNELS)
+        public Builder setExcludeLocalRoutes(boolean excludeLocalRoutes) {
+            mExcludeLocalRoutes = excludeLocalRoutes;
+            return this;
+        }
+
+        /**
          * Validates, builds and provisions the VpnProfile.
          *
          * @throws IllegalArgumentException if any of the required keys or values were invalid
@@ -924,7 +941,8 @@
                     mIsBypassable,
                     mIsMetered,
                     mMaxMtu,
-                    mIsRestrictedToTestNetworks);
+                    mIsRestrictedToTestNetworks,
+                    mExcludeLocalRoutes);
         }
     }
 }
diff --git a/core/java/android/net/NetworkPolicy.java b/core/java/android/net/NetworkPolicy.java
index d7e1857..8b3d49e 100644
--- a/core/java/android/net/NetworkPolicy.java
+++ b/core/java/android/net/NetworkPolicy.java
@@ -369,11 +369,13 @@
 
         try {
             final NetworkTemplate.Builder builder = new NetworkTemplate.Builder(matchRule)
-                    .setWifiNetworkKey(wifiNetworkKey)
                     .setMeteredness(metered);
             if (subscriberId != null) {
                 builder.setSubscriberIds(Set.of(subscriberId));
             }
+            if (wifiNetworkKey != null) {
+                builder.setWifiNetworkKeys(Set.of(wifiNetworkKey));
+            }
             return builder.build();
         } catch (IllegalArgumentException e) {
             throw new BackupUtils.BadVersionException(
@@ -393,7 +395,7 @@
             case MATCH_MOBILE:
                 return !template.getSubscriberIds().isEmpty();
             case MATCH_WIFI:
-                if (Objects.equals(template.getWifiNetworkKey(), null)
+                if (template.getWifiNetworkKeys().isEmpty()
                         && template.getSubscriberIds().isEmpty()) {
                     return false;
                 }
diff --git a/core/java/android/net/PlatformVpnProfile.java b/core/java/android/net/PlatformVpnProfile.java
index 445ec91..777a90c 100644
--- a/core/java/android/net/PlatformVpnProfile.java
+++ b/core/java/android/net/PlatformVpnProfile.java
@@ -66,15 +66,30 @@
     @PlatformVpnType protected final int mType;
 
     /** @hide */
-    PlatformVpnProfile(@PlatformVpnType int type) {
+    protected final boolean mExcludeLocalRoutes;
+
+    /** @hide */
+    PlatformVpnProfile(@PlatformVpnType int type, boolean excludeLocalRoutes) {
         mType = type;
+        mExcludeLocalRoutes = excludeLocalRoutes;
     }
+
     /** Returns the profile integer type. */
     @PlatformVpnType
     public final int getType() {
         return mType;
     }
 
+
+    /**
+     * Returns if the local traffic is exempted from the VPN.
+     *
+     * @hide TODO(184750836): unhide once the implementation is completed
+     */
+    public final boolean getExcludeLocalRoutes() {
+        return mExcludeLocalRoutes;
+    }
+
     /** Returns a type string describing the VPN profile type */
     @NonNull
     public final String getTypeString() {
diff --git a/core/java/android/provider/Telephony.java b/core/java/android/provider/Telephony.java
index 0adc00e..1b26465 100644
--- a/core/java/android/provider/Telephony.java
+++ b/core/java/android/provider/Telephony.java
@@ -3758,6 +3758,25 @@
         public static final String NETWORK_TYPE_BITMASK = "network_type_bitmask";
 
         /**
+         * Lingering radio technology (network type) bitmask.
+         * To check what values can be contained, refer to the NETWORK_TYPE_ constants in
+         * {@link android.telephony.TelephonyManager}.
+         * Bitmask for a radio tech R is (1 << (R - 1))
+         * <P>Type: INTEGER (long)</P>
+         * @hide
+         */
+        public static final String LINGERING_NETWORK_TYPE_BITMASK =
+                "lingering_network_type_bitmask";
+
+        /**
+         * Sets whether the PDU session brought up by this APN should always be on.
+         * See 3GPP TS 23.501 section 5.6.13
+         * <P>Type: INTEGER</P>
+         * @hide
+         */
+        public static final String ALWAYS_ON = "always_on";
+
+        /**
          * MVNO type:
          * {@code SPN (Service Provider Name), IMSI, GID (Group Identifier Level 1)}.
          * <P>Type: TEXT</P>
@@ -3835,11 +3854,31 @@
          * connected, in bytes.
          * <p>Type: INTEGER </p>
          * @hide
+         * @deprecated use {@link #MTU_V4} or {@link #MTU_V6} instead
          */
         @SystemApi
+        @Deprecated
         public static final String MTU = "mtu";
 
         /**
+         * The MTU (maximum transmit unit) size of the mobile interface for IPv4 to which the APN is
+         * connected, in bytes.
+         * <p>Type: INTEGER </p>
+         * @hide
+         */
+        @SystemApi
+        public static final String MTU_V4 = "mtu_v4";
+
+        /**
+         * The MTU (maximum transmit unit) size of the mobile interface for IPv6 to which the APN is
+         * connected, in bytes.
+         * <p>Type: INTEGER </p>
+         * @hide
+         */
+        @SystemApi
+        public static final String MTU_V6 = "mtu_v6";
+
+        /**
          * APN edit status. APN could be added/edited/deleted by a user or carrier.
          * see all possible returned APN edit status.
          * <ul>
diff --git a/core/java/android/service/autofill/AutofillService.java b/core/java/android/service/autofill/AutofillService.java
index 13274c6..29c7796 100644
--- a/core/java/android/service/autofill/AutofillService.java
+++ b/core/java/android/service/autofill/AutofillService.java
@@ -465,7 +465,7 @@
  * <p>Prior to Android {@link android.os.Build.VERSION_CODES#P}, the metrics covered just the
  * scenarios where the service knew how to autofill an activity, but Android
  * {@link android.os.Build.VERSION_CODES#P} introduced a new mechanism called field classification,
- * which allows the service to dinamically classify the meaning of fields based on the existing user
+ * which allows the service to dynamically classify the meaning of fields based on the existing user
  * data known by the service.
  *
  * <p>Typically, field classification can be used to detect fields that can be autofilled with
diff --git a/core/java/com/android/internal/net/VpnProfile.java b/core/java/com/android/internal/net/VpnProfile.java
index 5f84b5a..d8dc143 100644
--- a/core/java/com/android/internal/net/VpnProfile.java
+++ b/core/java/com/android/internal/net/VpnProfile.java
@@ -143,17 +143,24 @@
     public boolean areAuthParamsInline = false;                  // 23
     public final boolean isRestrictedToTestNetworks;             // 24
 
+    public final boolean excludeLocalRoutes;                     // 25
+
     // Helper fields.
     @UnsupportedAppUsage
     public transient boolean saveLogin = false;
 
     public VpnProfile(String key) {
-        this(key, false);
+        this(key, false, false);
     }
 
     public VpnProfile(String key, boolean isRestrictedToTestNetworks) {
+        this(key, isRestrictedToTestNetworks, false);
+    }
+
+    public VpnProfile(String key, boolean isRestrictedToTestNetworks, boolean excludeLocalRoutes) {
         this.key = key;
         this.isRestrictedToTestNetworks = isRestrictedToTestNetworks;
+        this.excludeLocalRoutes = excludeLocalRoutes;
     }
 
     @UnsupportedAppUsage
@@ -183,6 +190,7 @@
         maxMtu = in.readInt();
         areAuthParamsInline = in.readBoolean();
         isRestrictedToTestNetworks = in.readBoolean();
+        excludeLocalRoutes = in.readBoolean();
     }
 
     /**
@@ -230,6 +238,7 @@
         out.writeInt(maxMtu);
         out.writeBoolean(areAuthParamsInline);
         out.writeBoolean(isRestrictedToTestNetworks);
+        out.writeBoolean(excludeLocalRoutes);
     }
 
     /**
@@ -249,8 +258,9 @@
             // 14-19: Standard profile, with option for serverCert, proxy
             // 24: Standard profile with serverCert, proxy and platform-VPN parameters
             // 25: Standard profile with platform-VPN parameters and isRestrictedToTestNetworks
+            // 26: Standard profile with platform-VPN parameters and excludeLocalRoutes
             if ((values.length < 14 || values.length > 19)
-                    && values.length != 24 && values.length != 25) {
+                    && values.length != 24 && values.length != 25 && values.length != 26) {
                 return null;
             }
 
@@ -261,7 +271,15 @@
                 isRestrictedToTestNetworks = false;
             }
 
-            VpnProfile profile = new VpnProfile(key, isRestrictedToTestNetworks);
+            final boolean excludeLocalRoutes;
+            if (values.length >= 26) {
+                excludeLocalRoutes = Boolean.parseBoolean(values[25]);
+            } else {
+                excludeLocalRoutes = false;
+            }
+
+            VpnProfile profile = new VpnProfile(key, isRestrictedToTestNetworks,
+                    excludeLocalRoutes);
             profile.name = values[0];
             profile.type = Integer.parseInt(values[1]);
             if (profile.type < 0 || profile.type > TYPE_MAX) {
@@ -371,6 +389,8 @@
         builder.append(VALUE_DELIMITER).append(areAuthParamsInline);
         builder.append(VALUE_DELIMITER).append(isRestrictedToTestNetworks);
 
+        builder.append(VALUE_DELIMITER).append(excludeLocalRoutes);
+
         return builder.toString().getBytes(StandardCharsets.UTF_8);
     }
 
@@ -451,7 +471,7 @@
             key, type, server, username, password, dnsServers, searchDomains, routes, mppe,
             l2tpSecret, ipsecIdentifier, ipsecSecret, ipsecUserCert, ipsecCaCert, ipsecServerCert,
             proxy, mAllowedAlgorithms, isBypassable, isMetered, maxMtu, areAuthParamsInline,
-            isRestrictedToTestNetworks);
+            isRestrictedToTestNetworks, excludeLocalRoutes);
     }
 
     /** Checks VPN profiles for interior equality. */
@@ -484,7 +504,8 @@
                 && isMetered == other.isMetered
                 && maxMtu == other.maxMtu
                 && areAuthParamsInline == other.areAuthParamsInline
-                && isRestrictedToTestNetworks == other.isRestrictedToTestNetworks;
+                && isRestrictedToTestNetworks == other.isRestrictedToTestNetworks
+                && excludeLocalRoutes == other.excludeLocalRoutes;
     }
 
     @NonNull
diff --git a/core/jni/AndroidRuntime.cpp b/core/jni/AndroidRuntime.cpp
index a131111..0f98b74 100644
--- a/core/jni/AndroidRuntime.cpp
+++ b/core/jni/AndroidRuntime.cpp
@@ -228,8 +228,7 @@
 // TODO: Rename the server-level flag or remove.
 static const char* ENABLE_JITZYGOTE_IMAGE = "enable_apex_image";
 // Flag to pass to the runtime when using the JIT Zygote image.
-static const char* kJitZygoteImageOption =
-        "-Ximage:boot.art:/nonx/boot-framework.art!/system/etc/boot-image.prof";
+static const char* kJitZygoteImageOption = "-Xforcejitzygote";
 
 // Feature flag name for disabling lock profiling.
 static const char* DISABLE_LOCK_PROFILING = "disable_lock_profiling";
@@ -983,9 +982,9 @@
                         "--instruction-set-features=", "-Xcompiler-option");
 
     /*
-     * When running with debug.generate-debug-info, add --generate-debug-info to
-     * the compiler options so that both JITted code and the boot image extension,
-     * if it is compiled on device, will include native debugging information.
+     * When running with debug.generate-debug-info, add --generate-debug-info to the compiler
+     * options so that both JITted code and the boot image, if it is compiled on device, will
+     * include native debugging information.
      */
     property_get("debug.generate-debug-info", propBuf, "");
     bool generate_debug_info = (strcmp(propBuf, "true") == 0);
@@ -1008,7 +1007,7 @@
     property_get("dalvik.vm.extra-opts", extraOptsBuf, "");
     parseExtraOpts(extraOptsBuf, NULL);
 
-    // Extra options for boot image extension generation.
+    // Extra options for boot image generation.
     if (skip_compilation) {
         addOption("-Xnoimage-dex2oat");
     } else {
@@ -1031,8 +1030,8 @@
         parseCompilerOption("dalvik.vm.image-dex2oat-cpu-set", dex2oatCpuSetImageBuf, "--cpu-set=",
                             "-Ximage-compiler-option");
 
-        // The runtime may compile a boot image extension, when necessary, not using installd.
-        // Thus, we need to pass the instruction-set-features/variant as an image-compiler-option.
+        // The runtime may compile a boot image, when necessary, not using installd. Thus, we need
+        // to pass the instruction-set-features/variant as an image-compiler-option.
         // Note: it is OK to reuse the buffer, as the values are exactly the same between
         //       * compiler-option, used for runtime compilation (DexClassLoader)
         //       * image-compiler-option, used for boot-image compilation on device
diff --git a/core/tests/coretests/src/android/net/NetworkPolicyTest.kt b/core/tests/coretests/src/android/net/NetworkPolicyTest.kt
index 121caef..3c8f90c 100644
--- a/core/tests/coretests/src/android/net/NetworkPolicyTest.kt
+++ b/core/tests/coretests/src/android/net/NetworkPolicyTest.kt
@@ -32,14 +32,14 @@
 import kotlin.test.assertTrue
 
 private const val TEST_IMSI1 = "TESTIMSI1"
-private const val TEST_SSID1 = "TESTISSID1"
+private const val TEST_WIFI_NETWORK_KEY1 = "TESTKEY1"
 
 @RunWith(AndroidJUnit4::class)
 class NetworkPolicyTest {
     @Test
     fun testTemplateBackupRestore() {
         assertPolicyBackupRestore(createTestPolicyForTemplate(
-                NetworkTemplate.buildTemplateWifi(TEST_SSID1)))
+                NetworkTemplate.buildTemplateWifi(TEST_WIFI_NETWORK_KEY1)))
         assertPolicyBackupRestore(createTestPolicyForTemplate(
                 NetworkTemplate.buildTemplateMobileAll(TEST_IMSI1)))
         assertPolicyBackupRestore(createTestPolicyForTemplate(
@@ -79,6 +79,6 @@
 
         // Verify wifi template can be persistable if the Wifi Network Key is supplied.
         assertTrue(NetworkPolicy.isTemplatePersistable(NetworkTemplate.Builder(MATCH_WIFI)
-                .setWifiNetworkKey(TEST_SSID1).build()))
+                .setWifiNetworkKeys(setOf(TEST_WIFI_NETWORK_KEY1)).build()))
     }
-}
\ No newline at end of file
+}
diff --git a/media/java/android/media/JetPlayer.java b/media/java/android/media/JetPlayer.java
index 875c6f5..7749564 100644
--- a/media/java/android/media/JetPlayer.java
+++ b/media/java/android/media/JetPlayer.java
@@ -31,35 +31,33 @@
 
 /**
  * JetPlayer provides access to JET content playback and control.
- * 
- * <p>Please refer to the JET Creator User Manual for a presentation of the JET interactive
- * music concept and how to use the JetCreator tool to create content to be player by JetPlayer.
- * 
+ *
+ * <p>Please refer to the
+ * <a href="https://developer.android.com/guide/topics/media/jet/jetcreator_manual">JET Creator User
+ * Manual</a> for a presentation of the JET interactive music concept and how to use the JetCreator
+ * tool to create content to be player by JetPlayer.
+ *
  * <p>Use of the JetPlayer class is based around the playback of a number of JET segments
  * sequentially added to a playback FIFO queue. The rendering of the MIDI content stored in each
  * segment can be dynamically affected by two mechanisms:
  * <ul>
- * <li>tracks in a segment can be muted or unmuted at any moment, individually or through
- *    a mask (to change the mute state of multiple tracks at once)</li>
- * <li>parts of tracks in a segment can be played at predefined points in the segment, in order
- *    to maintain synchronization with the other tracks in the segment. This is achieved through
- *    the notion of "clips", which can be triggered at any time, but that will play only at the
- *    right time, as authored in the corresponding JET file.</li>
+ *   <li>Tracks in a segment can be muted or unmuted at any moment, individually or through a mask
+ *       (to change the mute state of multiple tracks at once).
+ *   <li>Parts of tracks in a segment can be played at predefined points in the segment, in order to
+ *       maintain synchronization with the other tracks in the segment. This is achieved through the
+ *       notion of "clips", which can be triggered at any time, but that will play only at the right
+ *       time, as authored in the corresponding JET file.
  * </ul>
- * As a result of the rendering and playback of the JET segments, the user of the JetPlayer instance
- * can receive notifications from the JET engine relative to:
- * <ul>
- * <li>the playback state,</li>
- * <li>the number of segments left to play in the queue,</li>
- * <li>application controller events (CC80-83) to mark points in the MIDI segments.</li>
- * </ul>
- * Use {@link #getJetPlayer()} to construct a JetPlayer instance. JetPlayer is a singleton class.
- * </p>
  *
- * <div class="special reference">
- * <h3>Developer Guides</h3>
- * <p>For more information about how to use JetPlayer, read the
- * <a href="{@docRoot}guide/topics/media/jetplayer.html">JetPlayer</a> developer guide.</p></div>
+ * <p>As a result of the rendering and playback of the JET segments, the user of the JetPlayer
+ * instance can receive notifications from the JET engine relative to:
+ * <ul>
+ *   <li>Playback state
+ *   <li>Number of segments left to play in the queue
+ *   <li>Application controller events (CC80-83) to mark points in the MIDI segments
+ * </ul>
+ *
+ * <p>Use {@link #getJetPlayer()} to construct a JetPlayer instance. JetPlayer is a singleton class.
  */
 public class JetPlayer
 {    
@@ -140,7 +138,7 @@
     //------------------------
     /**
      * Factory method for the JetPlayer class.
-     * @return the singleton JetPlayer instance
+     * @return the singleton JetPlayer instance.
      */
     public static JetPlayer getJetPlayer() {
         if (singletonRef == null) {
@@ -203,7 +201,8 @@
     // Getters
     //------------------------
     /**
-     * Returns the maximum number of simultaneous MIDI tracks supported by JetPlayer
+     * Gets the maximum number of simultaneous MIDI tracks supported by JetPlayer.
+     * @return the maximum number of simultaneous MIDI tracks supported by JetPlayer.
      */
     public static int getMaxTracks() {
         return JetPlayer.MAXTRACKS;
@@ -459,10 +458,9 @@
     //------------------------
     /**
      * Sets the listener JetPlayer notifies when a JET event is generated by the rendering and
-     * playback engine.
-     * Notifications will be received in the same thread as the one in which the JetPlayer
-     * instance was created.
-     * @param listener
+     * playback engine. Notifications are received in the same thread as the one in which the
+     * JetPlayer instance was created.
+     * @param listener the listener that will be notified when a JET event is generated.
      */
     public void setEventListener(OnJetEventListener listener) {
         setEventListener(listener, null);
@@ -470,10 +468,9 @@
     
     /**
      * Sets the listener JetPlayer notifies when a JET event is generated by the rendering and
-     * playback engine.
-     * Use this method to receive JET events in the Handler associated with another
-     * thread than the one in which you created the JetPlayer instance.
-     * @param listener
+     * playback engine. Use this method to receive JET events in the Handler associated with
+     * another thread than the one in which you created the JetPlayer instance.
+     * @param listener the listener that will be notified when a JET event is generated.
      * @param handler the Handler that will receive the event notification messages.
      */
     public void setEventListener(OnJetEventListener listener, Handler handler) {
diff --git a/packages/ConnectivityT/framework-t/src/android/app/usage/NetworkStatsManager.java b/packages/ConnectivityT/framework-t/src/android/app/usage/NetworkStatsManager.java
index 82c72ab..a316b8a 100644
--- a/packages/ConnectivityT/framework-t/src/android/app/usage/NetworkStatsManager.java
+++ b/packages/ConnectivityT/framework-t/src/android/app/usage/NetworkStatsManager.java
@@ -138,6 +138,7 @@
         mContext = context;
         mService = service;
         setPollOnOpen(true);
+        setAugmentWithSubscriptionPlan(true);
     }
 
     /** @hide */
@@ -169,16 +170,44 @@
         }
     }
 
-    /** @hide */
-    public Bucket querySummaryForDevice(NetworkTemplate template,
-            long startTime, long endTime) throws SecurityException, RemoteException {
-        Bucket bucket = null;
-        NetworkStats stats = new NetworkStats(mContext, template, mFlags, startTime, endTime,
-                mService);
-        bucket = stats.getDeviceSummaryForNetwork();
-
-        stats.close();
-        return bucket;
+    /**
+     * Query network usage statistics summaries.
+     *
+     * Result is summarised data usage for the whole
+     * device. Result is a single Bucket aggregated over time, state, uid, tag, metered, and
+     * roaming. This means the bucket's start and end timestamp will be the same as the
+     * 'startTime' and 'endTime' arguments. State is going to be
+     * {@link NetworkStats.Bucket#STATE_ALL}, uid {@link NetworkStats.Bucket#UID_ALL},
+     * tag {@link NetworkStats.Bucket#TAG_NONE},
+     * default network {@link NetworkStats.Bucket#DEFAULT_NETWORK_ALL},
+     * metered {@link NetworkStats.Bucket#METERED_ALL},
+     * and roaming {@link NetworkStats.Bucket#ROAMING_ALL}.
+     * This may take a long time, and apps should avoid calling this on their main thread.
+     *
+     * @param template Template used to match networks. See {@link NetworkTemplate}.
+     * @param startTime Start of period, in milliseconds since the Unix epoch, see
+     *            {@link java.lang.System#currentTimeMillis}.
+     * @param endTime End of period, in milliseconds since the Unix epoch, see
+     *            {@link java.lang.System#currentTimeMillis}.
+     * @return Bucket Summarised data usage.
+     *
+     * @hide
+     */
+    @NonNull
+    @WorkerThread
+    // @SystemApi(client = MODULE_LIBRARIES)
+    public Bucket querySummaryForDevice(@NonNull NetworkTemplate template,
+            long startTime, long endTime) {
+        try {
+            NetworkStats stats =
+                    new NetworkStats(mContext, template, mFlags, startTime, endTime, mService);
+            Bucket bucket = stats.getDeviceSummaryForNetwork();
+            stats.close();
+            return bucket;
+        } catch (RemoteException e) {
+            e.rethrowFromSystemServer();
+        }
+        return null; // To make the compiler happy.
     }
 
     /**
@@ -322,14 +351,37 @@
         return querySummary(template, startTime, endTime);
     }
 
-    /** @hide */
-    public NetworkStats querySummary(NetworkTemplate template, long startTime,
-            long endTime) throws SecurityException, RemoteException {
-        NetworkStats result;
-        result = new NetworkStats(mContext, template, mFlags, startTime, endTime, mService);
-        result.startSummaryEnumeration();
-
-        return result;
+    /**
+     * Query network usage statistics summaries.
+     *
+     * The results will only include traffic made by UIDs belonging to the calling user profile.
+     * The results are aggregated over time, so that all buckets will have the same start and
+     * end timestamps as the passed arguments. Not aggregated over state, uid, default network,
+     * metered, or roaming.
+     * This may take a long time, and apps should avoid calling this on their main thread.
+     *
+     * @param template Template used to match networks. See {@link NetworkTemplate}.
+     * @param startTime Start of period, in milliseconds since the Unix epoch, see
+     *            {@link java.lang.System#currentTimeMillis}.
+     * @param endTime End of period, in milliseconds since the Unix epoch, see
+     *            {@link java.lang.System#currentTimeMillis}.
+     * @return Statistics which is described above.
+     * @hide
+     */
+    @Nullable
+    // @SystemApi(client = MODULE_LIBRARIES)
+    @WorkerThread
+    public NetworkStats querySummary(@NonNull NetworkTemplate template, long startTime,
+            long endTime) throws SecurityException {
+        try {
+            NetworkStats result =
+                    new NetworkStats(mContext, template, mFlags, startTime, endTime, mService);
+            result.startSummaryEnumeration();
+            return result;
+        } catch (RemoteException e) {
+            e.rethrowFromSystemServer();
+        }
+        return null; // To make the compiler happy.
     }
 
     /**
diff --git a/packages/ConnectivityT/framework-t/src/android/net/NetworkIdentity.java b/packages/ConnectivityT/framework-t/src/android/net/NetworkIdentity.java
index eb8f43e..8f1115e 100644
--- a/packages/ConnectivityT/framework-t/src/android/net/NetworkIdentity.java
+++ b/packages/ConnectivityT/framework-t/src/android/net/NetworkIdentity.java
@@ -21,7 +21,6 @@
 import android.annotation.Nullable;
 import android.content.Context;
 import android.net.wifi.WifiInfo;
-import android.net.wifi.WifiManager;
 import android.service.NetworkIdentityProto;
 import android.telephony.Annotation.NetworkType;
 import android.util.proto.ProtoOutputStream;
@@ -228,11 +227,11 @@
         final int oemManaged = getOemBitfield(snapshot.getNetworkCapabilities());
 
         if (legacyType == TYPE_WIFI) {
-            networkId = snapshot.getNetworkCapabilities().getSsid();
-            if (networkId == null) {
-                final WifiManager wifi = context.getSystemService(WifiManager.class);
-                final WifiInfo info = wifi.getConnectionInfo();
-                networkId = info != null ? info.getSSID() : null;
+            final TransportInfo transportInfo = snapshot.getNetworkCapabilities()
+                    .getTransportInfo();
+            if (transportInfo instanceof WifiInfo) {
+                final WifiInfo info = (WifiInfo) transportInfo;
+                networkId = info != null ? info.getCurrentNetworkKey() : null;
             }
         }
 
diff --git a/packages/ConnectivityT/framework-t/src/android/net/NetworkTemplate.java b/packages/ConnectivityT/framework-t/src/android/net/NetworkTemplate.java
index 9fa777d..659ad06 100644
--- a/packages/ConnectivityT/framework-t/src/android/net/NetworkTemplate.java
+++ b/packages/ConnectivityT/framework-t/src/android/net/NetworkTemplate.java
@@ -35,7 +35,6 @@
 import static android.net.NetworkStats.ROAMING_ALL;
 import static android.net.NetworkStats.ROAMING_NO;
 import static android.net.NetworkStats.ROAMING_YES;
-import static android.net.wifi.WifiInfo.sanitizeSsid;
 
 import android.annotation.IntDef;
 import android.annotation.NonNull;
@@ -57,6 +56,7 @@
 import java.lang.annotation.RetentionPolicy;
 import java.util.Arrays;
 import java.util.Collection;
+import java.util.Comparator;
 import java.util.HashSet;
 import java.util.List;
 import java.util.Objects;
@@ -213,11 +213,14 @@
     public static NetworkTemplate buildTemplateMobileWithRatType(@Nullable String subscriberId,
             @NetworkType int ratType, int metered) {
         if (TextUtils.isEmpty(subscriberId)) {
-            return new NetworkTemplate(MATCH_MOBILE_WILDCARD, null, null, null,
-                    metered, ROAMING_ALL, DEFAULT_NETWORK_ALL, ratType, OEM_MANAGED_ALL,
+            return new NetworkTemplate(MATCH_MOBILE_WILDCARD, null /* subscriberId */,
+                    null /* matchSubscriberIds */,
+                    new String[0] /* matchWifiNetworkKeys */, metered, ROAMING_ALL,
+                    DEFAULT_NETWORK_ALL, ratType, OEM_MANAGED_ALL,
                     NetworkStatsUtils.SUBSCRIBER_ID_MATCH_RULE_EXACT);
         }
-        return new NetworkTemplate(MATCH_MOBILE, subscriberId, new String[]{subscriberId}, null,
+        return new NetworkTemplate(MATCH_MOBILE, subscriberId, new String[] { subscriberId },
+                new String[0] /* matchWifiNetworkKeys */,
                 metered, ROAMING_ALL, DEFAULT_NETWORK_ALL, ratType, OEM_MANAGED_ALL,
                 NetworkStatsUtils.SUBSCRIBER_ID_MATCH_RULE_EXACT);
     }
@@ -235,7 +238,7 @@
 
     /**
      * Template to match all metered {@link ConnectivityManager#TYPE_WIFI} networks,
-     * regardless of SSID.
+     * regardless of key of the wifi network.
      *
      * @hide
      */
@@ -255,33 +258,40 @@
 
     /**
      * Template to match {@link ConnectivityManager#TYPE_WIFI} networks with the
-     * given SSID.
+     * given key of the wifi network.
      *
+     * @param wifiNetworkKey key of the wifi network. see {@link WifiInfo#getCurrentNetworkKey()}
+     *                  to know details about the key.
      * @hide
      */
-    public static NetworkTemplate buildTemplateWifi(@NonNull String networkId) {
-        Objects.requireNonNull(networkId);
+    public static NetworkTemplate buildTemplateWifi(@NonNull String wifiNetworkKey) {
+        Objects.requireNonNull(wifiNetworkKey);
         return new NetworkTemplate(MATCH_WIFI, null /* subscriberId */,
                 new String[] { null } /* matchSubscriberIds */,
-                networkId, METERED_ALL, ROAMING_ALL,
+                new String[] { wifiNetworkKey }, METERED_ALL, ROAMING_ALL,
                 DEFAULT_NETWORK_ALL, NETWORK_TYPE_ALL, OEM_MANAGED_ALL,
                 NetworkStatsUtils.SUBSCRIBER_ID_MATCH_RULE_ALL);
     }
 
     /**
-     * Template to match all {@link ConnectivityManager#TYPE_WIFI} networks with the given SSID,
-     * and IMSI.
+     * Template to match all {@link ConnectivityManager#TYPE_WIFI} networks with the given
+     * key of the wifi network and IMSI.
      *
-     * Call with {@link #WIFI_NETWORK_KEY_ALL} for {@code networkId} to get result regardless
-     * of SSID.
+     * Call with {@link #WIFI_NETWORK_KEY_ALL} for {@code wifiNetworkKey} to get result regardless
+     * of key of the wifi network.
+     *
+     * @param wifiNetworkKey key of the wifi network. see {@link WifiInfo#getCurrentNetworkKey()}
+     *                  to know details about the key.
+     * @param subscriberId the IMSI associated to this wifi network.
      *
      * @hide
      */
-    public static NetworkTemplate buildTemplateWifi(@Nullable String networkId,
+    public static NetworkTemplate buildTemplateWifi(@Nullable String wifiNetworkKey,
             @Nullable String subscriberId) {
         return new NetworkTemplate(MATCH_WIFI, subscriberId, new String[] { subscriberId },
-                networkId, METERED_ALL, ROAMING_ALL,
-                DEFAULT_NETWORK_ALL, NETWORK_TYPE_ALL, OEM_MANAGED_ALL,
+                wifiNetworkKey != null
+                        ? new String[] { wifiNetworkKey } : new String[0],
+                METERED_ALL, ROAMING_ALL, DEFAULT_NETWORK_ALL, NETWORK_TYPE_ALL, OEM_MANAGED_ALL,
                 NetworkStatsUtils.SUBSCRIBER_ID_MATCH_RULE_EXACT);
     }
 
@@ -324,7 +334,9 @@
     public static NetworkTemplate buildTemplateCarrierMetered(@NonNull String subscriberId) {
         Objects.requireNonNull(subscriberId);
         return new NetworkTemplate(MATCH_CARRIER, subscriberId,
-                new String[] { subscriberId }, null /* networkId */, METERED_YES, ROAMING_ALL,
+                new String[] { subscriberId },
+                new String[0] /* matchWifiNetworkKeys */,
+                METERED_YES, ROAMING_ALL,
                 DEFAULT_NETWORK_ALL, NETWORK_TYPE_ALL, OEM_MANAGED_ALL,
                 NetworkStatsUtils.SUBSCRIBER_ID_MATCH_RULE_EXACT);
     }
@@ -342,8 +354,8 @@
      */
     private final String[] mMatchSubscriberIds;
 
-    // TODO: Change variable name to match the Api surface.
-    private final String mNetworkId;
+    @NonNull
+    private final String[] mMatchWifiNetworkKeys;
 
     // Matches for the NetworkStats constants METERED_*, ROAMING_* and DEFAULT_NETWORK_*.
     private final int mMetered;
@@ -377,18 +389,19 @@
     /** @hide */
     // TODO: Deprecate this constructor, mark it @UnsupportedAppUsage(maxTargetSdk = S)
     @UnsupportedAppUsage
-    public NetworkTemplate(int matchRule, String subscriberId, String networkId) {
-        this(matchRule, subscriberId, new String[] { subscriberId }, networkId);
+    public NetworkTemplate(int matchRule, String subscriberId, String wifiNetworkKey) {
+        this(matchRule, subscriberId, new String[] { subscriberId }, wifiNetworkKey);
     }
 
     /** @hide */
     public NetworkTemplate(int matchRule, String subscriberId, String[] matchSubscriberIds,
-            String networkId) {
+            String wifiNetworkKey) {
         // Older versions used to only match MATCH_MOBILE and MATCH_MOBILE_WILDCARD templates
         // to metered networks. It is now possible to match mobile with any meteredness, but
         // in order to preserve backward compatibility of @UnsupportedAppUsage methods, this
         //constructor passes METERED_YES for these types.
-        this(matchRule, subscriberId, matchSubscriberIds, networkId,
+        this(matchRule, subscriberId, matchSubscriberIds,
+                wifiNetworkKey != null ? new String[] { wifiNetworkKey } : new String[0],
                 (matchRule == MATCH_MOBILE || matchRule == MATCH_MOBILE_WILDCARD) ? METERED_YES
                 : METERED_ALL , ROAMING_ALL, DEFAULT_NETWORK_ALL, NETWORK_TYPE_ALL,
                 OEM_MANAGED_ALL, NetworkStatsUtils.SUBSCRIBER_ID_MATCH_RULE_EXACT);
@@ -397,23 +410,25 @@
     /** @hide */
     // TODO: Remove it after updating all of the caller.
     public NetworkTemplate(int matchRule, String subscriberId, String[] matchSubscriberIds,
-            String networkId, int metered, int roaming, int defaultNetwork, int subType,
+            String wifiNetworkKey, int metered, int roaming, int defaultNetwork, int subType,
             int oemManaged) {
-        this(matchRule, subscriberId, matchSubscriberIds, networkId, metered, roaming,
-                defaultNetwork, subType, oemManaged,
+        this(matchRule, subscriberId, matchSubscriberIds,
+                wifiNetworkKey != null ? new String[] { wifiNetworkKey } : new String[0],
+                metered, roaming, defaultNetwork, subType, oemManaged,
                 NetworkStatsUtils.SUBSCRIBER_ID_MATCH_RULE_EXACT);
     }
 
     /** @hide */
     public NetworkTemplate(int matchRule, String subscriberId, String[] matchSubscriberIds,
-            String networkId, int metered, int roaming, int defaultNetwork, int subType,
-            int oemManaged, int subscriberIdMatchRule) {
+            String[] matchWifiNetworkKeys, int metered, int roaming,
+            int defaultNetwork, int subType, int oemManaged, int subscriberIdMatchRule) {
+        Objects.requireNonNull(matchWifiNetworkKeys);
         mMatchRule = matchRule;
         mSubscriberId = subscriberId;
         // TODO: Check whether mMatchSubscriberIds = null or mMatchSubscriberIds = {null} when
         // mSubscriberId is null
         mMatchSubscriberIds = matchSubscriberIds;
-        mNetworkId = networkId;
+        mMatchWifiNetworkKeys = matchWifiNetworkKeys;
         mMetered = metered;
         mRoaming = roaming;
         mDefaultNetwork = defaultNetwork;
@@ -431,7 +446,7 @@
         mMatchRule = in.readInt();
         mSubscriberId = in.readString();
         mMatchSubscriberIds = in.createStringArray();
-        mNetworkId = in.readString();
+        mMatchWifiNetworkKeys = in.createStringArray();
         mMetered = in.readInt();
         mRoaming = in.readInt();
         mDefaultNetwork = in.readInt();
@@ -445,7 +460,7 @@
         dest.writeInt(mMatchRule);
         dest.writeString(mSubscriberId);
         dest.writeStringArray(mMatchSubscriberIds);
-        dest.writeString(mNetworkId);
+        dest.writeStringArray(mMatchWifiNetworkKeys);
         dest.writeInt(mMetered);
         dest.writeInt(mRoaming);
         dest.writeInt(mDefaultNetwork);
@@ -471,9 +486,7 @@
             builder.append(", matchSubscriberIds=").append(
                     Arrays.toString(NetworkIdentityUtils.scrubSubscriberIds(mMatchSubscriberIds)));
         }
-        if (mNetworkId != null) {
-            builder.append(", networkId=").append(mNetworkId);
-        }
+        builder.append(", matchWifiNetworkKeys=").append(Arrays.toString(mMatchWifiNetworkKeys));
         if (mMetered != METERED_ALL) {
             builder.append(", metered=").append(NetworkStats.meteredToString(mMetered));
         }
@@ -497,8 +510,8 @@
 
     @Override
     public int hashCode() {
-        return Objects.hash(mMatchRule, mSubscriberId, mNetworkId, mMetered, mRoaming,
-                mDefaultNetwork, mSubType, mOemManaged, mSubscriberIdMatchRule);
+        return Objects.hash(mMatchRule, mSubscriberId, Arrays.hashCode(mMatchWifiNetworkKeys),
+                mMetered, mRoaming, mDefaultNetwork, mSubType, mOemManaged, mSubscriberIdMatchRule);
     }
 
     @Override
@@ -507,13 +520,13 @@
             final NetworkTemplate other = (NetworkTemplate) obj;
             return mMatchRule == other.mMatchRule
                     && Objects.equals(mSubscriberId, other.mSubscriberId)
-                    && Objects.equals(mNetworkId, other.mNetworkId)
                     && mMetered == other.mMetered
                     && mRoaming == other.mRoaming
                     && mDefaultNetwork == other.mDefaultNetwork
                     && mSubType == other.mSubType
                     && mOemManaged == other.mOemManaged
-                    && mSubscriberIdMatchRule == other.mSubscriberIdMatchRule;
+                    && mSubscriberIdMatchRule == other.mSubscriberIdMatchRule
+                    && Arrays.equals(mMatchWifiNetworkKeys, other.mMatchWifiNetworkKeys);
         }
         return false;
     }
@@ -579,14 +592,22 @@
      */
     @Nullable
     public String getWifiNetworkKey() {
-        return mNetworkId;
+        return CollectionUtils.isEmpty(mMatchWifiNetworkKeys) ? null : mMatchWifiNetworkKeys[0];
+    }
+
+    /**
+     * Get set of Wifi Network Keys of the template.
+     */
+    @Nullable
+    public Set<String> getWifiNetworkKeys() {
+        return new ArraySet<>(Arrays.asList(mMatchWifiNetworkKeys));
     }
 
     /** @hide */
     // TODO: Remove this and replace all callers with {@link #getWifiNetworkKey()}.
     @Nullable
     public String getNetworkId() {
-        return mNetworkId;
+        return getWifiNetworkKey();
     }
 
     /**
@@ -707,16 +728,21 @@
     }
 
     /**
-     * Check if network with matching SSID. Returns true when the SSID matches, or when
-     * {@code mNetworkId} is {@code WIFI_NETWORK_KEY_ALL}.
+     * Check if network matches key of the wifi network.
+     * Returns true when the key matches, or when {@code mMatchWifiNetworkKeys} is
+     * empty.
+     *
+     * @param wifiNetworkKey key of the wifi network. see {@link WifiInfo#getCurrentNetworkKey()}
+     *                  to know details about the key.
      */
-    private boolean matchesWifiNetworkId(@Nullable String networkId) {
-        return Objects.equals(mNetworkId, WIFI_NETWORK_KEY_ALL)
-                || Objects.equals(sanitizeSsid(mNetworkId), sanitizeSsid(networkId));
+    private boolean matchesWifiNetworkKey(@NonNull String wifiNetworkKey) {
+        Objects.requireNonNull(wifiNetworkKey);
+        return CollectionUtils.isEmpty(mMatchWifiNetworkKeys)
+                || CollectionUtils.contains(mMatchWifiNetworkKeys, wifiNetworkKey);
     }
 
     /**
-     * Check if mobile network with matching IMSI.
+     * Check if mobile network matches IMSI.
      */
     private boolean matchesMobile(NetworkIdentity ident) {
         if (ident.mType == TYPE_WIMAX) {
@@ -814,7 +840,7 @@
         switch (ident.mType) {
             case TYPE_WIFI:
                 return matchesSubscriberId(ident.mSubscriberId)
-                        && matchesWifiNetworkId(ident.mNetworkId);
+                        && matchesWifiNetworkKey(ident.mNetworkId);
             default:
                 return false;
         }
@@ -956,8 +982,10 @@
             if (CollectionUtils.contains(merged, template.mSubscriberId)) {
                 // Requested template subscriber is part of the merge group; return
                 // a template that matches all merged subscribers.
+                final String[] matchWifiNetworkKeys = template.mMatchWifiNetworkKeys;
                 return new NetworkTemplate(template.mMatchRule, merged[0], merged,
-                        template.mNetworkId);
+                        CollectionUtils.isEmpty(matchWifiNetworkKeys)
+                                ? null : matchWifiNetworkKeys[0]);
             }
         }
 
@@ -984,9 +1012,10 @@
         private final int mMatchRule;
         // Use a SortedSet to provide a deterministic order when fetching the first one.
         @NonNull
-        private final SortedSet<String> mMatchSubscriberIds = new TreeSet<>();
-        @Nullable
-        private String mWifiNetworkKey;
+        private final SortedSet<String> mMatchSubscriberIds =
+                new TreeSet<>(Comparator.nullsFirst(Comparator.naturalOrder()));
+        @NonNull
+        private final SortedSet<String> mMatchWifiNetworkKeys = new TreeSet<>();
 
         // Matches for the NetworkStats constants METERED_*, ROAMING_* and DEFAULT_NETWORK_*.
         private int mMetered;
@@ -1006,7 +1035,6 @@
             assertRequestableMatchRule(matchRule);
             // Initialize members with default values.
             mMatchRule = matchRule;
-            mWifiNetworkKey = WIFI_NETWORK_KEY_ALL;
             mMetered = METERED_ALL;
             mRoaming = ROAMING_ALL;
             mDefaultNetwork = DEFAULT_NETWORK_ALL;
@@ -1030,15 +1058,28 @@
         }
 
         /**
-         * Set the Wifi Network Key.
+         * Set the Wifi Network Keys. Calling this function with an empty set represents
+         * the intention of matching any Wifi Network Key.
          *
-         * @param wifiNetworkKey the Wifi Network Key, see {@link WifiInfo#getCurrentNetworkKey()}.
-         *                       Or null to match all networks.
+         * @param wifiNetworkKeys the list of Wifi Network Key,
+         *                        see {@link WifiInfo#getCurrentNetworkKey()}.
+         *                        Or an empty list to match all networks.
+         *                        Note that {@code getCurrentNetworkKey()} might get null key
+         *                        when wifi disconnects. However, the caller should never invoke
+         *                        this function with a null Wifi Network Key since such statistics
+         *                        never exists.
          * @return this builder.
          */
         @NonNull
-        public Builder setWifiNetworkKey(@Nullable String wifiNetworkKey) {
-            mWifiNetworkKey = wifiNetworkKey;
+        public Builder setWifiNetworkKeys(@NonNull Set<String> wifiNetworkKeys) {
+            Objects.requireNonNull(wifiNetworkKeys);
+            for (String key : wifiNetworkKeys) {
+                if (key == null) {
+                    throw new IllegalArgumentException("Null is not a valid key");
+                }
+            }
+            mMatchWifiNetworkKeys.clear();
+            mMatchWifiNetworkKeys.addAll(wifiNetworkKeys);
             return this;
         }
 
@@ -1122,9 +1163,17 @@
         }
 
         private void assertRequestableParameters() {
+            validateWifiNetworkKeys();
             // TODO: Check all the input are legitimate.
         }
 
+        private void validateWifiNetworkKeys() {
+            if (mMatchRule != MATCH_WIFI && !mMatchWifiNetworkKeys.isEmpty()) {
+                throw new IllegalArgumentException("Trying to build non wifi match rule: "
+                        + mMatchRule + " with wifi network keys");
+            }
+        }
+
         /**
          * For backward compatibility, deduce match rule to a wildcard match rule
          * if the Subscriber Ids are empty.
@@ -1133,7 +1182,7 @@
             if (mMatchRule == MATCH_MOBILE && mMatchSubscriberIds.isEmpty()) {
                 return MATCH_MOBILE_WILDCARD;
             } else if (mMatchRule == MATCH_WIFI && mMatchSubscriberIds.isEmpty()
-                    && mWifiNetworkKey == WIFI_NETWORK_KEY_ALL) {
+                    && mMatchWifiNetworkKeys.isEmpty()) {
                 return MATCH_WIFI_WILDCARD;
             }
             return mMatchRule;
@@ -1153,8 +1202,8 @@
             return new NetworkTemplate(getWildcardDeducedMatchRule(),
                     mMatchSubscriberIds.isEmpty() ? null : mMatchSubscriberIds.iterator().next(),
                     mMatchSubscriberIds.toArray(new String[0]),
-                    mWifiNetworkKey, mMetered, mRoaming, mDefaultNetwork, mRatType, mOemManaged,
-                    subscriberIdMatchRule);
+                    mMatchWifiNetworkKeys.toArray(new String[0]), mMetered, mRoaming,
+                    mDefaultNetwork, mRatType, mOemManaged, subscriberIdMatchRule);
         }
     }
 }
diff --git a/packages/ConnectivityT/service/src/com/android/server/net/NetworkStatsService.java b/packages/ConnectivityT/service/src/com/android/server/net/NetworkStatsService.java
index 4fd62c1..a3de9e4 100644
--- a/packages/ConnectivityT/service/src/com/android/server/net/NetworkStatsService.java
+++ b/packages/ConnectivityT/service/src/com/android/server/net/NetworkStatsService.java
@@ -655,8 +655,6 @@
 
     @Override
     public INetworkStatsSession openSession() {
-        // NOTE: if callers want to get non-augmented data, they should go
-        // through the public API
         return openSessionInternal(NetworkStatsManager.FLAG_AUGMENT_WITH_SUBSCRIPTION_PLAN, null);
     }
 
@@ -876,8 +874,6 @@
     private long getNetworkTotalBytes(NetworkTemplate template, long start, long end) {
         assertSystemReady();
 
-        // NOTE: if callers want to get non-augmented data, they should go
-        // through the public API
         return internalGetSummaryForNetwork(template,
                 NetworkStatsManager.FLAG_AUGMENT_WITH_SUBSCRIPTION_PLAN, start, end,
                 NetworkStatsAccess.Level.DEVICE, Binder.getCallingUid()).getTotalBytes();
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/CsipDeviceManager.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/CsipDeviceManager.java
index 36d9cf8..cc56a21 100644
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/CsipDeviceManager.java
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/CsipDeviceManager.java
@@ -68,7 +68,7 @@
             }
 
             for (Map.Entry<Integer, ParcelUuid> entry: groupIdMap.entrySet()) {
-                if (entry.getValue().equals(BluetoothUuid.BASE_UUID)) {
+                if (entry.getValue().equals(BluetoothUuid.CAP)) {
                     return entry.getKey();
                 }
             }
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/LocalBluetoothProfileManager.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/LocalBluetoothProfileManager.java
index 3347920..5e2f310 100644
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/LocalBluetoothProfileManager.java
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/LocalBluetoothProfileManager.java
@@ -338,7 +338,7 @@
                             .getGroupUuidMapByDevice(cachedDevice.getDevice());
                     if (groupIdMap != null) {
                         for (Map.Entry<Integer, ParcelUuid> entry: groupIdMap.entrySet()) {
-                            if (entry.getValue().equals(BluetoothUuid.BASE_UUID)) {
+                            if (entry.getValue().equals(BluetoothUuid.CAP)) {
                                 cachedDevice.setGroupId(entry.getKey());
                                 break;
                             }
diff --git a/packages/SettingsLib/src/com/android/settingslib/net/DataUsageController.java b/packages/SettingsLib/src/com/android/settingslib/net/DataUsageController.java
index 18c38c5..011ca0b 100644
--- a/packages/SettingsLib/src/com/android/settingslib/net/DataUsageController.java
+++ b/packages/SettingsLib/src/com/android/settingslib/net/DataUsageController.java
@@ -32,7 +32,6 @@
 import android.net.NetworkPolicy;
 import android.net.NetworkPolicyManager;
 import android.net.NetworkTemplate;
-import android.os.RemoteException;
 import android.os.ServiceManager;
 import android.telephony.SubscriptionManager;
 import android.telephony.TelephonyManager;
@@ -172,7 +171,7 @@
                 return bucket.getRxBytes() + bucket.getTxBytes();
             }
             Log.w(TAG, "Failed to get data usage, no entry data");
-        } catch (RemoteException e) {
+        } catch (RuntimeException e) {
             Log.w(TAG, "Failed to get data usage, remote call failed");
         }
         return -1L;
diff --git a/packages/SettingsLib/src/com/android/settingslib/net/NetworkCycleChartDataLoader.java b/packages/SettingsLib/src/com/android/settingslib/net/NetworkCycleChartDataLoader.java
index 787dc55..42e7100 100644
--- a/packages/SettingsLib/src/com/android/settingslib/net/NetworkCycleChartDataLoader.java
+++ b/packages/SettingsLib/src/com/android/settingslib/net/NetworkCycleChartDataLoader.java
@@ -18,7 +18,6 @@
 
 import android.app.usage.NetworkStats;
 import android.content.Context;
-import android.os.RemoteException;
 import android.util.Log;
 
 import java.util.ArrayList;
@@ -54,7 +53,7 @@
                     .setTotalUsage(total);
                 mData.add(builder.build());
             }
-        } catch (RemoteException e) {
+        } catch (RuntimeException e) {
             Log.e(TAG, "Exception querying network detail.", e);
         }
     }
@@ -85,7 +84,7 @@
                 if (bucket != null) {
                     usage = bucket.getRxBytes() + bucket.getTxBytes();
                 }
-            } catch (RemoteException e) {
+            } catch (RuntimeException e) {
                 Log.e(TAG, "Exception querying network detail.", e);
             }
             data.add(new NetworkCycleData.Builder()
diff --git a/packages/SettingsLib/src/com/android/settingslib/net/NetworkStatsSummaryLoader.java b/packages/SettingsLib/src/com/android/settingslib/net/NetworkStatsSummaryLoader.java
index ed093629..54d5c3d 100644
--- a/packages/SettingsLib/src/com/android/settingslib/net/NetworkStatsSummaryLoader.java
+++ b/packages/SettingsLib/src/com/android/settingslib/net/NetworkStatsSummaryLoader.java
@@ -20,7 +20,6 @@
 import android.app.usage.NetworkStatsManager;
 import android.content.Context;
 import android.net.NetworkTemplate;
-import android.os.RemoteException;
 import android.util.Log;
 
 import androidx.loader.content.AsyncTaskLoader;
@@ -55,7 +54,7 @@
     public NetworkStats loadInBackground() {
         try {
             return mNetworkStatsManager.querySummary(mNetworkTemplate, mStart, mEnd);
-        } catch (RemoteException e) {
+        } catch (RuntimeException e) {
             Log.e(TAG, "Exception querying network detail.", e);
             return null;
         }
diff --git a/services/core/java/com/android/server/BluetoothManagerService.java b/services/core/java/com/android/server/BluetoothManagerService.java
index 8860a81..450e988 100644
--- a/services/core/java/com/android/server/BluetoothManagerService.java
+++ b/services/core/java/com/android/server/BluetoothManagerService.java
@@ -1850,6 +1850,10 @@
                     mHandler.removeMessages(MESSAGE_RESTART_BLUETOOTH_SERVICE);
                     mEnable = true;
 
+                    if (isBle == 0) {
+                        persistBluetoothSetting(BLUETOOTH_ON_BLUETOOTH);
+                    }
+
                     // Use service interface to get the exact state
                     try {
                         mBluetoothLock.readLock().lock();
@@ -1863,7 +1867,6 @@
                                     } else {
                                         Slog.w(TAG, "BT Enable in BLE_ON State, going to ON");
                                         mBluetooth.onLeServiceUp(mContext.getAttributionSource());
-                                        persistBluetoothSetting(BLUETOOTH_ON_BLUETOOTH);
                                     }
                                     break;
                                 case BluetoothAdapter.STATE_BLE_TURNING_ON:
diff --git a/services/core/java/com/android/server/net/NetworkPolicyManagerService.java b/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
index c315b5c..2ca057d 100644
--- a/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
+++ b/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
@@ -2025,7 +2025,7 @@
         for (final NetworkStateSnapshot snapshot : snapshots) {
             mNetIdToSubId.put(snapshot.getNetwork().getNetId(), parseSubId(snapshot));
 
-            // Policies matched by NPMS only match by subscriber ID or by ssid. Thus subtype
+            // Policies matched by NPMS only match by subscriber ID or by network ID. Thus subtype
             // in the object created here is never used and its value doesn't matter, so use
             // NETWORK_TYPE_UNKNOWN.
             final NetworkIdentity ident = NetworkIdentity.buildNetworkIdentity(mContext, snapshot,
@@ -2455,7 +2455,6 @@
                         }
                         final NetworkTemplate.Builder builder =
                                 new NetworkTemplate.Builder(templateType)
-                                        .setWifiNetworkKey(networkId)
                                         .setMeteredness(templateMeteredness);
                         if (subscriberIdMatchRule
                                 == NetworkStatsUtils.SUBSCRIBER_ID_MATCH_RULE_EXACT) {
@@ -2463,6 +2462,9 @@
                             ids.add(subscriberId);
                             builder.setSubscriberIds(ids);
                         }
+                        if (networkId != null) {
+                            builder.setWifiNetworkKeys(Set.of(networkId));
+                        }
                         final NetworkTemplate template = builder.build();
                         if (NetworkPolicy.isTemplatePersistable(template)) {
                             mNetworkPolicy.put(template, new NetworkPolicy(template, cycleRule,
@@ -2613,35 +2615,39 @@
      * into {@link WifiConfiguration}.
      */
     private void upgradeWifiMeteredOverride() {
-        final ArrayMap<String, Boolean> wifiNetworkIds = new ArrayMap<>();
+        final ArrayMap<String, Boolean> wifiNetworkKeys = new ArrayMap<>();
         synchronized (mNetworkPoliciesSecondLock) {
             for (int i = 0; i < mNetworkPolicy.size();) {
                 final NetworkPolicy policy = mNetworkPolicy.valueAt(i);
                 if (policy.template.getMatchRule() == NetworkTemplate.MATCH_WIFI
                         && !policy.inferred) {
                     mNetworkPolicy.removeAt(i);
-                    wifiNetworkIds.put(policy.template.getNetworkId(), policy.metered);
+                    final Set<String> keys = policy.template.getWifiNetworkKeys();
+                    wifiNetworkKeys.put(keys.isEmpty() ? null : keys.iterator().next(),
+                            policy.metered);
                 } else {
                     i++;
                 }
             }
         }
 
-        if (wifiNetworkIds.isEmpty()) {
+        if (wifiNetworkKeys.isEmpty()) {
             return;
         }
         final WifiManager wm = mContext.getSystemService(WifiManager.class);
         final List<WifiConfiguration> configs = wm.getConfiguredNetworks();
         for (int i = 0; i < configs.size(); ++i) {
             final WifiConfiguration config = configs.get(i);
-            final String networkId = resolveNetworkId(config);
-            final Boolean metered = wifiNetworkIds.get(networkId);
-            if (metered != null) {
-                Slog.d(TAG, "Found network " + networkId + "; upgrading metered hint");
-                config.meteredOverride = metered
-                        ? WifiConfiguration.METERED_OVERRIDE_METERED
-                        : WifiConfiguration.METERED_OVERRIDE_NOT_METERED;
-                wm.updateNetwork(config);
+            for (String key : config.getAllPersistableNetworkKeys()) {
+                final Boolean metered = wifiNetworkKeys.get(key);
+                if (metered != null) {
+                    Slog.d(TAG, "Found network " + key + "; upgrading metered hint");
+                    config.meteredOverride = metered
+                            ? WifiConfiguration.METERED_OVERRIDE_METERED
+                            : WifiConfiguration.METERED_OVERRIDE_NOT_METERED;
+                    wm.updateNetwork(config);
+                    break;
+                }
             }
         }
 
@@ -2683,9 +2689,9 @@
                         ? NetworkStatsUtils.SUBSCRIBER_ID_MATCH_RULE_ALL
                         : NetworkStatsUtils.SUBSCRIBER_ID_MATCH_RULE_EXACT;
                 writeIntAttribute(out, ATTR_SUBSCRIBER_ID_MATCH_RULE, subscriberIdMatchRule);
-                final String networkId = template.getNetworkId();
-                if (networkId != null) {
-                    out.attribute(null, ATTR_NETWORK_ID, networkId);
+                if (!template.getWifiNetworkKeys().isEmpty()) {
+                    out.attribute(null, ATTR_NETWORK_ID,
+                            template.getWifiNetworkKeys().iterator().next());
                 }
                 writeIntAttribute(out, ATTR_TEMPLATE_METERED,
                         template.getMeteredness());
diff --git a/services/tests/servicestests/src/com/android/server/net/NetworkPolicyManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/net/NetworkPolicyManagerServiceTest.java
index eda05bf..b811e28 100644
--- a/services/tests/servicestests/src/com/android/server/net/NetworkPolicyManagerServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/net/NetworkPolicyManagerServiceTest.java
@@ -129,6 +129,7 @@
 import android.net.NetworkStatsHistory;
 import android.net.NetworkTemplate;
 import android.net.TelephonyNetworkSpecifier;
+import android.net.wifi.WifiInfo;
 import android.os.Binder;
 import android.os.Handler;
 import android.os.INetworkManagementService;
@@ -226,13 +227,13 @@
 
     private static final long TEST_START = 1194220800000L;
     private static final String TEST_IFACE = "test0";
-    private static final String TEST_SSID = "AndroidAP";
+    private static final String TEST_WIFI_NETWORK_KEY = "TestWifiNetworkKey";
     private static final String TEST_IMSI = "310210";
     private static final int TEST_SUB_ID = 42;
     private static final Network TEST_NETWORK = mock(Network.class, CALLS_REAL_METHODS);
 
 
-    private static NetworkTemplate sTemplateWifi = buildTemplateWifi(TEST_SSID);
+    private static NetworkTemplate sTemplateWifi = buildTemplateWifi(TEST_WIFI_NETWORK_KEY);
     private static NetworkTemplate sTemplateCarrierMetered =
             buildTemplateCarrierMetered(TEST_IMSI);
 
@@ -2096,10 +2097,13 @@
     }
 
     private static NetworkStateSnapshot buildWifi() {
+        WifiInfo mockWifiInfo = mock(WifiInfo.class);
+        when(mockWifiInfo.makeCopy(anyLong())).thenReturn(mockWifiInfo);
+        when(mockWifiInfo.getCurrentNetworkKey()).thenReturn(TEST_WIFI_NETWORK_KEY);
         final LinkProperties prop = new LinkProperties();
         prop.setInterfaceName(TEST_IFACE);
         final NetworkCapabilities networkCapabilities = new NetworkCapabilities.Builder()
-                .addTransportType(TRANSPORT_WIFI).setSsid(TEST_SSID).build();
+                .addTransportType(TRANSPORT_WIFI).setTransportInfo(mockWifiInfo).build();
         return new NetworkStateSnapshot(TEST_NETWORK, networkCapabilities, prop,
                 null /*subscriberId*/, TYPE_WIFI);
     }
diff --git a/telephony/java/android/telephony/data/ApnSetting.java b/telephony/java/android/telephony/data/ApnSetting.java
index 1ef04be..d6dce25 100644
--- a/telephony/java/android/telephony/data/ApnSetting.java
+++ b/telephony/java/android/telephony/data/ApnSetting.java
@@ -328,8 +328,6 @@
     @SystemApi
     public static final String TYPE_XCAP_STRING = "xcap";
 
-
-
     /**
      * APN type for Virtual SIM service.
      *
@@ -506,27 +504,21 @@
     private final int mRoamingProtocol;
     private final int mMtuV4;
     private final int mMtuV6;
-
     private final boolean mCarrierEnabled;
-
-    private final int mNetworkTypeBitmask;
-
+    private final @TelephonyManager.NetworkTypeBitMask int mNetworkTypeBitmask;
+    private final @TelephonyManager.NetworkTypeBitMask long mLingeringNetworkTypeBitmask;
     private final int mProfileId;
-
     private final boolean mPersistent;
     private final int mMaxConns;
     private final int mWaitTime;
     private final int mMaxConnsTime;
-
     private final int mMvnoType;
     private final String mMvnoMatchData;
-
     private final int mApnSetId;
-
     private boolean mPermanentFailed = false;
     private final int mCarrierId;
-
     private final int mSkip464Xlat;
+    private final boolean mAlwaysOn;
 
     /**
      * Returns the MTU size of the IPv4 mobile interface to which the APN connected. Note this value
@@ -843,20 +835,37 @@
     }
 
     /**
-     * Returns a bitmask describing the Radio Technologies(Network Types) which this APN may use.
+     * Returns a bitmask describing the Radio Technologies (Network Types) which this APN may use.
      *
      * NetworkType bitmask is calculated from NETWORK_TYPE defined in {@link TelephonyManager}.
      *
      * Examples of Network Types include {@link TelephonyManager#NETWORK_TYPE_UNKNOWN},
      * {@link TelephonyManager#NETWORK_TYPE_GPRS}, {@link TelephonyManager#NETWORK_TYPE_EDGE}.
      *
-     * @return a bitmask describing the Radio Technologies(Network Types)
+     * @return a bitmask describing the Radio Technologies (Network Types) or 0 if it is undefined.
      */
     public int getNetworkTypeBitmask() {
         return mNetworkTypeBitmask;
     }
 
     /**
+     * Returns a bitmask describing the Radio Technologies (Network Types) that should not be torn
+     * down if it exists or brought up if it already exists for this APN.
+     *
+     * NetworkType bitmask is calculated from NETWORK_TYPE defined in {@link TelephonyManager}.
+     *
+     * Examples of Network Types include {@link TelephonyManager#NETWORK_TYPE_UNKNOWN},
+     * {@link TelephonyManager#NETWORK_TYPE_GPRS}, {@link TelephonyManager#NETWORK_TYPE_EDGE}.
+     *
+     * @return a bitmask describing the Radio Technologies (Network Types) that should linger
+     *         or 0 if it is undefined.
+     * @hide
+     */
+    public @TelephonyManager.NetworkTypeBitMask long getLingeringNetworkTypeBitmask() {
+        return mLingeringNetworkTypeBitmask;
+    }
+
+    /**
      * Returns the MVNO match type for this APN.
      *
      * @see Builder#setMvnoType(int)
@@ -888,6 +897,18 @@
         return mSkip464Xlat;
     }
 
+    /**
+     * Returns whether User Plane resources have to be activated during every transition from
+     * CM-IDLE mode to CM-CONNECTED state for this APN
+     * See 3GPP TS 23.501 section 5.6.13
+     *
+     * @return True if the PDU session for this APN should always be on and false otherwise
+     * @hide
+     */
+    public boolean isAlwaysOn() {
+        return mAlwaysOn;
+    }
+
     private ApnSetting(Builder builder) {
         this.mEntryName = builder.mEntryName;
         this.mApnName = builder.mApnName;
@@ -912,6 +933,7 @@
         this.mMtuV6 = builder.mMtuV6;
         this.mCarrierEnabled = builder.mCarrierEnabled;
         this.mNetworkTypeBitmask = builder.mNetworkTypeBitmask;
+        this.mLingeringNetworkTypeBitmask = builder.mLingeringNetworkTypeBitmask;
         this.mProfileId = builder.mProfileId;
         this.mPersistent = builder.mModemCognitive;
         this.mMaxConns = builder.mMaxConns;
@@ -922,6 +944,7 @@
         this.mApnSetId = builder.mApnSetId;
         this.mCarrierId = builder.mCarrierId;
         this.mSkip464Xlat = builder.mSkip464Xlat;
+        this.mAlwaysOn = builder.mAlwaysOn;
     }
 
     /**
@@ -938,6 +961,10 @@
             networkTypeBitmask =
                 ServiceState.convertBearerBitmaskToNetworkTypeBitmask(bearerBitmask);
         }
+        int mtuV4 = cursor.getInt(cursor.getColumnIndexOrThrow(Telephony.Carriers.MTU_V4));
+        if (mtuV4 == -1) {
+            mtuV4 = cursor.getInt(cursor.getColumnIndexOrThrow(Telephony.Carriers.MTU));
+        }
 
         return new Builder()
                 .setId(cursor.getInt(cursor.getColumnIndexOrThrow(Telephony.Carriers._ID)))
@@ -972,6 +999,8 @@
                 .setCarrierEnabled(cursor.getInt(cursor.getColumnIndexOrThrow(
                         Telephony.Carriers.CARRIER_ENABLED)) == 1)
                 .setNetworkTypeBitmask(networkTypeBitmask)
+                .setLingeringNetworkTypeBitmask(cursor.getInt(cursor.getColumnIndexOrThrow(
+                        Carriers.LINGERING_NETWORK_TYPE_BITMASK)))
                 .setProfileId(cursor.getInt(
                         cursor.getColumnIndexOrThrow(Telephony.Carriers.PROFILE_ID)))
                 .setModemCognitive(cursor.getInt(cursor.getColumnIndexOrThrow(
@@ -982,8 +1011,8 @@
                         cursor.getColumnIndexOrThrow(Telephony.Carriers.WAIT_TIME_RETRY)))
                 .setMaxConnsTime(cursor.getInt(cursor.getColumnIndexOrThrow(
                         Telephony.Carriers.TIME_LIMIT_FOR_MAX_CONNECTIONS)))
-                .setMtuV4(cursor.getInt(cursor.getColumnIndexOrThrow(Telephony.Carriers.MTU)))
-                .setMtuV6(UNSET_MTU) // TODO: Add corresponding support in telephony provider
+                .setMtuV4(mtuV4)
+                .setMtuV6(cursor.getInt(cursor.getColumnIndexOrThrow(Telephony.Carriers.MTU_V6)))
                 .setMvnoType(getMvnoTypeIntFromString(
                         cursor.getString(cursor.getColumnIndexOrThrow(
                                 Telephony.Carriers.MVNO_TYPE))))
@@ -994,6 +1023,7 @@
                 .setCarrierId(cursor.getInt(
                         cursor.getColumnIndexOrThrow(Telephony.Carriers.CARRIER_ID)))
                 .setSkip464Xlat(cursor.getInt(cursor.getColumnIndexOrThrow(Carriers.SKIP_464XLAT)))
+                .setAlwaysOn(cursor.getInt(cursor.getColumnIndexOrThrow(Carriers.ALWAYS_ON)) == 1)
                 .buildWithoutCheck();
     }
 
@@ -1019,6 +1049,7 @@
                 .setRoamingProtocol(apn.mRoamingProtocol)
                 .setCarrierEnabled(apn.mCarrierEnabled)
                 .setNetworkTypeBitmask(apn.mNetworkTypeBitmask)
+                .setLingeringNetworkTypeBitmask(apn.mLingeringNetworkTypeBitmask)
                 .setProfileId(apn.mProfileId)
                 .setModemCognitive(apn.mPersistent)
                 .setMaxConns(apn.mMaxConns)
@@ -1031,6 +1062,7 @@
                 .setApnSetId(apn.mApnSetId)
                 .setCarrierId(apn.mCarrierId)
                 .setSkip464Xlat(apn.mSkip464Xlat)
+                .setAlwaysOn(apn.mAlwaysOn)
                 .buildWithoutCheck();
     }
 
@@ -1069,9 +1101,11 @@
         sb.append(", ").append(mMvnoMatchData);
         sb.append(", ").append(mPermanentFailed);
         sb.append(", ").append(mNetworkTypeBitmask);
+        sb.append(", ").append(mLingeringNetworkTypeBitmask);
         sb.append(", ").append(mApnSetId);
         sb.append(", ").append(mCarrierId);
         sb.append(", ").append(mSkip464Xlat);
+        sb.append(", ").append(mAlwaysOn);
         return sb.toString();
     }
 
@@ -1136,8 +1170,9 @@
         return Objects.hash(mApnName, mProxyAddress, mProxyPort, mMmsc, mMmsProxyAddress,
                 mMmsProxyPort, mUser, mPassword, mAuthType, mApnTypeBitmask, mId, mOperatorNumeric,
                 mProtocol, mRoamingProtocol, mMtuV4, mMtuV6, mCarrierEnabled, mNetworkTypeBitmask,
-                mProfileId, mPersistent, mMaxConns, mWaitTime, mMaxConnsTime, mMvnoType,
-                mMvnoMatchData, mApnSetId, mCarrierId, mSkip464Xlat);
+                mLingeringNetworkTypeBitmask, mProfileId, mPersistent, mMaxConns, mWaitTime,
+                mMaxConnsTime, mMvnoType, mMvnoMatchData, mApnSetId, mCarrierId, mSkip464Xlat,
+                mAlwaysOn);
     }
 
     @Override
@@ -1174,9 +1209,11 @@
                 && Objects.equals(mMvnoType, other.mMvnoType)
                 && Objects.equals(mMvnoMatchData, other.mMvnoMatchData)
                 && Objects.equals(mNetworkTypeBitmask, other.mNetworkTypeBitmask)
+                && Objects.equals(mLingeringNetworkTypeBitmask, other.mLingeringNetworkTypeBitmask)
                 && Objects.equals(mApnSetId, other.mApnSetId)
                 && Objects.equals(mCarrierId, other.mCarrierId)
-                && Objects.equals(mSkip464Xlat, other.mSkip464Xlat);
+                && Objects.equals(mSkip464Xlat, other.mSkip464Xlat)
+                && Objects.equals(mAlwaysOn, other.mAlwaysOn);
     }
 
     /**
@@ -1210,6 +1247,7 @@
                 && Objects.equals(mPassword, other.mPassword)
                 && Objects.equals(mAuthType, other.mAuthType)
                 && Objects.equals(mApnTypeBitmask, other.mApnTypeBitmask)
+                && Objects.equals(mLingeringNetworkTypeBitmask, other.mLingeringNetworkTypeBitmask)
                 && (isDataRoaming || Objects.equals(mProtocol, other.mProtocol))
                 && (!isDataRoaming || Objects.equals(mRoamingProtocol, other.mRoamingProtocol))
                 && Objects.equals(mCarrierEnabled, other.mCarrierEnabled)
@@ -1224,7 +1262,8 @@
                 && Objects.equals(mMvnoMatchData, other.mMvnoMatchData)
                 && Objects.equals(mApnSetId, other.mApnSetId)
                 && Objects.equals(mCarrierId, other.mCarrierId)
-                && Objects.equals(mSkip464Xlat, other.mSkip464Xlat);
+                && Objects.equals(mSkip464Xlat, other.mSkip464Xlat)
+                && Objects.equals(mAlwaysOn, other.mAlwaysOn);
     }
 
     /**
@@ -1304,9 +1343,13 @@
         apnValue.put(Telephony.Carriers.CARRIER_ENABLED, mCarrierEnabled);
         apnValue.put(Telephony.Carriers.MVNO_TYPE, getMvnoTypeStringFromInt(mMvnoType));
         apnValue.put(Telephony.Carriers.NETWORK_TYPE_BITMASK, mNetworkTypeBitmask);
+        apnValue.put(Telephony.Carriers.LINGERING_NETWORK_TYPE_BITMASK,
+                mLingeringNetworkTypeBitmask);
+        apnValue.put(Telephony.Carriers.MTU_V4, mMtuV4);
+        apnValue.put(Telephony.Carriers.MTU_V6, mMtuV6);
         apnValue.put(Telephony.Carriers.CARRIER_ID, mCarrierId);
         apnValue.put(Telephony.Carriers.SKIP_464XLAT, mSkip464Xlat);
-
+        apnValue.put(Telephony.Carriers.ALWAYS_ON, mAlwaysOn);
         return apnValue;
     }
 
@@ -1510,6 +1553,31 @@
         return ServiceState.bitmaskHasTech(mNetworkTypeBitmask, networkType);
     }
 
+    /**
+     * Check if this APN setting can support the given lingering network
+     *
+     * @param networkType The lingering network type
+     * @return {@code true} if this APN setting can support the given lingering network.
+     *
+     * @hide
+     */
+    public boolean canSupportLingeringNetworkType(@NetworkType int networkType) {
+        if (networkType == 0) {
+            return canSupportNetworkType(networkType);
+        }
+        // Do a special checking for GSM. In reality, GSM is a voice only network type and can never
+        // be used for data. We allow it here because in some DSDS corner cases, on the non-DDS
+        // sub, modem reports data rat unknown. In that case if voice is GSM and this APN supports
+        // GPRS or EDGE, this APN setting should be selected.
+        if (networkType == TelephonyManager.NETWORK_TYPE_GSM
+                && (mLingeringNetworkTypeBitmask & (TelephonyManager.NETWORK_TYPE_BITMASK_GPRS
+                | TelephonyManager.NETWORK_TYPE_BITMASK_EDGE)) != 0) {
+            return true;
+        }
+
+        return ServiceState.bitmaskHasTech((int) mLingeringNetworkTypeBitmask, networkType);
+    }
+
     // Implement Parcelable.
     @Override
     /** @hide */
@@ -1537,6 +1605,7 @@
         dest.writeInt(mRoamingProtocol);
         dest.writeBoolean(mCarrierEnabled);
         dest.writeInt(mNetworkTypeBitmask);
+        dest.writeLong(mLingeringNetworkTypeBitmask);
         dest.writeInt(mProfileId);
         dest.writeBoolean(mPersistent);
         dest.writeInt(mMaxConns);
@@ -1549,6 +1618,7 @@
         dest.writeInt(mApnSetId);
         dest.writeInt(mCarrierId);
         dest.writeInt(mSkip464Xlat);
+        dest.writeBoolean(mAlwaysOn);
     }
 
     private static ApnSetting readFromParcel(Parcel in) {
@@ -1570,6 +1640,7 @@
                 .setRoamingProtocol(in.readInt())
                 .setCarrierEnabled(in.readBoolean())
                 .setNetworkTypeBitmask(in.readInt())
+                .setLingeringNetworkTypeBitmask(in.readLong())
                 .setProfileId(in.readInt())
                 .setModemCognitive(in.readBoolean())
                 .setMaxConns(in.readInt())
@@ -1582,6 +1653,7 @@
                 .setApnSetId(in.readInt())
                 .setCarrierId(in.readInt())
                 .setSkip464Xlat(in.readInt())
+                .setAlwaysOn(in.readBoolean())
                 .buildWithoutCheck();
     }
 
@@ -1649,7 +1721,8 @@
         private int mRoamingProtocol = UNSPECIFIED_INT;
         private int mMtuV4;
         private int mMtuV6;
-        private int mNetworkTypeBitmask;
+        private @TelephonyManager.NetworkTypeBitMask int mNetworkTypeBitmask;
+        private @TelephonyManager.NetworkTypeBitMask long mLingeringNetworkTypeBitmask;
         private boolean mCarrierEnabled;
         private int mProfileId;
         private boolean mModemCognitive;
@@ -1661,6 +1734,7 @@
         private int mApnSetId;
         private int mCarrierId = TelephonyManager.UNKNOWN_CARRIER_ID;
         private int mSkip464Xlat = Carriers.SKIP_464XLAT_DEFAULT;
+        private boolean mAlwaysOn;
 
         /**
          * Default constructor for Builder.
@@ -2012,6 +2086,19 @@
         }
 
         /**
+         * Sets lingering Radio Technology (Network Type) for this APN.
+         *
+         * @param lingeringNetworkTypeBitmask the Radio Technology (Network Type) that should linger
+         * @hide
+         */
+        @NonNull
+        public Builder setLingeringNetworkTypeBitmask(@TelephonyManager.NetworkTypeBitMask
+                long lingeringNetworkTypeBitmask) {
+            this.mLingeringNetworkTypeBitmask = lingeringNetworkTypeBitmask;
+            return this;
+        }
+
+        /**
          * Sets the MVNO match type for this APN.
          *
          * @param mvnoType the MVNO match type to set for this APN
@@ -2048,6 +2135,18 @@
         }
 
         /**
+         * Sets whether the PDU session brought up by this APN should always be on.
+         * See 3GPP TS 23.501 section 5.6.13
+         *
+         * @param alwaysOn the always on status to set for this APN
+         * @hide
+         */
+        public Builder setAlwaysOn(boolean alwaysOn) {
+            this.mAlwaysOn = alwaysOn;
+            return this;
+        }
+
+        /**
          * Builds {@link ApnSetting} from this builder.
          *
          * @return {@code null} if {@link #setApnName(String)} or {@link #setEntryName(String)}