Merge "new WFC registration failure notification string"
diff --git a/PREUPLOAD.cfg b/PREUPLOAD.cfg
index 50a5974..75b7491 100644
--- a/PREUPLOAD.cfg
+++ b/PREUPLOAD.cfg
@@ -6,4 +6,5 @@
                       packages/PrintSpooler/
                       services/print/
                       services/usb/
+                      telephony/
 
diff --git a/api/current.txt b/api/current.txt
index 047a20e..603b6d4 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -7922,7 +7922,7 @@
     method public java.util.List<android.bluetooth.BluetoothDevice> getConnectedDevices();
     method public int getConnectionState(android.bluetooth.BluetoothDevice);
     method public java.util.List<android.bluetooth.BluetoothDevice> getDevicesMatchingConnectionStates(int[]);
-    method public boolean registerApp(android.bluetooth.BluetoothHidDeviceAppSdpSettings, android.bluetooth.BluetoothHidDeviceAppQosSettings, android.bluetooth.BluetoothHidDeviceAppQosSettings, android.bluetooth.BluetoothHidDeviceCallback);
+    method public boolean registerApp(android.bluetooth.BluetoothHidDeviceAppSdpSettings, android.bluetooth.BluetoothHidDeviceAppQosSettings, android.bluetooth.BluetoothHidDeviceAppQosSettings, java.util.concurrent.Executor, android.bluetooth.BluetoothHidDevice.Callback);
     method public boolean replyReport(android.bluetooth.BluetoothDevice, byte, byte, byte[]);
     method public boolean reportError(android.bluetooth.BluetoothDevice, byte);
     method public boolean sendReport(android.bluetooth.BluetoothDevice, int, byte[]);
@@ -7952,49 +7952,8 @@
     field public static final byte SUBCLASS2_UNCATEGORIZED = 0; // 0x0
   }
 
