Merge "Atom: Update BluetoothConnectionStateChanged atom"
diff --git a/Android.bp b/Android.bp
index ab2bd9d..580df85 100644
--- a/Android.bp
+++ b/Android.bp
@@ -704,7 +704,6 @@
     required: [
         // TODO: remove gps_debug when the build system propagates "required" properly.
         "gps_debug.conf",
-        "libtextclassifier",
         // Loaded with System.loadLibrary by android.view.textclassifier
         "libmedia2_jni",
     ],
@@ -830,7 +829,12 @@
         "core/java/android/net/IIpMemoryStore.aidl",
         "core/java/android/net/INetworkStackConnector.aidl",
         "core/java/android/net/INetworkStackStatusCallback.aidl",
+        "core/java/android/net/IpPrefixParcelable.aidl",
+        "core/java/android/net/LinkAddressParcelable.aidl",
+        "core/java/android/net/LinkPropertiesParcelable.aidl",
         "core/java/android/net/PrivateDnsConfigParcel.aidl",
+        "core/java/android/net/ProxyInfoParcelable.aidl",
+        "core/java/android/net/RouteInfoParcelable.aidl",
         "core/java/android/net/dhcp/DhcpServingParamsParcel.aidl",
         "core/java/android/net/dhcp/IDhcpServer.aidl",
         "core/java/android/net/dhcp/IDhcpServerCallbacks.aidl",
@@ -850,6 +854,10 @@
         "nist-sip",
         "tagsoup",
         "rappor",
+        "libtextclassifier-java",
+    ],
+    required: [
+        "libtextclassifier",
     ],
     dxflags: ["--core-library"],
 }
@@ -1256,7 +1264,6 @@
         "ext",
         "framework",
         "voip-common",
-        "android.test.mock.impl",
     ],
     local_sourcepaths: frameworks_base_subdirs,
     installable: false,
diff --git a/api/current.txt b/api/current.txt
index 7c7429f..e4ecd5e 100755
--- a/api/current.txt
+++ b/api/current.txt
@@ -41302,10 +41302,10 @@
     ctor public CallRedirectionService();
     method public final void cancelCall();
     method public final android.os.IBinder onBind(android.content.Intent);
-    method public abstract void onPlaceCall(android.net.Uri, android.telecom.PhoneAccountHandle);
+    method public abstract void onPlaceCall(android.net.Uri, android.telecom.PhoneAccountHandle, boolean);
     method public final boolean onUnbind(android.content.Intent);
     method public final void placeCallUnmodified();
-    method public final void redirectCall(android.net.Uri, android.telecom.PhoneAccountHandle);
+    method public final void redirectCall(android.net.Uri, android.telecom.PhoneAccountHandle, boolean);
     field public static final java.lang.String SERVICE_INTERFACE = "android.telecom.CallRedirectionService";
   }
 
@@ -43336,7 +43336,7 @@
     field public static final int PROTOCOL_IPV6 = 1; // 0x1
     field public static final int PROTOCOL_PPP = 3; // 0x3
     field public static final int TYPE_CBS = 128; // 0x80
-    field public static final int TYPE_DEFAULT = 1; // 0x1
+    field public static final int TYPE_DEFAULT = 17; // 0x11
     field public static final int TYPE_DUN = 8; // 0x8
     field public static final int TYPE_EMERGENCY = 512; // 0x200
     field public static final int TYPE_FOTA = 32; // 0x20
@@ -43380,6 +43380,7 @@
     method public int compareTo(android.telephony.emergency.EmergencyNumber);
     method public int describeContents();
     method public java.lang.String getCountryIso();
+    method public int getEmergencyCallRouting();
     method public int getEmergencyNumberSourceBitmask();
     method public java.util.List<java.lang.Integer> getEmergencyNumberSources();
     method public java.util.List<java.lang.Integer> getEmergencyServiceCategories();
@@ -43390,6 +43391,9 @@
     method public boolean isInEmergencyServiceCategories(int);
     method public void writeToParcel(android.os.Parcel, int);
     field public static final android.os.Parcelable.Creator<android.telephony.emergency.EmergencyNumber> CREATOR;
+    field public static final int EMERGENCY_CALL_ROUTING_EMERGENCY = 1; // 0x1
+    field public static final int EMERGENCY_CALL_ROUTING_NORMAL = 2; // 0x2
+    field public static final int EMERGENCY_CALL_ROUTING_UNKNOWN = 0; // 0x0
     field public static final int EMERGENCY_NUMBER_SOURCE_DATABASE = 16; // 0x10
     field public static final int EMERGENCY_NUMBER_SOURCE_DEFAULT = 8; // 0x8
     field public static final int EMERGENCY_NUMBER_SOURCE_MODEM_CONFIG = 4; // 0x4