-  public final class BluetoothHidDeviceAppQosSettings implements android.os.Parcelable {
-    ctor public BluetoothHidDeviceAppQosSettings(int, int, int, int, int, int);
-    method public int describeContents();
-    method public int[] toArray();
-    method public void writeToParcel(android.os.Parcel, int);
-    field public static final android.os.Parcelable.Creator<android.bluetooth.BluetoothHidDeviceAppQosSettings> CREATOR;
-    field public static final int MAX = -1; // 0xffffffff
-    field public static final int SERVICE_BEST_EFFORT = 1; // 0x1
-    field public static final int SERVICE_GUARANTEED = 2; // 0x2
-    field public static final int SERVICE_NO_TRAFFIC = 0; // 0x0
-    field public final int delayVariation;
-    field public final int latency;
-    field public final int peakBandwidth;
-    field public final int serviceType;
-    field public final int tokenBucketSize;
-    field public final int tokenRate;
-  }
-
-  public static class BluetoothHidDeviceAppQosSettings.Builder {
-    ctor public BluetoothHidDeviceAppQosSettings.Builder();
-    method public android.bluetooth.BluetoothHidDeviceAppQosSettings build();
-    method public android.bluetooth.BluetoothHidDeviceAppQosSettings.Builder delayVariation(int);
-    method public android.bluetooth.BluetoothHidDeviceAppQosSettings.Builder latency(int);
-    method public android.bluetooth.BluetoothHidDeviceAppQosSettings.Builder peakBandwidth(int);
-    method public android.bluetooth.BluetoothHidDeviceAppQosSettings.Builder serviceType(int);
-    method public android.bluetooth.BluetoothHidDeviceAppQosSettings.Builder tokenBucketSize(int);
-    method public android.bluetooth.BluetoothHidDeviceAppQosSettings.Builder tokenRate(int);
-  }
-
-  public final class BluetoothHidDeviceAppSdpSettings implements android.os.Parcelable {
-    ctor public BluetoothHidDeviceAppSdpSettings(java.lang.String, java.lang.String, java.lang.String, byte, byte[]);
-    method public int describeContents();
-    method public void writeToParcel(android.os.Parcel, int);
-    field public static final android.os.Parcelable.Creator<android.bluetooth.BluetoothHidDeviceAppSdpSettings> CREATOR;
-    field public final java.lang.String description;
-    field public final byte[] descriptors;
-    field public final java.lang.String name;
-    field public final java.lang.String provider;
-    field public final byte subclass;
-  }
-
-  public abstract class BluetoothHidDeviceCallback {
-    ctor public BluetoothHidDeviceCallback();
+  public static abstract class BluetoothHidDevice.Callback {
+    ctor public BluetoothHidDevice.Callback();
     method public void onAppStatusChanged(android.bluetooth.BluetoothDevice, boolean);
     method public void onConnectionStateChanged(android.bluetooth.BluetoothDevice, int);
     method public void onGetReport(android.bluetooth.BluetoothDevice, byte, byte, int);
@@ -8004,6 +7963,35 @@
     method public void onVirtualCableUnplug(android.bluetooth.BluetoothDevice);
   }
 
+  public final class BluetoothHidDeviceAppQosSettings implements android.os.Parcelable {
+    ctor public BluetoothHidDeviceAppQosSettings(int, int, int, int, int, int);
+    method public int describeContents();
+    method public int getDelayVariation();
+    method public int getLatency();
+    method public int getPeakBandwidth();
+    method public int getServiceType();
+    method public int getTokenBucketSize();
+    method public int getTokenRate();
+    method public void writeToParcel(android.os.Parcel, int);
+    field public static final android.os.Parcelable.Creator<android.bluetooth.BluetoothHidDeviceAppQosSettings> CREATOR;
+    field public static final int MAX = -1; // 0xffffffff
+    field public static final int SERVICE_BEST_EFFORT = 1; // 0x1
+    field public static final int SERVICE_GUARANTEED = 2; // 0x2
+    field public static final int SERVICE_NO_TRAFFIC = 0; // 0x0
+  }
+
+  public final class BluetoothHidDeviceAppSdpSettings implements android.os.Parcelable {
+    ctor public BluetoothHidDeviceAppSdpSettings(java.lang.String, java.lang.String, java.lang.String, byte, byte[]);
+    method public int describeContents();
+    method public java.lang.String getDescription();
+    method public byte[] getDescriptors();
+    method public java.lang.String getName();
+    method public java.lang.String getProvider();
+    method public byte getSubclass();
+    method public void writeToParcel(android.os.Parcel, int);
+    field public static final android.os.Parcelable.Creator<android.bluetooth.BluetoothHidDeviceAppSdpSettings> CREATOR;
+  }
+
   public final class BluetoothManager {
     method public android.bluetooth.BluetoothAdapter getAdapter();
     method public java.util.List<android.bluetooth.BluetoothDevice> getConnectedDevices(int);
diff --git a/api/system-current.txt b/api/system-current.txt
index 878749f4..6325de7 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -4533,6 +4533,7 @@
 
   public class EuiccManager {
     method public void continueOperation(android.content.Intent, android.os.Bundle);
+    method public void eraseSubscriptions(android.app.PendingIntent);
     method public void getDefaultDownloadableSubscriptionList(android.app.PendingIntent);
     method public void getDownloadableSubscriptionMetadata(android.telephony.euicc.DownloadableSubscription, android.app.PendingIntent);
     method public int getOtaStatus();
diff --git a/core/java/android/bluetooth/BluetoothHidDevice.java b/core/java/android/bluetooth/BluetoothHidDevice.java
index 2fab305..a3d6968 100644
--- a/core/java/android/bluetooth/BluetoothHidDevice.java
+++ b/core/java/android/bluetooth/BluetoothHidDevice.java
@@ -27,8 +27,8 @@
 import android.util.Log;
 
 import java.util.ArrayList;
-import java.util.Arrays;
 import java.util.List;
+import java.util.concurrent.Executor;
 
 /**
  * Provides the public APIs to control the Bluetooth HID Device profile.
@@ -37,7 +37,6 @@
  * Use {@link BluetoothAdapter#getProfileProxy} to get the BluetoothHidDevice proxy object.
  */
 public final class BluetoothHidDevice implements BluetoothProfile {
-
     private static final String TAG = BluetoothHidDevice.class.getSimpleName();
 
     /**
@@ -62,106 +61,327 @@
             "android.bluetooth.hiddevice.profile.action.CONNECTION_STATE_CHANGED";
 
     /**
-     * Constants representing device subclass.
+     * Constant representing unspecified HID device subclass.
      *
      * @see #registerApp (BluetoothHidDeviceAppQosSettings, BluetoothHidDeviceAppQosSettings,
-     *     BluetoothHidDeviceAppQosSettings, BluetoothHidDeviceCallback)
+     *     BluetoothHidDeviceAppQosSettings, Executor, Callback)
      */
     public static final byte SUBCLASS1_NONE = (byte) 0x00;
+    /**
+     * Constant representing keyboard subclass.
+     *
+     * @see #registerApp (BluetoothHidDeviceAppQosSettings, BluetoothHidDeviceAppQosSettings,
+     *     BluetoothHidDeviceAppQosSettings, Executor, Callback)
+     */
     public static final byte SUBCLASS1_KEYBOARD = (byte) 0x40;
+    /**
+     * Constant representing mouse subclass.
+     *
+     * @see #registerApp (BluetoothHidDeviceAppQosSettings, BluetoothHidDeviceAppQosSettings,
+     *     BluetoothHidDeviceAppQosSettings, Executor, Callback)
+     */
     public static final byte SUBCLASS1_MOUSE = (byte) 0x80;
+    /**
+     * Constant representing combo keyboard and mouse subclass.
+     *
+     * @see #registerApp (BluetoothHidDeviceAppQosSettings, BluetoothHidDeviceAppQosSettings,
+     *     BluetoothHidDeviceAppQosSettings, Executor, Callback)
+     */
     public static final byte SUBCLASS1_COMBO = (byte) 0xC0;
 
+    /**
+     * Constant representing uncategorized HID device subclass.
+     *
+     * @see #registerApp (BluetoothHidDeviceAppQosSettings, BluetoothHidDeviceAppQosSettings,
+     *     BluetoothHidDeviceAppQosSettings, Executor, Callback)
+     */
     public static final byte SUBCLASS2_UNCATEGORIZED = (byte) 0x00;
+    /**
+     * Constant representing joystick subclass.
+     *
+     * @see #registerApp (BluetoothHidDeviceAppQosSettings, BluetoothHidDeviceAppQosSettings,
+     *     BluetoothHidDeviceAppQosSettings, Executor, Callback)
+     */
     public static final byte SUBCLASS2_JOYSTICK = (byte) 0x01;
+    /**
+     * Constant representing gamepad subclass.
+     *
+     * @see #registerApp (BluetoothHidDeviceAppQosSettings, BluetoothHidDeviceAppQosSettings,
+     *     BluetoothHidDeviceAppQosSettings, Executor, Callback)
+     */
     public static final byte SUBCLASS2_GAMEPAD = (byte) 0x02;
+    /**
+     * Constant representing remote control subclass.
+     *
+     * @see #registerApp (BluetoothHidDeviceAppQosSettings, BluetoothHidDeviceAppQosSettings,
+     *     BluetoothHidDeviceAppQosSettings, Executor, Callback)
+     */
     public static final byte SUBCLASS2_REMOTE_CONTROL = (byte) 0x03;
+    /**
+     * Constant representing sensing device subclass.
+     *
+     * @see #registerApp (BluetoothHidDeviceAppQosSettings, BluetoothHidDeviceAppQosSettings,
+     *     BluetoothHidDeviceAppQosSettings, Executor, Callback)
+     */
     public static final byte SUBCLASS2_SENSING_DEVICE = (byte) 0x04;
+    /**
+     * Constant representing digitizer tablet subclass.
+     *
+     * @see #registerApp (BluetoothHidDeviceAppQosSettings, BluetoothHidDeviceAppQosSettings,
+     *     BluetoothHidDeviceAppQosSettings, Executor, Callback)
+     */
     public static final byte SUBCLASS2_DIGITIZER_TABLET = (byte) 0x05;
+    /**
+     * Constant representing card reader subclass.
+     *
+     * @see #registerApp (BluetoothHidDeviceAppQosSettings, BluetoothHidDeviceAppQosSettings,
+     *     BluetoothHidDeviceAppQosSettings, Executor, Callback)
+     */
     public static final byte SUBCLASS2_CARD_READER = (byte) 0x06;
 
     /**
-     * Constants representing report types.
+     * Constant representing HID Input Report type.
      *
-     * @see BluetoothHidDeviceCallback#onGetReport(BluetoothDevice, byte, byte, int)
-     * @see BluetoothHidDeviceCallback#onSetReport(BluetoothDevice, byte, byte, byte[])
-     * @see BluetoothHidDeviceCallback#onInterruptData(BluetoothDevice, byte, byte[])
+     * @see Callback#onGetReport(BluetoothDevice, byte, byte, int)
+     * @see Callback#onSetReport(BluetoothDevice, byte, byte, byte[])
+     * @see Callback#onInterruptData(BluetoothDevice, byte, byte[])
      */
     public static final byte REPORT_TYPE_INPUT = (byte) 1;
+    /**
+     * Constant representing HID Output Report type.
+     *
+     * @see Callback#onGetReport(BluetoothDevice, byte, byte, int)
+     * @see Callback#onSetReport(BluetoothDevice, byte, byte, byte[])
+     * @see Callback#onInterruptData(BluetoothDevice, byte, byte[])
+     */
     public static final byte REPORT_TYPE_OUTPUT = (byte) 2;
+    /**
+     * Constant representing HID Feature Report type.
+     *
+     * @see Callback#onGetReport(BluetoothDevice, byte, byte, int)
+     * @see Callback#onSetReport(BluetoothDevice, byte, byte, byte[])
+     * @see Callback#onInterruptData(BluetoothDevice, byte, byte[])
+     */
     public static final byte REPORT_TYPE_FEATURE = (byte) 3;
 
     /**
-     * Constants representing error response for Set Report.
+     * Constant representing success response for Set Report.
      *
-     * @see BluetoothHidDeviceCallback#onSetReport(BluetoothDevice, byte, byte, byte[])
+     * @see Callback#onSetReport(BluetoothDevice, byte, byte, byte[])
      */
     public static final byte ERROR_RSP_SUCCESS = (byte) 0;
+    /**
+     * Constant representing error response for Set Report due to "not ready".
+     *
+     * @see Callback#onSetReport(BluetoothDevice, byte, byte, byte[])
+     */
     public static final byte ERROR_RSP_NOT_READY = (byte) 1;
+    /**
+     * Constant representing error response for Set Report due to "invalid report ID".
+     *
+     * @see Callback#onSetReport(BluetoothDevice, byte, byte, byte[])
+     */
     public static final byte ERROR_RSP_INVALID_RPT_ID = (byte) 2;
+    /**
+     * Constant representing error response for Set Report due to "unsupported request".
+     *
+     * @see Callback#onSetReport(BluetoothDevice, byte, byte, byte[])
+     */
     public static final byte ERROR_RSP_UNSUPPORTED_REQ = (byte) 3;
+    /**
+     * Constant representing error response for Set Report due to "invalid parameter".
+     *
+     * @see Callback#onSetReport(BluetoothDevice, byte, byte, byte[])
+     */
     public static final byte ERROR_RSP_INVALID_PARAM = (byte) 4;
+    /**
+     * Constant representing error response for Set Report with unknown reason.
+     *
+     * @see Callback#onSetReport(BluetoothDevice, byte, byte, byte[])
+     */
     public static final byte ERROR_RSP_UNKNOWN = (byte) 14;
 
     /**
-     * Constants representing protocol mode used set by host. Default is always {@link
+     * Constant representing boot protocol mode used set by host. Default is always {@link
      * #PROTOCOL_REPORT_MODE} unless notified otherwise.
      *
-     * @see BluetoothHidDeviceCallback#onSetProtocol(BluetoothDevice, byte)
+     * @see Callback#onSetProtocol(BluetoothDevice, byte)
      */
     public static final byte PROTOCOL_BOOT_MODE = (byte) 0;
+    /**
+     * Constant representing report protocol mode used set by host. Default is always {@link
+     * #PROTOCOL_REPORT_MODE} unless notified otherwise.
+     *
+     * @see Callback#onSetProtocol(BluetoothDevice, byte)
+     */
     public static final byte PROTOCOL_REPORT_MODE = (byte) 1;
 
+    /**
+     * The template class that applications use to call callback functions on events from the HID
+     * host. Callback functions are wrapped in this class and registered to the Android system
+     * during app registration.
+     */
+    public abstract static class Callback {
+
+        private static final String TAG = "BluetoothHidDevCallback";
+
+        /**
+         * Callback called when application registration state changes. Usually it's called due to
+         * either {@link BluetoothHidDevice#registerApp (String, String, String, byte, byte[],
+         * Executor, Callback)} or {@link BluetoothHidDevice#unregisterApp()} , but can be also
+         * unsolicited in case e.g. Bluetooth was turned off in which case application is
+         * unregistered automatically.
+         *
+         * @param pluggedDevice {@link BluetoothDevice} object which represents host that currently
+         *     has Virtual Cable established with device. Only valid when application is registered,
+         *     can be <code>null</code>.
+         * @param registered <code>true</code> if application is registered, <code>false</code>
+         *     otherwise.
+         */
+        public void onAppStatusChanged(BluetoothDevice pluggedDevice, boolean registered) {
+            Log.d(
+                    TAG,
+                    "onAppStatusChanged: pluggedDevice="
+                            + pluggedDevice
+                            + " registered="
+                            + registered);
+        }
+
+        /**
+         * Callback called when connection state with remote host was changed. Application can
+         * assume than Virtual Cable is established when called with {@link
+         * BluetoothProfile#STATE_CONNECTED} <code>state</code>.
+         *
+         * @param device {@link BluetoothDevice} object representing host device which connection
+         *     state was changed.
+         * @param state Connection state as defined in {@link BluetoothProfile}.
+         */
+        public void onConnectionStateChanged(BluetoothDevice device, int state) {
+            Log.d(TAG, "onConnectionStateChanged: device=" + device + " state=" + state);
+        }
+
+        /**
+         * Callback called when GET_REPORT is received from remote host. Should be replied by
+         * application using {@link BluetoothHidDevice#replyReport(BluetoothDevice, byte, byte,
+         * byte[])}.
+         *
+         * @param type Requested Report Type.
+         * @param id Requested Report Id, can be 0 if no Report Id are defined in descriptor.
+         * @param bufferSize Requested buffer size, application shall respond with at least given
+         *     number of bytes.
+         */
+        public void onGetReport(BluetoothDevice device, byte type, byte id, int bufferSize) {
+            Log.d(
+                    TAG,
+                    "onGetReport: device="
+                            + device
+                            + " type="
+                            + type
+                            + " id="
+                            + id
+                            + " bufferSize="
+                            + bufferSize);
+        }
+
+        /**
+         * Callback called when SET_REPORT is received from remote host. In case received data are
+         * invalid, application shall respond with {@link
+         * BluetoothHidDevice#reportError(BluetoothDevice, byte)}.
+         *
+         * @param type Report Type.
+         * @param id Report Id.
+         * @param data Report data.
+         */
+        public void onSetReport(BluetoothDevice device, byte type, byte id, byte[] data) {
+            Log.d(TAG, "onSetReport: device=" + device + " type=" + type + " id=" + id);
+        }
+
+        /**
+         * Callback called when SET_PROTOCOL is received from remote host. Application shall use
+         * this information to send only reports valid for given protocol mode. By default, {@link
+         * BluetoothHidDevice#PROTOCOL_REPORT_MODE} shall be assumed.
+         *
+         * @param protocol Protocol Mode.
+         */
+        public void onSetProtocol(BluetoothDevice device, byte protocol) {
+            Log.d(TAG, "onSetProtocol: device=" + device + " protocol=" + protocol);
+        }
+
+        /**
+         * Callback called when report data is received over interrupt channel. Report Type is
+         * assumed to be {@link BluetoothHidDevice#REPORT_TYPE_OUTPUT}.
+         *
+         * @param reportId Report Id.
+         * @param data Report data.
+         */
+        public void onInterruptData(BluetoothDevice device, byte reportId, byte[] data) {
+            Log.d(TAG, "onInterruptData: device=" + device + " reportId=" + reportId);
+        }
+
+        /**
+         * Callback called when Virtual Cable is removed. After this callback is received connection
+         * will be disconnected automatically.
+         */
+        public void onVirtualCableUnplug(BluetoothDevice device) {
+            Log.d(TAG, "onVirtualCableUnplug: device=" + device);
+        }
+    }
+
     private Context mContext;
-
     private ServiceListener mServiceListener;
-
     private volatile IBluetoothHidDevice mService;
-
     private BluetoothAdapter mAdapter;
 
-    private static class BluetoothHidDeviceCallbackWrapper
-            extends IBluetoothHidDeviceCallback.Stub {
+    private static class CallbackWrapper extends IBluetoothHidDeviceCallback.Stub {
 
-        private BluetoothHidDeviceCallback mCallback;
+        private final Executor mExecutor;
+        private final Callback mCallback;
 
-        public BluetoothHidDeviceCallbackWrapper(BluetoothHidDeviceCallback callback) {
+        CallbackWrapper(Executor executor, Callback callback) {
+            mExecutor = executor;
             mCallback = callback;
         }
 
         @Override
         public void onAppStatusChanged(BluetoothDevice pluggedDevice, boolean registered) {
-            mCallback.onAppStatusChanged(pluggedDevice, registered);
+            clearCallingIdentity();
+            mExecutor.execute(() -> mCallback.onAppStatusChanged(pluggedDevice, registered));
         }
 
         @Override
         public void onConnectionStateChanged(BluetoothDevice device, int state) {
-            mCallback.onConnectionStateChanged(device, state);
+            clearCallingIdentity();
+            mExecutor.execute(() -> mCallback.onConnectionStateChanged(device, state));
         }
 
         @Override
         public void onGetReport(BluetoothDevice device, byte type, byte id, int bufferSize) {
-            mCallback.onGetReport(device, type, id, bufferSize);
+            clearCallingIdentity();
+            mExecutor.execute(() -> mCallback.onGetReport(device, type, id, bufferSize));
         }
 
         @Override
         public void onSetReport(BluetoothDevice device, byte type, byte id, byte[] data) {
-            mCallback.onSetReport(device, type, id, data);
+            clearCallingIdentity();
+            mExecutor.execute(() -> mCallback.onSetReport(device, type, id, data));
         }
 
         @Override
         public void onSetProtocol(BluetoothDevice device, byte protocol) {
-            mCallback.onSetProtocol(device, protocol);
+            clearCallingIdentity();
+            mExecutor.execute(() -> mCallback.onSetProtocol(device, protocol));
         }
 
         @Override
         public void onInterruptData(BluetoothDevice device, byte reportId, byte[] data) {
-            mCallback.onInterruptData(device, reportId, data);
+            clearCallingIdentity();
+            mExecutor.execute(() -> mCallback.onInterruptData(device, reportId, data));
         }
 
         @Override
         public void onVirtualCableUnplug(BluetoothDevice device) {
-            mCallback.onVirtualCableUnplug(device);
+            clearCallingIdentity();
+            mExecutor.execute(() -> mCallback.onVirtualCableUnplug(device));
         }
     }
 
@@ -213,8 +433,6 @@
             };
 
     BluetoothHidDevice(Context context, ServiceListener listener) {
-        Log.v(TAG, "BluetoothHidDevice");
-
         mContext = context;
         mServiceListener = listener;
         mAdapter = BluetoothAdapter.getDefaultAdapter();
@@ -245,7 +463,6 @@
     }
 
     void doUnbind() {
-        Log.d(TAG, "Unbinding HidDevService");
         if (mService != null) {
             mService = null;
             try {
@@ -257,8 +474,6 @@
     }
 
     void close() {
-        Log.v(TAG, "close()");
-
         IBluetoothManager mgr = mAdapter.getBluetoothManager();
         if (mgr != null) {
             try {
@@ -277,8 +492,6 @@
     /** {@inheritDoc} */
     @Override
     public List<BluetoothDevice> getConnectedDevices() {
-        Log.v(TAG, "getConnectedDevices()");
-
         final IBluetoothHidDevice service = mService;
         if (service != null) {
             try {
@@ -290,14 +503,12 @@
             Log.w(TAG, "Proxy not attached to service");
         }
 
-        return new ArrayList<BluetoothDevice>();
+        return new ArrayList<>();
     }
 
     /** {@inheritDoc} */
     @Override
     public List<BluetoothDevice> getDevicesMatchingConnectionStates(int[] states) {
-        Log.v(TAG, "getDevicesMatchingConnectionStates(): states=" + Arrays.toString(states));
-
         final IBluetoothHidDevice service = mService;
         if (service != null) {
             try {
@@ -309,14 +520,12 @@
             Log.w(TAG, "Proxy not attached to service");
         }
 
-        return new ArrayList<BluetoothDevice>();
+        return new ArrayList<>();
     }
 
     /** {@inheritDoc} */
     @Override
     public int getConnectionState(BluetoothDevice device) {
-        Log.v(TAG, "getConnectionState(): device=" + device);
-
         final IBluetoothHidDevice service = mService;
         if (service != null) {
             try {
@@ -336,9 +545,9 @@
      * when application is registered. Only one application can be registered at one time. When an
      * application is registered, the HID Host service will be disabled until it is unregistered.
      * When no longer used, application should be unregistered using {@link #unregisterApp()}. The
-     * registration status should be tracked by the application by handling callback from
-     * BluetoothHidDeviceCallback#onAppStatusChanged. The app registration status is not related to
-     * the return value of this method.
+     * app will be automatically unregistered if it is not foreground. The registration status
+     * should be tracked by the application by handling callback from Callback#onAppStatusChanged.
+     * The app registration status is not related to the return value of this method.
      *
      * @param sdp {@link BluetoothHidDeviceAppSdpSettings} object of HID Device SDP record. The HID
      *     Device SDP record is required.
@@ -348,27 +557,36 @@
      * @param outQos {@link BluetoothHidDeviceAppQosSettings} object of Outgoing QoS Settings. The
      *     Outgoing QoS Settings is not required. Use null or default
      *     BluetoothHidDeviceAppQosSettings.Builder for default values.
-     * @param callback {@link BluetoothHidDeviceCallback} object to which callback messages will be
-     *     sent. The BluetoothHidDeviceCallback object is required.
+     * @param executor {@link Executor} object on which callback will be executed. The Executor
+     *     object is required.
+     * @param callback {@link Callback} object to which callback messages will be sent. The Callback
+     *     object is required.
      * @return true if the command is successfully sent; otherwise false.
      */
-    public boolean registerApp(BluetoothHidDeviceAppSdpSettings sdp,
-            BluetoothHidDeviceAppQosSettings inQos, BluetoothHidDeviceAppQosSettings outQos,
-            BluetoothHidDeviceCallback callback) {
-        Log.v(TAG, "registerApp(): sdp=" + sdp + " inQos=" + inQos + " outQos=" + outQos
-                        + " callback=" + callback);
-
+    public boolean registerApp(
+            BluetoothHidDeviceAppSdpSettings sdp,
+            BluetoothHidDeviceAppQosSettings inQos,
+            BluetoothHidDeviceAppQosSettings outQos,
+            Executor executor,
+            Callback callback) {
         boolean result = false;
 
-        if (sdp == null || callback == null) {
-            return false;
+        if (sdp == null) {
+            throw new IllegalArgumentException("sdp parameter cannot be null");
+        }
+
+        if (executor == null) {
+            throw new IllegalArgumentException("executor parameter cannot be null");
+        }
+
+        if (callback == null) {
+            throw new IllegalArgumentException("callback parameter cannot be null");
         }
 
         final IBluetoothHidDevice service = mService;
         if (service != null) {
             try {
-                BluetoothHidDeviceCallbackWrapper cbw =
-                        new BluetoothHidDeviceCallbackWrapper(callback);
+                CallbackWrapper cbw = new CallbackWrapper(executor, callback);
                 result = service.registerApp(sdp, inQos, outQos, cbw);
             } catch (RemoteException e) {
                 Log.e(TAG, e.toString());
@@ -384,16 +602,13 @@
      * Unregisters application. Active connection will be disconnected and no new connections will
      * be allowed until registered again using {@link #registerApp
      * (BluetoothHidDeviceAppQosSettings, BluetoothHidDeviceAppQosSettings,
-     * BluetoothHidDeviceAppQosSettings, BluetoothHidDeviceCallback)} The registration status should
-     * be tracked by the application by handling callback from
-     * BluetoothHidDeviceCallback#onAppStatusChanged. The app registration status is not related to
-     * the return value of this method.
+     * BluetoothHidDeviceAppQosSettings, Executor, Callback)}. The registration status should be
+     * tracked by the application by handling callback from Callback#onAppStatusChanged. The app
+     * registration status is not related to the return value of this method.
      *
      * @return true if the command is successfully sent; otherwise false.
      */
     public boolean unregisterApp() {
-        Log.v(TAG, "unregisterApp()");
-
         boolean result = false;
 
         final IBluetoothHidDevice service = mService;
@@ -437,7 +652,7 @@
 
     /**
      * Sends report to remote host as reply for GET_REPORT request from {@link
-     * BluetoothHidDeviceCallback#onGetReport(BluetoothDevice, byte, byte, int)}.
+     * Callback#onGetReport(BluetoothDevice, byte, byte, int)}.
      *
      * @param type Report Type, as in request.
      * @param id Report Id, as in request.
@@ -445,8 +660,6 @@
      * @return true if the command is successfully sent; otherwise false.
      */
     public boolean replyReport(BluetoothDevice device, byte type, byte id, byte[] data) {
-        Log.v(TAG, "replyReport(): device=" + device + " type=" + type + " id=" + id);
-
         boolean result = false;
 
         final IBluetoothHidDevice service = mService;
@@ -465,14 +678,12 @@
 
     /**
      * Sends error handshake message as reply for invalid SET_REPORT request from {@link
-     * BluetoothHidDeviceCallback#onSetReport(BluetoothDevice, byte, byte, byte[])}.
+     * Callback#onSetReport(BluetoothDevice, byte, byte, byte[])}.
      *
      * @param error Error to be sent for SET_REPORT via HANDSHAKE.
      * @return true if the command is successfully sent; otherwise false.
      */
     public boolean reportError(BluetoothDevice device, byte error) {
-        Log.v(TAG, "reportError(): device=" + device + " error=" + error);
-
         boolean result = false;
 
         final IBluetoothHidDevice service = mService;
@@ -496,8 +707,6 @@
      * {@hide}
      */
     public boolean unplug(BluetoothDevice device) {
-        Log.v(TAG, "unplug(): device=" + device);
-
         boolean result = false;
 
         final IBluetoothHidDevice service = mService;
@@ -517,15 +726,12 @@
     /**
      * Initiates connection to host which is currently paired with this device. If the application
      * is not registered, #connect(BluetoothDevice) will fail. The connection state should be
-     * tracked by the application by handling callback from
-     * BluetoothHidDeviceCallback#onConnectionStateChanged. The connection state is not related to
-     * the return value of this method.
+     * tracked by the application by handling callback from Callback#onConnectionStateChanged. The
+     * connection state is not related to the return value of this method.
      *
      * @return true if the command is successfully sent; otherwise false.
      */
     public boolean connect(BluetoothDevice device) {
-        Log.v(TAG, "connect(): device=" + device);
-
         boolean result = false;
 
         final IBluetoothHidDevice service = mService;
@@ -544,14 +750,12 @@
 
     /**
      * Disconnects from currently connected host. The connection state should be tracked by the
-     * application by handling callback from BluetoothHidDeviceCallback#onConnectionStateChanged.
-     * The connection state is not related to the return value of this method.
+     * application by handling callback from Callback#onConnectionStateChanged. The connection state
+     * is not related to the return value of this method.
      *
      * @return true if the command is successfully sent; otherwise false.
      */
     public boolean disconnect(BluetoothDevice device) {
-        Log.v(TAG, "disconnect(): device=" + device);
-
         boolean result = false;
 
         final IBluetoothHidDevice service = mService;
diff --git a/core/java/android/bluetooth/BluetoothHidDeviceAppQosSettings.java b/core/java/android/bluetooth/BluetoothHidDeviceAppQosSettings.java
index c05df2d..a485b89 100644
--- a/core/java/android/bluetooth/BluetoothHidDeviceAppQosSettings.java
+++ b/core/java/android/bluetooth/BluetoothHidDeviceAppQosSettings.java
@@ -29,12 +29,12 @@
  */
 public final class BluetoothHidDeviceAppQosSettings implements Parcelable {
 
-    public final int serviceType;
-    public final int tokenRate;
-    public final int tokenBucketSize;
-    public final int peakBandwidth;
-    public final int latency;
-    public final int delayVariation;
+    private final int mServiceType;
+    private final int mTokenRate;
+    private final int mTokenBucketSize;
+    private final int mPeakBandwidth;
+    private final int mLatency;
+    private final int mDelayVariation;
 
     public static final int SERVICE_NO_TRAFFIC = 0x00;
     public static final int SERVICE_BEST_EFFORT = 0x01;
@@ -44,38 +44,53 @@
 
     /**
      * Create a BluetoothHidDeviceAppQosSettings object for the Bluetooth L2CAP channel. The QoS
-     * Settings is optional. Recommended to use BluetoothHidDeviceAppQosSettings.Builder.
-     * Please refer to Bluetooth HID Specfication v1.1.1 Section 5.2 and Appendix D for parameters.
+     * Settings is optional. Please refer to Bluetooth HID Specfication v1.1.1 Section 5.2 and
+     * Appendix D for parameters.
      *
-     * @param serviceType L2CAP service type
-     * @param tokenRate L2CAP token rate
-     * @param tokenBucketSize L2CAP token bucket size
-     * @param peakBandwidth L2CAP peak bandwidth
-     * @param latency L2CAP latency
-     * @param delayVariation L2CAP delay variation
+     * @param serviceType L2CAP service type, default = SERVICE_BEST_EFFORT
+     * @param tokenRate L2CAP token rate, default = 0
+     * @param tokenBucketSize L2CAP token bucket size, default = 0
+     * @param peakBandwidth L2CAP peak bandwidth, default = 0
+     * @param latency L2CAP latency, default = MAX
+     * @param delayVariation L2CAP delay variation, default = MAX
      */
-    public BluetoothHidDeviceAppQosSettings(int serviceType, int tokenRate, int tokenBucketSize,
-            int peakBandwidth, int latency, int delayVariation) {
-        this.serviceType = serviceType;
-        this.tokenRate = tokenRate;
-        this.tokenBucketSize = tokenBucketSize;
-        this.peakBandwidth = peakBandwidth;
-        this.latency = latency;
-        this.delayVariation = delayVariation;
+    public BluetoothHidDeviceAppQosSettings(
+            int serviceType,
+            int tokenRate,
+            int tokenBucketSize,
+            int peakBandwidth,
+            int latency,
+            int delayVariation) {
+        mServiceType = serviceType;
+        mTokenRate = tokenRate;
+        mTokenBucketSize = tokenBucketSize;
+        mPeakBandwidth = peakBandwidth;
+        mLatency = latency;
+        mDelayVariation = delayVariation;
     }
 
-    @Override
-    public boolean equals(Object o) {
-        if (o instanceof BluetoothHidDeviceAppQosSettings) {
-            BluetoothHidDeviceAppQosSettings qos = (BluetoothHidDeviceAppQosSettings) o;
-            return this.serviceType == qos.serviceType
-                    && this.tokenRate == qos.tokenRate
-                    && this.tokenBucketSize == qos.tokenBucketSize
-                    && this.peakBandwidth == qos.peakBandwidth
-                    && this.latency == qos.latency
-                    && this.delayVariation == qos.delayVariation;
-        }
-        return false;
+    public int getServiceType() {
+        return mServiceType;
+    }
+
+    public int getTokenRate() {
+        return mTokenRate;
+    }
+
+    public int getTokenBucketSize() {
+        return mTokenBucketSize;
+    }
+
+    public int getPeakBandwidth() {
+        return mPeakBandwidth;
+    }
+
+    public int getLatency() {
+        return mLatency;
+    }
+
+    public int getDelayVariation() {
+        return mDelayVariation;
     }
 
     @Override
@@ -106,104 +121,11 @@
 
     @Override
     public void writeToParcel(Parcel out, int flags) {
-        out.writeInt(serviceType);
-        out.writeInt(tokenRate);
-        out.writeInt(tokenBucketSize);
-        out.writeInt(peakBandwidth);
-        out.writeInt(latency);
-        out.writeInt(delayVariation);
-    }
-
-    /** @return an int array representation of this instance */
-    public int[] toArray() {
-        return new int[] {
-            serviceType, tokenRate, tokenBucketSize, peakBandwidth, latency, delayVariation
-        };
-    }
-
-    /** A helper to build the BluetoothHidDeviceAppQosSettings object. */
-    public static class Builder {
-        // Optional parameters - initialized to default values
-        private int mServiceType = SERVICE_BEST_EFFORT;
-        private int mTokenRate = 0;
-        private int mTokenBucketSize = 0;
-        private int mPeakBandwidth = 0;
-        private int mLatency = MAX;
-        private int mDelayVariation = MAX;
-
-        /**
-         * Set the service type.
-         *
-         * @param val service type. Should be one of {SERVICE_NO_TRAFFIC, SERVICE_BEST_EFFORT,
-         *     SERVICE_GUARANTEED}, with SERVICE_BEST_EFFORT being the default one.
-         * @return BluetoothHidDeviceAppQosSettings Builder with specified service type.
-         */
-        public Builder serviceType(int val) {
-            mServiceType = val;
-            return this;
-        }
-        /**
-         * Set the token rate.
-         *
-         * @param val token rate
-         * @return BluetoothHidDeviceAppQosSettings Builder with specified token rate.
-         */
-        public Builder tokenRate(int val) {
-            mTokenRate = val;
-            return this;
-        }
-
-        /**
-         * Set the bucket size.
-         *
-         * @param val bucket size
-         * @return BluetoothHidDeviceAppQosSettings Builder with specified bucket size.
-         */
-        public Builder tokenBucketSize(int val) {
-            mTokenBucketSize = val;
-            return this;
-        }
-
-        /**
-         * Set the peak bandwidth.
-         *
-         * @param val peak bandwidth
-         * @return BluetoothHidDeviceAppQosSettings Builder with specified peak bandwidth.
-         */
-        public Builder peakBandwidth(int val) {
-            mPeakBandwidth = val;
-            return this;
-        }
-        /**
-         * Set the latency.
-         *
-         * @param val latency
-         * @return BluetoothHidDeviceAppQosSettings Builder with specified latency.
-         */
-        public Builder latency(int val) {
-            mLatency = val;
-            return this;
-        }
-
-        /**
-         * Set the delay variation.
-         *
-         * @param val delay variation
-         * @return BluetoothHidDeviceAppQosSettings Builder with specified delay variation.
-         */
-        public Builder delayVariation(int val) {
-            mDelayVariation = val;
-            return this;
-        }
-
-        /**
-         * Build the BluetoothHidDeviceAppQosSettings object.
-         *
-         * @return BluetoothHidDeviceAppQosSettings object with current settings.
-         */
-        public BluetoothHidDeviceAppQosSettings build() {
-            return new BluetoothHidDeviceAppQosSettings(mServiceType, mTokenRate, mTokenBucketSize,
-                    mPeakBandwidth, mLatency, mDelayVariation);
-        }
+        out.writeInt(mServiceType);
+        out.writeInt(mTokenRate);
+        out.writeInt(mTokenBucketSize);
+        out.writeInt(mPeakBandwidth);
+        out.writeInt(mLatency);
+        out.writeInt(mDelayVariation);
     }
 }
diff --git a/core/java/android/bluetooth/BluetoothHidDeviceAppSdpSettings.java b/core/java/android/bluetooth/BluetoothHidDeviceAppSdpSettings.java
index 562c559..237082e 100644
--- a/core/java/android/bluetooth/BluetoothHidDeviceAppSdpSettings.java
+++ b/core/java/android/bluetooth/BluetoothHidDeviceAppSdpSettings.java
@@ -19,7 +19,6 @@
 import android.os.Parcel;
 import android.os.Parcelable;
 
-import java.util.Arrays;
 
 /**
  * Represents the Service Discovery Protocol (SDP) settings for a Bluetooth HID Device application.
@@ -31,11 +30,11 @@
  */
 public final class BluetoothHidDeviceAppSdpSettings implements Parcelable {
 
-    public final String name;
-    public final String description;
-    public final String provider;
-    public final byte subclass;
-    public final byte[] descriptors;
+    private final String mName;
+    private final String mDescription;
+    private final String mProvider;
+    private final byte mSubclass;
+    private final byte[] mDescriptors;
 
     /**
      * Create a BluetoothHidDeviceAppSdpSettings object for the Bluetooth SDP record.
@@ -52,24 +51,31 @@
      */
     public BluetoothHidDeviceAppSdpSettings(
             String name, String description, String provider, byte subclass, byte[] descriptors) {
-        this.name = name;
-        this.description = description;
-        this.provider = provider;
-        this.subclass = subclass;
-        this.descriptors = descriptors.clone();
+        mName = name;
+        mDescription = description;
+        mProvider = provider;
+        mSubclass = subclass;
+        mDescriptors = descriptors.clone();
     }
 
-    @Override
-    public boolean equals(Object o) {
-        if (o instanceof BluetoothHidDeviceAppSdpSettings) {
-            BluetoothHidDeviceAppSdpSettings sdp = (BluetoothHidDeviceAppSdpSettings) o;
-            return this.name.equals(sdp.name)
-                    && this.description.equals(sdp.description)
-                    && this.provider.equals(sdp.provider)
-                    && this.subclass == sdp.subclass
-                    && Arrays.equals(this.descriptors, sdp.descriptors);
-        }
-        return false;
+    public String getName() {
+        return mName;
+    }
+
+    public String getDescription() {
+        return mDescription;
+    }
+
+    public String getProvider() {
+        return mProvider;
+    }
+
+    public byte getSubclass() {
+        return mSubclass;
+    }
+
+    public byte[] getDescriptors() {
+        return mDescriptors;
     }
 
     @Override
@@ -99,10 +105,10 @@
 
     @Override
     public void writeToParcel(Parcel out, int flags) {
-        out.writeString(name);
-        out.writeString(description);
-        out.writeString(provider);
-        out.writeByte(subclass);
-        out.writeByteArray(descriptors);
+        out.writeString(mName);
+        out.writeString(mDescription);
+        out.writeString(mProvider);
+        out.writeByte(mSubclass);
+        out.writeByteArray(mDescriptors);
     }
 }
diff --git a/core/java/android/bluetooth/BluetoothHidDeviceCallback.java b/core/java/android/bluetooth/BluetoothHidDeviceCallback.java
deleted file mode 100644
index e71b00f..0000000
--- a/core/java/android/bluetooth/BluetoothHidDeviceCallback.java
+++ /dev/null
@@ -1,120 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.bluetooth;
-
-import android.util.Log;
-
-/**
- * The template class that applications use to call callback functions on events from the HID host.
- * Callback functions are wrapped in this class and registered to the Android system during app
- * registration.
- *
- * <p>{@see BluetoothHidDevice}
- */
-public abstract class BluetoothHidDeviceCallback {
-
-    private static final String TAG = "BluetoothHidDevCallback";
-
-    /**
-     * Callback called when application registration state changes. Usually it's called due to
-     * either {@link BluetoothHidDevice#registerApp (String, String, String, byte, byte[],
-     * BluetoothHidDeviceCallback)} or {@link BluetoothHidDevice#unregisterApp()} , but can be also
-     * unsolicited in case e.g. Bluetooth was turned off in which case application is unregistered
-     * automatically.
-     *
-     * @param pluggedDevice {@link BluetoothDevice} object which represents host that currently has
-     *     Virtual Cable established with device. Only valid when application is registered, can be
-     *     <code>null</code>.
-     * @param registered <code>true</code> if application is registered, <code>false</code>
-     *     otherwise.
-     */
-    public void onAppStatusChanged(BluetoothDevice pluggedDevice, boolean registered) {
-        Log.d(TAG,
-                "onAppStatusChanged: pluggedDevice=" + pluggedDevice + " registered=" + registered);
-    }
-
-    /**
-     * Callback called when connection state with remote host was changed. Application can assume
-     * than Virtual Cable is established when called with {@link BluetoothProfile#STATE_CONNECTED}
-     * <code>state</code>.
-     *
-     * @param device {@link BluetoothDevice} object representing host device which connection state
-     *     was changed.
-     * @param state Connection state as defined in {@link BluetoothProfile}.
-     */
-    public void onConnectionStateChanged(BluetoothDevice device, int state) {
-        Log.d(TAG, "onConnectionStateChanged: device=" + device + " state=" + state);
-    }
-
-    /**
-     * Callback called when GET_REPORT is received from remote host. Should be replied by
-     * application using {@link BluetoothHidDevice#replyReport(BluetoothDevice, byte, byte,
-     * byte[])}.
-     *
-     * @param type Requested Report Type.
-     * @param id Requested Report Id, can be 0 if no Report Id are defined in descriptor.
-     * @param bufferSize Requested buffer size, application shall respond with at least given number
-     *     of bytes.
-     */
-    public void onGetReport(BluetoothDevice device, byte type, byte id, int bufferSize) {
-        Log.d(TAG, "onGetReport: device=" + device + " type=" + type + " id=" + id + " bufferSize="
-                + bufferSize);
-    }
-
-    /**
-     * Callback called when SET_REPORT is received from remote host. In case received data are
-     * invalid, application shall respond with {@link
-     * BluetoothHidDevice#reportError(BluetoothDevice, byte)}.
-     *
-     * @param type Report Type.
-     * @param id Report Id.
-     * @param data Report data.
-     */
-    public void onSetReport(BluetoothDevice device, byte type, byte id, byte[] data) {
-        Log.d(TAG, "onSetReport: device=" + device + " type=" + type + " id=" + id);
-    }
-
-    /**
-     * Callback called when SET_PROTOCOL is received from remote host. Application shall use this
-     * information to send only reports valid for given protocol mode. By default, {@link
-     * BluetoothHidDevice#PROTOCOL_REPORT_MODE} shall be assumed.
-     *
-     * @param protocol Protocol Mode.
-     */
-    public void onSetProtocol(BluetoothDevice device, byte protocol) {
-        Log.d(TAG, "onSetProtocol: device=" + device + " protocol=" + protocol);
-    }
-
-    /**
-     * Callback called when report data is received over interrupt channel. Report Type is assumed
-     * to be {@link BluetoothHidDevice#REPORT_TYPE_OUTPUT}.
-     *
-     * @param reportId Report Id.
-     * @param data Report data.
-     */
-    public void onInterruptData(BluetoothDevice device, byte reportId, byte[] data) {
-        Log.d(TAG, "onInterruptData: device=" + device + " reportId=" + reportId);
-    }
-
-    /**
-     * Callback called when Virtual Cable is removed. After this callback is
-     * received connection will be disconnected automatically.
-     */
-    public void onVirtualCableUnplug(BluetoothDevice device) {
-        Log.d(TAG, "onVirtualCableUnplug: device=" + device);
-    }
-}
diff --git a/core/java/android/net/INetworkStatsService.aidl b/core/java/android/net/INetworkStatsService.aidl
index 90e3ffd..eab7041 100644
--- a/core/java/android/net/INetworkStatsService.aidl
+++ b/core/java/android/net/INetworkStatsService.aidl
@@ -44,6 +44,16 @@
 
     /** Return data layer snapshot of UID network usage. */
     NetworkStats getDataLayerSnapshotForUid(int uid);
+
+    /** Get a detailed snapshot of stats since boot for all UIDs.
+    *
+    * <p>Results will not always be limited to stats on requiredIfaces when specified: stats for
+    * interfaces stacked on the specified interfaces, or for interfaces on which the specified
+    * interfaces are stacked on, will also be included.
+    * @param requiredIfaces Interface names to get data for, or {@link NetworkStats#INTERFACES_ALL}.
+    */
+    NetworkStats getDetailedUidStats(in String[] requiredIfaces);
+
     /** Return set of any ifaces associated with mobile networks since boot. */
     String[] getMobileIfaces();
 
diff --git a/core/java/android/net/IpSecAlgorithm.java b/core/java/android/net/IpSecAlgorithm.java
index f4b328e..57f0588 100644
--- a/core/java/android/net/IpSecAlgorithm.java
+++ b/core/java/android/net/IpSecAlgorithm.java
@@ -129,7 +129,7 @@
      * @param algorithm name of the algorithm.
      * @param key key padded to a multiple of 8 bits.
      */
-    public IpSecAlgorithm(@AlgorithmName String algorithm, @NonNull byte[] key) {
+    public IpSecAlgorithm(@NonNull @AlgorithmName String algorithm, @NonNull byte[] key) {
         this(algorithm, key, key.length * 8);
     }
 
@@ -144,7 +144,8 @@
      * @param key key padded to a multiple of 8 bits.
      * @param truncLenBits number of bits of output hash to use.
      */
-    public IpSecAlgorithm(@AlgorithmName String algorithm, @NonNull byte[] key, int truncLenBits) {
+    public IpSecAlgorithm(
+            @NonNull @AlgorithmName String algorithm, @NonNull byte[] key, int truncLenBits) {
         mName = algorithm;
         mKey = key.clone();
         mTruncLenBits = truncLenBits;
@@ -152,11 +153,13 @@
     }
 
     /** Get the algorithm name */
+    @NonNull
     public String getName() {
         return mName;
     }
 
     /** Get the key for this algorithm */
+    @NonNull
     public byte[] getKey() {
         return mKey.clone();
     }
@@ -270,6 +273,7 @@
     }
 
     @Override
+    @NonNull
     public String toString() {
         return new StringBuilder()
                 .append("{mName=")
diff --git a/core/java/android/net/IpSecManager.java b/core/java/android/net/IpSecManager.java
index cb4299e..4157845 100644
--- a/core/java/android/net/IpSecManager.java
+++ b/core/java/android/net/IpSecManager.java
@@ -253,8 +253,9 @@
      * @throws {@link #ResourceUnavailableException} indicating that too many SPIs are
      *     currently allocated for this user
      */
-    public SecurityParameterIndex allocateSecurityParameterIndex(InetAddress destinationAddress)
-            throws ResourceUnavailableException {
+    @NonNull
+    public SecurityParameterIndex allocateSecurityParameterIndex(
+                @NonNull InetAddress destinationAddress) throws ResourceUnavailableException {
         try {
             return new SecurityParameterIndex(
                     mService,
@@ -280,8 +281,9 @@
      * @throws {@link #SpiUnavailableException} indicating that the requested SPI could not be
      *     reserved
      */
+    @NonNull
     public SecurityParameterIndex allocateSecurityParameterIndex(
-            InetAddress destinationAddress, int requestedSpi)
+            @NonNull InetAddress destinationAddress, int requestedSpi)
             throws SpiUnavailableException, ResourceUnavailableException {
         if (requestedSpi == IpSecManager.INVALID_SECURITY_PARAMETER_INDEX) {
             throw new IllegalArgumentException("Requested SPI must be a valid (non-zero) SPI");
@@ -318,9 +320,8 @@
      * @param transform a transport mode {@code IpSecTransform}
      * @throws IOException indicating that the transform could not be applied
      */
-    public void applyTransportModeTransform(
-            Socket socket, @PolicyDirection int direction, IpSecTransform transform)
-            throws IOException {
+    public void applyTransportModeTransform(@NonNull Socket socket,
+            @PolicyDirection int direction, @NonNull IpSecTransform transform) throws IOException {
         applyTransportModeTransform(socket.getFileDescriptor$(), direction, transform);
     }
 
@@ -353,9 +354,8 @@
      * @param transform a transport mode {@code IpSecTransform}
      * @throws IOException indicating that the transform could not be applied
      */
-    public void applyTransportModeTransform(
-            DatagramSocket socket, @PolicyDirection int direction, IpSecTransform transform)
-            throws IOException {
+    public void applyTransportModeTransform(@NonNull DatagramSocket socket,
+            @PolicyDirection int direction, @NonNull IpSecTransform transform) throws IOException {
         applyTransportModeTransform(socket.getFileDescriptor$(), direction, transform);
     }
 
@@ -388,9 +388,8 @@
      * @param transform a transport mode {@code IpSecTransform}
      * @throws IOException indicating that the transform could not be applied
      */
-    public void applyTransportModeTransform(
-            FileDescriptor socket, @PolicyDirection int direction, IpSecTransform transform)
-            throws IOException {
+    public void applyTransportModeTransform(@NonNull FileDescriptor socket,
+            @PolicyDirection int direction, @NonNull IpSecTransform transform) throws IOException {
         // We dup() the FileDescriptor here because if we don't, then the ParcelFileDescriptor()
         // constructor takes control and closes the user's FD when we exit the method.
         try (ParcelFileDescriptor pfd = ParcelFileDescriptor.dup(socket)) {
@@ -413,8 +412,7 @@
      * @param socket a socket that previously had a transform applied to it
      * @throws IOException indicating that the transform could not be removed from the socket
      */
-    public void removeTransportModeTransforms(Socket socket)
-            throws IOException {
+    public void removeTransportModeTransforms(@NonNull Socket socket) throws IOException {
         removeTransportModeTransforms(socket.getFileDescriptor$());
     }
 
@@ -431,8 +429,7 @@
      * @param socket a socket that previously had a transform applied to it
      * @throws IOException indicating that the transform could not be removed from the socket
      */
-    public void removeTransportModeTransforms(DatagramSocket socket)
-            throws IOException {
+    public void removeTransportModeTransforms(@NonNull DatagramSocket socket) throws IOException {
         removeTransportModeTransforms(socket.getFileDescriptor$());
     }
 
@@ -449,8 +446,7 @@
      * @param socket a socket that previously had a transform applied to it
      * @throws IOException indicating that the transform could not be removed from the socket
      */
-    public void removeTransportModeTransforms(FileDescriptor socket)
-            throws IOException {
+    public void removeTransportModeTransforms(@NonNull FileDescriptor socket) throws IOException {
         try (ParcelFileDescriptor pfd = ParcelFileDescriptor.dup(socket)) {
             mService.removeTransportModeTransforms(pfd);
         } catch (RemoteException e) {
@@ -588,6 +584,7 @@
     // safely usable for Encapsulation without allowing a user to possibly unbind from/close
     // the port, which could potentially impact the traffic of the next user who binds to that
     // socket.
+    @NonNull
     public UdpEncapsulationSocket openUdpEncapsulationSocket(int port)
             throws IOException, ResourceUnavailableException {
         /*
@@ -617,6 +614,7 @@
     // safely usable for Encapsulation without allowing a user to possibly unbind from/close
     // the port, which could potentially impact the traffic of the next user who binds to that
     // socket.
+    @NonNull
     public UdpEncapsulationSocket openUdpEncapsulationSocket()
             throws IOException, ResourceUnavailableException {
         return new UdpEncapsulationSocket(mService, 0);
@@ -645,6 +643,7 @@
         private int mResourceId = INVALID_RESOURCE_ID;
 
         /** Get the underlying SPI held by this object. */
+        @NonNull
         public String getInterfaceName() {
             return mInterfaceName;
         }
@@ -659,7 +658,7 @@
          * @hide
          */
         @SystemApi
-        public void addAddress(LinkAddress address) throws IOException {
+        public void addAddress(@NonNull LinkAddress address) throws IOException {
             try {
                 mService.addAddressToTunnelInterface(mResourceId, address);
             } catch (RemoteException e) {
@@ -676,7 +675,7 @@
          * @hide
          */
         @SystemApi
-        public void removeAddress(LinkAddress address) throws IOException {
+        public void removeAddress(@NonNull LinkAddress address) throws IOException {
             try {
                 mService.removeAddressFromTunnelInterface(mResourceId, address);
             } catch (RemoteException e) {
@@ -768,6 +767,7 @@
      * @hide
      */
     @SystemApi
+    @NonNull
     @RequiresPermission(android.Manifest.permission.NETWORK_STACK)
     public IpSecTunnelInterface createIpSecTunnelInterface(@NonNull InetAddress localAddress,
             @NonNull InetAddress remoteAddress, @NonNull Network underlyingNetwork)
@@ -794,8 +794,8 @@
      */
     @SystemApi
     @RequiresPermission(android.Manifest.permission.NETWORK_STACK)
-    public void applyTunnelModeTransform(IpSecTunnelInterface tunnel,
-            @PolicyDirection int direction, IpSecTransform transform) throws IOException {
+    public void applyTunnelModeTransform(@NonNull IpSecTunnelInterface tunnel,
+            @PolicyDirection int direction, @NonNull IpSecTransform transform) throws IOException {
         try {
             mService.applyTunnelModeTransform(
                     tunnel.getResourceId(), direction, transform.getResourceId());
diff --git a/core/java/android/net/IpSecTransform.java b/core/java/android/net/IpSecTransform.java
index 60e96f9..cf58647 100644
--- a/core/java/android/net/IpSecTransform.java
+++ b/core/java/android/net/IpSecTransform.java
@@ -350,6 +350,7 @@
          *
          * @param algo {@link IpSecAlgorithm} specifying the encryption to be applied.
          */
+        @NonNull
         public IpSecTransform.Builder setEncryption(@NonNull IpSecAlgorithm algo) {
             // TODO: throw IllegalArgumentException if algo is not an encryption algorithm.
             Preconditions.checkNotNull(algo);
@@ -364,6 +365,7 @@
          *
          * @param algo {@link IpSecAlgorithm} specifying the authentication to be applied.
          */
+        @NonNull
         public IpSecTransform.Builder setAuthentication(@NonNull IpSecAlgorithm algo) {
             // TODO: throw IllegalArgumentException if algo is not an authentication algorithm.
             Preconditions.checkNotNull(algo);
@@ -384,6 +386,7 @@
          * @param algo {@link IpSecAlgorithm} specifying the authenticated encryption algorithm to
          *     be applied.
          */
+        @NonNull
         public IpSecTransform.Builder setAuthenticatedEncryption(@NonNull IpSecAlgorithm algo) {
             Preconditions.checkNotNull(algo);
             mConfig.setAuthenticatedEncryption(algo);
@@ -403,6 +406,7 @@
          * @param remotePort the UDP port number of the remote host that will send and receive
          *     encapsulated traffic. In the case of IKEv2, this should be port 4500.
          */
+        @NonNull
         public IpSecTransform.Builder setIpv4Encapsulation(
                 @NonNull IpSecManager.UdpEncapsulationSocket localSocket, int remotePort) {
             Preconditions.checkNotNull(localSocket);
@@ -436,6 +440,7 @@
          *     collides with an existing transform
          * @throws IOException indicating other errors
          */
+        @NonNull
         public IpSecTransform buildTransportModeTransform(
                 @NonNull InetAddress sourceAddress,
                 @NonNull IpSecManager.SecurityParameterIndex spi)
@@ -472,6 +477,7 @@
          * @hide
          */
         @SystemApi
+        @NonNull
         @RequiresPermission(android.Manifest.permission.NETWORK_STACK)
         public IpSecTransform buildTunnelModeTransform(
                 @NonNull InetAddress sourceAddress,
diff --git a/core/java/android/net/NetworkStats.java b/core/java/android/net/NetworkStats.java
index 01b2b39..940f985 100644
--- a/core/java/android/net/NetworkStats.java
+++ b/core/java/android/net/NetworkStats.java
@@ -64,6 +64,9 @@
     /** Debug {@link #set} value when the VPN stats are moved out of a vpn UID. */
     public static final int SET_DBG_VPN_OUT = 1002;
 
+    /** Include all interfaces when filtering */
+    public static final String[] INTERFACES_ALL = null;
+
     /** {@link #tag} value for total data across all tags. */
     // TODO: Rename TAG_NONE to TAG_ALL.
     public static final int TAG_NONE = 0;
@@ -359,23 +362,27 @@
             capacity = newLength;
         }
 
-        iface[size] = entry.iface;
-        uid[size] = entry.uid;
-        set[size] = entry.set;
-        tag[size] = entry.tag;
-        metered[size] = entry.metered;
-        roaming[size] = entry.roaming;
-        defaultNetwork[size] = entry.defaultNetwork;
-        rxBytes[size] = entry.rxBytes;
-        rxPackets[size] = entry.rxPackets;
-        txBytes[size] = entry.txBytes;
-        txPackets[size] = entry.txPackets;
-        operations[size] = entry.operations;
+        setValues(size, entry);
         size++;
 
         return this;
     }
 
+    private void setValues(int i, Entry entry) {
+        iface[i] = entry.iface;
+        uid[i] = entry.uid;
+        set[i] = entry.set;
+        tag[i] = entry.tag;
+        metered[i] = entry.metered;
+        roaming[i] = entry.roaming;
+        defaultNetwork[i] = entry.defaultNetwork;
+        rxBytes[i] = entry.rxBytes;
+        rxPackets[i] = entry.rxPackets;
+        txBytes[i] = entry.txBytes;
+        txPackets[i] = entry.txPackets;
+        operations[i] = entry.operations;
+    }
+
     /**
      * Return specific stats entry.
      */
@@ -824,6 +831,39 @@
         return stats;
     }
 
+    /**
+     * Only keep entries that match all specified filters.
+     *
+     * <p>This mutates the original structure in place. After this method is called,
+     * size is the number of matching entries, and capacity is the previous capacity.
+     * @param limitUid UID to filter for, or {@link #UID_ALL}.
+     * @param limitIfaces Interfaces to filter for, or {@link #INTERFACES_ALL}.
+     * @param limitTag Tag to filter for, or {@link #TAG_ALL}.
+     */
+    public void filter(int limitUid, String[] limitIfaces, int limitTag) {
+        if (limitUid == UID_ALL && limitTag == TAG_ALL && limitIfaces == INTERFACES_ALL) {
+            return;
+        }
+
+        Entry entry = new Entry();
+        int nextOutputEntry = 0;
+        for (int i = 0; i < size; i++) {
+            entry = getValues(i, entry);
+            final boolean matches =
+                    (limitUid == UID_ALL || limitUid == entry.uid)
+                    && (limitTag == TAG_ALL || limitTag == entry.tag)
+                    && (limitIfaces == INTERFACES_ALL
+                            || ArrayUtils.contains(limitIfaces, entry.iface));
+
+            if (matches) {
+                setValues(nextOutputEntry, entry);
+                nextOutputEntry++;
+            }
+        }
+
+        size = nextOutputEntry;
+    }
+
     public void dump(String prefix, PrintWriter pw) {
         pw.print(prefix);
         pw.print("NetworkStats: elapsedRealtime="); pw.println(elapsedRealtime);
diff --git a/core/java/android/os/INetworkManagementService.aidl b/core/java/android/os/INetworkManagementService.aidl
index a5e1934..9a8f5cb 100644
--- a/core/java/android/os/INetworkManagementService.aidl
+++ b/core/java/android/os/INetworkManagementService.aidl
@@ -268,10 +268,12 @@
     NetworkStats getNetworkStatsDetail();
 
     /**
-     * Return detailed network statistics for the requested UID,
+     * Return detailed network statistics for the requested UID and interfaces,
      * including interface and tag details.
+     * @param uid UID to obtain statistics for, or {@link NetworkStats#UID_ALL}.
+     * @param ifaces Interfaces to obtain statistics for, or {@link NetworkStats#INTERFACES_ALL}.
      */
-    NetworkStats getNetworkStatsUidDetail(int uid);
+    NetworkStats getNetworkStatsUidDetail(int uid, in String[] ifaces);
 
     /**
      * Return summary of network statistics all tethering interfaces.
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index 517995e..2b5353d 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -3621,6 +3621,14 @@
         public static final Validator VIBRATE_WHEN_RINGING_VALIDATOR = sBooleanValidator;
 
         /**
+         * When {@code 1}, Telecom enhanced call blocking functionality is enabled.  When
+         * {@code 0}, enhanced call blocking functionality is disabled.
+         * @hide
+         */
+        public static final String DEBUG_ENABLE_ENHANCED_CALL_BLOCKING =
+                "debug.enable_enhanced_calling";
+
+        /**
          * Whether the audible DTMF tones are played by the dialer when dialing. The value is
          * boolean (1 or 0).
          */
diff --git a/core/java/com/android/internal/net/NetworkStatsFactory.java b/core/java/com/android/internal/net/NetworkStatsFactory.java
index 902bd12..8172a20 100644
--- a/core/java/com/android/internal/net/NetworkStatsFactory.java
+++ b/core/java/com/android/internal/net/NetworkStatsFactory.java
@@ -22,16 +22,14 @@
 import static android.net.NetworkStats.UID_ALL;
 import static com.android.server.NetworkManagementSocketTagger.kernelToTag;
 
+import android.annotation.Nullable;
 import android.net.NetworkStats;
 import android.os.StrictMode;
 import android.os.SystemClock;
-import android.util.ArrayMap;
 
-import com.android.internal.annotations.GuardedBy;
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.util.ArrayUtils;
 import com.android.internal.util.ProcFileReader;
-import com.google.android.collect.Lists;
 
 import libcore.io.IoUtils;
 
@@ -41,8 +39,10 @@
 import java.io.FileReader;
 import java.io.IOException;
 import java.net.ProtocolException;
-import java.util.ArrayList;
-import java.util.Objects;
+import java.util.Arrays;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
 
 /**
  * Creates {@link NetworkStats} instances by parsing various {@code /proc/}
@@ -70,18 +70,55 @@
 
     private boolean mUseBpfStats;
 
-    // TODO: to improve testability and avoid global state, do not use a static variable.
-    @GuardedBy("sStackedIfaces")
-    private static final ArrayMap<String, String> sStackedIfaces = new ArrayMap<>();
+    // TODO: only do adjustments in NetworkStatsService and remove this.
+    /**
+     * (Stacked interface) -> (base interface) association for all connected ifaces since boot.
+     *
+     * Because counters must never roll backwards, once a given interface is stacked on top of an
+     * underlying interface, the stacked interface can never be stacked on top of
+     * another interface. */
+    private static final ConcurrentHashMap<String, String> sStackedIfaces
+            = new ConcurrentHashMap<>();
 
     public static void noteStackedIface(String stackedIface, String baseIface) {
-        synchronized (sStackedIfaces) {
-            if (baseIface != null) {
-                sStackedIfaces.put(stackedIface, baseIface);
-            } else {
-                sStackedIfaces.remove(stackedIface);
+        if (stackedIface != null && baseIface != null) {
+            sStackedIfaces.put(stackedIface, baseIface);
+        }
+    }
+
+    /**
+     * Get a set of interfaces containing specified ifaces and stacked interfaces.
+     *
+     * <p>The added stacked interfaces are ifaces stacked on top of the specified ones, or ifaces
+     * on which the specified ones are stacked. Stacked interfaces are those noted with
+     * {@link #noteStackedIface(String, String)}, but only interfaces noted before this method
+     * is called are guaranteed to be included.
+     */
+    public static String[] augmentWithStackedInterfacesLocked(@Nullable String[] requiredIfaces) {
+        if (requiredIfaces == NetworkStats.INTERFACES_ALL) {
+            return null;
+        }
+
+        HashSet<String> relatedIfaces = new HashSet<>(Arrays.asList(requiredIfaces));
+        // ConcurrentHashMap's EntrySet iterators are "guaranteed to traverse
+        // elements as they existed upon construction exactly once, and may
+        // (but are not guaranteed to) reflect any modifications subsequent to construction".
+        // This is enough here.
+        for (Map.Entry<String, String> entry : sStackedIfaces.entrySet()) {
+            if (relatedIfaces.contains(entry.getKey())) {
+                relatedIfaces.add(entry.getValue());
+            } else if (relatedIfaces.contains(entry.getValue())) {
+                relatedIfaces.add(entry.getKey());
             }
         }
+
+        String[] outArray = new String[relatedIfaces.size()];
+        return relatedIfaces.toArray(outArray);
+    }
+
+    @VisibleForTesting
+    public static void clearStackedIfaces() {
+        sStackedIfaces.clear();
     }
 
     public NetworkStatsFactory() {
@@ -250,12 +287,9 @@
             NetworkStats lastStats) throws IOException {
         final NetworkStats stats =
               readNetworkStatsDetailInternal(limitUid, limitIfaces, limitTag, lastStats);
-        final ArrayMap<String, String> stackedIfaces;
-        synchronized (sStackedIfaces) {
-            stackedIfaces = new ArrayMap<>(sStackedIfaces);
-        }
         // Total 464xlat traffic to subtract from uid 0 on all base interfaces.
-        final NetworkStats adjustments = new NetworkStats(0, stackedIfaces.size());
+        // sStackedIfaces may grow afterwards, but NetworkStats will just be resized automatically.
+        final NetworkStats adjustments = new NetworkStats(0, sStackedIfaces.size());
 
         NetworkStats.Entry entry = null; // For recycling
 
@@ -269,7 +303,7 @@
             if (entry.iface == null || !entry.iface.startsWith(CLATD_INTERFACE_PREFIX)) {
                 continue;
             }
-            final String baseIface = stackedIfaces.get(entry.iface);
+            final String baseIface = sStackedIfaces.get(entry.iface);
             if (baseIface == null) {
                 continue;
             }
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index ecaf89e..9e38efe 100644
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -149,6 +149,9 @@
     <!-- Notification content to tell the user that voice/data/emergency service is blocked by access control. -->
     <string name="RestrictedStateContent">Temporarily turned off by your carrier</string>
 
+    <!-- Notification content to tell the user that voice/data/emergency service is blocked by access control when multiple SIMs are active. -->
+    <string name="RestrictedStateContentMsimTemplate">Temporarily turned off by your carrier for SIM <xliff:g id="simNumber" example="1">%d</xliff:g></string>
+
     <!-- Displayed to tell the user that they should switch their network preference. -->
     <string name="NetworkPreferenceSwitchTitle">Can\u2019t reach mobile network</string>
     <!-- Displayed to tell the user that they should switch their network preference. -->
@@ -4437,14 +4440,14 @@
 
     <!-- Displayed when the USSD/SS request is modified by STK CC to a
     different request. This will be displayed in a toast. -->
-    <string name="stk_cc_ussd_to_dial">USSD request is modified to DIAL request.</string>
-    <string name="stk_cc_ussd_to_ss">USSD request is modified to SS request.</string>
-    <string name="stk_cc_ussd_to_ussd">USSD request is modified to new USSD request.</string>
-    <string name="stk_cc_ussd_to_dial_video">USSD request is modified to Video DIAL request.</string>
-    <string name="stk_cc_ss_to_dial">SS request is modified to DIAL request.</string>
-    <string name="stk_cc_ss_to_dial_video">SS request is modified to Video DIAL request.</string>
-    <string name="stk_cc_ss_to_ussd">SS request is modified to USSD request.</string>
-    <string name="stk_cc_ss_to_ss">SS request is modified to new SS request.</string>
+    <string name="stk_cc_ussd_to_dial">USSD request changed to regular call</string>
+    <string name="stk_cc_ussd_to_ss">USSD request changed to SS request</string>
+    <string name="stk_cc_ussd_to_ussd">Changed to new USSD request</string>
+    <string name="stk_cc_ussd_to_dial_video">USSD request changed to video call</string>
+    <string name="stk_cc_ss_to_dial">SS request changed to regular call</string>
+    <string name="stk_cc_ss_to_dial_video">SS request changed to video call</string>
+    <string name="stk_cc_ss_to_ussd">SS request changed to USSD request</string>
+    <string name="stk_cc_ss_to_ss">Changed to new SS request</string>
 
     <!-- Content description of the work profile icon in the notification. -->
     <string name="notification_work_profile_content_description">Work profile</string>
@@ -4688,6 +4691,12 @@
     <string name="mmcc_illegal_ms">SIM not allowed for voice</string>
     <string name="mmcc_illegal_me">Phone not allowed for voice</string>
 
+    <!-- Title of notification when UE fails to register network with MM reject cause code when multiple SIMs are active. -->
+    <string name="mmcc_authentication_reject_msim_template">SIM <xliff:g id="simNumber" example="1">%d</xliff:g> not allowed</string>
+    <string name="mmcc_imsi_unknown_in_hlr_msim_template">SIM <xliff:g id="simNumber" example="1">%d</xliff:g> not provisioned</string>
+    <string name="mmcc_illegal_ms_msim_template">SIM <xliff:g id="simNumber" example="1">%d</xliff:g> not allowed</string>
+    <string name="mmcc_illegal_me_msim_template">SIM <xliff:g id="simNumber" example="1">%d</xliff:g> not allowed</string>
+
     <!-- Popup window default title to be read by a screen reader-->
     <string name="popup_window_default_title">Popup Window</string>
 </resources>
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index f089ff0..e52f0f8 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -547,6 +547,7 @@
   <java-symbol type="string" name="RestrictedOnEmergencyTitle" />
   <java-symbol type="string" name="RestrictedOnNormalTitle" />
   <java-symbol type="string" name="RestrictedStateContent" />
+  <java-symbol type="string" name="RestrictedStateContentMsimTemplate" />
   <java-symbol type="string" name="notification_channel_network_alert" />
   <java-symbol type="string" name="notification_channel_call_forward" />
   <java-symbol type="string" name="notification_channel_emergency_callback" />
@@ -1956,6 +1957,10 @@
   <java-symbol type="string" name="mmcc_imsi_unknown_in_hlr" />
   <java-symbol type="string" name="mmcc_illegal_ms" />
   <java-symbol type="string" name="mmcc_illegal_me" />
+  <java-symbol type="string" name="mmcc_authentication_reject_msim_template" />
+  <java-symbol type="string" name="mmcc_imsi_unknown_in_hlr_msim_template" />
+  <java-symbol type="string" name="mmcc_illegal_ms_msim_template" />
+  <java-symbol type="string" name="mmcc_illegal_me_msim_template" />
   <java-symbol type="string" name="notification_listener_binding_label" />
   <java-symbol type="string" name="vr_listener_binding_label" />
   <java-symbol type="string" name="condition_provider_service_binding_label" />
diff --git a/core/tests/coretests/src/android/provider/SettingsBackupTest.java b/core/tests/coretests/src/android/provider/SettingsBackupTest.java
index 16c0b8c..8a7c586 100644
--- a/core/tests/coretests/src/android/provider/SettingsBackupTest.java
+++ b/core/tests/coretests/src/android/provider/SettingsBackupTest.java
@@ -64,6 +64,7 @@
                     Settings.System.NOTIFICATION_LIGHT_PULSE, // candidate for backup?
                     Settings.System.NOTIFICATION_SOUND_CACHE, // internal cache
                     Settings.System.POINTER_LOCATION, // backup candidate?
+                    Settings.System.DEBUG_ENABLE_ENHANCED_CALL_BLOCKING, // used for testing only
                     Settings.System.RINGTONE_CACHE, // internal cache
                     Settings.System.SETUP_WIZARD_HAS_RUN, // Only used by SuW
                     Settings.System.SHOW_GTALK_SERVICE_STATUS, // candidate for backup?
diff --git a/services/core/java/com/android/server/BluetoothManagerService.java b/services/core/java/com/android/server/BluetoothManagerService.java
index 62bab76..a7515e5 100644
--- a/services/core/java/com/android/server/BluetoothManagerService.java
+++ b/services/core/java/com/android/server/BluetoothManagerService.java
@@ -637,29 +637,10 @@
                 IBinder token = entry.getKey();
                 ClientDeathRecipient deathRec = entry.getValue();
                 if (deathRec.equals(this)) {
-                    mBleApps.remove(token);
+                    updateBleAppCount(token, false, mPackageName);
                     break;
                 }
             }
-
-            if (isBleAppPresent()) {
-                // Nothing to do, another app is here.
-                return;
-            }
-            if (DBG) {
-                Slog.d(TAG, "Disabling LE only mode after application crash");
-            }
-            try {
-                mBluetoothLock.readLock().lock();
-                if (mBluetooth != null && mBluetooth.getState() == BluetoothAdapter.STATE_BLE_ON) {
-                    mEnable = false;
-                    mBluetooth.onBrEdrDown();
-                }
-            } catch (RemoteException e) {
-                Slog.e(TAG, "Unable to call onBrEdrDown", e);
-            } finally {
-                mBluetoothLock.readLock().unlock();
-            }
         }
 
         public String getPackageName() {
diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java
index 6c24e94..c044242 100644
--- a/services/core/java/com/android/server/ConnectivityService.java
+++ b/services/core/java/com/android/server/ConnectivityService.java
@@ -5268,7 +5268,6 @@
                 for (LinkProperties stacked : newNetwork.linkProperties.getStackedLinks()) {
                     final String stackedIface = stacked.getInterfaceName();
                     bs.noteNetworkInterfaceType(stackedIface, type);
-                    NetworkStatsFactory.noteStackedIface(stackedIface, baseIface);
                 }
             } catch (RemoteException ignored) {
             }
diff --git a/services/core/java/com/android/server/IpSecService.java b/services/core/java/com/android/server/IpSecService.java
index f1f251f..d09a161 100644
--- a/services/core/java/com/android/server/IpSecService.java
+++ b/services/core/java/com/android/server/IpSecService.java
@@ -676,10 +676,12 @@
         @Override
         public void freeUnderlyingResources() {
             try {
-                mSrvConfig
-                        .getNetdInstance()
-                        .ipSecDeleteSecurityAssociation(
-                                mResourceId, mSourceAddress, mDestinationAddress, mSpi, 0, 0);
+                if (!mOwnedByTransform) {
+                    mSrvConfig
+                            .getNetdInstance()
+                            .ipSecDeleteSecurityAssociation(
+                                    mResourceId, mSourceAddress, mDestinationAddress, mSpi, 0, 0);
+                }
             } catch (ServiceSpecificException | RemoteException e) {
                 Log.e(TAG, "Failed to delete SPI reservation with ID: " + mResourceId, e);
             }
diff --git a/services/core/java/com/android/server/NetworkManagementService.java b/services/core/java/com/android/server/NetworkManagementService.java
index 88ae224..fc4ec11 100644
--- a/services/core/java/com/android/server/NetworkManagementService.java
+++ b/services/core/java/com/android/server/NetworkManagementService.java
@@ -1867,10 +1867,10 @@
     }
 
     @Override
-    public NetworkStats getNetworkStatsUidDetail(int uid) {
+    public NetworkStats getNetworkStatsUidDetail(int uid, String[] ifaces) {
         mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
         try {
-            return mStatsFactory.readNetworkStatsDetail(uid, null, TAG_ALL, null);
+            return mStatsFactory.readNetworkStatsDetail(uid, ifaces, TAG_ALL, null);
         } catch (IOException e) {
             throw new IllegalStateException(e);
         }
diff --git a/services/core/java/com/android/server/net/NetworkStatsService.java b/services/core/java/com/android/server/net/NetworkStatsService.java
index 8298127..e0a8643 100644
--- a/services/core/java/com/android/server/net/NetworkStatsService.java
+++ b/services/core/java/com/android/server/net/NetworkStatsService.java
@@ -27,6 +27,7 @@
 import static android.net.ConnectivityManager.isNetworkTypeMobile;
 import static android.net.NetworkStats.DEFAULT_NETWORK_ALL;
 import static android.net.NetworkStats.IFACE_ALL;
+import static android.net.NetworkStats.INTERFACES_ALL;
 import static android.net.NetworkStats.METERED_ALL;
 import static android.net.NetworkStats.ROAMING_ALL;
 import static android.net.NetworkStats.SET_ALL;
@@ -34,6 +35,7 @@
 import static android.net.NetworkStats.SET_FOREGROUND;
 import static android.net.NetworkStats.STATS_PER_IFACE;
 import static android.net.NetworkStats.STATS_PER_UID;
+import static android.net.NetworkStats.TAG_ALL;
 import static android.net.NetworkStats.TAG_NONE;
 import static android.net.NetworkStats.UID_ALL;
 import static android.net.NetworkStatsHistory.FIELD_ALL;
@@ -128,6 +130,7 @@
 
 import com.android.internal.annotations.GuardedBy;
 import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.net.NetworkStatsFactory;
 import com.android.internal.net.VpnInfo;
 import com.android.internal.util.ArrayUtils;
 import com.android.internal.util.DumpUtils;
@@ -143,6 +146,7 @@
 import java.util.Arrays;
 import java.util.HashSet;
 import java.util.List;
+import java.util.Map;
 
 /**
  * Collect and persist detailed network statistics, and provide this data to
@@ -726,7 +730,8 @@
         final long token = Binder.clearCallingIdentity();
         final NetworkStats networkLayer;
         try {
-            networkLayer = mNetworkManager.getNetworkStatsUidDetail(uid);
+            networkLayer = mNetworkManager.getNetworkStatsUidDetail(uid,
+                    NetworkStats.INTERFACES_ALL);
         } finally {
             Binder.restoreCallingIdentity(token);
         }
@@ -748,6 +753,18 @@
     }
 
     @Override
+    public NetworkStats getDetailedUidStats(String[] requiredIfaces) {
+        try {
+            final String[] ifacesToQuery =
+                    NetworkStatsFactory.augmentWithStackedInterfacesLocked(requiredIfaces);
+            return getNetworkStatsUidDetail(ifacesToQuery);
+        } catch (RemoteException e) {
+            Log.wtf(TAG, "Error compiling UID stats", e);
+            return new NetworkStats(0L, 0);
+        }
+    }
+
+    @Override
     public String[] getMobileIfaces() {
         return mMobileIfaces;
     }
@@ -1109,6 +1126,8 @@
                         if (isMobile) {
                             mobileIfaces.add(stackedIface);
                         }
+
+                        NetworkStatsFactory.noteStackedIface(stackedIface, baseIface);
                     }
                 }
             }
@@ -1130,7 +1149,7 @@
     private void recordSnapshotLocked(long currentTime) throws RemoteException {
         // snapshot and record current counters; read UID stats first to
         // avoid over counting dev stats.
-        final NetworkStats uidSnapshot = getNetworkStatsUidDetail();
+        final NetworkStats uidSnapshot = getNetworkStatsUidDetail(INTERFACES_ALL);
         final NetworkStats xtSnapshot = getNetworkStatsXt();
         final NetworkStats devSnapshot = mNetworkManager.getNetworkStatsSummaryDev();
 
@@ -1464,12 +1483,19 @@
      * Return snapshot of current UID statistics, including any
      * {@link TrafficStats#UID_TETHERING}, video calling data usage, and {@link #mUidOperations}
      * values.
+     *
+     * @param ifaces A list of interfaces the stats should be restricted to, or
+     *               {@link NetworkStats#INTERFACES_ALL}.
      */
-    private NetworkStats getNetworkStatsUidDetail() throws RemoteException {
-        final NetworkStats uidSnapshot = mNetworkManager.getNetworkStatsUidDetail(UID_ALL);
+    private NetworkStats getNetworkStatsUidDetail(String[] ifaces)
+            throws RemoteException {
+
+        final NetworkStats uidSnapshot = mNetworkManager.getNetworkStatsUidDetail(UID_ALL,
+                ifaces);
 
         // fold tethering stats and operations into uid snapshot
         final NetworkStats tetherSnapshot = getNetworkStatsTethering(STATS_PER_UID);
+        tetherSnapshot.filter(UID_ALL, ifaces, TAG_ALL);
         uidSnapshot.combineAllValues(tetherSnapshot);
 
         final TelephonyManager telephonyManager = (TelephonyManager) mContext.getSystemService(
@@ -1478,10 +1504,14 @@
         // fold video calling data usage stats into uid snapshot
         final NetworkStats vtStats = telephonyManager.getVtDataUsage(STATS_PER_UID);
         if (vtStats != null) {
+            vtStats.filter(UID_ALL, ifaces, TAG_ALL);
             uidSnapshot.combineAllValues(vtStats);
         }
+
         uidSnapshot.combineAllValues(mUidOperations);
 
+        // TODO: apply tethering & VC 464xlat adjustments here
+
         return uidSnapshot;
     }
 
diff --git a/services/core/java/com/android/server/policy/PhoneWindowManager.java b/services/core/java/com/android/server/policy/PhoneWindowManager.java
index 2579e56..0971058 100644
--- a/services/core/java/com/android/server/policy/PhoneWindowManager.java
+++ b/services/core/java/com/android/server/policy/PhoneWindowManager.java
@@ -992,7 +992,7 @@
             resolver.registerContentObserver(Settings.Global.getUriFor(
                     Settings.Global.POLICY_CONTROL), false, this,
                     UserHandle.USER_ALL);
-            resolver.registerContentObserver(Settings.Global.getUriFor(
+            resolver.registerContentObserver(Settings.Secure.getUriFor(
                     Settings.Secure.SYSTEM_NAVIGATION_KEYS_ENABLED), false, this,
                     UserHandle.USER_ALL);
             updateSettings();
diff --git a/telephony/java/android/telephony/CarrierConfigManager.java b/telephony/java/android/telephony/CarrierConfigManager.java
index fa07777..cc3cd4d 100644
--- a/telephony/java/android/telephony/CarrierConfigManager.java
+++ b/telephony/java/android/telephony/CarrierConfigManager.java
@@ -1926,7 +1926,7 @@
         sDefaults.putBoolean(KEY_CARRIER_FORCE_DISABLE_ETWS_CMAS_TEST_BOOL, false);
         sDefaults.putBoolean(KEY_CARRIER_VOLTE_PROVISIONING_REQUIRED_BOOL, false);
         sDefaults.putBoolean(KEY_CARRIER_VOLTE_OVERRIDE_WFC_PROVISIONING_BOOL, false);
-        sDefaults.putBoolean(KEY_CARRIER_VOLTE_TTY_SUPPORTED_BOOL, false);
+        sDefaults.putBoolean(KEY_CARRIER_VOLTE_TTY_SUPPORTED_BOOL, true);
         sDefaults.putBoolean(KEY_CARRIER_ALLOW_TURNOFF_IMS_BOOL, true);
         sDefaults.putBoolean(KEY_CARRIER_IMS_GBA_REQUIRED_BOOL, false);
         sDefaults.putBoolean(KEY_CARRIER_INSTANT_LETTERING_AVAILABLE_BOOL, false);
@@ -2209,7 +2209,9 @@
     /**
      * Gets the configuration values for a particular subscription, which is associated with a
      * specific SIM card. If an invalid subId is used, the returned config will contain default
-     * values.
+     * values. After using this method to get the configuration bundle,
+     * {@link #isConfigForIdentifiedCarrier(PersistableBundle)} should be called to confirm whether
+     * any carrier specific configuration has been applied.
      *
      * <p>Requires Permission:
      * {@link android.Manifest.permission#READ_PHONE_STATE READ_PHONE_STATE}
@@ -2236,7 +2238,9 @@
     }
 
     /**
-     * Gets the configuration values for the default subscription.
+     * Gets the configuration values for the default subscription. After using this method to get
+     * the configuration bundle, {@link #isConfigForIdentifiedCarrier(PersistableBundle)} should be
+     * called to confirm whether any carrier specific configuration has been applied.
      *
      * <p>Requires Permission:
      * {@link android.Manifest.permission#READ_PHONE_STATE READ_PHONE_STATE}
@@ -2265,6 +2269,9 @@
      * <p>
      * After using {@link #getConfig()} or {@link #getConfigForSubId(int)} an app should always
      * use this method to confirm whether any carrier specific configuration has been applied.
+     * Especially when an app misses the broadcast {@link #ACTION_CARRIER_CONFIG_CHANGED} but it
+     * still needs to get the current configuration, it must use this method to verify whether the
+     * configuration is default or carrier overridden.
      * </p>
      *
      * @param bundle the configuration bundle to be checked.
diff --git a/telephony/java/android/telephony/CellIdentityCdma.java b/telephony/java/android/telephony/CellIdentityCdma.java
index 105ddb0..713ac00 100644
--- a/telephony/java/android/telephony/CellIdentityCdma.java
+++ b/telephony/java/android/telephony/CellIdentityCdma.java
@@ -16,6 +16,7 @@
 
 package android.telephony;
 
+import android.annotation.Nullable;
 import android.os.Parcel;
 import android.text.TextUtils;
 
@@ -181,6 +182,7 @@
      * @return The long alpha tag associated with the current scan result (may be the operator
      * name string or extended operator name string). May be null if unknown.
      */
+    @Nullable
     public CharSequence getOperatorAlphaLong() {
         return mAlphaLong;
     }
@@ -189,6 +191,7 @@
      * @return The short alpha tag associated with the current scan result (may be the operator
      * name string or extended operator name string).  May be null if unknown.
      */
+    @Nullable
     public CharSequence getOperatorAlphaShort() {
         return mAlphaShort;
     }
diff --git a/telephony/java/android/telephony/CellIdentityGsm.java b/telephony/java/android/telephony/CellIdentityGsm.java
index 52944a8..aae7929 100644
--- a/telephony/java/android/telephony/CellIdentityGsm.java
+++ b/telephony/java/android/telephony/CellIdentityGsm.java
@@ -16,6 +16,7 @@
 
 package android.telephony;
 
+import android.annotation.Nullable;
 import android.os.Parcel;
 import android.text.TextUtils;
 
@@ -191,6 +192,7 @@
      * @return The long alpha tag associated with the current scan result (may be the operator
      * name string or extended operator name string). May be null if unknown.
      */
+    @Nullable
     public CharSequence getOperatorAlphaLong() {
         return mAlphaLong;
     }
@@ -199,6 +201,7 @@
      * @return The short alpha tag associated with the current scan result (may be the operator
      * name string or extended operator name string).  May be null if unknown.
      */
+    @Nullable
     public CharSequence getOperatorAlphaShort() {
         return mAlphaShort;
     }
diff --git a/telephony/java/android/telephony/CellIdentityLte.java b/telephony/java/android/telephony/CellIdentityLte.java
index 37fb075..9b3ef56 100644
--- a/telephony/java/android/telephony/CellIdentityLte.java
+++ b/telephony/java/android/telephony/CellIdentityLte.java
@@ -16,6 +16,7 @@
 
 package android.telephony;
 
+import android.annotation.Nullable;
 import android.os.Parcel;
 import android.text.TextUtils;
 
@@ -201,6 +202,7 @@
      * @return The long alpha tag associated with the current scan result (may be the operator
      * name string or extended operator name string). May be null if unknown.
      */
+    @Nullable
     public CharSequence getOperatorAlphaLong() {
         return mAlphaLong;
     }
@@ -209,6 +211,7 @@
      * @return The short alpha tag associated with the current scan result (may be the operator
      * name string or extended operator name string).  May be null if unknown.
      */
+    @Nullable
     public CharSequence getOperatorAlphaShort() {
         return mAlphaShort;
     }
diff --git a/telephony/java/android/telephony/CellIdentityTdscdma.java b/telephony/java/android/telephony/CellIdentityTdscdma.java
index 992545d..7475c74 100644
--- a/telephony/java/android/telephony/CellIdentityTdscdma.java
+++ b/telephony/java/android/telephony/CellIdentityTdscdma.java
@@ -16,6 +16,7 @@
 
 package android.telephony;
 
+import android.annotation.Nullable;
 import android.os.Parcel;
 import android.text.TextUtils;
 
@@ -34,6 +35,10 @@
     private final int mCid;
     // 8-bit Cell Parameters ID described in TS 25.331, 0..127, INT_MAX if unknown.
     private final int mCpid;
+    // long alpha Operator Name String or Enhanced Operator Name String
+    private final String mAlphaLong;
+    // short alpha Operator Name String or Enhanced Operator Name String
+    private final String mAlphaShort;
 
     /**
      * @hide
@@ -43,6 +48,8 @@
         mLac = Integer.MAX_VALUE;
         mCid = Integer.MAX_VALUE;
         mCpid = Integer.MAX_VALUE;
+        mAlphaLong = null;
+        mAlphaShort = null;
     }
 
     /**
@@ -55,7 +62,7 @@
      * @hide
      */
     public CellIdentityTdscdma(int mcc, int mnc, int lac, int cid, int cpid) {
-        this(String.valueOf(mcc), String.valueOf(mnc), lac, cid, cpid);
+        this(String.valueOf(mcc), String.valueOf(mnc), lac, cid, cpid, null, null);
     }
 
     /**
@@ -65,6 +72,7 @@
      * @param cid 28-bit UMTS Cell Identity described in TS 25.331, 0..268435455, INT_MAX if unknown
      * @param cpid 8-bit Cell Parameters ID described in TS 25.331, 0..127, INT_MAX if unknown
      *
+     * FIXME: This is a temporary constructor to facilitate migration.
      * @hide
      */
     public CellIdentityTdscdma(String mcc, String mnc, int lac, int cid, int cpid) {
@@ -72,10 +80,34 @@
         mLac = lac;
         mCid = cid;
         mCpid = cpid;
+        mAlphaLong = null;
+        mAlphaShort = null;
+    }
+
+    /**
+     * @param mcc 3-digit Mobile Country Code in string format
+     * @param mnc 2 or 3-digit Mobile Network Code in string format
+     * @param lac 16-bit Location Area Code, 0..65535, INT_MAX if unknown
+     * @param cid 28-bit UMTS Cell Identity described in TS 25.331, 0..268435455, INT_MAX if unknown
+     * @param cpid 8-bit Cell Parameters ID described in TS 25.331, 0..127, INT_MAX if unknown
+     * @param alphal long alpha Operator Name String or Enhanced Operator Name String
+     * @param alphas short alpha Operator Name String or Enhanced Operator Name String
+     *
+     * @hide
+     */
+    public CellIdentityTdscdma(String mcc, String mnc, int lac, int cid, int cpid,
+            String alphal, String alphas) {
+        super(TAG, TYPE_TDSCDMA, mcc, mnc);
+        mLac = lac;
+        mCid = cid;
+        mCpid = cpid;
+        mAlphaLong = alphal;
+        mAlphaShort = alphas;
     }
 
     private CellIdentityTdscdma(CellIdentityTdscdma cid) {
-        this(cid.mMccStr, cid.mMncStr, cid.mLac, cid.mCid, cid.mCpid);
+        this(cid.mMccStr, cid.mMncStr, cid.mLac, cid.mCid,
+                cid.mCpid, cid.mAlphaLong, cid.mAlphaShort);
     }
 
     CellIdentityTdscdma copy() {
@@ -119,9 +151,31 @@
         return mCpid;
     }
 
+    /**
+     * @return The long alpha tag associated with the current scan result (may be the operator
+     * name string or extended operator name string). May be null if unknown.
+     *
+     * @hide
+     */
+    @Nullable
+    public CharSequence getOperatorAlphaLong() {
+        return mAlphaLong;
+    }
+
+    /**
+     * @return The short alpha tag associated with the current scan result (may be the operator
+     * name string or extended operator name string).  May be null if unknown.
+     *
+     * @hide
+     */
+    @Nullable
+    public CharSequence getOperatorAlphaShort() {
+        return mAlphaShort;
+    }
+
     @Override
     public int hashCode() {
-        return Objects.hash(mMccStr, mMncStr, mLac, mCid, mCpid);
+        return Objects.hash(mMccStr, mMncStr, mLac, mCid, mCpid, mAlphaLong, mAlphaShort);
     }
 
     @Override
@@ -139,7 +193,9 @@
                 && TextUtils.equals(mMncStr, o.mMncStr)
                 && mLac == o.mLac
                 && mCid == o.mCid
-                && mCpid == o.mCpid;
+                && mCpid == o.mCpid
+                && mAlphaLong == o.mAlphaLong
+                && mAlphaShort == o.mAlphaShort;
     }
 
     @Override
@@ -150,6 +206,8 @@
         .append(" mLac=").append(mLac)
         .append(" mCid=").append(mCid)
         .append(" mCpid=").append(mCpid)
+        .append(" mAlphaLong=").append(mAlphaLong)
+        .append(" mAlphaShort=").append(mAlphaShort)
         .append("}").toString();
     }
 
@@ -161,6 +219,8 @@
         dest.writeInt(mLac);
         dest.writeInt(mCid);
         dest.writeInt(mCpid);
+        dest.writeString(mAlphaLong);
+        dest.writeString(mAlphaShort);
     }
 
     /** Construct from Parcel, type has already been processed */
@@ -169,6 +229,8 @@
         mLac = in.readInt();
         mCid = in.readInt();
         mCpid = in.readInt();
+        mAlphaLong = in.readString();
+        mAlphaShort = in.readString();
 
         if (DBG) log(toString());
     }
diff --git a/telephony/java/android/telephony/CellIdentityWcdma.java b/telephony/java/android/telephony/CellIdentityWcdma.java
index affa0c1..52fa54f 100644
--- a/telephony/java/android/telephony/CellIdentityWcdma.java
+++ b/telephony/java/android/telephony/CellIdentityWcdma.java
@@ -16,6 +16,7 @@
 
 package android.telephony;
 
+import android.annotation.Nullable;
 import android.os.Parcel;
 import android.text.TextUtils;
 
@@ -182,6 +183,7 @@
      * @return The long alpha tag associated with the current scan result (may be the operator
      * name string or extended operator name string). May be null if unknown.
      */
+    @Nullable
     public CharSequence getOperatorAlphaLong() {
         return mAlphaLong;
     }
@@ -190,6 +192,7 @@
      * @return The short alpha tag associated with the current scan result (may be the operator
      * name string or extended operator name string).  May be null if unknown.
      */
+    @Nullable
     public CharSequence getOperatorAlphaShort() {
         return mAlphaShort;
     }
diff --git a/telephony/java/android/telephony/euicc/EuiccManager.java b/telephony/java/android/telephony/euicc/EuiccManager.java
index 71ef5de..8279123 100644
--- a/telephony/java/android/telephony/euicc/EuiccManager.java
+++ b/telephony/java/android/telephony/euicc/EuiccManager.java
@@ -15,11 +15,12 @@
  */
 package android.telephony.euicc;
 
+import android.Manifest;
 import android.annotation.IntDef;
 import android.annotation.Nullable;
+import android.annotation.RequiresPermission;
 import android.annotation.SdkConstant;
 import android.annotation.SystemApi;
-import android.annotation.TestApi;
 import android.app.Activity;
 import android.app.PendingIntent;
 import android.content.Context;
@@ -73,6 +74,7 @@
      */
     @SystemApi
     @SdkConstant(SdkConstant.SdkConstantType.BROADCAST_INTENT_ACTION)
+    @RequiresPermission(Manifest.permission.WRITE_EMBEDDED_SUBSCRIPTIONS)
     public static final String ACTION_OTA_STATUS_CHANGED =
             "android.telephony.euicc.action.OTA_STATUS_CHANGED";
 
@@ -301,6 +303,7 @@
      * @hide
      */
     @SystemApi
+    @RequiresPermission(Manifest.permission.WRITE_EMBEDDED_SUBSCRIPTIONS)
     public int getOtaStatus() {
         if (!isEnabled()) {
             return EUICC_OTA_STATUS_UNAVAILABLE;
@@ -325,6 +328,7 @@
      * @param switchAfterDownload if true, the profile will be activated upon successful download.
      * @param callbackIntent a PendingIntent to launch when the operation completes.
      */
+    @RequiresPermission(Manifest.permission.WRITE_EMBEDDED_SUBSCRIPTIONS)
     public void downloadSubscription(DownloadableSubscription subscription,
             boolean switchAfterDownload, PendingIntent callbackIntent) {
         if (!isEnabled()) {
@@ -387,6 +391,7 @@
      * @hide
      */
     @SystemApi
+    @RequiresPermission(Manifest.permission.WRITE_EMBEDDED_SUBSCRIPTIONS)
     public void continueOperation(Intent resolutionIntent, Bundle resolutionExtras) {
         if (!isEnabled()) {
             PendingIntent callbackIntent =
@@ -422,6 +427,7 @@
      * @hide
      */
     @SystemApi
+    @RequiresPermission(Manifest.permission.WRITE_EMBEDDED_SUBSCRIPTIONS)
     public void getDownloadableSubscriptionMetadata(
             DownloadableSubscription subscription, PendingIntent callbackIntent) {
         if (!isEnabled()) {
@@ -452,6 +458,7 @@
      * @hide
      */
     @SystemApi
+    @RequiresPermission(Manifest.permission.WRITE_EMBEDDED_SUBSCRIPTIONS)
     public void getDefaultDownloadableSubscriptionList(PendingIntent callbackIntent) {
         if (!isEnabled()) {
             sendUnavailableError(callbackIntent);
@@ -496,6 +503,7 @@
      * @param subscriptionId the ID of the subscription to delete.
      * @param callbackIntent a PendingIntent to launch when the operation completes.
      */
+    @RequiresPermission(Manifest.permission.WRITE_EMBEDDED_SUBSCRIPTIONS)
     public void deleteSubscription(int subscriptionId, PendingIntent callbackIntent) {
         if (!isEnabled()) {
             sendUnavailableError(callbackIntent);
@@ -523,6 +531,7 @@
      *     current profile without activating another profile to replace it.
      * @param callbackIntent a PendingIntent to launch when the operation completes.
      */
+    @RequiresPermission(Manifest.permission.WRITE_EMBEDDED_SUBSCRIPTIONS)
     public void switchToSubscription(int subscriptionId, PendingIntent callbackIntent) {
         if (!isEnabled()) {
             sendUnavailableError(callbackIntent);
@@ -548,6 +557,7 @@
      * @param callbackIntent a PendingIntent to launch when the operation completes.
      * @hide
      */
+    @RequiresPermission(Manifest.permission.WRITE_EMBEDDED_SUBSCRIPTIONS)
     public void updateSubscriptionNickname(
             int subscriptionId, String nickname, PendingIntent callbackIntent) {
         if (!isEnabled()) {
@@ -566,12 +576,13 @@
      * Erase all subscriptions and reset the eUICC.
      *
      * <p>Requires that the calling app has the
-     * {@link android.Manifest.permission#WRITE_EMBEDDED_SUBSCRIPTIONS} permission. This is for
-     * internal system use only.
+     * {@code android.Manifest.permission#WRITE_EMBEDDED_SUBSCRIPTIONS} permission.
      *
      * @param callbackIntent a PendingIntent to launch when the operation completes.
      * @hide
      */
+    @SystemApi
+    @RequiresPermission(Manifest.permission.WRITE_EMBEDDED_SUBSCRIPTIONS)
     public void eraseSubscriptions(PendingIntent callbackIntent) {
         if (!isEnabled()) {
             sendUnavailableError(callbackIntent);
diff --git a/tests/net/java/android/net/NetworkStatsTest.java b/tests/net/java/android/net/NetworkStatsTest.java
index 035a4cd7..0530a86 100644
--- a/tests/net/java/android/net/NetworkStatsTest.java
+++ b/tests/net/java/android/net/NetworkStatsTest.java
@@ -19,6 +19,7 @@
 import static android.net.NetworkStats.DEFAULT_NETWORK_ALL;
 import static android.net.NetworkStats.DEFAULT_NETWORK_NO;
 import static android.net.NetworkStats.DEFAULT_NETWORK_YES;
+import static android.net.NetworkStats.INTERFACES_ALL;
 import static android.net.NetworkStats.METERED_ALL;
 import static android.net.NetworkStats.METERED_NO;
 import static android.net.NetworkStats.METERED_YES;
@@ -31,6 +32,7 @@
 import static android.net.NetworkStats.SET_DBG_VPN_OUT;
 import static android.net.NetworkStats.SET_ALL;
 import static android.net.NetworkStats.IFACE_ALL;
+import static android.net.NetworkStats.TAG_ALL;
 import static android.net.NetworkStats.TAG_NONE;
 import static android.net.NetworkStats.UID_ALL;
 import static org.junit.Assert.assertEquals;
@@ -641,6 +643,136 @@
                 ROAMING_ALL, DEFAULT_NETWORK_ALL, 50500L, 27L, 100200L, 55, 0);
     }
 
+    @Test
+    public void testFilter_NoFilter() {
+        NetworkStats.Entry entry1 = new NetworkStats.Entry(
+                "test1", 10100, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO,
+                DEFAULT_NETWORK_NO, 50000L, 25L, 100000L, 50L, 0L);
+
+        NetworkStats.Entry entry2 = new NetworkStats.Entry(
+                "test2", 10101, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO,
+                DEFAULT_NETWORK_NO, 50000L, 25L, 100000L, 50L, 0L);
+
+        NetworkStats.Entry entry3 = new NetworkStats.Entry(
+                "test2", 10101, SET_DEFAULT, 123, METERED_NO, ROAMING_NO,
+                DEFAULT_NETWORK_NO, 50000L, 25L, 100000L, 50L, 0L);
+
+        NetworkStats stats = new NetworkStats(TEST_START, 3)
+                .addValues(entry1)
+                .addValues(entry2)
+                .addValues(entry3);
+
+        stats.filter(UID_ALL, INTERFACES_ALL, TAG_ALL);
+        assertEquals(3, stats.size());
+        assertEquals(entry1, stats.getValues(0, null));
+        assertEquals(entry2, stats.getValues(1, null));
+        assertEquals(entry3, stats.getValues(2, null));
+    }
+
+    @Test
+    public void testFilter_UidFilter() {
+        final int testUid = 10101;
+        NetworkStats.Entry entry1 = new NetworkStats.Entry(
+                "test1", 10100, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO,
+                DEFAULT_NETWORK_NO, 50000L, 25L, 100000L, 50L, 0L);
+
+        NetworkStats.Entry entry2 = new NetworkStats.Entry(
+                "test2", testUid, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO,
+                DEFAULT_NETWORK_NO, 50000L, 25L, 100000L, 50L, 0L);
+
+        NetworkStats.Entry entry3 = new NetworkStats.Entry(
+                "test2", testUid, SET_DEFAULT, 123, METERED_NO, ROAMING_NO,
+                DEFAULT_NETWORK_NO, 50000L, 25L, 100000L, 50L, 0L);
+
+        NetworkStats stats = new NetworkStats(TEST_START, 3)
+                .addValues(entry1)
+                .addValues(entry2)
+                .addValues(entry3);
+
+        stats.filter(testUid, INTERFACES_ALL, TAG_ALL);
+        assertEquals(2, stats.size());
+        assertEquals(entry2, stats.getValues(0, null));
+        assertEquals(entry3, stats.getValues(1, null));
+    }
+
+    @Test
+    public void testFilter_InterfaceFilter() {
+        final String testIf1 = "testif1";
+        final String testIf2 = "testif2";
+        NetworkStats.Entry entry1 = new NetworkStats.Entry(
+                testIf1, 10100, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO,
+                DEFAULT_NETWORK_NO, 50000L, 25L, 100000L, 50L, 0L);
+
+        NetworkStats.Entry entry2 = new NetworkStats.Entry(
+                "otherif", 10101, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO,
+                DEFAULT_NETWORK_NO, 50000L, 25L, 100000L, 50L, 0L);
+
+        NetworkStats.Entry entry3 = new NetworkStats.Entry(
+                testIf1, 10101, SET_DEFAULT, 123, METERED_NO, ROAMING_NO,
+                DEFAULT_NETWORK_NO, 50000L, 25L, 100000L, 50L, 0L);
+
+        NetworkStats.Entry entry4 = new NetworkStats.Entry(
+                testIf2, 10101, SET_DEFAULT, 123, METERED_NO, ROAMING_NO,
+                DEFAULT_NETWORK_NO, 50000L, 25L, 100000L, 50L, 0L);
+
+        NetworkStats stats = new NetworkStats(TEST_START, 4)
+                .addValues(entry1)
+                .addValues(entry2)
+                .addValues(entry3)
+                .addValues(entry4);
+
+        stats.filter(UID_ALL, new String[] { testIf1, testIf2 }, TAG_ALL);
+        assertEquals(3, stats.size());
+        assertEquals(entry1, stats.getValues(0, null));
+        assertEquals(entry3, stats.getValues(1, null));
+        assertEquals(entry4, stats.getValues(2, null));
+    }
+
+    @Test
+    public void testFilter_EmptyInterfaceFilter() {
+        NetworkStats.Entry entry1 = new NetworkStats.Entry(
+                "if1", 10100, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO,
+                DEFAULT_NETWORK_NO, 50000L, 25L, 100000L, 50L, 0L);
+
+        NetworkStats.Entry entry2 = new NetworkStats.Entry(
+                "if2", 10101, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO,
+                DEFAULT_NETWORK_NO, 50000L, 25L, 100000L, 50L, 0L);
+
+        NetworkStats stats = new NetworkStats(TEST_START, 3)
+                .addValues(entry1)
+                .addValues(entry2);
+
+        stats.filter(UID_ALL, new String[] { }, TAG_ALL);
+        assertEquals(0, stats.size());
+    }
+
+    @Test
+    public void testFilter_TagFilter() {
+        final int testTag = 123;
+        final int otherTag = 456;
+        NetworkStats.Entry entry1 = new NetworkStats.Entry(
+                "test1", 10100, SET_DEFAULT, testTag, METERED_NO, ROAMING_NO,
+                DEFAULT_NETWORK_NO, 50000L, 25L, 100000L, 50L, 0L);
+
+        NetworkStats.Entry entry2 = new NetworkStats.Entry(
+                "test2", 10101, SET_DEFAULT, testTag, METERED_NO, ROAMING_NO,
+                DEFAULT_NETWORK_NO, 50000L, 25L, 100000L, 50L, 0L);
+
+        NetworkStats.Entry entry3 = new NetworkStats.Entry(
+                "test2", 10101, SET_DEFAULT, otherTag, METERED_NO, ROAMING_NO,
+                DEFAULT_NETWORK_NO, 50000L, 25L, 100000L, 50L, 0L);
+
+        NetworkStats stats = new NetworkStats(TEST_START, 3)
+                .addValues(entry1)
+                .addValues(entry2)
+                .addValues(entry3);
+
+        stats.filter(UID_ALL, INTERFACES_ALL, testTag);
+        assertEquals(2, stats.size());
+        assertEquals(entry1, stats.getValues(0, null));
+        assertEquals(entry2, stats.getValues(1, null));
+    }
+
     private static void assertContains(NetworkStats stats,  String iface, int uid, int set,
             int tag, int metered, int roaming, int defaultNetwork, long rxBytes, long rxPackets,
             long txBytes, long txPackets, long operations) {
diff --git a/tests/net/java/com/android/internal/net/NetworkStatsFactoryTest.java b/tests/net/java/com/android/internal/net/NetworkStatsFactoryTest.java
index b14f550..fc46b9c 100644
--- a/tests/net/java/com/android/internal/net/NetworkStatsFactoryTest.java
+++ b/tests/net/java/com/android/internal/net/NetworkStatsFactoryTest.java
@@ -184,7 +184,7 @@
         assertStatsEntry(stats, "dummy0", 0, SET_DEFAULT, 0x0, 0L, 168L);
         assertStatsEntry(stats, "lo", 0, SET_DEFAULT, 0x0, 1288L, 1288L);
 
-        NetworkStatsFactory.noteStackedIface("v4-wlan0", null);
+        NetworkStatsFactory.clearStackedIfaces();
     }
 
     @Test
@@ -212,7 +212,7 @@
         assertStatsEntry(stats, "v4-wlan0", 10106, SET_FOREGROUND, 0x0, appRxBytesAfter, 7867488L);
         assertStatsEntry(stats, "wlan0", 0, SET_DEFAULT, 0x0, rootRxBytesAfter, 647587L);
 
-        NetworkStatsFactory.noteStackedIface("v4-wlan0", null);
+        NetworkStatsFactory.clearStackedIfaces();
     }
 
     /**
diff --git a/tests/net/java/com/android/server/IpSecServiceParameterizedTest.java b/tests/net/java/com/android/server/IpSecServiceParameterizedTest.java
index a5c55e8..410f754 100644
--- a/tests/net/java/com/android/server/IpSecServiceParameterizedTest.java
+++ b/tests/net/java/com/android/server/IpSecServiceParameterizedTest.java
@@ -23,6 +23,7 @@
 import static org.mockito.Matchers.anyString;
 import static org.mockito.Matchers.eq;
 import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.times;
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
 
@@ -320,6 +321,30 @@
     }
 
     @Test
+    public void testReleaseOwnedSpi() throws Exception {
+        IpSecConfig ipSecConfig = new IpSecConfig();
+        addDefaultSpisAndRemoteAddrToIpSecConfig(ipSecConfig);
+        addAuthAndCryptToIpSecConfig(ipSecConfig);
+
+        IpSecTransformResponse createTransformResp =
+                mIpSecService.createTransform(ipSecConfig, new Binder());
+        IpSecService.UserRecord userRecord =
+                mIpSecService.mUserResourceTracker.getUserRecord(Os.getuid());
+        assertEquals(1, userRecord.mSpiQuotaTracker.mCurrent);
+        mIpSecService.releaseSecurityParameterIndex(ipSecConfig.getSpiResourceId());
+        verify(mMockNetd, times(0))
+                .ipSecDeleteSecurityAssociation(
+                        eq(createTransformResp.resourceId),
+                        anyString(),
+                        anyString(),
+                        eq(TEST_SPI),
+                        anyInt(),
+                        anyInt());
+        // quota is not released until the SPI is released by the Transform
+        assertEquals(1, userRecord.mSpiQuotaTracker.mCurrent);
+    }
+
+    @Test
     public void testDeleteTransform() throws Exception {
         IpSecConfig ipSecConfig = new IpSecConfig();
         addDefaultSpisAndRemoteAddrToIpSecConfig(ipSecConfig);
@@ -329,7 +354,7 @@
                 mIpSecService.createTransform(ipSecConfig, new Binder());
         mIpSecService.deleteTransform(createTransformResp.resourceId);
 
-        verify(mMockNetd)
+        verify(mMockNetd, times(1))
                 .ipSecDeleteSecurityAssociation(
                         eq(createTransformResp.resourceId),
                         anyString(),
@@ -342,6 +367,21 @@
         IpSecService.UserRecord userRecord =
                 mIpSecService.mUserResourceTracker.getUserRecord(Os.getuid());
         assertEquals(0, userRecord.mTransformQuotaTracker.mCurrent);
+        assertEquals(1, userRecord.mSpiQuotaTracker.mCurrent);
+
+        mIpSecService.releaseSecurityParameterIndex(ipSecConfig.getSpiResourceId());
+        // Verify that ipSecDeleteSa was not called when the SPI was released because the
+        // ownedByTransform property should prevent it; (note, the called count is cumulative).
+        verify(mMockNetd, times(1))
+                .ipSecDeleteSecurityAssociation(
+                        anyInt(),
+                        anyString(),
+                        anyString(),
+                        anyInt(),
+                        anyInt(),
+                        anyInt());
+        assertEquals(0, userRecord.mSpiQuotaTracker.mCurrent);
+
         try {
             userRecord.mTransformRecords.getRefcountedResourceOrThrow(
                     createTransformResp.resourceId);
diff --git a/tests/net/java/com/android/server/net/NetworkStatsServiceTest.java b/tests/net/java/com/android/server/net/NetworkStatsServiceTest.java
index 47c3455..17ca651 100644
--- a/tests/net/java/com/android/server/net/NetworkStatsServiceTest.java
+++ b/tests/net/java/com/android/server/net/NetworkStatsServiceTest.java
@@ -25,6 +25,7 @@
 import static android.net.NetworkStats.DEFAULT_NETWORK_NO;
 import static android.net.NetworkStats.DEFAULT_NETWORK_YES;
 import static android.net.NetworkStats.IFACE_ALL;
+import static android.net.NetworkStats.INTERFACES_ALL;
 import static android.net.NetworkStats.METERED_ALL;
 import static android.net.NetworkStats.METERED_NO;
 import static android.net.NetworkStats.METERED_YES;
@@ -58,6 +59,9 @@
 import static org.mockito.ArgumentMatchers.any;
 import static org.mockito.ArgumentMatchers.anyInt;
 import static org.mockito.ArgumentMatchers.anyLong;
+import static org.mockito.ArgumentMatchers.argThat;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.times;
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
 
@@ -95,6 +99,7 @@
 import android.util.TrustedTime;
 
 import com.android.internal.net.VpnInfo;
+import com.android.internal.util.ArrayUtils;
 import com.android.internal.util.test.BroadcastInterceptingContext;
 import com.android.server.net.NetworkStatsService.NetworkStatsSettings;
 import com.android.server.net.NetworkStatsService.NetworkStatsSettings.Config;
@@ -668,6 +673,94 @@
     }
 
     @Test
+    public void testDetailedUidStats() throws Exception {
+        // pretend that network comes online
+        expectDefaultSettings();
+        expectNetworkState(buildWifiState());
+        expectNetworkStatsSummary(buildEmptyStats());
+        expectNetworkStatsUidDetail(buildEmptyStats());
+        expectBandwidthControlCheck();
+
+        mService.forceUpdateIfaces(NETWORKS_WIFI);
+
+        NetworkStats.Entry entry1 = new NetworkStats.Entry(
+                TEST_IFACE, UID_RED, SET_DEFAULT, TAG_NONE, 50L, 5L, 50L, 5L, 0L);
+        NetworkStats.Entry entry2 = new NetworkStats.Entry(
+                TEST_IFACE, UID_RED, SET_DEFAULT, 0xF00D, 50L, 5L, 50L, 5L, 0L);
+        NetworkStats.Entry entry3 = new NetworkStats.Entry(
+                TEST_IFACE, UID_BLUE, SET_DEFAULT, 0xBEEF, 1024L, 8L, 512L, 4L, 0L);
+
+        incrementCurrentTime(HOUR_IN_MILLIS);
+        expectDefaultSettings();
+        expectNetworkStatsSummary(buildEmptyStats());
+        expectNetworkStatsUidDetail(new NetworkStats(getElapsedRealtime(), 3)
+                .addValues(entry1)
+                .addValues(entry2)
+                .addValues(entry3));
+        mService.incrementOperationCount(UID_RED, 0xF00D, 1);
+
+        NetworkStats stats = mService.getDetailedUidStats(INTERFACES_ALL);
+
+        assertEquals(3, stats.size());
+        entry1.operations = 1;
+        assertEquals(entry1, stats.getValues(0, null));
+        entry2.operations = 1;
+        assertEquals(entry2, stats.getValues(1, null));
+        assertEquals(entry3, stats.getValues(2, null));
+    }
+
+    @Test
+    public void testDetailedUidStats_Filtered() throws Exception {
+        // pretend that network comes online
+        expectDefaultSettings();
+
+        final String stackedIface = "stacked-test0";
+        final LinkProperties stackedProp = new LinkProperties();
+        stackedProp.setInterfaceName(stackedIface);
+        final NetworkState wifiState = buildWifiState();
+        wifiState.linkProperties.addStackedLink(stackedProp);
+        expectNetworkState(wifiState);
+
+        expectNetworkStatsSummary(buildEmptyStats());
+        expectNetworkStatsUidDetail(buildEmptyStats());
+        expectBandwidthControlCheck();
+
+        mService.forceUpdateIfaces(NETWORKS_WIFI);
+
+        NetworkStats.Entry uidStats = new NetworkStats.Entry(
+                TEST_IFACE, UID_BLUE, SET_DEFAULT, 0xF00D, 1024L, 8L, 512L, 4L, 0L);
+        // Stacked on matching interface
+        NetworkStats.Entry tetheredStats1 = new NetworkStats.Entry(
+                stackedIface, UID_BLUE, SET_DEFAULT, 0xF00D, 1024L, 8L, 512L, 4L, 0L);
+        // Different interface
+        NetworkStats.Entry tetheredStats2 = new NetworkStats.Entry(
+                "otherif", UID_BLUE, SET_DEFAULT, 0xF00D, 1024L, 8L, 512L, 4L, 0L);
+
+        final String[] ifaceFilter = new String[] { TEST_IFACE };
+        incrementCurrentTime(HOUR_IN_MILLIS);
+        expectDefaultSettings();
+        expectNetworkStatsSummary(buildEmptyStats());
+        when(mNetManager.getNetworkStatsUidDetail(eq(UID_ALL), any()))
+                .thenReturn(new NetworkStats(getElapsedRealtime(), 1)
+                        .addValues(uidStats));
+        when(mNetManager.getNetworkStatsTethering(STATS_PER_UID))
+                .thenReturn(new NetworkStats(getElapsedRealtime(), 2)
+                        .addValues(tetheredStats1)
+                        .addValues(tetheredStats2));
+
+        NetworkStats stats = mService.getDetailedUidStats(ifaceFilter);
+
+        verify(mNetManager, times(1)).getNetworkStatsUidDetail(eq(UID_ALL), argThat(ifaces ->
+                ifaces != null && ifaces.length == 2
+                        && ArrayUtils.contains(ifaces, TEST_IFACE)
+                        && ArrayUtils.contains(ifaces, stackedIface)));
+
+        assertEquals(2, stats.size());
+        assertEquals(uidStats, stats.getValues(0, null));
+        assertEquals(tetheredStats1, stats.getValues(1, null));
+    }
+
+    @Test
     public void testForegroundBackground() throws Exception {
         // pretend that network comes online
         expectCurrentTime();
@@ -1056,7 +1149,7 @@
 
     private void expectNetworkStatsUidDetail(NetworkStats detail, NetworkStats tetherStats)
             throws Exception {
-        when(mNetManager.getNetworkStatsUidDetail(UID_ALL)).thenReturn(detail);
+        when(mNetManager.getNetworkStatsUidDetail(UID_ALL, INTERFACES_ALL)).thenReturn(detail);
 
         // also include tethering details, since they are folded into UID
         when(mNetManager.getNetworkStatsTethering(STATS_PER_UID)).thenReturn(tetherStats);
diff --git a/tools/fonts/fontchain_linter.py b/tools/fonts/fontchain_linter.py
index c6ad4c2..dcb90e4 100755
--- a/tools/fonts/fontchain_linter.py
+++ b/tools/fonts/fontchain_linter.py
@@ -13,6 +13,7 @@
 
 LANG_TO_SCRIPT = {
     'as': 'Beng',
+    'be': 'Cyrl',
     'bg': 'Cyrl',
     'bn': 'Beng',
     'cu': 'Cyrl',
@@ -33,6 +34,7 @@
     'ja': 'Jpan',
     'kn': 'Knda',
     'ko': 'Kore',
+    'la': 'Latn',
     'ml': 'Mlym',
     'mn': 'Cyrl',
     'mr': 'Deva',