@@ -43427,6 +43431,7 @@
   }
 
   public class EuiccManager {
+    method public android.telephony.euicc.EuiccManager createForCardId(int);
     method public void deleteSubscription(int, android.app.PendingIntent);
     method public void downloadSubscription(android.telephony.euicc.DownloadableSubscription, boolean, android.app.PendingIntent);
     method public java.lang.String getEid();
diff --git a/api/system-current.txt b/api/system-current.txt
index 1bf6cf9..9cdc682 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -6040,6 +6040,7 @@
     method public android.os.Bundle getCallExtras();
     method public int getCallType();
     method public static int getCallTypeFromVideoState(int);
+    method public int getEmergencyCallRouting();
     method public int getEmergencyServiceCategories();
     method public android.telephony.ims.ImsStreamMediaProfile getMediaProfile();
     method public int getRestrictCause();
@@ -6053,6 +6054,7 @@
     method public void setCallExtraBoolean(java.lang.String, boolean);
     method public void setCallExtraInt(java.lang.String, int);
     method public void setCallRestrictCause(int);
+    method public void setEmergencyCallRouting(int);
     method public void setEmergencyServiceCategories(int);
     method public void updateCallExtras(android.telephony.ims.ImsCallProfile);
     method public void updateCallType(android.telephony.ims.ImsCallProfile);
diff --git a/config/hiddenapi-greylist.txt b/config/hiddenapi-greylist.txt
index 7b1c26a..2bd813e 100644
--- a/config/hiddenapi-greylist.txt
+++ b/config/hiddenapi-greylist.txt
@@ -3643,11 +3643,9 @@
 Lcom/android/internal/telephony/SubscriptionInfoUpdater;->mContext:Landroid/content/Context;
 Lcom/android/internal/telephony/SubscriptionInfoUpdater;->mCurrentlyActiveUserId:I
 Lcom/android/internal/telephony/SubscriptionInfoUpdater;->mIccId:[Ljava/lang/String;
-Lcom/android/internal/telephony/SubscriptionInfoUpdater;->mInsertSimState:[I
 Lcom/android/internal/telephony/SubscriptionInfoUpdater;->mPackageManager:Landroid/content/pm/IPackageManager;
 Lcom/android/internal/telephony/SubscriptionInfoUpdater;->mPhone:[Lcom/android/internal/telephony/Phone;
 Lcom/android/internal/telephony/SubscriptionInfoUpdater;->PROJECT_SIM_NUM:I
-Lcom/android/internal/telephony/SubscriptionInfoUpdater;->updateSubscriptionInfoByIccId()V
 Lcom/android/internal/telephony/TelephonyCapabilities;->supportsAdn(I)Z
 Lcom/android/internal/telephony/TelephonyProperties;->PROPERTY_ICC_OPERATOR_NUMERIC:Ljava/lang/String;
 Lcom/android/internal/telephony/test/InterpreterEx;-><init>(Ljava/lang/String;)V
diff --git a/core/java/android/net/IpPrefixParcelable.aidl b/core/java/android/net/IpPrefixParcelable.aidl
new file mode 100644
index 0000000..93a8d41
--- /dev/null
+++ b/core/java/android/net/IpPrefixParcelable.aidl
@@ -0,0 +1,22 @@
+/*
+ * Copyright (C) 2019 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.net;
+
+parcelable IpPrefixParcelable {
+    String address;
+    int prefixLength;
+}
\ No newline at end of file
diff --git a/core/java/android/net/LinkAddressParcelable.aidl b/core/java/android/net/LinkAddressParcelable.aidl
new file mode 100644
index 0000000..af8e79b
--- /dev/null
+++ b/core/java/android/net/LinkAddressParcelable.aidl
@@ -0,0 +1,24 @@
+/*
+ * Copyright (C) 2019 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.net;
+
+parcelable LinkAddressParcelable {
+    String address;
+    int prefixLength;
+    int flags;
+    int scope;
+}
\ No newline at end of file
diff --git a/core/java/android/net/LinkPropertiesParcelable.aidl b/core/java/android/net/LinkPropertiesParcelable.aidl
new file mode 100644
index 0000000..b153dc7
--- /dev/null
+++ b/core/java/android/net/LinkPropertiesParcelable.aidl
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2019 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.net;
+
+import android.net.IpPrefixParcelable;
+import android.net.LinkAddressParcelable;
+import android.net.ProxyInfoParcelable;
+import android.net.RouteInfoParcelable;
+
+parcelable LinkPropertiesParcelable {
+    String ifaceName;
+    LinkAddressParcelable[] linkAddresses;
+    String[] dnses;
+    String[] pcscfs;
+    String[] validatedPrivateDnses;
+    boolean usePrivateDns;
+    String privateDnsServerName;
+    String domains;
+    RouteInfoParcelable[] routes;
+    ProxyInfoParcelable httpProxy;
+    int mtu;
+    String tcpBufferSizes;
+    IpPrefixParcelable nat64Prefix;
+    LinkPropertiesParcelable[] stackedLinks;
+}
\ No newline at end of file
diff --git a/core/java/android/net/ProxyInfoParcelable.aidl b/core/java/android/net/ProxyInfoParcelable.aidl
new file mode 100644
index 0000000..59fd846
--- /dev/null
+++ b/core/java/android/net/ProxyInfoParcelable.aidl
@@ -0,0 +1,24 @@
+/*
+ * Copyright (C) 2019 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.net;
+
+parcelable ProxyInfoParcelable {
+    String host;
+    int port;
+    String[] exclusionList;
+    String pacFileUrl;
+}
diff --git a/core/java/android/net/RouteInfoParcelable.aidl b/core/java/android/net/RouteInfoParcelable.aidl
new file mode 100644
index 0000000..15bcdcf
--- /dev/null
+++ b/core/java/android/net/RouteInfoParcelable.aidl
@@ -0,0 +1,26 @@
+/*
+ * Copyright (C) 2019 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.net;
+
+import android.net.IpPrefixParcelable;
+
+parcelable RouteInfoParcelable {
+    IpPrefixParcelable destination;
+    String gatewayAddr;
+    String ifaceName;
+    int type;
+}
diff --git a/core/java/android/view/LayoutInflater.java b/core/java/android/view/LayoutInflater.java
index 7232890..f2259b0 100644
--- a/core/java/android/view/LayoutInflater.java
+++ b/core/java/android/view/LayoutInflater.java
@@ -28,6 +28,7 @@
 import android.graphics.Canvas;
 import android.os.Handler;
 import android.os.Message;
+import android.os.SystemProperties;
 import android.os.Trace;
 import android.util.AttributeSet;
 import android.util.Log;
@@ -37,6 +38,9 @@
 
 import com.android.internal.R;
 
+import dalvik.system.PathClassLoader;
+import java.io.File;
+import java.lang.reflect.Method;
 import org.xmlpull.v1.XmlPullParser;
 import org.xmlpull.v1.XmlPullParserException;
 
@@ -71,6 +75,10 @@
     private static final String TAG = LayoutInflater.class.getSimpleName();
     private static final boolean DEBUG = false;
 
+    private static final String USE_PRECOMPILED_LAYOUT_SYSTEM_PROPERTY
+        = "view.precompiled_layout_enabled";
+    private static final String COMPILED_VIEW_DEX_FILE_NAME = "/compiled_view.dex";
+
     /** Empty stack trace used to avoid log spam in re-throw exceptions. */
     private static final StackTraceElement[] EMPTY_STACK_TRACE = new StackTraceElement[0];
 
@@ -92,6 +100,13 @@
     private Factory2 mPrivateFactory;
     private Filter mFilter;
 
+    // Indicates whether we should try to inflate layouts using a precompiled layout instead of
+    // inflating from the XML resource.
+    private boolean mUseCompiledView;
+    // This variable holds the classloader that will be used to look for precompiled layouts. The
+    // The classloader includes the generated compiled_view.dex file.
+    private ClassLoader mPrecompiledClassLoader;
+
     @UnsupportedAppUsage
     final Object[] mConstructorArgs = new Object[2];
 
@@ -214,6 +229,7 @@
      */
     protected LayoutInflater(Context context) {
         mContext = context;
+        initPrecompiledViews();
     }
 
     /**
@@ -230,6 +246,7 @@
         mFactory2 = original.mFactory2;
         mPrivateFactory = original.mPrivateFactory;
         setFilter(original.mFilter);
+        initPrecompiledViews();
     }
 
     /**
@@ -371,6 +388,29 @@
         }
     }
 
+    private void initPrecompiledViews() {
+        try {
+            mUseCompiledView =
+                SystemProperties.getBoolean(USE_PRECOMPILED_LAYOUT_SYSTEM_PROPERTY, false);
+            if (mUseCompiledView) {
+                mPrecompiledClassLoader = mContext.getClassLoader();
+                String dexFile = mContext.getCodeCacheDir() + COMPILED_VIEW_DEX_FILE_NAME;
+                if (new File(dexFile).exists()) {
+                    mPrecompiledClassLoader = new PathClassLoader(dexFile, mPrecompiledClassLoader);
+                } else {
+                    // If the precompiled layout file doesn't exist, then disable precompiled
+                    // layouts.
+                    mUseCompiledView = false;
+                }
+            }
+        } catch (Throwable e) {
+            if (DEBUG) {
+                Log.e(TAG, "Failed to initialized precompiled views layouts", e);
+            }
+            mUseCompiledView = false;
+        }
+    }
+
     /**
      * Inflate a new view hierarchy from the specified xml resource. Throws
      * {@link InflateException} if there is an error.
@@ -427,10 +467,14 @@
         final Resources res = getContext().getResources();
         if (DEBUG) {
             Log.d(TAG, "INFLATING from resource: \"" + res.getResourceName(resource) + "\" ("
-                    + Integer.toHexString(resource) + ")");
+                  + Integer.toHexString(resource) + ")");
         }
 
-        final XmlResourceParser parser = res.getLayout(resource);
+        View view = tryInflatePrecompiled(resource, res, root, attachToRoot);
+        if (view != null) {
+            return view;
+        }
+        XmlResourceParser parser = res.getLayout(resource);
         try {
             return inflate(parser, root, attachToRoot);
         } finally {
@@ -438,6 +482,73 @@
         }
     }
 
+    private @Nullable
+    View tryInflatePrecompiled(@LayoutRes int resource, Resources res, @Nullable ViewGroup root,
+        boolean attachToRoot) {
+        if (!mUseCompiledView) {
+            return null;
+        }
+
+        Trace.traceBegin(Trace.TRACE_TAG_VIEW, "inflate (precompiled)");
+
+        // Try to inflate using a precompiled layout.
+        String pkg = res.getResourcePackageName(resource);
+        String layout = res.getResourceEntryName(resource);
+
+        try {
+            Class clazz = mPrecompiledClassLoader.loadClass("" + pkg + ".CompiledView");
+            Method inflater = clazz.getMethod(layout, Context.class, int.class);
+            View view = (View) inflater.invoke(null, mContext, resource);
+
+            if (view != null && root != null) {
+                // We were able to use the precompiled inflater, but now we need to do some work to
+                // attach the view to the root correctly.
+                XmlResourceParser parser = res.getLayout(resource);
+                try {
+                    AttributeSet attrs = Xml.asAttributeSet(parser);
+                    advanceToRootNode(parser);
+                    ViewGroup.LayoutParams params = root.generateLayoutParams(attrs);
+
+                    if (attachToRoot) {
+                        root.addView(view, params);
+                    } else {
+                        view.setLayoutParams(params);
+                    }
+                } finally {
+                    parser.close();
+                }
+            }
+
+            return view;
+        } catch (Throwable e) {
+            if (DEBUG) {
+                Log.e(TAG, "Failed to use precompiled view", e);
+            }
+        } finally {
+            Trace.traceEnd(Trace.TRACE_TAG_VIEW);
+        }
+        return null;
+    }
+
+    /**
+     * Advances the given parser to the first START_TAG. Throws InflateException if no start tag is
+     * found.
+     */
+    private void advanceToRootNode(XmlPullParser parser)
+        throws InflateException, IOException, XmlPullParserException {
+        // Look for the root node.
+        int type;
+        while ((type = parser.next()) != XmlPullParser.START_TAG &&
+            type != XmlPullParser.END_DOCUMENT) {
+            // Empty
+        }
+
+        if (type != XmlPullParser.START_TAG) {
+            throw new InflateException(parser.getPositionDescription()
+                + ": No start tag found!");
+        }
+    }
+
     /**
      * Inflate a new view hierarchy from the specified XML node. Throws
      * {@link InflateException} if there is an error.
@@ -471,18 +582,7 @@
             View result = root;
 
             try {
-                // Look for the root node.
-                int type;
-                while ((type = parser.next()) != XmlPullParser.START_TAG &&
-                        type != XmlPullParser.END_DOCUMENT) {
-                    // Empty
-                }
-
-                if (type != XmlPullParser.START_TAG) {
-                    throw new InflateException(parser.getPositionDescription()
-                            + ": No start tag found!");
-                }
-
+                advanceToRootNode(parser);
                 final String name = parser.getName();
 
                 if (DEBUG) {
@@ -985,82 +1085,85 @@
                 + "reference. The layout ID " + value + " is not valid.");
         }
 
-        final XmlResourceParser childParser = context.getResources().getLayout(layout);
+        final View precompiled = tryInflatePrecompiled(layout, context.getResources(),
+            (ViewGroup) parent, /*attachToRoot=*/true);
+        if (precompiled == null) {
+            final XmlResourceParser childParser = context.getResources().getLayout(layout);
 
-        try {
-            final AttributeSet childAttrs = Xml.asAttributeSet(childParser);
+            try {
+                final AttributeSet childAttrs = Xml.asAttributeSet(childParser);
 
-            while ((type = childParser.next()) != XmlPullParser.START_TAG &&
-                type != XmlPullParser.END_DOCUMENT) {
-                // Empty.
+                while ((type = childParser.next()) != XmlPullParser.START_TAG &&
+                    type != XmlPullParser.END_DOCUMENT) {
+                    // Empty.
+                }
+
+                if (type != XmlPullParser.START_TAG) {
+                    throw new InflateException(childParser.getPositionDescription() +
+                        ": No start tag found!");
+                }
+
+                final String childName = childParser.getName();
+
+                if (TAG_MERGE.equals(childName)) {
+                    // The <merge> tag doesn't support android:theme, so
+                    // nothing special to do here.
+                    rInflate(childParser, parent, context, childAttrs, false);
+                } else {
+                    final View view = createViewFromTag(parent, childName,
+                        context, childAttrs, hasThemeOverride);
+                    final ViewGroup group = (ViewGroup) parent;
+
+                    final TypedArray a = context.obtainStyledAttributes(
+                        attrs, R.styleable.Include);
+                    final int id = a.getResourceId(R.styleable.Include_id, View.NO_ID);
+                    final int visibility = a.getInt(R.styleable.Include_visibility, -1);
+                    a.recycle();
+
+                    // We try to load the layout params set in the <include /> tag.
+                    // If the parent can't generate layout params (ex. missing width
+                    // or height for the framework ViewGroups, though this is not
+                    // necessarily true of all ViewGroups) then we expect it to throw
+                    // a runtime exception.
+                    // We catch this exception and set localParams accordingly: true
+                    // means we successfully loaded layout params from the <include>
+                    // tag, false means we need to rely on the included layout params.
+                    ViewGroup.LayoutParams params = null;
+                    try {
+                        params = group.generateLayoutParams(attrs);
+                    } catch (RuntimeException e) {
+                        // Ignore, just fail over to child attrs.
+                    }
+                    if (params == null) {
+                        params = group.generateLayoutParams(childAttrs);
+                    }
+                    view.setLayoutParams(params);
+
+                    // Inflate all children.
+                    rInflateChildren(childParser, view, childAttrs, true);
+
+                    if (id != View.NO_ID) {
+                        view.setId(id);
+                    }
+
+                    switch (visibility) {
+                        case 0:
+                            view.setVisibility(View.VISIBLE);
+                            break;
+                        case 1:
+                            view.setVisibility(View.INVISIBLE);
+                            break;
+                        case 2:
+                            view.setVisibility(View.GONE);
+                            break;
+                    }
+
+                    group.addView(view);
+                }
+            } finally {
+                childParser.close();
             }
-
-            if (type != XmlPullParser.START_TAG) {
-                throw new InflateException(childParser.getPositionDescription() +
-                    ": No start tag found!");
-            }
-
-            final String childName = childParser.getName();
-
-            if (TAG_MERGE.equals(childName)) {
-                // The <merge> tag doesn't support android:theme, so
-                // nothing special to do here.
-                rInflate(childParser, parent, context, childAttrs, false);
-            } else {
-                final View view = createViewFromTag(parent, childName,
-                    context, childAttrs, hasThemeOverride);
-                final ViewGroup group = (ViewGroup) parent;
-
-                final TypedArray a = context.obtainStyledAttributes(
-                    attrs, R.styleable.Include);
-                final int id = a.getResourceId(R.styleable.Include_id, View.NO_ID);
-                final int visibility = a.getInt(R.styleable.Include_visibility, -1);
-                a.recycle();
-
-                // We try to load the layout params set in the <include /> tag.
-                // If the parent can't generate layout params (ex. missing width
-                // or height for the framework ViewGroups, though this is not
-                // necessarily true of all ViewGroups) then we expect it to throw
-                // a runtime exception.
-                // We catch this exception and set localParams accordingly: true
-                // means we successfully loaded layout params from the <include>
-                // tag, false means we need to rely on the included layout params.
-                ViewGroup.LayoutParams params = null;
-                try {
-                    params = group.generateLayoutParams(attrs);
-                } catch (RuntimeException e) {
-                    // Ignore, just fail over to child attrs.
-                }
-                if (params == null) {
-                    params = group.generateLayoutParams(childAttrs);
-                }
-                view.setLayoutParams(params);
-
-                // Inflate all children.
-                rInflateChildren(childParser, view, childAttrs, true);
-
-                if (id != View.NO_ID) {
-                    view.setId(id);
-                }
-
-                switch (visibility) {
-                    case 0:
-                        view.setVisibility(View.VISIBLE);
-                        break;
-                    case 1:
-                        view.setVisibility(View.INVISIBLE);
-                        break;
-                    case 2:
-                        view.setVisibility(View.GONE);
-                        break;
-                }
-
-                group.addView(view);
-            }
-        } finally {
-            childParser.close();
         }
-
         LayoutInflater.consumeChildElements(parser);
     }
 
diff --git a/core/java/android/view/textclassifier/TextClassifierImpl.java b/core/java/android/view/textclassifier/TextClassifierImpl.java
index 6e5751a..00a267c 100644
--- a/core/java/android/view/textclassifier/TextClassifierImpl.java
+++ b/core/java/android/view/textclassifier/TextClassifierImpl.java
@@ -43,6 +43,8 @@
 import com.android.internal.annotations.GuardedBy;
 import com.android.internal.util.Preconditions;
 
+import com.google.android.textclassifier.AnnotatorModel;
+
 import java.io.File;
 import java.io.FileNotFoundException;
 import java.io.IOException;
@@ -91,7 +93,7 @@
     @GuardedBy("mLock") // Do not access outside this lock.
     private ModelFile mModel;
     @GuardedBy("mLock") // Do not access outside this lock.
-    private TextClassifierImplNative mNative;
+    private AnnotatorModel mNative;
 
     private final Object mLoggerLock = new Object();
     @GuardedBy("mLoggerLock") // Do not access outside this lock.
@@ -124,7 +126,7 @@
                     && rangeLength <= mSettings.getSuggestSelectionMaxRangeLength()) {
                 final String localesString = concatenateLocales(request.getDefaultLocales());
                 final ZonedDateTime refTime = ZonedDateTime.now();
-                final TextClassifierImplNative nativeImpl = getNative(request.getDefaultLocales());
+                final AnnotatorModel nativeImpl = getNative(request.getDefaultLocales());
                 final int start;
                 final int end;
                 if (mSettings.isModelDarkLaunchEnabled() && !request.isDarkLaunchAllowed()) {
@@ -133,7 +135,7 @@
                 } else {
                     final int[] startEnd = nativeImpl.suggestSelection(
                             string, request.getStartIndex(), request.getEndIndex(),
-                            new TextClassifierImplNative.SelectionOptions(localesString));
+                            new AnnotatorModel.SelectionOptions(localesString));
                     start = startEnd[0];
                     end = startEnd[1];
                 }
@@ -141,10 +143,10 @@
                         && start >= 0 && end <= string.length()
                         && start <= request.getStartIndex() && end >= request.getEndIndex()) {
                     final TextSelection.Builder tsBuilder = new TextSelection.Builder(start, end);
-                    final TextClassifierImplNative.ClassificationResult[] results =
+                    final AnnotatorModel.ClassificationResult[] results =
                             nativeImpl.classifyText(
                                     string, start, end,
-                                    new TextClassifierImplNative.ClassificationOptions(
+                                    new AnnotatorModel.ClassificationOptions(
                                             refTime.toInstant().toEpochMilli(),
                                             refTime.getZone().getId(),
                                             localesString));
@@ -183,11 +185,11 @@
                 final String localesString = concatenateLocales(request.getDefaultLocales());
                 final ZonedDateTime refTime = request.getReferenceTime() != null
                         ? request.getReferenceTime() : ZonedDateTime.now();
-                final TextClassifierImplNative.ClassificationResult[] results =
+                final AnnotatorModel.ClassificationResult[] results =
                         getNative(request.getDefaultLocales())
                                 .classifyText(
                                         string, request.getStartIndex(), request.getEndIndex(),
-                                        new TextClassifierImplNative.ClassificationOptions(
+                                        new AnnotatorModel.ClassificationOptions(
                                                 refTime.toInstant().toEpochMilli(),
                                                 refTime.getZone().getId(),
                                                 localesString));
@@ -227,17 +229,17 @@
                     ? request.getEntityConfig().resolveEntityListModifications(
                             getEntitiesForHints(request.getEntityConfig().getHints()))
                     : mSettings.getEntityListDefault();
-            final TextClassifierImplNative nativeImpl =
+            final AnnotatorModel nativeImpl =
                     getNative(request.getDefaultLocales());
-            final TextClassifierImplNative.AnnotatedSpan[] annotations =
+            final AnnotatorModel.AnnotatedSpan[] annotations =
                     nativeImpl.annotate(
                         textString,
-                        new TextClassifierImplNative.AnnotationOptions(
+                        new AnnotatorModel.AnnotationOptions(
                                 refTime.toInstant().toEpochMilli(),
                                         refTime.getZone().getId(),
                                 concatenateLocales(request.getDefaultLocales())));
-            for (TextClassifierImplNative.AnnotatedSpan span : annotations) {
-                final TextClassifierImplNative.ClassificationResult[] results =
+            for (AnnotatorModel.AnnotatedSpan span : annotations) {
+                final AnnotatorModel.ClassificationResult[] results =
                         span.getClassification();
                 if (results.length == 0
                         || !entitiesToIdentify.contains(results[0].getCollection())) {
@@ -296,7 +298,7 @@
         }
     }
 
-    private TextClassifierImplNative getNative(LocaleList localeList)
+    private AnnotatorModel getNative(LocaleList localeList)
             throws FileNotFoundException {
         synchronized (mLock) {
             localeList = localeList == null ? LocaleList.getEmptyLocaleList() : localeList;
@@ -309,7 +311,7 @@
                 destroyNativeIfExistsLocked();
                 final ParcelFileDescriptor fd = ParcelFileDescriptor.open(
                         new File(bestModel.getPath()), ParcelFileDescriptor.MODE_READ_ONLY);
-                mNative = new TextClassifierImplNative(fd.getFd());
+                mNative = new AnnotatorModel(fd.getFd());
                 closeAndLogError(fd);
                 mModel = bestModel;
             }
@@ -397,14 +399,14 @@
     }
 
     private TextClassification createClassificationResult(
-            TextClassifierImplNative.ClassificationResult[] classifications,
+            AnnotatorModel.ClassificationResult[] classifications,
             String text, int start, int end, @Nullable Instant referenceTime) {
         final String classifiedText = text.substring(start, end);
         final TextClassification.Builder builder = new TextClassification.Builder()
                 .setText(classifiedText);
 
         final int size = classifications.length;
-        TextClassifierImplNative.ClassificationResult highestScoringResult = null;
+        AnnotatorModel.ClassificationResult highestScoringResult = null;
         float highestScore = Float.MIN_VALUE;
         for (int i = 0; i < size; i++) {
             builder.setEntityType(classifications[i].getCollection(),
@@ -467,9 +469,9 @@
             try {
                 final ParcelFileDescriptor modelFd = ParcelFileDescriptor.open(
                         file, ParcelFileDescriptor.MODE_READ_ONLY);
-                final int version = TextClassifierImplNative.getVersion(modelFd.getFd());
+                final int version = AnnotatorModel.getVersion(modelFd.getFd());
                 final String supportedLocalesStr =
-                        TextClassifierImplNative.getLocales(modelFd.getFd());
+                        AnnotatorModel.getLocales(modelFd.getFd());
                 if (supportedLocalesStr.isEmpty()) {
                     Log.d(DEFAULT_LOG_TAG, "Ignoring " + file.getAbsolutePath());
                     return null;
@@ -657,7 +659,7 @@
         public static List<LabeledIntent> create(
                 Context context,
                 @Nullable Instant referenceTime,
-                TextClassifierImplNative.ClassificationResult classification,
+                AnnotatorModel.ClassificationResult classification,
                 String text) {
             final String type = classification.getCollection().trim().toLowerCase(Locale.ENGLISH);
             text = text.trim();
diff --git a/core/java/android/view/textclassifier/TextClassifierImplNative.java b/core/java/android/view/textclassifier/TextClassifierImplNative.java
deleted file mode 100644
index 3d4c8f2..0000000
--- a/core/java/android/view/textclassifier/TextClassifierImplNative.java
+++ /dev/null
@@ -1,301 +0,0 @@
-/*
- * Copyright (C) 2017 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.view.textclassifier;
-
-import android.content.res.AssetFileDescriptor;
-
-/**
- * Java wrapper for TextClassifier native library interface. This library is used for detecting
- * entities in text.
- */
-final class TextClassifierImplNative {
-
-    static {
-        System.loadLibrary("textclassifier");
-    }
-
-    private final long mModelPtr;
-
-    /**
-     * Creates a new instance of TextClassifierImplNative, using the provided model image, given as
-     * a file descriptor.
-     */
-    TextClassifierImplNative(int fd) {
-        mModelPtr = nativeNew(fd);
-        if (mModelPtr == 0L) {
-            throw new IllegalArgumentException("Couldn't initialize TC from file descriptor.");
-        }
-    }
-
-    /**
-     * Creates a new instance of TextClassifierImplNative, using the provided model image, given as
-     * a file path.
-     */
-    TextClassifierImplNative(String path) {
-        mModelPtr = nativeNewFromPath(path);
-        if (mModelPtr == 0L) {
-            throw new IllegalArgumentException("Couldn't initialize TC from given file.");
-        }
-    }
-
-    /**
-     * Creates a new instance of TextClassifierImplNative, using the provided model image, given as
-     * an AssetFileDescriptor.
-     */
-    TextClassifierImplNative(AssetFileDescriptor afd) {
-        mModelPtr = nativeNewFromAssetFileDescriptor(afd, afd.getStartOffset(), afd.getLength());
-        if (mModelPtr == 0L) {
-            throw new IllegalArgumentException(
-                    "Couldn't initialize TC from given AssetFileDescriptor");
-        }
-    }
-
-    /**
-     * Given a string context and current selection, computes the SmartSelection suggestion.
-     *
-     * <p>The begin and end are character indices into the context UTF8 string. selectionBegin is
-     * the character index where the selection begins, and selectionEnd is the index of one
-     * character past the selection span.
-     *
-     * <p>The return value is an array of two ints: suggested selection beginning and end, with the
-     * same semantics as the input selectionBeginning and selectionEnd.
-     */
-    public int[] suggestSelection(
-            String context, int selectionBegin, int selectionEnd, SelectionOptions options) {
-        return nativeSuggestSelection(mModelPtr, context, selectionBegin, selectionEnd, options);
-    }
-
-    /**
-     * Given a string context and current selection, classifies the type of the selected text.
-     *
-     * <p>The begin and end params are character indices in the context string.
-     *
-     * <p>Returns an array of ClassificationResult objects with the probability scores for different
-     * collections.
-     */
-    public ClassificationResult[] classifyText(
-            String context, int selectionBegin, int selectionEnd, ClassificationOptions options) {
-        return nativeClassifyText(mModelPtr, context, selectionBegin, selectionEnd, options);
-    }
-
-    /**
-     * Annotates given input text. The annotations should cover the whole input context except for
-     * whitespaces, and are sorted by their position in the context string.
-     */
-    public AnnotatedSpan[] annotate(String text, AnnotationOptions options) {
-        return nativeAnnotate(mModelPtr, text, options);
-    }
-
-    /** Frees up the allocated memory. */
-    public void close() {
-        nativeClose(mModelPtr);
-    }
-
-    /** Returns a comma separated list of locales supported by the model as BCP 47 tags. */
-    public static String getLocales(int fd) {
-        return nativeGetLocales(fd);
-    }
-
-    /** Returns the version of the model. */
-    public static int getVersion(int fd) {
-        return nativeGetVersion(fd);
-    }
-
-    /** Represents a datetime parsing result from classifyText calls. */
-    public static final class DatetimeResult {
-        static final int GRANULARITY_YEAR = 0;
-        static final int GRANULARITY_MONTH = 1;
-        static final int GRANULARITY_WEEK = 2;
-        static final int GRANULARITY_DAY = 3;
-        static final int GRANULARITY_HOUR = 4;
-        static final int GRANULARITY_MINUTE = 5;
-        static final int GRANULARITY_SECOND = 6;
-
-        private final long mTimeMsUtc;
-        private final int mGranularity;
-
-        DatetimeResult(long timeMsUtc, int granularity) {
-            mGranularity = granularity;
-            mTimeMsUtc = timeMsUtc;
-        }
-
-        public long getTimeMsUtc() {
-            return mTimeMsUtc;
-        }
-
-        public int getGranularity() {
-            return mGranularity;
-        }
-    }
-
-    /** Represents a result of classifyText method call. */
-    public static final class ClassificationResult {
-        private final String mCollection;
-        private final float mScore;
-        private final DatetimeResult mDatetimeResult;
-
-        ClassificationResult(
-                String collection, float score, DatetimeResult datetimeResult) {
-            mCollection = collection;
-            mScore = score;
-            mDatetimeResult = datetimeResult;
-        }
-
-        public String getCollection() {
-            if (mCollection.equals(TextClassifier.TYPE_DATE) && mDatetimeResult != null) {
-                switch (mDatetimeResult.getGranularity()) {
-                    case DatetimeResult.GRANULARITY_HOUR:
-                        // fall through
-                    case DatetimeResult.GRANULARITY_MINUTE:
-                        // fall through
-                    case DatetimeResult.GRANULARITY_SECOND:
-                        return TextClassifier.TYPE_DATE_TIME;
-                    default:
-                        return TextClassifier.TYPE_DATE;
-                }
-            }
-            return mCollection;
-        }
-
-        public float getScore() {
-            return mScore;
-        }
-
-        public DatetimeResult getDatetimeResult() {
-            return mDatetimeResult;
-        }
-    }
-
-    /** Represents a result of Annotate call. */
-    public static final class AnnotatedSpan {
-        private final int mStartIndex;
-        private final int mEndIndex;
-        private final ClassificationResult[] mClassification;
-
-        AnnotatedSpan(
-                int startIndex, int endIndex, ClassificationResult[] classification) {
-            mStartIndex = startIndex;
-            mEndIndex = endIndex;
-            mClassification = classification;
-        }
-
-        public int getStartIndex() {
-            return mStartIndex;
-        }
-
-        public int getEndIndex() {
-            return mEndIndex;
-        }
-
-        public ClassificationResult[] getClassification() {
-            return mClassification;
-        }
-    }
-
-    /** Represents options for the suggestSelection call. */
-    public static final class SelectionOptions {
-        private final String mLocales;
-
-        SelectionOptions(String locales) {
-            mLocales = locales;
-        }
-
-        public String getLocales() {
-            return mLocales;
-        }
-    }
-
-    /** Represents options for the classifyText call. */
-    public static final class ClassificationOptions {
-        private final long mReferenceTimeMsUtc;
-        private final String mReferenceTimezone;
-        private final String mLocales;
-
-        ClassificationOptions(long referenceTimeMsUtc, String referenceTimezone, String locale) {
-            mReferenceTimeMsUtc = referenceTimeMsUtc;
-            mReferenceTimezone = referenceTimezone;
-            mLocales = locale;
-        }
-
-        public long getReferenceTimeMsUtc() {
-            return mReferenceTimeMsUtc;
-        }
-
-        public String getReferenceTimezone() {
-            return mReferenceTimezone;
-        }
-
-        public String getLocale() {
-            return mLocales;
-        }
-    }
-
-    /** Represents options for the Annotate call. */
-    public static final class AnnotationOptions {
-        private final long mReferenceTimeMsUtc;
-        private final String mReferenceTimezone;
-        private final String mLocales;
-
-        AnnotationOptions(long referenceTimeMsUtc, String referenceTimezone, String locale) {
-            mReferenceTimeMsUtc = referenceTimeMsUtc;
-            mReferenceTimezone = referenceTimezone;
-            mLocales = locale;
-        }
-
-        public long getReferenceTimeMsUtc() {
-            return mReferenceTimeMsUtc;
-        }
-
-        public String getReferenceTimezone() {
-            return mReferenceTimezone;
-        }
-
-        public String getLocale() {
-            return mLocales;
-        }
-    }
-
-    private static native long nativeNew(int fd);
-
-    private static native long nativeNewFromPath(String path);
-
-    private static native long nativeNewFromAssetFileDescriptor(
-            AssetFileDescriptor afd, long offset, long size);
-
-    private static native int[] nativeSuggestSelection(
-            long context,
-            String text,
-            int selectionBegin,
-            int selectionEnd,
-            SelectionOptions options);
-
-    private static native ClassificationResult[] nativeClassifyText(
-            long context,
-            String text,
-            int selectionBegin,
-            int selectionEnd,
-            ClassificationOptions options);
-
-    private static native AnnotatedSpan[] nativeAnnotate(
-            long context, String text, AnnotationOptions options);
-
-    private static native void nativeClose(long context);
-
-    private static native String nativeGetLocales(int fd);
-
-    private static native int nativeGetVersion(int fd);
-}
diff --git a/data/etc/platform.xml b/data/etc/platform.xml
index 73c10d2..afe7913 100644
--- a/data/etc/platform.xml
+++ b/data/etc/platform.xml
@@ -182,11 +182,11 @@
          code to link against. -->
 
     <library name="android.test.base"
-            file="/system/framework/android.test.base.impl.jar" />
+            file="/system/framework/android.test.base.jar" />
     <library name="android.test.mock"
-            file="/system/framework/android.test.mock.impl.jar" />
+            file="/system/framework/android.test.mock.jar" />
     <library name="android.test.runner"
-            file="/system/framework/android.test.runner.impl.jar" />
+            file="/system/framework/android.test.runner.jar" />
 
     <!-- In BOOT_JARS historically, and now added to legacy applications. -->
     <library name="android.hidl.base-V1.0-java"
diff --git a/services/core/java/com/android/server/camera/CameraServiceProxy.java b/services/core/java/com/android/server/camera/CameraServiceProxy.java
index 0ee55ed..527539d 100644
--- a/services/core/java/com/android/server/camera/CameraServiceProxy.java
+++ b/services/core/java/com/android/server/camera/CameraServiceProxy.java
@@ -21,6 +21,7 @@
 import android.content.IntentFilter;
 import android.hardware.ICameraService;
 import android.hardware.ICameraServiceProxy;
+import android.media.AudioManager;
 import android.metrics.LogMaker;
 import android.nfc.INfcAdapter;
 import android.os.Binder;
@@ -393,6 +394,19 @@
             boolean wasEmpty = mActiveCameraUsage.isEmpty();
             switch (newCameraState) {
                 case ICameraServiceProxy.CAMERA_STATE_OPEN:
+                    // Notify the audio subsystem about the facing of the most-recently opened
+                    // camera This can be used to select the best audio tuning in case video
+                    // recording with that camera will happen.  Since only open events are used, if
+                    // multiple cameras are opened at once, the one opened last will be used to
+                    // select audio tuning.
+                    AudioManager audioManager = getContext().getSystemService(AudioManager.class);
+                    if (audioManager != null) {
+                        // Map external to front for audio tuning purposes
+                        String facingStr = (facing == ICameraServiceProxy.CAMERA_FACING_BACK) ?
+                                "back" : "front";
+                        String facingParameter = "cameraFacing=" + facingStr;
+                        audioManager.setParameters(facingParameter);
+                    }
                     break;
                 case ICameraServiceProxy.CAMERA_STATE_ACTIVE:
                     CameraUsageEvent newEvent = new CameraUsageEvent(facing, clientName, apiLevel);
diff --git a/services/core/java/com/android/server/connectivity/PacManager.java b/services/core/java/com/android/server/connectivity/PacManager.java
index 3ea9810..9789688 100644
--- a/services/core/java/com/android/server/connectivity/PacManager.java
+++ b/services/core/java/com/android/server/connectivity/PacManager.java
@@ -282,6 +282,7 @@
     private void setCurrentProxyScript(String script) {
         if (mProxyService == null) {
             Log.e(TAG, "setCurrentProxyScript: no proxy service");
+            return;
         }
         try {
             mProxyService.setPacFile(script);
diff --git a/services/net/java/android/net/shared/LinkPropertiesParcelableUtil.java b/services/net/java/android/net/shared/LinkPropertiesParcelableUtil.java
new file mode 100644
index 0000000..5b77f54
--- /dev/null
+++ b/services/net/java/android/net/shared/LinkPropertiesParcelableUtil.java
@@ -0,0 +1,222 @@
+/*
+ * Copyright (C) 2019 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.net.shared;
+
+import static android.net.shared.ParcelableUtil.fromParcelableArray;
+import static android.net.shared.ParcelableUtil.toParcelableArray;
+
+import android.annotation.Nullable;
+import android.net.InetAddresses;
+import android.net.IpPrefix;
+import android.net.IpPrefixParcelable;
+import android.net.LinkAddress;
+import android.net.LinkAddressParcelable;
+import android.net.LinkProperties;
+import android.net.LinkPropertiesParcelable;
+import android.net.ProxyInfo;
+import android.net.ProxyInfoParcelable;
+import android.net.RouteInfo;
+import android.net.RouteInfoParcelable;
+import android.net.Uri;
+
+import java.net.InetAddress;
+import java.util.Arrays;
+
+/**
+ * Collection of utility methods to convert to and from stable AIDL parcelables for LinkProperties
+ * and its attributes.
+ * @hide
+ */
+public final class LinkPropertiesParcelableUtil {
+
+    /**
+     * Convert a ProxyInfo to a ProxyInfoParcelable
+     */
+    public static ProxyInfoParcelable toStableParcelable(@Nullable ProxyInfo proxyInfo) {
+        if (proxyInfo == null) {
+            return null;
+        }
+        final ProxyInfoParcelable parcel = new ProxyInfoParcelable();
+        parcel.host = proxyInfo.getHost();
+        parcel.port = proxyInfo.getPort();
+        parcel.exclusionList = proxyInfo.getExclusionList();
+        parcel.pacFileUrl = proxyInfo.getPacFileUrl().toString();
+        return parcel;
+    }
+
+    /**
+     * Convert a ProxyInfoParcelable to a ProxyInfo
+     */
+    public static ProxyInfo fromStableParcelable(@Nullable ProxyInfoParcelable parcel) {
+        if (parcel == null) {
+            return null;
+        }
+        if (Uri.EMPTY.toString().equals(parcel.pacFileUrl)) {
+            return ProxyInfo.buildDirectProxy(
+                    parcel.host, parcel.port, Arrays.asList(parcel.exclusionList));
+        } else {
+            return ProxyInfo.buildPacProxy(Uri.parse(parcel.pacFileUrl));
+        }
+    }
+
+    /**
+     * Convert an IpPrefixParcelable to an IpPrefix
+     */
+    public static IpPrefixParcelable toStableParcelable(@Nullable IpPrefix ipPrefix) {
+        if (ipPrefix == null) {
+            return null;
+        }
+        final IpPrefixParcelable parcel = new IpPrefixParcelable();
+        parcel.address = ipPrefix.getAddress().getHostAddress();
+        parcel.prefixLength = ipPrefix.getPrefixLength();
+        return parcel;
+    }
+
+    /**
+     * Convert an IpPrefix to an IpPrefixParcelable
+     */
+    public static IpPrefix fromStableParcelable(@Nullable IpPrefixParcelable parcel) {
+        if (parcel == null) {
+            return null;
+        }
+        return new IpPrefix(InetAddresses.parseNumericAddress(parcel.address), parcel.prefixLength);
+    }
+
+    /**
+     * Convert a RouteInfoParcelable to a RouteInfo
+     */
+    public static RouteInfoParcelable toStableParcelable(@Nullable RouteInfo routeInfo) {
+        if (routeInfo == null) {
+            return null;
+        }
+        final RouteInfoParcelable parcel = new RouteInfoParcelable();
+        parcel.destination = toStableParcelable(routeInfo.getDestination());
+        parcel.gatewayAddr = routeInfo.getGateway().getHostAddress();
+        parcel.ifaceName = routeInfo.getInterface();
+        parcel.type = routeInfo.getType();
+        return parcel;
+    }
+
+    /**
+     * Convert a RouteInfo to a RouteInfoParcelable
+     */
+    public static RouteInfo fromStableParcelable(@Nullable RouteInfoParcelable parcel) {
+        if (parcel == null) {
+            return null;
+        }
+        final IpPrefix destination = fromStableParcelable(parcel.destination);
+        return new RouteInfo(
+                destination, InetAddresses.parseNumericAddress(parcel.gatewayAddr),
+                parcel.ifaceName, parcel.type);
+    }
+
+    /**
+     * Convert a LinkAddressParcelable to a LinkAddress
+     */
+    public static LinkAddressParcelable toStableParcelable(@Nullable LinkAddress la) {
+        if (la == null) {
+            return null;
+        }
+        final LinkAddressParcelable parcel = new LinkAddressParcelable();
+        parcel.address = la.getAddress().getHostAddress();
+        parcel.prefixLength = la.getPrefixLength();
+        parcel.flags = la.getFlags();
+        parcel.scope = la.getScope();
+        return parcel;
+    }
+
+    /**
+     * Convert a LinkAddress to a LinkAddressParcelable
+     */
+    public static LinkAddress fromStableParcelable(@Nullable LinkAddressParcelable parcel) {
+        if (parcel == null) {
+            return null;
+        }
+        return new LinkAddress(
+                InetAddresses.parseNumericAddress(parcel.address),
+                parcel.prefixLength,
+                parcel.flags,
+                parcel.scope);
+    }
+
+    /**
+     * Convert a LinkProperties to a LinkPropertiesParcelable
+     */
+    public static LinkPropertiesParcelable toStableParcelable(@Nullable LinkProperties lp) {
+        if (lp == null) {
+            return null;
+        }
+        final LinkPropertiesParcelable parcel = new LinkPropertiesParcelable();
+        parcel.ifaceName = lp.getInterfaceName();
+        parcel.linkAddresses = toParcelableArray(
+                lp.getLinkAddresses(),
+                LinkPropertiesParcelableUtil::toStableParcelable,
+                LinkAddressParcelable.class);
+        parcel.dnses = toParcelableArray(
+                lp.getDnsServers(), InetAddress::getHostAddress, String.class);
+        parcel.pcscfs = toParcelableArray(
+                lp.getPcscfServers(), InetAddress::getHostAddress, String.class);
+        parcel.validatedPrivateDnses = toParcelableArray(
+                lp.getValidatedPrivateDnsServers(), InetAddress::getHostAddress, String.class);
+        parcel.usePrivateDns = lp.isPrivateDnsActive();
+        parcel.privateDnsServerName = lp.getPrivateDnsServerName();
+        parcel.domains = lp.getDomains();
+        parcel.routes = toParcelableArray(
+                lp.getRoutes(), LinkPropertiesParcelableUtil::toStableParcelable,
+                RouteInfoParcelable.class);
+        parcel.httpProxy = toStableParcelable(lp.getHttpProxy());
+        parcel.mtu = lp.getMtu();
+        parcel.tcpBufferSizes = lp.getTcpBufferSizes();
+        parcel.nat64Prefix = toStableParcelable(lp.getNat64Prefix());
+        parcel.stackedLinks = toParcelableArray(
+                lp.getStackedLinks(), LinkPropertiesParcelableUtil::toStableParcelable,
+                LinkPropertiesParcelable.class);
+        return parcel;
+    }
+
+    /**
+     * Convert a LinkPropertiesParcelable to a LinkProperties
+     */
+    public static LinkProperties fromStableParcelable(@Nullable LinkPropertiesParcelable parcel) {
+        if (parcel == null) {
+            return null;
+        }
+        final LinkProperties lp = new LinkProperties();
+        lp.setInterfaceName(parcel.ifaceName);
+        lp.setLinkAddresses(fromParcelableArray(parcel.linkAddresses,
+                LinkPropertiesParcelableUtil::fromStableParcelable));
+        lp.setDnsServers(fromParcelableArray(parcel.dnses, InetAddresses::parseNumericAddress));
+        lp.setPcscfServers(fromParcelableArray(parcel.pcscfs, InetAddresses::parseNumericAddress));
+        lp.setValidatedPrivateDnsServers(
+                fromParcelableArray(parcel.validatedPrivateDnses,
+                InetAddresses::parseNumericAddress));
+        lp.setUsePrivateDns(parcel.usePrivateDns);
+        lp.setPrivateDnsServerName(parcel.privateDnsServerName);
+        lp.setDomains(parcel.domains);
+        for (RouteInfoParcelable route : parcel.routes) {
+            lp.addRoute(fromStableParcelable(route));
+        }
+        lp.setHttpProxy(fromStableParcelable(parcel.httpProxy));
+        lp.setMtu(parcel.mtu);
+        lp.setTcpBufferSizes(parcel.tcpBufferSizes);
+        lp.setNat64Prefix(fromStableParcelable(parcel.nat64Prefix));
+        for (LinkPropertiesParcelable stackedLink : parcel.stackedLinks) {
+            lp.addStackedLink(fromStableParcelable(stackedLink));
+        }
+        return lp;
+    }
+}
diff --git a/services/net/java/android/net/shared/ParcelableUtil.java b/services/net/java/android/net/shared/ParcelableUtil.java
new file mode 100644
index 0000000..a18976c
--- /dev/null
+++ b/services/net/java/android/net/shared/ParcelableUtil.java
@@ -0,0 +1,63 @@
+/*
+ * Copyright (C) 2019 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.net.shared;
+
+import android.annotation.NonNull;
+
+import java.lang.reflect.Array;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.function.Function;
+
+/**
+ * Utility methods to help convert to/from stable parcelables.
+ * @hide
+ */
+public final class ParcelableUtil {
+    // Below methods could be implemented easily with streams, but streams are frowned upon in
+    // frameworks code.
+
+    /**
+     * Convert a list of BaseType items to an array of ParcelableType items using the specified
+     * converter function.
+     */
+    public static <ParcelableType, BaseType> ParcelableType[] toParcelableArray(
+            @NonNull List<BaseType> base,
+            @NonNull Function<BaseType, ParcelableType> conv,
+            @NonNull Class<ParcelableType> parcelClass) {
+        final ParcelableType[] out = (ParcelableType[]) Array.newInstance(parcelClass, base.size());
+        int i = 0;
+        for (BaseType b : base) {
+            out[i] = conv.apply(b);
+            i++;
+        }
+        return out;
+    }
+
+    /**
+     * Convert an array of ParcelableType items to a list of BaseType items using the specified
+     * converter function.
+     */
+    public static <ParcelableType, BaseType> ArrayList<BaseType> fromParcelableArray(
+            @NonNull ParcelableType[] parceled, @NonNull Function<ParcelableType, BaseType> conv) {
+        final ArrayList<BaseType> out = new ArrayList<>(parceled.length);
+        for (ParcelableType t : parceled) {
+            out.add(conv.apply(t));
+        }
+        return out;
+    }
+}
diff --git a/telecomm/java/android/telecom/CallRedirectionService.java b/telecomm/java/android/telecom/CallRedirectionService.java
index b906d0b..3299117 100644
--- a/telecomm/java/android/telecom/CallRedirectionService.java
+++ b/telecomm/java/android/telecom/CallRedirectionService.java
@@ -16,6 +16,7 @@
 
 package android.telecom;
 
+import android.annotation.NonNull;
 import android.annotation.SdkConstant;
 import android.app.Service;
 import android.content.Intent;
@@ -27,8 +28,8 @@
 import android.os.RemoteException;
 
 import com.android.internal.os.SomeArgs;
-import com.android.internal.telecom.ICallRedirectionService;
 import com.android.internal.telecom.ICallRedirectionAdapter;
+import com.android.internal.telecom.ICallRedirectionService;
 
 /**
  * This service can be implemented to interact between Telecom and its implementor
@@ -62,22 +63,35 @@
 
     /**
      * Telecom calls this method to inform the implemented {@link CallRedirectionService} of
-     * a new outgoing call which is being placed.
+     * a new outgoing call which is being placed. Telecom does not request to redirect emergency
+     * calls and does not request to redirect calls with gateway information.
      *
-     * The implemented {@link CallRedirectionService} can call {@link #placeCallUnmodified()},
-     * {@link #redirectCall(Uri, PhoneAccountHandle)}, and {@link #cancelCall()} only from here.
+     * <p>Telecom will cancel the call if Telecom does not receive a response in 5 seconds from
+     * the implemented {@link CallRedirectionService} set by users.
      *
-     * @param handle the phone number dialed by the user
-     * @param targetPhoneAccount the {@link PhoneAccountHandle} on which the call will be placed.
+     * <p>The implemented {@link CallRedirectionService} can call {@link #placeCallUnmodified()},
+     * {@link #redirectCall(Uri, PhoneAccountHandle, boolean)}, and {@link #cancelCall()} only
+     * from here.
+     *
+     * @param handle the phone number dialed by the user, represented in E.164 format if possible
+     * @param initialPhoneAccount the {@link PhoneAccountHandle} on which the call will be placed.
+     * @param allowInteractiveResponse a boolean to tell if the implemented
+     *                                 {@link CallRedirectionService} should allow interactive
+     *                                 responses with users. Will be {@code false} if, for example
+     *                                 the device is in car mode and the user would not be able to
+     *                                 interact with their device.
      */
-    public abstract void onPlaceCall(Uri handle, PhoneAccountHandle targetPhoneAccount);
+    public abstract void onPlaceCall(@NonNull Uri handle,
+                                     @NonNull PhoneAccountHandle initialPhoneAccount,
+                                     boolean allowInteractiveResponse);
 
     /**
      * The implemented {@link CallRedirectionService} calls this method to response a request
-     * received via {@link #onPlaceCall(Uri, PhoneAccountHandle)} to inform Telecom that no changes
-     * are required to the outgoing call, and that the call should be placed as-is.
+     * received via {@link #onPlaceCall(Uri, PhoneAccountHandle, boolean)} to inform Telecom that
+     * no changes are required to the outgoing call, and that the call should be placed as-is.
      *
-     * This can only be called from implemented {@link #onPlaceCall(Uri, PhoneAccountHandle)}.
+     * <p>This can only be called from implemented
+     * {@link #onPlaceCall(Uri, PhoneAccountHandle, boolean)}.
      *
      */
     public final void placeCallUnmodified() {
@@ -89,29 +103,39 @@
 
     /**
      * The implemented {@link CallRedirectionService} calls this method to response a request
-     * received via {@link #onPlaceCall(Uri, PhoneAccountHandle)} to inform Telecom that changes
-     * are required to the phone number or/and {@link PhoneAccountHandle} for the outgoing call.
+     * received via {@link #onPlaceCall(Uri, PhoneAccountHandle, boolean)} to inform Telecom that
+     * changes are required to the phone number or/and {@link PhoneAccountHandle} for the outgoing
+     * call. Telecom will cancel the call if the implemented {@link CallRedirectionService}
+     * replies Telecom a handle for an emergency number.
      *
-     * This can only be called from implemented {@link #onPlaceCall(Uri, PhoneAccountHandle)}.
+     * <p>This can only be called from implemented
+     * {@link #onPlaceCall(Uri, PhoneAccountHandle, boolean)}.
      *
      * @param handle the new phone number to dial
      * @param targetPhoneAccount the {@link PhoneAccountHandle} to use when placing the call.
      *                           If {@code null}, no change will be made to the
      *                           {@link PhoneAccountHandle} used to place the call.
+     * @param confirmFirst Telecom will ask users to confirm the redirection via a yes/no dialog
+     *                     if the confirmFirst is true, and if the redirection request of this
+     *                     response was sent with a true flag of allowInteractiveResponse via
+     *                     {@link #onPlaceCall(Uri, PhoneAccountHandle, boolean)}
      */
-    public final void redirectCall(Uri handle, PhoneAccountHandle targetPhoneAccount) {
+    public final void redirectCall(@NonNull Uri handle,
+                                   @NonNull PhoneAccountHandle targetPhoneAccount,
+                                   boolean confirmFirst) {
         try {
-            mCallRedirectionAdapter.redirectCall(handle, targetPhoneAccount);
+            mCallRedirectionAdapter.redirectCall(handle, targetPhoneAccount, confirmFirst);
         } catch (RemoteException e) {
         }
     }
 
     /**
      * The implemented {@link CallRedirectionService} calls this method to response a request
-     * received via {@link #onPlaceCall(Uri, PhoneAccountHandle)} to inform Telecom that an outgoing
-     * call should be canceled entirely.
+     * received via {@link #onPlaceCall(Uri, PhoneAccountHandle, boolean)} to inform Telecom that
+     * an outgoing call should be canceled entirely.
      *
-     * This can only be called from implemented {@link #onPlaceCall(Uri, PhoneAccountHandle)}.
+     * <p>This can only be called from implemented
+     * {@link #onPlaceCall(Uri, PhoneAccountHandle, boolean)}.
      *
      */
     public final void cancelCall() {
@@ -137,7 +161,8 @@
                     SomeArgs args = (SomeArgs) msg.obj;
                     try {
                         mCallRedirectionAdapter = (ICallRedirectionAdapter) args.arg1;
-                        onPlaceCall((Uri) args.arg2, (PhoneAccountHandle) args.arg3);
+                        onPlaceCall((Uri) args.arg2, (PhoneAccountHandle) args.arg3,
+                                (boolean) args.arg4);
                     } finally {
                         args.recycle();
                     }
@@ -152,15 +177,20 @@
          * Telecom calls this method to inform the CallRedirectionService of a new outgoing call
          * which is about to be placed.
          * @param handle the phone number dialed by the user
-         * @param targetPhoneAccount the URI of the number the user dialed
+         * @param initialPhoneAccount the URI of the number the user dialed
+         * @param allowInteractiveResponse a boolean to tell if the implemented
+         *                                 {@link CallRedirectionService} should allow interactive
+         *                                 responses with users.
          */
         @Override
-        public void placeCall(ICallRedirectionAdapter adapter, Uri handle,
-                              PhoneAccountHandle targetPhoneAccount) {
+        public void placeCall(@NonNull ICallRedirectionAdapter adapter, @NonNull Uri handle,
+                              @NonNull PhoneAccountHandle initialPhoneAccount,
+                              boolean allowInteractiveResponse) {
             SomeArgs args = SomeArgs.obtain();
             args.arg1 = adapter;
             args.arg2 = handle;
-            args.arg3 = targetPhoneAccount;
+            args.arg3 = initialPhoneAccount;
+            args.arg4 = allowInteractiveResponse;
             mHandler.obtainMessage(MSG_PLACE_CALL, args).sendToTarget();
         }
     }
diff --git a/telecomm/java/com/android/internal/telecom/ICallRedirectionAdapter.aidl b/telecomm/java/com/android/internal/telecom/ICallRedirectionAdapter.aidl
index 46bf983..0a42a3f 100644
--- a/telecomm/java/com/android/internal/telecom/ICallRedirectionAdapter.aidl
+++ b/telecomm/java/com/android/internal/telecom/ICallRedirectionAdapter.aidl
@@ -31,5 +31,6 @@
 
     void placeCallUnmodified();
 
-    void redirectCall(in Uri handle, in PhoneAccountHandle targetPhoneAccount);
+    void redirectCall(in Uri handle, in PhoneAccountHandle targetPhoneAccount,
+            boolean confirmFirst);
 }
diff --git a/telecomm/java/com/android/internal/telecom/ICallRedirectionService.aidl b/telecomm/java/com/android/internal/telecom/ICallRedirectionService.aidl
index d8d360b..c1bc440 100644
--- a/telecomm/java/com/android/internal/telecom/ICallRedirectionService.aidl
+++ b/telecomm/java/com/android/internal/telecom/ICallRedirectionService.aidl
@@ -30,5 +30,5 @@
  */
 oneway interface ICallRedirectionService {
     void placeCall(in ICallRedirectionAdapter adapter, in Uri handle,
-            in PhoneAccountHandle targetPhoneAccount);
+            in PhoneAccountHandle initialPhoneAccount, boolean allowInteractiveResponse);
 }
diff --git a/telephony/java/android/telephony/CellConfigLte.java b/telephony/java/android/telephony/CellConfigLte.java
index 35769f0..eafbfbc 100644
--- a/telephony/java/android/telephony/CellConfigLte.java
+++ b/telephony/java/android/telephony/CellConfigLte.java
@@ -34,6 +34,11 @@
     }
 
     /** @hide */
+    public CellConfigLte(android.hardware.radio.V1_4.CellConfigLte cellConfig) {
+        mIsEndcAvailable = cellConfig.isEndcAvailable;
+    }
+
+    /** @hide */
     public CellConfigLte(boolean isEndcAvailable) {
         mIsEndcAvailable = isEndcAvailable;
     }
diff --git a/telephony/java/android/telephony/CellInfo.java b/telephony/java/android/telephony/CellInfo.java
index b761bd7..8ce5c54 100644
--- a/telephony/java/android/telephony/CellInfo.java
+++ b/telephony/java/android/telephony/CellInfo.java
@@ -19,8 +19,10 @@
 import android.annotation.IntDef;
 import android.annotation.NonNull;
 import android.annotation.UnsupportedAppUsage;
+import android.hardware.radio.V1_4.CellInfo.Info;
 import android.os.Parcel;
 import android.os.Parcelable;
+import android.os.SystemClock;
 
 import com.android.internal.annotations.VisibleForTesting;
 
@@ -318,6 +320,13 @@
     }
 
     /** @hide */
+    protected CellInfo(android.hardware.radio.V1_4.CellInfo ci) {
+        this.mRegistered = ci.isRegistered;
+        this.mTimeStamp = SystemClock.elapsedRealtimeNanos();
+        this.mCellConnectionStatus = ci.connectionStatus;
+    }
+
+    /** @hide */
     public static CellInfo create(android.hardware.radio.V1_0.CellInfo ci) {
         if (ci == null) return null;
         switch(ci.cellInfoType) {
@@ -342,4 +351,17 @@
             default: return null;
         }
     }
+
+    /** @hide */
+    public static CellInfo create(android.hardware.radio.V1_4.CellInfo ci) {
+        if (ci == null) return null;
+        switch (ci.info.getDiscriminator()) {
+            case Info.hidl_discriminator.gsm: return new CellInfoGsm(ci);
+            case Info.hidl_discriminator.cdma: return new CellInfoCdma(ci);
+            case Info.hidl_discriminator.lte: return new CellInfoLte(ci);
+            case Info.hidl_discriminator.wcdma: return new CellInfoWcdma(ci);
+            case Info.hidl_discriminator.tdscdma: return new CellInfoTdscdma(ci);
+            default: return null;
+        }
+    }
 }
diff --git a/telephony/java/android/telephony/CellInfoCdma.java b/telephony/java/android/telephony/CellInfoCdma.java
index c9f07da..4440108 100644
--- a/telephony/java/android/telephony/CellInfoCdma.java
+++ b/telephony/java/android/telephony/CellInfoCdma.java
@@ -67,6 +67,15 @@
             new CellSignalStrengthCdma(cic.signalStrengthCdma, cic.signalStrengthEvdo);
     }
 
+    /** @hide */
+    public CellInfoCdma(android.hardware.radio.V1_4.CellInfo ci) {
+        super(ci);
+        final android.hardware.radio.V1_2.CellInfoCdma cic = ci.info.cdma();
+        mCellIdentityCdma = new CellIdentityCdma(cic.cellIdentityCdma);
+        mCellSignalStrengthCdma =
+                new CellSignalStrengthCdma(cic.signalStrengthCdma, cic.signalStrengthEvdo);
+    }
+
     @Override
     public CellIdentityCdma getCellIdentity() {
         return mCellIdentityCdma;
diff --git a/telephony/java/android/telephony/CellInfoGsm.java b/telephony/java/android/telephony/CellInfoGsm.java
index ad16dfa..248adfc 100644
--- a/telephony/java/android/telephony/CellInfoGsm.java
+++ b/telephony/java/android/telephony/CellInfoGsm.java
@@ -63,6 +63,14 @@
         mCellSignalStrengthGsm = new CellSignalStrengthGsm(cig.signalStrengthGsm);
     }
 
+    /** @hide */
+    public CellInfoGsm(android.hardware.radio.V1_4.CellInfo ci) {
+        super(ci);
+        final android.hardware.radio.V1_2.CellInfoGsm cig = ci.info.gsm();
+        mCellIdentityGsm = new CellIdentityGsm(cig.cellIdentityGsm);
+        mCellSignalStrengthGsm = new CellSignalStrengthGsm(cig.signalStrengthGsm);
+    }
+
     @Override
     public CellIdentityGsm getCellIdentity() {
         return mCellIdentityGsm;
diff --git a/telephony/java/android/telephony/CellInfoLte.java b/telephony/java/android/telephony/CellInfoLte.java
index 7593831..8e8ce8a 100644
--- a/telephony/java/android/telephony/CellInfoLte.java
+++ b/telephony/java/android/telephony/CellInfoLte.java
@@ -70,6 +70,15 @@
         mCellConfig = new CellConfigLte();
     }
 
+    /** @hide */
+    public CellInfoLte(android.hardware.radio.V1_4.CellInfo ci) {
+        super(ci);
+        final android.hardware.radio.V1_4.CellInfoLte cil = ci.info.lte();
+        mCellIdentityLte = new CellIdentityLte(cil.base.cellIdentityLte);
+        mCellSignalStrengthLte = new CellSignalStrengthLte(cil.base.signalStrengthLte);
+        mCellConfig = new CellConfigLte(cil.cellConfig);
+    }
+
     @Override
     public CellIdentityLte getCellIdentity() {
         if (DBG) log("getCellIdentity: " + mCellIdentityLte);
diff --git a/telephony/java/android/telephony/CellInfoTdscdma.java b/telephony/java/android/telephony/CellInfoTdscdma.java
index a8c49b7..2ab38fb 100644
--- a/telephony/java/android/telephony/CellInfoTdscdma.java
+++ b/telephony/java/android/telephony/CellInfoTdscdma.java
@@ -64,6 +64,14 @@
         mCellSignalStrengthTdscdma = new CellSignalStrengthTdscdma(cit.signalStrengthTdscdma);
     }
 
+    /** @hide */
+    public CellInfoTdscdma(android.hardware.radio.V1_4.CellInfo ci) {
+        super(ci);
+        final android.hardware.radio.V1_2.CellInfoTdscdma cit = ci.info.tdscdma();
+        mCellIdentityTdscdma = new CellIdentityTdscdma(cit.cellIdentityTdscdma);
+        mCellSignalStrengthTdscdma = new CellSignalStrengthTdscdma(cit.signalStrengthTdscdma);
+    }
+
     @Override public CellIdentityTdscdma getCellIdentity() {
         return mCellIdentityTdscdma;
     }
diff --git a/telephony/java/android/telephony/CellInfoWcdma.java b/telephony/java/android/telephony/CellInfoWcdma.java
index a427e80..65e0470 100644
--- a/telephony/java/android/telephony/CellInfoWcdma.java
+++ b/telephony/java/android/telephony/CellInfoWcdma.java
@@ -63,6 +63,14 @@
         mCellSignalStrengthWcdma = new CellSignalStrengthWcdma(ciw.signalStrengthWcdma);
     }
 
+    /** @hide */
+    public CellInfoWcdma(android.hardware.radio.V1_4.CellInfo ci) {
+        super(ci);
+        final android.hardware.radio.V1_2.CellInfoWcdma ciw = ci.info.wcdma();
+        mCellIdentityWcdma = new CellIdentityWcdma(ciw.cellIdentityWcdma);
+        mCellSignalStrengthWcdma = new CellSignalStrengthWcdma(ciw.signalStrengthWcdma);
+    }
+
     @Override
     public CellIdentityWcdma getCellIdentity() {
         return mCellIdentityWcdma;
diff --git a/telephony/java/android/telephony/PhoneStateListener.java b/telephony/java/android/telephony/PhoneStateListener.java
index c816701..9fee593 100644
--- a/telephony/java/android/telephony/PhoneStateListener.java
+++ b/telephony/java/android/telephony/PhoneStateListener.java
@@ -805,9 +805,11 @@
             PhoneStateListener psl = mPhoneStateListenerWeakRef.get();
             if (psl == null) return;
 
-            Binder.withCleanCallingIdentity(
-                    () -> mExecutor.execute(
-                            () -> psl.onDataConnectionStateChanged(state, networkType)));
+            Binder.withCleanCallingIdentity(() -> mExecutor.execute(
+                    () -> {
+                        psl.onDataConnectionStateChanged(state, networkType);
+                        psl.onDataConnectionStateChanged(state);
+                    }));
         }
 
         public void onDataActivity(int direction) {
diff --git a/telephony/java/android/telephony/data/ApnSetting.java b/telephony/java/android/telephony/data/ApnSetting.java
index 200b540..8d148c3 100644
--- a/telephony/java/android/telephony/data/ApnSetting.java
+++ b/telephony/java/android/telephony/data/ApnSetting.java
@@ -81,7 +81,7 @@
      */
     public static final int TYPE_ALL = ApnTypes.ALL;
     /** APN type for default data traffic. */
-    public static final int TYPE_DEFAULT = ApnTypes.DEFAULT;
+    public static final int TYPE_DEFAULT = ApnTypes.DEFAULT | ApnTypes.HIPRI;
     /** APN type for MMS traffic. */
     public static final int TYPE_MMS = ApnTypes.MMS;
     /** APN type for SUPL assisted GPS. */
@@ -1019,7 +1019,7 @@
             return false;
         }
         // DEFAULT can handle HIPRI.
-        if (hasApnType(type) || (type == TYPE_HIPRI && hasApnType(TYPE_DEFAULT))) {
+        if (hasApnType(type)) {
             return true;
         }
         return false;
diff --git a/telephony/java/android/telephony/emergency/EmergencyNumber.java b/telephony/java/android/telephony/emergency/EmergencyNumber.java
index fe062d5..a94b163 100644
--- a/telephony/java/android/telephony/emergency/EmergencyNumber.java
+++ b/telephony/java/android/telephony/emergency/EmergencyNumber.java
@@ -29,6 +29,7 @@
 import java.util.ArrayList;
 import java.util.HashSet;
 import java.util.List;
+import java.util.Objects;
 import java.util.Set;
 
 /**
@@ -198,21 +199,53 @@
         EMERGENCY_NUMBER_SOURCE_SET.add(EMERGENCY_NUMBER_SOURCE_DEFAULT);
     }
 
+    /**
+     * Indicated the framework does not know whether an emergency call should be placed using
+     * emergency or normal call routing. This means the underlying radio or IMS implementation is
+     * free to determine for itself how to route the call.
+     */
+    public static final int EMERGENCY_CALL_ROUTING_UNKNOWN = 0;
+    /**
+     * Indicates the radio or IMS implementation must handle the call through emergency routing.
+     */
+    public static final int EMERGENCY_CALL_ROUTING_EMERGENCY = 1;
+    /**
+     * Indicates the radio or IMS implementation must handle the call through normal call routing.
+     */
+    public static final int EMERGENCY_CALL_ROUTING_NORMAL = 2;
+
+    /**
+     * The routing to tell how to handle the call for the corresponding emergency number.
+     *
+     * @hide
+     */
+    @IntDef(flag = false, prefix = { "EMERGENCY_CALL_ROUTING_" }, value = {
+            EMERGENCY_CALL_ROUTING_UNKNOWN,
+            EMERGENCY_CALL_ROUTING_EMERGENCY,
+            EMERGENCY_CALL_ROUTING_NORMAL
+    })
+    @Retention(RetentionPolicy.SOURCE)
+    public @interface EmergencyCallRouting {}
+
+
     private final String mNumber;
     private final String mCountryIso;
     private final String mMnc;
     private final int mEmergencyServiceCategoryBitmask;
     private final int mEmergencyNumberSourceBitmask;
+    private final int mEmergencyCallRouting;
 
     /** @hide */
-    public EmergencyNumber(@NonNull String number, @NonNull String countryIso,
-                           @NonNull String mnc, int emergencyServiceCategories,
-                           int emergencyNumberSources) {
+    public EmergencyNumber(@NonNull String number, @NonNull String countryIso, @NonNull String mnc,
+                           @EmergencyServiceCategories int emergencyServiceCategories,
+                           @EmergencyNumberSources int emergencyNumberSources,
+                           @EmergencyCallRouting int emergencyCallRouting) {
         this.mNumber = number;
         this.mCountryIso = countryIso;
         this.mMnc = mnc;
         this.mEmergencyServiceCategoryBitmask = emergencyServiceCategories;
         this.mEmergencyNumberSourceBitmask = emergencyNumberSources;
+        this.mEmergencyCallRouting = emergencyCallRouting;
     }
 
     /** @hide */
@@ -222,8 +255,33 @@
         mMnc = source.readString();
         mEmergencyServiceCategoryBitmask = source.readInt();
         mEmergencyNumberSourceBitmask = source.readInt();
+        mEmergencyCallRouting = source.readInt();
     }
 
+    @Override
+    /** @hide */
+    public void writeToParcel(Parcel dest, int flags) {
+        dest.writeString(mNumber);
+        dest.writeString(mCountryIso);
+        dest.writeString(mMnc);
+        dest.writeInt(mEmergencyServiceCategoryBitmask);
+        dest.writeInt(mEmergencyNumberSourceBitmask);
+        dest.writeInt(mEmergencyCallRouting);
+    }
+
+    public static final Parcelable.Creator<EmergencyNumber> CREATOR =
+            new Parcelable.Creator<EmergencyNumber>() {
+                @Override
+                public EmergencyNumber createFromParcel(Parcel in) {
+                    return new EmergencyNumber(in);
+                }
+
+                @Override
+                public EmergencyNumber[] newArray(int size) {
+                    return new EmergencyNumber[size];
+                }
+            };
+
     /**
      * Get the dialing number of the emergency number.
      *
@@ -352,14 +410,17 @@
         return (mEmergencyNumberSourceBitmask & sources) == sources;
     }
 
-    @Override
-    /** @hide */
-    public void writeToParcel(Parcel dest, int flags) {
-        dest.writeString(mNumber);
-        dest.writeString(mCountryIso);
-        dest.writeString(mMnc);
-        dest.writeInt(mEmergencyServiceCategoryBitmask);
-        dest.writeInt(mEmergencyNumberSourceBitmask);
+    /**
+     * Returns the emergency call routing information.
+     *
+     * <p>Some regions require some emergency numbers which are not routed using typical emergency
+     * call processing, but are instead placed as regular phone calls. The emergency call routing
+     * field provides information about how an emergency call will be routed when it is placed.
+     *
+     * @return the emergency call routing requirement
+     */
+    public @EmergencyCallRouting int getEmergencyCallRouting() {
+        return mEmergencyCallRouting;
     }
 
     @Override
@@ -373,7 +434,8 @@
         return "EmergencyNumber:" + "Number-" + mNumber + "|CountryIso-" + mCountryIso
                 + "|Mnc-" + mMnc
                 + "|ServiceCategories-" + Integer.toBinaryString(mEmergencyServiceCategoryBitmask)
-                + "|Sources-" + Integer.toBinaryString(mEmergencyNumberSourceBitmask);
+                + "|Sources-" + Integer.toBinaryString(mEmergencyNumberSourceBitmask)
+                + "|Routing-" + Integer.toBinaryString(mEmergencyCallRouting);
     }
 
     @Override
@@ -381,7 +443,19 @@
         if (!EmergencyNumber.class.isInstance(o)) {
             return false;
         }
-        return (o == this || toString().equals(o.toString()));
+        EmergencyNumber other = (EmergencyNumber) o;
+        return mNumber.equals(other.mNumber)
+                && mCountryIso.equals(other.mCountryIso)
+                && mMnc.equals(other.mMnc)
+                && mEmergencyServiceCategoryBitmask == other.mEmergencyServiceCategoryBitmask
+                && mEmergencyNumberSourceBitmask == other.mEmergencyNumberSourceBitmask
+                && mEmergencyCallRouting == other.mEmergencyCallRouting;
+    }
+
+    @Override
+    public int hashCode() {
+        return Objects.hash(mNumber, mCountryIso, mMnc, mEmergencyServiceCategoryBitmask,
+                mEmergencyNumberSourceBitmask, mEmergencyCallRouting);
     }
 
     /**
@@ -462,12 +536,12 @@
                 continue;
             }
             for (int j = i + 1; j < emergencyNumberList.size(); j++) {
-                if (isSameEmergencyNumber(
+                if (areSameEmergencyNumbers(
                         emergencyNumberList.get(i), emergencyNumberList.get(j))) {
                     Rlog.e(LOG_TAG, "Found unexpected duplicate numbers: "
                             + emergencyNumberList.get(i) + " vs " + emergencyNumberList.get(j));
                     // Set the merged emergency number in the current position
-                    emergencyNumberList.set(i, mergeNumbers(
+                    emergencyNumberList.set(i, mergeSameEmergencyNumbers(
                             emergencyNumberList.get(i), emergencyNumberList.get(j)));
                     // Mark the emergency number has been merged
                     mergedEmergencyNumber.add(emergencyNumberList.get(j));
@@ -486,8 +560,8 @@
      * Check if two emergency numbers are the same.
      *
      * A unique EmergencyNumber has a unique combination of ‘number’, ‘mcc’, 'mnc' and
-     * 'categories' fields. Multiple Emergency Number Sources should be merged into one bitfield
-     * for the same EmergencyNumber.
+     * 'categories', and 'routing' fields. Multiple Emergency Number Sources should be
+     * merged into one bitfield for the same EmergencyNumber.
      *
      * @param first first EmergencyNumber to compare
      * @param second second EmergencyNumber to compare
@@ -495,8 +569,8 @@
      *
      * @hide
      */
-    public static boolean isSameEmergencyNumber(@NonNull EmergencyNumber first,
-                                                @NonNull EmergencyNumber second) {
+    public static boolean areSameEmergencyNumbers(@NonNull EmergencyNumber first,
+                                                  @NonNull EmergencyNumber second) {
         if (!first.getNumber().equals(second.getNumber())) {
             return false;
         }
@@ -510,11 +584,15 @@
                 != second.getEmergencyServiceCategoryBitmask()) {
             return false;
         }
+        if (first.getEmergencyCallRouting() != second.getEmergencyCallRouting()) {
+            return false;
+        }
         return true;
     }
 
     /**
-     * Get a merged EmergencyNumber for two numbers if they are the same.
+     * Get a merged EmergencyNumber from two same emergency numbers. Two emergency numbers are
+     * the same if {@link #areSameEmergencyNumbers} returns {@code true}.
      *
      * @param first first EmergencyNumber to compare
      * @param second second EmergencyNumber to compare
@@ -522,27 +600,15 @@
      *
      * @hide
      */
-    public static EmergencyNumber mergeNumbers(@NonNull EmergencyNumber first,
-                                         @NonNull EmergencyNumber second) {
-        if (isSameEmergencyNumber(first, second)) {
+    public static EmergencyNumber mergeSameEmergencyNumbers(@NonNull EmergencyNumber first,
+                                                            @NonNull EmergencyNumber second) {
+        if (areSameEmergencyNumbers(first, second)) {
             return new EmergencyNumber(first.getNumber(), first.getCountryIso(), first.getMnc(),
                     first.getEmergencyServiceCategoryBitmask(),
                     first.getEmergencyNumberSourceBitmask()
-                            | second.getEmergencyNumberSourceBitmask());
+                            | second.getEmergencyNumberSourceBitmask(),
+                    first.getEmergencyCallRouting());
         }
         return null;
     }
-
-    public static final Parcelable.Creator<EmergencyNumber> CREATOR =
-            new Parcelable.Creator<EmergencyNumber>() {
-        @Override
-        public EmergencyNumber createFromParcel(Parcel in) {
-            return new EmergencyNumber(in);
-        }
-
-        @Override
-        public EmergencyNumber[] newArray(int size) {
-            return new EmergencyNumber[size];
-        }
-    };
 }
diff --git a/telephony/java/android/telephony/euicc/EuiccManager.java b/telephony/java/android/telephony/euicc/EuiccManager.java
index 9164402..95dfffd 100644
--- a/telephony/java/android/telephony/euicc/EuiccManager.java
+++ b/telephony/java/android/telephony/euicc/EuiccManager.java
@@ -30,6 +30,7 @@
 import android.os.Bundle;
 import android.os.RemoteException;
 import android.os.ServiceManager;
+import android.telephony.TelephonyManager;
 
 import com.android.internal.telephony.euicc.IEuiccController;
 
@@ -40,7 +41,11 @@
  * EuiccManager is the application interface to eUICCs, or eSIMs/embedded SIMs.
  *
  * <p>You do not instantiate this class directly; instead, you retrieve an instance through
- * {@link Context#getSystemService(String)} and {@link Context#EUICC_SERVICE}.
+ * {@link Context#getSystemService(String)} and {@link Context#EUICC_SERVICE}. This instance will be
+ * created using the default eUICC.
+ *
+ * <p>On a device with multiple eUICCs, you may want to create multiple EuiccManagers. To do this
+ * you can call {@link #createForCardId}.
  *
  * <p>See {@link #isEnabled} before attempting to use these APIs.
  */
@@ -248,10 +253,29 @@
     public static final int EUICC_OTA_STATUS_UNAVAILABLE = 5;
 
     private final Context mContext;
+    private final int mCardId;
 
     /** @hide */
     public EuiccManager(Context context) {
         mContext = context;
+        TelephonyManager tm = (TelephonyManager)
+                context.getSystemService(Context.TELEPHONY_SERVICE);
+        mCardId = tm.getCardIdForDefaultEuicc();
+    }
+
+    /** @hide */
+    private EuiccManager(Context context, int cardId) {
+        mContext = context;
+        mCardId = cardId;
+    }
+
+    /**
+     * Create a new EuiccManager object pinned to the given card ID.
+     *
+     * @return an EuiccManager that uses the given card ID for all calls.
+     */
+    public EuiccManager createForCardId(int cardId) {
+        return new EuiccManager(mContext, cardId);
     }
 
     /**
@@ -274,7 +298,8 @@
      * Returns the EID identifying the eUICC hardware.
      *
      * <p>Requires that the calling app has carrier privileges on the active subscription on the
-     * eUICC.
+     * current eUICC. A calling app with carrier privileges for one eUICC may not necessarily have
+     * access to the EID of another eUICC.
      *
      * @return the EID. May be null if {@link #isEnabled()} is false or the eUICC is not ready.
      */
@@ -284,7 +309,7 @@
             return null;
         }
         try {
-            return getIEuiccController().getEid();
+            return getIEuiccController().getEid(mCardId);
         } catch (RemoteException e) {
             throw e.rethrowFromSystemServer();
         }
@@ -307,7 +332,7 @@
             return EUICC_OTA_STATUS_UNAVAILABLE;
         }
         try {
-            return getIEuiccController().getOtaStatus();
+            return getIEuiccController().getOtaStatus(mCardId);
         } catch (RemoteException e) {
             throw e.rethrowFromSystemServer();
         }
@@ -317,10 +342,10 @@
      * Attempt to download the given {@link DownloadableSubscription}.
      *
      * <p>Requires the {@code android.Manifest.permission#WRITE_EMBEDDED_SUBSCRIPTIONS} permission,
-     * or the calling app must be authorized to manage both the currently-active subscription and
-     * the subscription to be downloaded according to the subscription metadata. Without the former,
-     * an {@link #EMBEDDED_SUBSCRIPTION_RESULT_RESOLVABLE_ERROR} will be returned in the callback
-     * intent to prompt the user to accept the download.
+     * or the calling app must be authorized to manage both the currently-active subscription on the
+     * current eUICC and the subscription to be downloaded according to the subscription metadata.
+     * Without the former, an {@link #EMBEDDED_SUBSCRIPTION_RESULT_RESOLVABLE_ERROR} will be
+     * returned in the callback intent to prompt the user to accept the download.
      *
      * @param subscription the subscription to download.
      * @param switchAfterDownload if true, the profile will be activated upon successful download.
@@ -334,7 +359,7 @@
             return;
         }
         try {
-            getIEuiccController().downloadSubscription(subscription, switchAfterDownload,
+            getIEuiccController().downloadSubscription(mCardId, subscription, switchAfterDownload,
                     mContext.getOpPackageName(), null /* resolvedBundle */, callbackIntent);
         } catch (RemoteException e) {
             throw e.rethrowFromSystemServer();
@@ -401,7 +426,7 @@
             return;
         }
         try {
-            getIEuiccController().continueOperation(resolutionIntent, resolutionExtras);
+            getIEuiccController().continueOperation(mCardId, resolutionIntent, resolutionExtras);
         } catch (RemoteException e) {
             throw e.rethrowFromSystemServer();
         }
@@ -433,8 +458,8 @@
             return;
         }
         try {
-            getIEuiccController().getDownloadableSubscriptionMetadata(
-                    subscription, mContext.getOpPackageName(), callbackIntent);
+            getIEuiccController().getDownloadableSubscriptionMetadata(mCardId, subscription,
+                    mContext.getOpPackageName(), callbackIntent);
         } catch (RemoteException e) {
             throw e.rethrowFromSystemServer();
         }
@@ -463,7 +488,7 @@
             return;
         }
         try {
-            getIEuiccController().getDefaultDownloadableSubscriptionList(
+            getIEuiccController().getDefaultDownloadableSubscriptionList(mCardId,
                     mContext.getOpPackageName(), callbackIntent);
         } catch (RemoteException e) {
             throw e.rethrowFromSystemServer();
@@ -482,7 +507,7 @@
             return null;
         }
         try {
-            return getIEuiccController().getEuiccInfo();
+            return getIEuiccController().getEuiccInfo(mCardId);
         } catch (RemoteException e) {
             throw e.rethrowFromSystemServer();
         }
@@ -508,7 +533,7 @@
             return;
         }
         try {
-            getIEuiccController().deleteSubscription(
+            getIEuiccController().deleteSubscription(mCardId,
                     subscriptionId, mContext.getOpPackageName(), callbackIntent);
         } catch (RemoteException e) {
             throw e.rethrowFromSystemServer();
@@ -536,7 +561,7 @@
             return;
         }
         try {
-            getIEuiccController().switchToSubscription(
+            getIEuiccController().switchToSubscription(mCardId,
                     subscriptionId, mContext.getOpPackageName(), callbackIntent);
         } catch (RemoteException e) {
             throw e.rethrowFromSystemServer();
@@ -562,7 +587,7 @@
             return;
         }
         try {
-            getIEuiccController().updateSubscriptionNickname(
+            getIEuiccController().updateSubscriptionNickname(mCardId,
                     subscriptionId, nickname, mContext.getOpPackageName(), callbackIntent);
         } catch (RemoteException e) {
             throw e.rethrowFromSystemServer();
@@ -586,7 +611,7 @@
             return;
         }
         try {
-            getIEuiccController().eraseSubscriptions(callbackIntent);
+            getIEuiccController().eraseSubscriptions(mCardId, callbackIntent);
         } catch (RemoteException e) {
             throw e.rethrowFromSystemServer();
         }
@@ -616,7 +641,7 @@
             return;
         }
         try {
-            getIEuiccController().retainSubscriptionsForFactoryReset(callbackIntent);
+            getIEuiccController().retainSubscriptionsForFactoryReset(mCardId, callbackIntent);
         } catch (RemoteException e) {
             throw e.rethrowFromSystemServer();
         }
diff --git a/telephony/java/android/telephony/ims/ImsCallProfile.java b/telephony/java/android/telephony/ims/ImsCallProfile.java
index cb6fcd7..9c8d078 100644
--- a/telephony/java/android/telephony/ims/ImsCallProfile.java
+++ b/telephony/java/android/telephony/ims/ImsCallProfile.java
@@ -24,9 +24,11 @@
 import android.os.Parcelable;
 import android.telecom.VideoProfile;
 import android.telephony.emergency.EmergencyNumber;
+import android.telephony.emergency.EmergencyNumber.EmergencyCallRouting;
 import android.telephony.emergency.EmergencyNumber.EmergencyServiceCategories;
 import android.util.Log;
 
+import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.telephony.PhoneConstants;
 
 import java.lang.annotation.Retention;
@@ -321,6 +323,20 @@
             EmergencyNumber.EMERGENCY_SERVICE_CATEGORY_UNSPECIFIED;
 
     /**
+     * The emergency call routing, only valid if {@link #getServiceType} returns
+     * {@link #SERVICE_TYPE_EMERGENCY}
+     *
+     * If valid, the value is any of the following constants:
+     * <ol>
+     * <li>{@link EmergencyNumber#EMERGENCY_CALL_ROUTING_UNKNOWN} </li>
+     * <li>{@link EmergencyNumber#EMERGENCY_CALL_ROUTING_NORMAL} </li>
+     * <li>{@link EmergencyNumber#EMERGENCY_CALL_ROUTING_EMERGENCY} </li>
+     * </ol>
+     */
+    private @EmergencyCallRouting int mEmergencyCallRouting =
+            EmergencyNumber.EMERGENCY_CALL_ROUTING_UNKNOWN;
+
+    /**
      * Extras associated with this {@link ImsCallProfile}.
      * <p>
      * Valid data types include:
@@ -503,10 +519,12 @@
 
     @Override
     public String toString() {
-        return "{ serviceType=" + mServiceType +
-                ", callType=" + mCallType +
-                ", restrictCause=" + mRestrictCause +
-                ", mediaProfile=" + mMediaProfile.toString() + " }";
+        return "{ serviceType=" + mServiceType
+                + ", callType=" + mCallType
+                + ", restrictCause=" + mRestrictCause
+                + ", mediaProfile=" + mMediaProfile.toString()
+                + ", emergencyServiceCategories=" + mEmergencyCallRouting
+                + ", emergencyCallRouting=" + mEmergencyCallRouting + " }";
     }
 
     @Override
@@ -522,6 +540,7 @@
         out.writeBundle(filteredExtras);
         out.writeParcelable(mMediaProfile, 0);
         out.writeInt(mEmergencyServiceCategories);
+        out.writeInt(mEmergencyCallRouting);
     }
 
     private void readFromParcel(Parcel in) {
@@ -530,6 +549,7 @@
         mCallExtras = in.readBundle();
         mMediaProfile = in.readParcelable(ImsStreamMediaProfile.class.getClassLoader());
         mEmergencyServiceCategories = in.readInt();
+        mEmergencyCallRouting = in.readInt();
     }
 
     public static final Creator<ImsCallProfile> CREATOR = new Creator<ImsCallProfile>() {
@@ -740,6 +760,21 @@
     }
 
     /**
+     * Set the emergency service categories and emergency call routing. The set value is valid
+     * only if {@link #getServiceType} returns {@link #SERVICE_TYPE_EMERGENCY}
+     *
+     * Reference: 3gpp 23.167, Section 6 - Functional description;
+     *            3gpp 22.101, Section 10 - Emergency Calls.
+     *
+     * @hide
+     */
+    public void setEmergencyCallInfo(EmergencyNumber num) {
+        setEmergencyServiceCategories(num.getEmergencyServiceCategoryBitmask());
+        setEmergencyCallRouting(num.getEmergencyCallRouting());
+    }
+
+
+    /**
      * Set the emergency service categories. The set value is valid only if
      * {@link #getServiceType} returns {@link #SERVICE_TYPE_EMERGENCY}
      *
@@ -758,12 +793,29 @@
      * Reference: 3gpp 23.167, Section 6 - Functional description;
      *            3gpp 22.101, Section 10 - Emergency Calls.
      */
+    @VisibleForTesting
     public void setEmergencyServiceCategories(
             @EmergencyServiceCategories int emergencyServiceCategories) {
         mEmergencyServiceCategories = emergencyServiceCategories;
     }
 
     /**
+     * Set the emergency call routing, only valid if {@link #getServiceType} returns
+     * {@link #SERVICE_TYPE_EMERGENCY}
+     *
+     * If valid, the value is any of the following constants:
+     * <ol>
+     * <li>{@link EmergencyNumber#EMERGENCY_CALL_ROUTING_UNKNOWN} </li>
+     * <li>{@link EmergencyNumber#EMERGENCY_CALL_ROUTING_NORMAL} </li>
+     * <li>{@link EmergencyNumber#EMERGENCY_CALL_ROUTING_EMERGENCY} </li>
+     * </ol>
+     */
+    @VisibleForTesting
+    public void setEmergencyCallRouting(@EmergencyCallRouting int emergencyCallRouting) {
+        mEmergencyCallRouting = emergencyCallRouting;
+    }
+
+    /**
      * Get the emergency service categories, only valid if {@link #getServiceType} returns
      * {@link #SERVICE_TYPE_EMERGENCY}
      *
@@ -787,4 +839,19 @@
     public @EmergencyServiceCategories int getEmergencyServiceCategories() {
         return mEmergencyServiceCategories;
     }
+
+    /**
+     * Get the emergency call routing, only valid if {@link #getServiceType} returns
+     * {@link #SERVICE_TYPE_EMERGENCY}
+     *
+     * If valid, the value is any of the following constants:
+     * <ol>
+     * <li>{@link EmergencyNumber#EMERGENCY_CALL_ROUTING_UNKNOWN} </li>
+     * <li>{@link EmergencyNumber#EMERGENCY_CALL_ROUTING_NORMAL} </li>
+     * <li>{@link EmergencyNumber#EMERGENCY_CALL_ROUTING_EMERGENCY} </li>
+     * </ol>
+     */
+    public @EmergencyCallRouting int getEmergencyCallRouting() {
+        return mEmergencyCallRouting;
+    }
 }
diff --git a/telephony/java/android/telephony/ims/ImsMmTelManager.java b/telephony/java/android/telephony/ims/ImsMmTelManager.java
index e2350fe..9414abd 100644
--- a/telephony/java/android/telephony/ims/ImsMmTelManager.java
+++ b/telephony/java/android/telephony/ims/ImsMmTelManager.java
@@ -92,7 +92,7 @@
     public static final int WIFI_MODE_WIFI_PREFERRED = 2;
 
     /**
-     * Callback class for receiving Registration callback events.
+     * Callback class for receiving IMS network Registration callback events.
      * @see #registerImsRegistrationCallback(Executor, RegistrationCallback) (RegistrationCallback)
      * @see #unregisterImsRegistrationCallback(RegistrationCallback)
      */
@@ -241,7 +241,8 @@
     }
 
     /**
-     * Receives IMS capability status updates from the ImsService.
+     * Receives IMS capability status updates from the ImsService. This information is also
+     * available via the {@link #isAvailable(int, int)} method below.
      *
      * @see #registerMmTelCapabilityCallback(Executor, CapabilityCallback) (CapabilityCallback)
      * @see #unregisterMmTelCapabilityCallback(CapabilityCallback)
@@ -290,6 +291,8 @@
          * If unavailable, the feature is not able to support the unavailable capability at this
          * time.
          *
+         * This information can also be queried using the {@link #isAvailable(int, int)} API.
+         *
          * @param capabilities The new availability of the capabilities.
          */
         public void onCapabilitiesStatusChanged(
@@ -304,7 +307,7 @@
         /**@hide*/
         // Only exposed as public method for compatibility with deprecated ImsManager APIs.
         // TODO: clean up dependencies and change back to private visibility.
-        public void setExecutor(Executor executor) {
+        public final void setExecutor(Executor executor) {
             mBinder.setExecutor(executor);
         }
     }
@@ -342,8 +345,7 @@
      * Registers a {@link RegistrationCallback} with the system, which will provide registration
      * updates for the subscription specified in {@link #createForSubscriptionId(Context, int)}. Use
      * {@link SubscriptionManager.OnSubscriptionsChangedListener} to listen to Subscription changed
-     * events and call {@link #unregisterImsRegistrationCallback(RegistrationCallback)} to clean up
-     * after a subscription is removed.
+     * events and call {@link #unregisterImsRegistrationCallback(RegistrationCallback)} to clean up.
      *
      * When the callback is registered, it will initiate the callback c to be called with the
      * current registration state.
@@ -351,6 +353,12 @@
      * @param executor The executor the callback events should be run on.
      * @param c The {@link RegistrationCallback} to be added.
      * @see #unregisterImsRegistrationCallback(RegistrationCallback)
+     * @throws IllegalArgumentException if the subscription associated with this callback is not
+     * active (SIM is not inserted, ESIM inactive) or invalid, or a null {@link Executor} or
+     * {@link CapabilityCallback} callback.
+     * @throws IllegalStateException if the subscription associated with this callback is valid, but
+     * the {@link ImsService} associated with the subscription is not available. This can happen if
+     * the service crashed, for example.
      */
     @RequiresPermission(Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
     public void registerImsRegistrationCallback(@CallbackExecutor Executor executor,
@@ -370,11 +378,17 @@
     }
 
     /**
-     * Removes an existing {@link RegistrationCallback}. Ensure to call this method when cleaning
-     * up to avoid memory leaks or when the subscription is removed.
+     * Removes an existing {@link RegistrationCallback}.
+     *
+     * When the subscription associated with this callback is removed (SIM removed, ESIM swap,
+     * etc...), this callback will automatically be removed. If this method is called for an
+     * inactive subscription, it will result in a no-op.
+     *
      * @param c The {@link RegistrationCallback} to be removed.
      * @see SubscriptionManager.OnSubscriptionsChangedListener
      * @see #registerImsRegistrationCallback(Executor, RegistrationCallback)
+     * @throws IllegalArgumentException if the subscription ID associated with this callback is
+     * invalid.
      */
     @RequiresPermission(Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
     public void unregisterImsRegistrationCallback(@NonNull RegistrationCallback c) {
@@ -389,12 +403,14 @@
     }
 
     /**
-     * Registers a {@link CapabilityCallback} with the system, which will provide MmTel capability
-     * updates for the subscription specified in {@link #createForSubscriptionId(Context, int)}.
+     * Registers a {@link CapabilityCallback} with the system, which will provide MmTel service
+     * availability updates for the subscription specified in
+     * {@link #createForSubscriptionId(Context, int)}. The method {@link #isAvailable(int, int)}
+     * can also be used to query this information at any time.
+     *
      * Use {@link SubscriptionManager.OnSubscriptionsChangedListener} to listen to
      * subscription changed events and call
-     * {@link #unregisterImsRegistrationCallback(RegistrationCallback)} to clean up after a
-     * subscription is removed.
+     * {@link #unregisterImsRegistrationCallback(RegistrationCallback)} to clean up.
      *
      * When the callback is registered, it will initiate the callback c to be called with the
      * current capabilities.
@@ -402,9 +418,15 @@
      * @param executor The executor the callback events should be run on.
      * @param c The MmTel {@link CapabilityCallback} to be registered.
      * @see #unregisterMmTelCapabilityCallback(CapabilityCallback)
+     * @throws IllegalArgumentException if the subscription associated with this callback is not
+     * active (SIM is not inserted, ESIM inactive) or invalid, or a null {@link Executor} or
+     * {@link CapabilityCallback} callback.
+     * @throws IllegalStateException if the subscription associated with this callback is valid, but
+     * the {@link ImsService} associated with the subscription is not available. This can happen if
+     * the service crashed, for example.
      */
     @RequiresPermission(Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
-    public void registerMmTelCapabilityCallback(@CallbackExecutor Executor executor,
+    public void registerMmTelCapabilityCallback(@NonNull @CallbackExecutor Executor executor,
             @NonNull CapabilityCallback c) {
         if (c == null) {
             throw new IllegalArgumentException("Must include a non-null RegistrationCallback.");
@@ -421,10 +443,15 @@
     }
 
     /**
-     * Removes an existing MmTel {@link CapabilityCallback}. Be sure to call this when cleaning
-     * up to avoid memory leaks.
+     * Removes an existing MmTel {@link CapabilityCallback}.
+     *
+     * When the subscription associated with this callback is removed (SIM removed, ESIM swap,
+     * etc...), this callback will automatically be removed. If this method is called for an
+     * inactive subscription, it will result in a no-op.
      * @param c The MmTel {@link CapabilityCallback} to be removed.
      * @see #registerMmTelCapabilityCallback(Executor, CapabilityCallback)
+     * @throws IllegalArgumentException if the subscription ID associated with this callback is
+     * invalid.
      */
     @RequiresPermission(Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
     public void unregisterMmTelCapabilityCallback(@NonNull CapabilityCallback c) {
diff --git a/telephony/java/android/telephony/ims/ProvisioningManager.java b/telephony/java/android/telephony/ims/ProvisioningManager.java
index 916e282..d37198a 100644
--- a/telephony/java/android/telephony/ims/ProvisioningManager.java
+++ b/telephony/java/android/telephony/ims/ProvisioningManager.java
@@ -133,33 +133,40 @@
     }
 
     /**
-     * Register a new {@link Callback} to listen to changes to changes in
-     * IMS provisioning. Use {@link SubscriptionManager.OnSubscriptionsChangedListener} to listen to
-     * Subscription changed events and call
-     * {@link #unregisterProvisioningChangedCallback(Callback)} to clean up after a
-     * subscription is removed.
+     * Register a new {@link Callback} to listen to changes to changes in IMS provisioning.
+     *
+     * When the subscription associated with this callback is removed (SIM removed, ESIM swap,
+     * etc...), this callback will automatically be removed.
      * @param executor The {@link Executor} to call the callback methods on
      * @param callback The provisioning callbackto be registered.
      * @see #unregisterProvisioningChangedCallback(Callback)
      * @see SubscriptionManager.OnSubscriptionsChangedListener
+     * @throws IllegalArgumentException if the subscription associated with this callback is not
+     * active (SIM is not inserted, ESIM inactive) or the subscription is invalid.
+     * @throws IllegalStateException if the subscription associated with this callback is valid, but
+     * the {@link ImsService} associated with the subscription is not available. This can happen if
+     * the service crashed, for example.
      */
     @RequiresPermission(Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
     public void registerProvisioningChangedCallback(@CallbackExecutor Executor executor,
             @NonNull Callback callback) {
         callback.setExecutor(executor);
         try {
-            getITelephony().registerImsProvisioningChangedCallback(mSubId,
-                    callback.getBinder());
+            getITelephony().registerImsProvisioningChangedCallback(mSubId, callback.getBinder());
         } catch (RemoteException e) {
             throw e.rethrowAsRuntimeException();
         }
     }
 
     /**
-     * Unregister an existing {@link Callback}. Ensure to call this method when cleaning
-     * up to avoid memory leaks or when the subscription is removed.
+     * Unregister an existing {@link Callback}. When the subscription associated with this
+     * callback is removed (SIM removed, ESIM swap, etc...), this callback will automatically be
+     * removed. If this method is called for an inactive subscription, it will result in a no-op.
      * @param callback The existing {@link Callback} to be removed.
      * @see #registerProvisioningChangedCallback(Executor, Callback)
+     *
+     * @throws IllegalArgumentException if the subscription associated with this callback is
+     * invalid.
      */
     @RequiresPermission(Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
     public void unregisterProvisioningChangedCallback(@NonNull Callback callback) {
diff --git a/telephony/java/com/android/internal/telephony/euicc/IEuiccController.aidl b/telephony/java/com/android/internal/telephony/euicc/IEuiccController.aidl
index dd40d56..14a36c8 100644
--- a/telephony/java/com/android/internal/telephony/euicc/IEuiccController.aidl
+++ b/telephony/java/com/android/internal/telephony/euicc/IEuiccController.aidl
@@ -24,22 +24,25 @@
 
 /** @hide */
 interface IEuiccController {
-    oneway void continueOperation(in Intent resolutionIntent, in Bundle resolutionExtras);
-    oneway void getDownloadableSubscriptionMetadata(in DownloadableSubscription subscription,
+    oneway void continueOperation(int cardId, in Intent resolutionIntent,
+            in Bundle resolutionExtras);
+    oneway void getDownloadableSubscriptionMetadata(int cardId,
+            in DownloadableSubscription subscription,
         String callingPackage, in PendingIntent callbackIntent);
-    oneway void getDefaultDownloadableSubscriptionList(
+    oneway void getDefaultDownloadableSubscriptionList(int cardId,
         String callingPackage, in PendingIntent callbackIntent);
-    String getEid();
-    int getOtaStatus();
-    oneway void downloadSubscription(in DownloadableSubscription subscription,
-        boolean switchAfterDownload, String callingPackage, in Bundle resolvedBundle, in PendingIntent callbackIntent);
-    EuiccInfo getEuiccInfo();
-    oneway void deleteSubscription(int subscriptionId, String callingPackage,
+    String getEid(int cardId);
+    int getOtaStatus(int cardId);
+    oneway void downloadSubscription(int cardId, in DownloadableSubscription subscription,
+        boolean switchAfterDownload, String callingPackage, in Bundle resolvedBundle,
         in PendingIntent callbackIntent);
-    oneway void switchToSubscription(int subscriptionId, String callingPackage,
+    EuiccInfo getEuiccInfo(int cardId);
+    oneway void deleteSubscription(int cardId, int subscriptionId, String callingPackage,
         in PendingIntent callbackIntent);
-    oneway void updateSubscriptionNickname(int subscriptionId, String nickname,
+    oneway void switchToSubscription(int cardId, int subscriptionId, String callingPackage,
+        in PendingIntent callbackIntent);
+    oneway void updateSubscriptionNickname(int cardId, int subscriptionId, String nickname,
         String callingPackage, in PendingIntent callbackIntent);
-    oneway void eraseSubscriptions(in PendingIntent callbackIntent);
-    oneway void retainSubscriptionsForFactoryReset(in PendingIntent callbackIntent);
-}
\ No newline at end of file
+    oneway void eraseSubscriptions(int cardId, in PendingIntent callbackIntent);
+    oneway void retainSubscriptionsForFactoryReset(int cardId, in PendingIntent callbackIntent);
+}
diff --git a/test-legacy/Android.bp b/test-legacy/Android.bp
index 833c714..a69f422 100644
--- a/test-legacy/Android.bp
+++ b/test-legacy/Android.bp
@@ -25,7 +25,7 @@
     static_libs: [
         "android.test.base-minus-junit",
         "android.test.runner-minus-junit",
-        "android.test.mock.impl",
+        "android.test.mock_static",
     ],
 
     no_framework_libs: true,
diff --git a/test-mock/Android.bp b/test-mock/Android.bp
index e1d6e01..43b765d 100644
--- a/test-mock/Android.bp
+++ b/test-mock/Android.bp
@@ -30,3 +30,19 @@
     srcs_lib_whitelist_pkgs: ["android"],
     compile_dex: true,
 }
+
+// Build the android.test.mock_static library
+// ==========================================
+// This is only intended for inclusion in the legacy-android-test.
+// Must not be used elewhere.
+java_library_static {
+    name: "android.test.mock_static",
+
+    java_version: "1.8",
+    srcs: ["src/**/*.java"],
+
+    no_framework_libs: true,
+    libs: [
+        "framework",
+    ],
+}
diff --git a/tests/net/java/android/net/shared/LinkPropertiesParcelableUtilTest.java b/tests/net/java/android/net/shared/LinkPropertiesParcelableUtilTest.java
new file mode 100644
index 0000000..4cabfc9
--- /dev/null
+++ b/tests/net/java/android/net/shared/LinkPropertiesParcelableUtilTest.java
@@ -0,0 +1,193 @@
+/*
+ * Copyright (C) 2019 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.net.shared;
+
+import static android.net.shared.LinkPropertiesParcelableUtil.fromStableParcelable;
+import static android.net.shared.LinkPropertiesParcelableUtil.toStableParcelable;
+
+import static org.junit.Assert.assertEquals;
+
+import android.net.InetAddresses;
+import android.net.IpPrefix;
+import android.net.LinkAddress;
+import android.net.LinkProperties;
+import android.net.ProxyInfo;
+import android.net.RouteInfo;
+import android.net.Uri;
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.lang.reflect.Modifier;
+import java.util.Arrays;
+import java.util.Collections;
+
+/**
+ * Tests for {@link LinkPropertiesParcelableUtil}
+ */
+@RunWith(AndroidJUnit4.class)
+@SmallTest
+public class LinkPropertiesParcelableUtilTest {
+    private LinkProperties mLinkProperties;
+
+    private static final String TEST_LINKPROPS_IFACE = "TEST_IFACE";
+    private static final String TEST_STACKED_LINK_1_IFACE = "TEST_STACKED_IFACE_1";
+    private static final String TEST_STACKED_LINK_2_IFACE = "TEST_STACKED_IFACE_2";
+
+    @Before
+    public void setUp() {
+        mLinkProperties = makeLinkProperties(TEST_LINKPROPS_IFACE);
+        mLinkProperties.addStackedLink(makeLinkProperties(TEST_STACKED_LINK_1_IFACE));
+        mLinkProperties.addStackedLink(makeLinkProperties(TEST_STACKED_LINK_2_IFACE));
+    }
+
+    private static LinkProperties makeLinkProperties(String iface) {
+        final LinkProperties lp = new LinkProperties();
+        lp.setInterfaceName(iface);
+        lp.setLinkAddresses(Arrays.asList(
+                new LinkAddress(InetAddresses.parseNumericAddress("192.168.0.42"), 16),
+                new LinkAddress(InetAddresses.parseNumericAddress("2001:db8::7"), 42)));
+        lp.setDnsServers(Arrays.asList(
+                InetAddresses.parseNumericAddress("2001:db8::42"),
+                InetAddresses.parseNumericAddress("192.168.1.1")
+        ));
+        lp.setValidatedPrivateDnsServers(Arrays.asList(
+                InetAddresses.parseNumericAddress("2001:db8::43"),
+                InetAddresses.parseNumericAddress("192.168.42.43")
+        ));
+        lp.setPcscfServers(Arrays.asList(
+                InetAddresses.parseNumericAddress("2001:db8::47"),
+                InetAddresses.parseNumericAddress("192.168.42.47")
+        ));
+        lp.setUsePrivateDns(true);
+        lp.setPrivateDnsServerName("test.example.com");
+        lp.setDomains("test1.example.com,test2.example.com");
+        lp.addRoute(new RouteInfo(
+                new IpPrefix(InetAddresses.parseNumericAddress("2001:db8::44"), 45),
+                InetAddresses.parseNumericAddress("2001:db8::45"),
+                iface,
+                RouteInfo.RTN_UNICAST
+        ));
+        lp.addRoute(new RouteInfo(
+                new IpPrefix(InetAddresses.parseNumericAddress("192.168.44.45"), 16),
+                InetAddresses.parseNumericAddress("192.168.45.1"),
+                iface,
+                RouteInfo.RTN_THROW
+        ));
+        lp.setHttpProxy(new ProxyInfo("test3.example.com", 8000,
+                "excl1.example.com,excl2.example.com"));
+        lp.setMtu(5000);
+        lp.setTcpBufferSizes("1,2,3,4,5,6");
+        lp.setNat64Prefix(new IpPrefix(InetAddresses.parseNumericAddress("2001:db8::48"), 96));
+
+        // Verify that this test does not miss any new field added later.
+        // If any added field is not included in LinkProperties#equals, assertLinkPropertiesEquals
+        // must also be updated.
+        assertEquals(14, Arrays.stream(LinkProperties.class.getDeclaredFields())
+                .filter(f -> !Modifier.isStatic(f.getModifiers())).count());
+
+        return lp;
+    }
+
+    @Test
+    public void testParcelUnparcel() {
+        doParcelUnparcelTest();
+    }
+
+    @Test
+    public void testParcelUnparcel_NullInterface() {
+        mLinkProperties.setInterfaceName(null);
+        doParcelUnparcelTest();
+    }
+
+    @Test
+    public void testParcelUnparcel_NullPrivateDnsServer() {
+        mLinkProperties.setPrivateDnsServerName(null);
+        doParcelUnparcelTest();
+    }
+
+    @Test
+    public void testParcelUnparcel_NullDomains() {
+        mLinkProperties.setDomains(null);
+        doParcelUnparcelTest();
+    }
+
+    @Test
+    public void testParcelUnparcel_NullProxy() {
+        mLinkProperties.setHttpProxy(null);
+        doParcelUnparcelTest();
+    }
+
+    @Test
+    public void testParcelUnparcel_NullTcpBufferSizes() {
+        mLinkProperties.setTcpBufferSizes(null);
+        doParcelUnparcelTest();
+    }
+
+    @Test
+    public void testParcelUnparcel_EmptyLinkAddresses() {
+        mLinkProperties.setLinkAddresses(Collections.emptyList());
+        doParcelUnparcelTest();
+    }
+
+    @Test
+    public void testParcelUnparcel_EmptyDnses() {
+        mLinkProperties.setDnsServers(Collections.emptyList());
+        doParcelUnparcelTest();
+    }
+
+    @Test
+    public void testParcelUnparcel_EmptyValidatedPrivateDnses() {
+        mLinkProperties.setValidatedPrivateDnsServers(Collections.emptyList());
+        doParcelUnparcelTest();
+    }
+
+    @Test
+    public void testParcelUnparcel_EmptyRoutes() {
+        for (RouteInfo r : mLinkProperties.getAllRoutes()) {
+            mLinkProperties.removeRoute(r);
+        }
+        doParcelUnparcelTest();
+    }
+
+    @Test
+    public void testParcelUnparcel_PacFileProxyInfo() {
+        mLinkProperties.setHttpProxy(new ProxyInfo(Uri.parse("http://pacfile.example.com")));
+        doParcelUnparcelTest();
+    }
+
+    @Test
+    public void testParcelUnparcel_NullNat64Prefix() {
+        mLinkProperties.setNat64Prefix(null);
+        doParcelUnparcelTest();
+    }
+
+    private void doParcelUnparcelTest() {
+        final LinkProperties unparceled = fromStableParcelable(toStableParcelable(mLinkProperties));
+        assertLinkPropertiesEquals(mLinkProperties, unparceled);
+    }
+
+    private static void assertLinkPropertiesEquals(LinkProperties expected, LinkProperties actual) {
+        assertEquals(expected, actual);
+
+        // LinkProperties equals() does not include stacked links
+        assertEquals(expected.getStackedLinks(), actual.getStackedLinks());
+    }
+}