Merge "Don't allow PI-based starts and trampolines when sender is SYSTEM_UID and it happens to pass foregroundness check at the time of sending" into qt-dev
diff --git a/api/current.txt b/api/current.txt
index eb244e4..8ec7594 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -41758,7 +41758,7 @@
     method public int getDisabledShowContext();
     method public static boolean isActiveService(android.content.Context, android.content.ComponentName);
     method public android.os.IBinder onBind(android.content.Intent);
-    method @Nullable public java.util.Set<java.lang.String> onGetSupportedVoiceActions(@NonNull java.util.Set<java.lang.String>);
+    method @NonNull public java.util.Set<java.lang.String> onGetSupportedVoiceActions(@NonNull java.util.Set<java.lang.String>);
     method public void onLaunchVoiceAssistFromKeyguard();
     method public void onReady();
     method public void onShutdown();
diff --git a/api/system-current.txt b/api/system-current.txt
index d15d006..c031429 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -604,7 +604,7 @@
   public final class Vr2dDisplayProperties implements android.os.Parcelable {
     ctor public Vr2dDisplayProperties(int, int, int);
     method public int describeContents();
-    method public void dump(java.io.PrintWriter, String);
+    method public void dump(@NonNull java.io.PrintWriter, @NonNull String);
     method public int getAddedFlags();
     method public int getDpi();
     method public int getHeight();
@@ -615,26 +615,26 @@
     field public static final int FLAG_VIRTUAL_DISPLAY_ENABLED = 1; // 0x1
   }
 
-  public static class Vr2dDisplayProperties.Builder {
+  public static final class Vr2dDisplayProperties.Builder {
     ctor public Vr2dDisplayProperties.Builder();
-    method public android.app.Vr2dDisplayProperties.Builder addFlags(int);
-    method public android.app.Vr2dDisplayProperties build();
-    method public android.app.Vr2dDisplayProperties.Builder removeFlags(int);
-    method public android.app.Vr2dDisplayProperties.Builder setDimensions(int, int, int);
-    method public android.app.Vr2dDisplayProperties.Builder setEnabled(boolean);
+    method @NonNull public android.app.Vr2dDisplayProperties.Builder addFlags(int);
+    method @NonNull public android.app.Vr2dDisplayProperties build();
+    method @NonNull public android.app.Vr2dDisplayProperties.Builder removeFlags(int);
+    method @NonNull public android.app.Vr2dDisplayProperties.Builder setDimensions(int, int, int);
+    method @NonNull public android.app.Vr2dDisplayProperties.Builder setEnabled(boolean);
   }
 
   public class VrManager {
     method @RequiresPermission(android.Manifest.permission.RESTRICTED_VR_ACCESS) public int getVr2dDisplayId();
     method @RequiresPermission(anyOf={android.Manifest.permission.RESTRICTED_VR_ACCESS, "android.permission.ACCESS_VR_STATE"}) public boolean isPersistentVrModeEnabled();
     method @RequiresPermission(anyOf={android.Manifest.permission.RESTRICTED_VR_ACCESS, "android.permission.ACCESS_VR_STATE"}) public boolean isVrModeEnabled();
-    method @RequiresPermission(anyOf={android.Manifest.permission.RESTRICTED_VR_ACCESS, "android.permission.ACCESS_VR_STATE"}) public void registerVrStateCallback(@NonNull java.util.concurrent.Executor, android.app.VrStateCallback);
+    method @RequiresPermission(anyOf={android.Manifest.permission.RESTRICTED_VR_ACCESS, "android.permission.ACCESS_VR_STATE"}) public void registerVrStateCallback(@NonNull java.util.concurrent.Executor, @NonNull android.app.VrStateCallback);
     method @RequiresPermission(android.Manifest.permission.RESTRICTED_VR_ACCESS) public void setAndBindVrCompositor(android.content.ComponentName);
     method @RequiresPermission(android.Manifest.permission.RESTRICTED_VR_ACCESS) public void setPersistentVrModeEnabled(boolean);
     method @RequiresPermission("android.permission.ACCESS_VR_MANAGER") public void setStandbyEnabled(boolean);
-    method @RequiresPermission(android.Manifest.permission.RESTRICTED_VR_ACCESS) public void setVr2dDisplayProperties(android.app.Vr2dDisplayProperties);
-    method @RequiresPermission(android.Manifest.permission.RESTRICTED_VR_ACCESS) public void setVrInputMethod(android.content.ComponentName);
-    method @RequiresPermission(anyOf={android.Manifest.permission.RESTRICTED_VR_ACCESS, "android.permission.ACCESS_VR_STATE"}) public void unregisterVrStateCallback(android.app.VrStateCallback);
+    method @RequiresPermission(android.Manifest.permission.RESTRICTED_VR_ACCESS) public void setVr2dDisplayProperties(@NonNull android.app.Vr2dDisplayProperties);
+    method @RequiresPermission(android.Manifest.permission.RESTRICTED_VR_ACCESS) public void setVrInputMethod(@Nullable android.content.ComponentName);
+    method @RequiresPermission(anyOf={android.Manifest.permission.RESTRICTED_VR_ACCESS, "android.permission.ACCESS_VR_STATE"}) public void unregisterVrStateCallback(@NonNull android.app.VrStateCallback);
   }
 
   public abstract class VrStateCallback {
diff --git a/core/java/android/app/Vr2dDisplayProperties.java b/core/java/android/app/Vr2dDisplayProperties.java
index bcb8592..fc200bf 100644
--- a/core/java/android/app/Vr2dDisplayProperties.java
+++ b/core/java/android/app/Vr2dDisplayProperties.java
@@ -17,6 +17,7 @@
 package android.app;
 
 import android.annotation.IntDef;
+import android.annotation.NonNull;
 import android.annotation.SystemApi;
 import android.os.Parcel;
 import android.os.Parcelable;
@@ -136,7 +137,7 @@
     /**
      * Prints out dump info.
      */
-    public void dump(PrintWriter pw, String prefix) {
+    public void dump(@NonNull PrintWriter pw, @NonNull String prefix) {
         pw.println(prefix + toString());
     }
 
@@ -188,7 +189,7 @@
     /**
      * Convenience class for creating Vr2dDisplayProperties.
      */
-    public static class Builder {
+    public static final class Builder {
         private int mAddedFlags = 0;
         private int mRemovedFlags = 0;
 
@@ -203,6 +204,7 @@
         /**
          * Sets the dimensions to use for the virtual display.
          */
+        @NonNull
         public Builder setDimensions(int width, int height, int dpi) {
             mWidth = width;
             mHeight = height;
@@ -213,6 +215,7 @@
         /**
          * Toggles the virtual display functionality for 2D activities in VR.
          */
+        @NonNull
         public Builder setEnabled(boolean enabled) {
             if (enabled) {
                 addFlags(FLAG_VIRTUAL_DISPLAY_ENABLED);
@@ -225,6 +228,7 @@
         /**
          * Adds property flags.
          */
+        @NonNull
         public Builder addFlags(@Vr2dDisplayFlag int flags) {
             mAddedFlags |= flags;
             mRemovedFlags &= ~flags;
@@ -234,6 +238,7 @@
         /**
          * Removes property flags.
          */
+        @NonNull
         public Builder removeFlags(@Vr2dDisplayFlag int flags) {
             mRemovedFlags |= flags;
             mAddedFlags &= ~flags;
@@ -243,6 +248,7 @@
         /**
          * Builds the Vr2dDisplayProperty instance.
          */
+        @NonNull
         public Vr2dDisplayProperties build() {
             return new Vr2dDisplayProperties(mWidth, mHeight, mDpi, mAddedFlags, mRemovedFlags);
         }
diff --git a/core/java/android/app/VrManager.java b/core/java/android/app/VrManager.java
index 5f1a94c..c74f8c3 100644
--- a/core/java/android/app/VrManager.java
+++ b/core/java/android/app/VrManager.java
@@ -2,6 +2,7 @@
 
 import android.annotation.CallbackExecutor;
 import android.annotation.NonNull;
+import android.annotation.Nullable;
 import android.annotation.RequiresPermission;
 import android.annotation.SystemApi;
 import android.annotation.SystemService;
@@ -71,7 +72,7 @@
             android.Manifest.permission.ACCESS_VR_STATE
     })
     public void registerVrStateCallback(@NonNull @CallbackExecutor Executor executor,
-            VrStateCallback callback) {
+            @NonNull VrStateCallback callback) {
         if (callback == null || mCallbackMap.containsKey(callback)) {
             return;
         }
@@ -99,7 +100,7 @@
             android.Manifest.permission.RESTRICTED_VR_ACCESS,
             android.Manifest.permission.ACCESS_VR_STATE
     })
-    public void unregisterVrStateCallback(VrStateCallback callback) {
+    public void unregisterVrStateCallback(@NonNull VrStateCallback callback) {
         CallbackEntry entry = mCallbackMap.remove(callback);
         if (entry != null) {
             try {
@@ -175,7 +176,7 @@
      */
     @RequiresPermission(android.Manifest.permission.RESTRICTED_VR_ACCESS)
     public void setVr2dDisplayProperties(
-            Vr2dDisplayProperties vr2dDisplayProp) {
+            @NonNull Vr2dDisplayProperties vr2dDisplayProp) {
         try {
             mService.setVr2dDisplayProperties(vr2dDisplayProp);
         } catch (RemoteException e) {
@@ -220,7 +221,7 @@
      * @param componentName not used
      */
     @RequiresPermission(android.Manifest.permission.RESTRICTED_VR_ACCESS)
-    public void setVrInputMethod(ComponentName componentName) {
+    public void setVrInputMethod(@Nullable ComponentName componentName) {
     }
 
     /**
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index cc39e56..335ed21 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -1531,6 +1531,9 @@
     /**
      * Activity Action: Show More default apps settings.
      * <p>
+     * If a Settings activity handles this intent action, a "More defaults" entry will be shown in
+     * the Default apps settings, and clicking it will launch that activity.
+     * <p>
      * In some cases, a matching Activity may not exist, so ensure you safeguard against this.
      * <p>
      * Input: Nothing.
diff --git a/core/java/android/service/voice/VoiceInteractionService.java b/core/java/android/service/voice/VoiceInteractionService.java
index e3e63e5..0de17ca 100644
--- a/core/java/android/service/voice/VoiceInteractionService.java
+++ b/core/java/android/service/voice/VoiceInteractionService.java
@@ -17,7 +17,6 @@
 package android.service.voice;
 
 import android.annotation.NonNull;
-import android.annotation.Nullable;
 import android.annotation.SdkConstant;
 import android.annotation.UnsupportedAppUsage;
 import android.app.Service;
@@ -41,6 +40,7 @@
 import java.io.FileDescriptor;
 import java.io.PrintWriter;
 import java.util.ArrayList;
+import java.util.Collections;
 import java.util.List;
 import java.util.Locale;
 import java.util.Set;
@@ -211,11 +211,11 @@
      *
      * @param voiceActions A set of checked voice actions.
      * @return Returns a subset of checked voice actions. Additional voice actions in the
-     * returned set will be ignored. Returns null or empty set if no actions are supported.
+     * returned set will be ignored. Returns empty set if no actions are supported.
      */
-    @Nullable
+    @NonNull
     public Set<String> onGetSupportedVoiceActions(@NonNull Set<String> voiceActions) {
-        return null;
+        return Collections.emptySet();
     }
 
     @Override
@@ -272,7 +272,7 @@
             try {
                 Set<String> voiceActionsSet = new ArraySet<>(voiceActions);
                 Set<String> resultSet = onGetSupportedVoiceActions(voiceActionsSet);
-                callback.onComplete(resultSet == null ? null : new ArrayList<>(resultSet));
+                callback.onComplete(new ArrayList<>(resultSet));
             } catch (RemoteException e) {
             }
         }
diff --git a/core/jni/android_nio_utils.cpp b/core/jni/android_nio_utils.cpp
index 19a1c72..a62dd7c 100644
--- a/core/jni/android_nio_utils.cpp
+++ b/core/jni/android_nio_utils.cpp
@@ -18,42 +18,51 @@
 
 #include "core_jni_helpers.h"
 
-void* android::nio_getPointer(JNIEnv *_env, jobject buffer, jarray *array) {
-    assert(array);
+namespace {
 
+void* getPointer(JNIEnv *_env, jobject buffer, jarray *array, void** elements) {
+    assert(array);
     jint position;
     jint limit;
     jint elementSizeShift;
     jlong pointer = jniGetNioBufferFields(_env, buffer, &position, &limit, &elementSizeShift);
     if (pointer != 0L) {
+        *array = nullptr;
+        *elements = nullptr;
         pointer += position << elementSizeShift;
         return reinterpret_cast<void*>(pointer);
     }
-
     jint offset = jniGetNioBufferBaseArrayOffset(_env, buffer);
     *array = jniGetNioBufferBaseArray(_env, buffer);
-    void * data = _env->GetPrimitiveArrayCritical(*array, (jboolean *) 0);
-    return reinterpret_cast<void*>(reinterpret_cast<char*>(data) + offset);
+    *elements = _env->GetPrimitiveArrayCritical(*array, (jboolean *) 0);
+    return reinterpret_cast<void*>(reinterpret_cast<char*>(*elements) + offset);
 }
 
+void releasePointer(JNIEnv *_env, jarray array, void *elements, jboolean commit) {
+    _env->ReleasePrimitiveArrayCritical(array, elements, commit ? 0 : JNI_ABORT);
+}
 
-void android::nio_releasePointer(JNIEnv *_env, jarray array, void *data,
-                                jboolean commit) {
-    _env->ReleasePrimitiveArrayCritical(array, data,
-                                        commit ? 0 : JNI_ABORT);
+}  // namespace
+
+void* android::nio_getPointer(JNIEnv *_env, jobject buffer, jarray *array) {
+    void* elements;
+    return getPointer(_env, buffer, array, &elements);
+}
+
+void android::nio_releasePointer(JNIEnv *_env, jarray array, void *data, jboolean commit) {
+    releasePointer(_env, array, data, commit);
 }
 
 ///////////////////////////////////////////////////////////////////////////////
 
-android::AutoBufferPointer::AutoBufferPointer(JNIEnv* env, jobject nioBuffer,
-                                              jboolean commit) {
+android::AutoBufferPointer::AutoBufferPointer(JNIEnv* env, jobject nioBuffer, jboolean commit) {
     fEnv = env;
     fCommit = commit;
-    fPointer = android::nio_getPointer(env, nioBuffer, &fArray);
+    fPointer = getPointer(env, nioBuffer, &fArray, &fElements);
 }
 
 android::AutoBufferPointer::~AutoBufferPointer() {
-    if (NULL != fArray) {
-        android::nio_releasePointer(fEnv, fArray, fPointer, fCommit);
+    if (nullptr != fArray) {
+        releasePointer(fEnv, fArray, fElements, fCommit);
     }
 }
diff --git a/core/jni/android_nio_utils.h b/core/jni/android_nio_utils.h
index c634cb91..7c9acd2 100644
--- a/core/jni/android_nio_utils.h
+++ b/core/jni/android_nio_utils.h
@@ -20,7 +20,7 @@
 #include <android_runtime/AndroidRuntime.h>
 
 namespace android {
-    
+
 /**
  * Given an nio.Buffer, return a pointer to it, beginning at its current
  * position. The returned pointer is only valid for the current JNI stack-frame.
@@ -63,9 +63,10 @@
 
 private:
     JNIEnv* fEnv;
-    void*   fPointer;
-    jarray  fArray;
-    jboolean fCommit;
+    void*   fPointer;   // pointer to current buffer position.
+    void*   fElements;  // pointer to array element 0 (may be directly in fArray or a copy).
+    jarray  fArray;     // pointer to array on managed heap.
+    jboolean fCommit;   // commit data to source if required (when fElements is a copy of fArray).
 };
 
 }   /* namespace android */
diff --git a/core/res/res/anim/activity_close_enter.xml b/core/res/res/anim/activity_close_enter.xml
index 371bcfe..9fa7c54 100644
--- a/core/res/res/anim/activity_close_enter.xml
+++ b/core/res/res/anim/activity_close_enter.xml
@@ -19,15 +19,16 @@
 
 <set xmlns:android="http://schemas.android.com/apk/res/android"
     android:shareInterpolator="false">
-    <translate
-        android:fromYDelta="-2%"
-        android:toYDelta="0"
-        android:interpolator="@interpolator/fast_out_slow_in"
-        android:duration="425"/>
-    <alpha
-        android:fromAlpha="0.9"
-        android:toAlpha="1.0"
-        android:interpolator="@interpolator/activity_close_dim"
-        android:startOffset="0"
-        android:duration="425"/>
+    <scale
+        android:fromXScale="1.1"
+        android:toXScale="1"
+        android:fromYScale="1.1"
+        android:toYScale="1"
+        android:pivotX="50%"
+        android:pivotY="50%"
+        android:fillEnabled="true"
+        android:fillBefore="true"
+        android:fillAfter="true"
+        android:interpolator="@interpolator/fast_out_extra_slow_in"
+        android:duration="400"/>
 </set>
\ No newline at end of file
diff --git a/core/res/res/anim/activity_close_exit.xml b/core/res/res/anim/activity_close_exit.xml
index d87f100..1599ae8 100644
--- a/core/res/res/anim/activity_close_exit.xml
+++ b/core/res/res/anim/activity_close_exit.xml
@@ -20,25 +20,25 @@
 <set xmlns:android="http://schemas.android.com/apk/res/android"
     android:shareInterpolator="false"
     android:zAdjustment="top">
-    <translate
-        android:fromYDelta="0"
-        android:toYDelta="4.1%"
-        android:interpolator="@interpolator/fast_out_slow_in"
-        android:duration="425"/>
-    <cliprect
-        android:fromLeft="0%"
-        android:fromTop="0%"
-        android:fromRight="100%"
-        android:fromBottom="100%"
-        android:toLeft="0%"
-        android:toTop="95.9%"
-        android:toRight="100%"
-        android:toBottom="100%"
-        android:interpolator="@interpolator/fast_out_extra_slow_in"
-        android:duration="425"/>
     <alpha
-        android:fromAlpha="1.0"
-        android:toAlpha="1.0"
-        android:interpolator="@interpolator/fast_out_linear_in"
-        android:duration="425"/>
+        android:fromAlpha="1"
+        android:toAlpha="0.0"
+        android:fillEnabled="true"
+        android:fillBefore="true"
+        android:fillAfter="true"
+        android:interpolator="@interpolator/linear"
+        android:startOffset="33"
+        android:duration="50"/>
+    <scale
+        android:fromXScale="1"
+        android:toXScale="0.9"
+        android:fromYScale="1"
+        android:toYScale="0.9"
+        android:pivotX="50%"
+        android:pivotY="50%"
+        android:fillEnabled="true"
+        android:fillBefore="true"
+        android:fillAfter="true"
+        android:interpolator="@interpolator/fast_out_extra_slow_in"
+        android:duration="400"/>
 </set>
diff --git a/core/res/res/anim/activity_open_enter.xml b/core/res/res/anim/activity_open_enter.xml
index cb03070..38d3e8ed 100644
--- a/core/res/res/anim/activity_open_enter.xml
+++ b/core/res/res/anim/activity_open_enter.xml
@@ -18,20 +18,25 @@
 
 <set xmlns:android="http://schemas.android.com/apk/res/android"
     android:shareInterpolator="false">
-    <translate
-        android:fromYDelta="4.1%"
-        android:toYDelta="0"
-        android:interpolator="@interpolator/fast_out_slow_in"
-        android:duration="425"/>
-    <cliprect
-        android:fromLeft="0%"
-        android:fromTop="95.9%"
-        android:fromRight="100%"
-        android:fromBottom="100%"
-        android:toLeft="0%"
-        android:toTop="0%"
-        android:toRight="100%"
-        android:toBottom="100%"
+    <alpha
+        android:fromAlpha="0"
+        android:toAlpha="1.0"
+        android:fillEnabled="true"
+        android:fillBefore="true"
+        android:fillAfter="true"
+        android:interpolator="@interpolator/linear"
+        android:startOffset="50"
+        android:duration="50"/>
+    <scale
+        android:fromXScale="0.85"
+        android:toXScale="1"
+        android:fromYScale="0.85"
+        android:toYScale="1"
+        android:pivotX="50%"
+        android:pivotY="50%"
+        android:fillEnabled="true"
+        android:fillBefore="true"
+        android:fillAfter="true"
         android:interpolator="@interpolator/fast_out_extra_slow_in"
-        android:duration="425"/>
+        android:duration="400"/>
 </set>
diff --git a/core/res/res/anim/activity_open_exit.xml b/core/res/res/anim/activity_open_exit.xml
index d52b150..3865d21 100644
--- a/core/res/res/anim/activity_open_exit.xml
+++ b/core/res/res/anim/activity_open_exit.xml
@@ -18,14 +18,28 @@
 
 <set xmlns:android="http://schemas.android.com/apk/res/android"
     android:shareInterpolator="false">
-    <translate
-        android:fromYDelta="0"
-        android:toYDelta="-2%"
-        android:interpolator="@interpolator/fast_out_slow_in"
-        android:duration="425"/>
+
+    <!-- Fade out, over a black surface, which simulates a black scrim -->
     <alpha
-        android:fromAlpha="1.0"
-        android:toAlpha="0.9"
+        android:fromAlpha="1"
+        android:toAlpha="0.4"
+        android:fillEnabled="true"
+        android:fillBefore="true"
+        android:fillAfter="true"
         android:interpolator="@interpolator/linear"
-        android:duration="117"/>
+        android:startOffset="83"
+        android:duration="167"/>
+
+    <scale
+        android:fromXScale="1"
+        android:toXScale="1.05"
+        android:fromYScale="1"
+        android:toYScale="1.05"
+        android:pivotX="50%"
+        android:pivotY="50%"
+        android:fillEnabled="true"
+        android:fillBefore="true"
+        android:fillAfter="true"
+        android:interpolator="@interpolator/fast_out_extra_slow_in"
+        android:duration="400"/>
 </set>
\ No newline at end of file
diff --git a/core/res/res/layout/chooser_grid_preview_text.xml b/core/res/res/layout/chooser_grid_preview_text.xml
index 3c9ffdb..f3ca0af 100644
--- a/core/res/res/layout/chooser_grid_preview_text.xml
+++ b/core/res/res/layout/chooser_grid_preview_text.xml
@@ -24,9 +24,9 @@
     android:layout_height="wrap_content"
     android:orientation="vertical"
     android:paddingBottom="@dimen/chooser_view_spacing"
-    android:background="?attr/colorBackgroundFloating">
+    android:background="?android:attr/colorBackgroundFloating">
 
-  <LinearLayout
+  <RelativeLayout
       android:layout_width="@dimen/chooser_preview_width"
       android:layout_height="wrap_content"
       android:layout_gravity="center"
@@ -35,28 +35,51 @@
       android:paddingRight="@dimen/chooser_edge_margin_normal"
       android:layout_marginBottom="@dimen/chooser_view_spacing"
       android:id="@+id/content_preview_text_layout">
+
     <TextView
         android:id="@+id/content_preview_text"
-        android:layout_width="0dp"
-        android:layout_weight="1"
+        android:layout_width="wrap_content"
         android:layout_height="wrap_content"
-        android:layout_gravity="center_vertical"
+        android:layout_alignParentStart="true"
+        android:layout_toStartOf="@id/copy_button"
+        android:layout_centerVertical="true"
         android:ellipsize="end"
-        android:gravity="start|top"
-        android:paddingRight="@dimen/chooser_view_spacing"
+        android:textColor="?android:attr/textColorPrimary"
         android:maxLines="2"/>
-    <ImageButton
+
+    <LinearLayout
         android:id="@+id/copy_button"
-        android:layout_width="48dp"
-        android:layout_height="48dp"
-        android:padding="12dp"
+        android:orientation="vertical"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_centerVertical="true"
+        android:layout_alignParentEnd="true"
+        android:layout_marginStart="@dimen/chooser_view_spacing"
         android:gravity="center"
-        android:layout_gravity="center_vertical"
-        android:src="@drawable/ic_content_copy_gm2"
+        android:minWidth="48dp"
+        android:minHeight="48dp"
         android:clickable="true"
-        android:contentDescription="@string/copy"
-        android:background="?attr/selectableItemBackgroundBorderless"/>
-  </LinearLayout>
+        android:background="?android:attr/selectableItemBackgroundBorderless">
+
+      <ImageView
+          android:layout_width="24dp"
+          android:layout_height="24dp"
+          android:gravity="top|center_horizontal"
+          android:src="@drawable/ic_content_copy_gm2" />
+
+      <TextView
+          android:layout_width="wrap_content"
+          android:layout_height="wrap_content"
+          android:layout_marginTop="4dp"
+          android:gravity="center_horizontal"
+          android:text="@string/copy"
+          android:textColor="?android:textColorSecondary"
+          android:textSize="12sp"
+          android:maxWidth="72dp"
+          android:maxLines="2"
+          android:ellipsize="end" />
+    </LinearLayout>
+  </RelativeLayout>
 
   <!-- Required sub-layout so we can get the nice rounded corners-->
   <!-- around this section -->
@@ -89,7 +112,8 @@
         android:layout_gravity="center_vertical"
         android:ellipsize="end"
         android:maxLines="2"
-        android:textSize="20sp"/>
+        android:textSize="20sp"
+        android:textColor="?android:attr/textColorPrimary"/>
   </LinearLayout>
 </LinearLayout>
 
diff --git a/core/tests/coretests/src/android/graphics/BitmapTest.java b/core/tests/coretests/src/android/graphics/BitmapTest.java
index d2a1dd9..4bee243 100644
--- a/core/tests/coretests/src/android/graphics/BitmapTest.java
+++ b/core/tests/coretests/src/android/graphics/BitmapTest.java
@@ -22,6 +22,8 @@
 
 import junit.framework.TestCase;
 
+import java.nio.ByteBuffer;
+
 public class BitmapTest extends TestCase {
 
     @SmallTest
@@ -262,4 +264,74 @@
         assertFalse(hardwareBitmap.isMutable());
         assertEquals(ColorSpace.get(ColorSpace.Named.DISPLAY_P3), hardwareBitmap.getColorSpace());
     }
+
+    @SmallTest
+    public void testCopyWithDirectBuffer() {
+        // Initialize Bitmap
+        final int width = 2;
+        final int height = 2;
+        Bitmap bm1 = Bitmap.createBitmap(width, height, Bitmap.Config.RGB_565);
+        bm1.setPixels(new int[] { 0xff, 0xeeee, 0xdddddd, 0xcccccccc }, 0, 2, 0, 0, 2, 2);
+
+        // Copy bytes to direct buffer, buffer is padded by fixed amount (pad bytes) either side
+        // of bitmap.
+        final int pad = 1;
+        final byte padValue = 0x5a;
+        final int bufferSize = pad + width * height * 2 + pad;
+        ByteBuffer directBuffer = ByteBuffer.allocateDirect(bufferSize);
+
+        // Write padding
+        directBuffer.put(0, padValue);
+        directBuffer.put(directBuffer.limit() - 1, padValue);
+
+        // Copy bitmap
+        directBuffer.position(pad);
+        bm1.copyPixelsToBuffer(directBuffer);
+        assertEquals(directBuffer.position(), pad + width * height * 2);
+
+        // Check padding
+        assertEquals(directBuffer.get(0), padValue);
+        assertEquals(directBuffer.get(directBuffer.limit() - 1), padValue);
+
+        // Create bitmap from direct buffer and check match.
+        directBuffer.position(pad);
+        Bitmap bm2 = Bitmap.createBitmap(width, height, Bitmap.Config.RGB_565);
+        bm2.copyPixelsFromBuffer(directBuffer);
+        assertTrue(bm2.sameAs(bm1));
+    }
+
+    @SmallTest
+    public void testCopyWithHeapBuffer() {
+        // Initialize Bitmap
+        final int width = 2;
+        final int height = 2;
+        Bitmap bm1 = Bitmap.createBitmap(width, height, Bitmap.Config.RGB_565);
+        bm1.setPixels(new int[] { 0xff, 0xeeee, 0xdddddd, 0xcccccccc }, 0, 2, 0, 0, 2, 2);
+
+        // Copy bytes to heap buffer, buffer is padded by fixed amount (pad bytes) either side
+        // of bitmap.
+        final int pad = 1;
+        final byte padValue = 0x5a;
+        final int bufferSize = pad + width * height * 2 + pad;
+        ByteBuffer heapBuffer = ByteBuffer.allocate(bufferSize);
+
+        // Write padding
+        heapBuffer.put(0, padValue);
+        heapBuffer.put(heapBuffer.limit() - 1, padValue);
+
+        // Copy bitmap
+        heapBuffer.position(pad);
+        bm1.copyPixelsToBuffer(heapBuffer);
+        assertEquals(heapBuffer.position(), pad + width * height * 2);
+
+        // Check padding
+        assertEquals(heapBuffer.get(0), padValue);
+        assertEquals(heapBuffer.get(heapBuffer.limit() - 1), padValue);
+
+        // Create bitmap from heap buffer and check match.
+        heapBuffer.position(pad);
+        Bitmap bm2 = Bitmap.createBitmap(width, height, Bitmap.Config.RGB_565);
+        bm2.copyPixelsFromBuffer(heapBuffer);
+        assertTrue(bm2.sameAs(bm1));
+    }
 }
diff --git a/core/tests/coretests/src/android/view/InsetsAnimationControlImplTest.java b/core/tests/coretests/src/android/view/InsetsAnimationControlImplTest.java
index ebbbdec..bdd3038 100644
--- a/core/tests/coretests/src/android/view/InsetsAnimationControlImplTest.java
+++ b/core/tests/coretests/src/android/view/InsetsAnimationControlImplTest.java
@@ -39,11 +39,13 @@
 import android.util.SparseArray;
 import android.view.SurfaceControl.Transaction;
 import android.view.SyncRtSurfaceTransactionApplier.SurfaceParams;
+import android.view.test.InsetsModeSession;
 
-import androidx.test.filters.FlakyTest;
 import androidx.test.runner.AndroidJUnit4;
 
+import org.junit.AfterClass;
 import org.junit.Before;
+import org.junit.BeforeClass;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.mockito.ArgumentCaptor;
@@ -62,7 +64,6 @@
  * {@link com.android.server.wm.test.filters.FrameworksTestsFilter}.
  */
 @Presubmit
-@FlakyTest(detail = "Promote once confirmed non-flaky")
 @RunWith(AndroidJUnit4.class)
 public class InsetsAnimationControlImplTest {
 
@@ -72,15 +73,25 @@
     private SurfaceControl mTopLeash;
     private SurfaceControl mNavLeash;
     private InsetsState mInsetsState;
+    private static InsetsModeSession sInsetsModeSession;
 
     @Mock Transaction mMockTransaction;
     @Mock InsetsController mMockController;
     @Mock WindowInsetsAnimationControlListener mMockListener;
     @Mock SyncRtSurfaceTransactionApplier mMockTransactionApplier;
 
+    @BeforeClass
+    public static void setupOnce() {
+        sInsetsModeSession = new InsetsModeSession(NEW_INSETS_MODE_FULL);
+    }
+
+    @AfterClass
+    public static void tearDownOnce() throws Exception {
+        sInsetsModeSession.close();
+    }
+
     @Before
     public void setup() {
-        ViewRootImpl.sNewInsetsMode = NEW_INSETS_MODE_FULL;
         MockitoAnnotations.initMocks(this);
         mTopLeash = new SurfaceControl.Builder(mSession)
                 .setName("testSurface")
diff --git a/core/tests/coretests/src/android/view/InsetsControllerTest.java b/core/tests/coretests/src/android/view/InsetsControllerTest.java
index 4d8d3f6..1e55828 100644
--- a/core/tests/coretests/src/android/view/InsetsControllerTest.java
+++ b/core/tests/coretests/src/android/view/InsetsControllerTest.java
@@ -43,7 +43,6 @@
 import android.widget.TextView;
 
 import androidx.test.InstrumentationRegistry;
-import androidx.test.filters.FlakyTest;
 import androidx.test.runner.AndroidJUnit4;
 
 import org.junit.Before;
@@ -63,7 +62,6 @@
  * {@link com.android.server.wm.test.filters.FrameworksTestsFilter}.
  */
 @Presubmit
-@FlakyTest(detail = "Promote once confirmed non-flaky")
 @RunWith(AndroidJUnit4.class)
 public class InsetsControllerTest {
 
diff --git a/core/tests/coretests/src/android/view/InsetsSourceConsumerTest.java b/core/tests/coretests/src/android/view/InsetsSourceConsumerTest.java
index a32fa77..971e143 100644
--- a/core/tests/coretests/src/android/view/InsetsSourceConsumerTest.java
+++ b/core/tests/coretests/src/android/view/InsetsSourceConsumerTest.java
@@ -34,7 +34,6 @@
 import android.widget.TextView;
 
 import androidx.test.InstrumentationRegistry;
-import androidx.test.filters.FlakyTest;
 import androidx.test.runner.AndroidJUnit4;
 
 import org.junit.Before;
@@ -53,7 +52,6 @@
  * {@link com.android.server.wm.test.filters.FrameworksTestsFilter}.
  */
 @Presubmit
-@FlakyTest(detail = "Promote once confirmed non-flaky")
 @RunWith(AndroidJUnit4.class)
 public class InsetsSourceConsumerTest {
 
diff --git a/core/tests/coretests/src/android/view/InsetsSourceTest.java b/core/tests/coretests/src/android/view/InsetsSourceTest.java
index b55a9c6..533a58e 100644
--- a/core/tests/coretests/src/android/view/InsetsSourceTest.java
+++ b/core/tests/coretests/src/android/view/InsetsSourceTest.java
@@ -24,7 +24,6 @@
 import android.graphics.Rect;
 import android.platform.test.annotations.Presubmit;
 
-import androidx.test.filters.FlakyTest;
 import androidx.test.runner.AndroidJUnit4;
 
 import org.junit.Before;
@@ -41,7 +40,6 @@
  * {@link com.android.server.wm.test.filters.FrameworksTestsFilter}.
  */
 @Presubmit
-@FlakyTest(detail = "Promote once confirmed non-flaky")
 @RunWith(AndroidJUnit4.class)
 public class InsetsSourceTest {
 
diff --git a/core/tests/coretests/src/android/view/InsetsStateTest.java b/core/tests/coretests/src/android/view/InsetsStateTest.java
index 8e167da..a73269a 100644
--- a/core/tests/coretests/src/android/view/InsetsStateTest.java
+++ b/core/tests/coretests/src/android/view/InsetsStateTest.java
@@ -40,7 +40,6 @@
 import android.view.WindowInsets.Type;
 import android.view.test.InsetsModeSession;
 
-import androidx.test.filters.FlakyTest;
 import androidx.test.runner.AndroidJUnit4;
 
 import org.junit.Test;
@@ -56,7 +55,6 @@
  * {@link com.android.server.wm.test.filters.FrameworksTestsFilter}.
  */
 @Presubmit
-@FlakyTest(detail = "Promote once confirmed non-flaky")
 @RunWith(AndroidJUnit4.class)
 public class InsetsStateTest {
 
diff --git a/packages/ExtServices/src/android/ext/services/notification/Assistant.java b/packages/ExtServices/src/android/ext/services/notification/Assistant.java
index 1544adb..b2baff5 100644
--- a/packages/ExtServices/src/android/ext/services/notification/Assistant.java
+++ b/packages/ExtServices/src/android/ext/services/notification/Assistant.java
@@ -272,6 +272,9 @@
                 final int importance = entry.getImportance() < IMPORTANCE_LOW
                         ? entry.getImportance() : IMPORTANCE_LOW;
                 signals.putInt(KEY_IMPORTANCE, importance);
+            } else {
+                // Even if no change is made, send an identity adjustment for metric logging.
+                signals.putInt(KEY_IMPORTANCE, entry.getImportance());
             }
         }
 
diff --git a/packages/SystemUI/res/layout/qs_tile_label.xml b/packages/SystemUI/res/layout/qs_tile_label.xml
index f34161e..81d44cf 100644
--- a/packages/SystemUI/res/layout/qs_tile_label.xml
+++ b/packages/SystemUI/res/layout/qs_tile_label.xml
@@ -44,8 +44,7 @@
             android:padding="0dp"
             android:gravity="center"
             android:ellipsize="marquee"
-            android:textAppearance="@style/TextAppearance.QS.TileLabel"
-            android:textColor="?android:attr/textColorPrimary"/>
+            android:textAppearance="@style/TextAppearance.QS.TileLabel"/>
 
         <ImageView android:id="@+id/restricted_padlock"
             android:layout_width="@dimen/qs_tile_text_size"
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileView.java b/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileView.java
index 91cd652..8a360ee 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileView.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileView.java
@@ -15,11 +15,10 @@
 package com.android.systemui.qs.tileimpl;
 
 import android.content.Context;
+import android.content.res.ColorStateList;
 import android.content.res.Configuration;
 import android.service.quicksettings.Tile;
-import android.text.SpannableStringBuilder;
 import android.text.TextUtils;
-import android.text.style.ForegroundColorSpan;
 import android.view.Gravity;
 import android.view.LayoutInflater;
 import android.view.View;
@@ -27,6 +26,7 @@
 import android.widget.ImageView;
 import android.widget.TextView;
 
+import com.android.settingslib.Utils;
 import com.android.systemui.FontSizeUtils;
 import com.android.systemui.R;
 import com.android.systemui.plugins.qs.QSIconView;
@@ -46,6 +46,8 @@
     private ViewGroup mLabelContainer;
     private View mExpandIndicator;
     private View mExpandSpace;
+    private ColorStateList mColorLabelDefault;
+    private ColorStateList mColorLabelUnavailable;
 
     public QSTileView(Context context, QSIconView icon) {
         this(context, icon, false);
@@ -62,6 +64,11 @@
         createLabel();
         setOrientation(VERTICAL);
         setGravity(Gravity.CENTER_HORIZONTAL | Gravity.TOP);
+        mColorLabelDefault = Utils.getColorAttr(getContext(), android.R.attr.textColorPrimary);
+        // The text color for unavailable tiles is textColorSecondary, same as secondaryLabel for
+        // contrast purposes
+        mColorLabelUnavailable = Utils.getColorAttr(getContext(),
+                android.R.attr.textColorSecondary);
     }
 
     TextView getLabel() {
@@ -111,12 +118,8 @@
     protected void handleStateChanged(QSTile.State state) {
         super.handleStateChanged(state);
         if (!Objects.equals(mLabel.getText(), state.label) || mState != state.state) {
-            if (state.state == Tile.STATE_UNAVAILABLE) {
-                int color = QSTileImpl.getColorForState(getContext(), state.state);
-                state.label = new SpannableStringBuilder().append(state.label,
-                        new ForegroundColorSpan(color),
-                        SpannableStringBuilder.SPAN_INCLUSIVE_INCLUSIVE);
-            }
+            mLabel.setTextColor(state.state == Tile.STATE_UNAVAILABLE ? mColorLabelUnavailable
+                    : mColorLabelDefault);
             mState = state.state;
             mLabel.setText(state.label);
         }
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index d2b1e8f..c12ee03 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -20032,7 +20032,7 @@
                     PreferredActivity pa = removed.get(j);
                     pir.removeFilter(pa);
                 }
-                outUserChanged.setValueAt(thisUserId, true);
+                outUserChanged.put(thisUserId, true);
             }
         }
     }
diff --git a/services/core/java/com/android/server/wm/DisplayPolicy.java b/services/core/java/com/android/server/wm/DisplayPolicy.java
index 1934e25..bd874ba 100644
--- a/services/core/java/com/android/server/wm/DisplayPolicy.java
+++ b/services/core/java/com/android/server/wm/DisplayPolicy.java
@@ -28,6 +28,7 @@
 import static android.view.InsetsState.TYPE_TOP_BAR;
 import static android.view.InsetsState.TYPE_TOP_GESTURES;
 import static android.view.InsetsState.TYPE_TOP_TAPPABLE_ELEMENT;
+import static android.view.View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION;
 import static android.view.ViewGroup.LayoutParams.MATCH_PARENT;
 import static android.view.ViewRootImpl.NEW_INSETS_MODE_NONE;
 import static android.view.WindowManager.INPUT_CONSUMER_NAVIGATION;
@@ -1230,7 +1231,7 @@
         final boolean screenDecor = (pfl & PRIVATE_FLAG_IS_SCREEN_DECOR) != 0;
 
         if (layoutInScreenAndInsetDecor && !screenDecor) {
-            if ((sysUiVis & View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION) != 0) {
+            if ((sysUiVis & SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION) != 0) {
                 outFrame.set(displayFrames.mUnrestricted);
             } else {
                 outFrame.set(displayFrames.mRestricted);
@@ -1290,7 +1291,7 @@
                 && attrs.height == MATCH_PARENT && attrs.width == MATCH_PARENT;
         if ((attrs.flags & FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS) != 0
                 || forceWindowDrawsBarBackgrounds) {
-            impliedFlags |= View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION;
+            impliedFlags |= SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION;
             impliedFlags |= View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN;
         }
         return impliedFlags;
@@ -1722,6 +1723,22 @@
             of.set(displayFrames.mDock);
             df.set(displayFrames.mDock);
         } else {
+
+            // In case we forced the window to draw behind the navigation bar, restrict df/of to
+            // DF.RestrictedOverscan to simulate old compat behavior.
+            Rect parentDisplayFrame = attached.getDisplayFrameLw();
+            Rect parentOverscan = attached.getOverscanFrameLw();
+            final WindowManager.LayoutParams attachedAttrs = attached.mAttrs;
+            if ((attachedAttrs.privateFlags & PRIVATE_FLAG_FORCE_DRAW_BAR_BACKGROUNDS) != 0
+                    && (attachedAttrs.flags & FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS) == 0
+                    && (attachedAttrs.systemUiVisibility
+                            & SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION) == 0) {
+                parentOverscan = new Rect(parentOverscan);
+                parentOverscan.intersect(displayFrames.mRestrictedOverscan);
+                parentDisplayFrame = new Rect(parentDisplayFrame);
+                parentDisplayFrame.intersect(displayFrames.mRestrictedOverscan);
+            }
+
             // The effective display frame of the attached window depends on whether it is taking
             // care of insetting its content. If not, we need to use the parent's content frame so
             // that the entire window is positioned within that content. Otherwise we can use the
@@ -1733,7 +1750,7 @@
                 // setting {@link WindowManager.LayoutParams#FLAG_LAYOUT_ATTACHED_IN_DECOR} flag.
                 // Otherwise, use the overscan frame.
                 cf.set((fl & FLAG_LAYOUT_ATTACHED_IN_DECOR) != 0
-                        ? attached.getContentFrameLw() : attached.getOverscanFrameLw());
+                        ? attached.getContentFrameLw() : parentOverscan);
             } else {
                 // If the window is resizing, then we want to base the content frame on our attached
                 // content frame to resize...however, things can be tricky if the attached window is
@@ -1747,8 +1764,8 @@
                     cf.intersectUnchecked(displayFrames.mContent);
                 }
             }
-            df.set(insetDecors ? attached.getDisplayFrameLw() : cf);
-            of.set(insetDecors ? attached.getOverscanFrameLw() : cf);
+            df.set(insetDecors ? parentDisplayFrame : cf);
+            of.set(insetDecors ? parentOverscan : cf);
             vf.set(attached.getVisibleFrameLw());
         }
         // The LAYOUT_IN_SCREEN flag is used to determine whether the attached window should be
@@ -1956,7 +1973,7 @@
                         of.set(displayFrames.mOverscan);
                         df.set(displayFrames.mOverscan);
                         pf.set(displayFrames.mOverscan);
-                    } else if ((sysUiFl & View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION) != 0
+                    } else if ((sysUiFl & SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION) != 0
                             && (type >= FIRST_APPLICATION_WINDOW && type <= LAST_SUB_WINDOW
                             || type == TYPE_VOLUME_OVERLAY)) {
                         // Asking for layout as if the nav bar is hidden, lets the application
@@ -2006,7 +2023,7 @@
                 }
             } else if (layoutInScreen || (sysUiFl
                     & (View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
-                    | View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION)) != 0) {
+                    | SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION)) != 0) {
                 if (DEBUG_LAYOUT) Slog.v(TAG, "layoutWindowLw(" + attrs.getTitle()
                         + "): IN_SCREEN");
                 // A window that has requested to fill the entire screen just
@@ -2051,7 +2068,7 @@
                     of.set(displayFrames.mOverscan);
                     df.set(displayFrames.mOverscan);
                     pf.set(displayFrames.mOverscan);
-                } else if ((sysUiFl & View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION) != 0
+                } else if ((sysUiFl & SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION) != 0
                         && (type == TYPE_STATUS_BAR
                         || type == TYPE_TOAST
                         || type == TYPE_DOCK_DIVIDER
diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java
index d990e6c..8e18683 100644
--- a/services/core/java/com/android/server/wm/WindowState.java
+++ b/services/core/java/com/android/server/wm/WindowState.java
@@ -1305,7 +1305,7 @@
     void onDisplayChanged(DisplayContent dc) {
         super.onDisplayChanged(dc);
         // Window was not laid out for this display yet, so make sure mLayoutSeq does not match.
-        if (dc != null) {
+        if (dc != null && mInputWindowHandle.displayId != dc.getDisplayId()) {
             mLayoutSeq = dc.mLayoutSeq - 1;
             mInputWindowHandle.displayId = dc.getDisplayId();
         }
diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowStateTests.java b/services/tests/wmtests/src/com/android/server/wm/WindowStateTests.java
index 4f8fe5b..715353e 100644
--- a/services/tests/wmtests/src/com/android/server/wm/WindowStateTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/WindowStateTests.java
@@ -397,7 +397,9 @@
         app.mLayoutSeq = 1;
         mDisplayContent.mLayoutSeq = 1;
 
-        app.onDisplayChanged(mDisplayContent);
+        DisplayContent newDisplay = createNewDisplay();
+
+        app.onDisplayChanged(newDisplay);
 
         assertThat(app.mLayoutSeq, not(is(mDisplayContent.mLayoutSeq)));
     }
diff --git a/telecomm/java/android/telecom/PhoneAccountHandle.java b/telecomm/java/android/telecom/PhoneAccountHandle.java
index 71a28b5..eb568e0 100644
--- a/telecomm/java/android/telecom/PhoneAccountHandle.java
+++ b/telecomm/java/android/telecom/PhoneAccountHandle.java
@@ -17,6 +17,7 @@
 package android.telecom;
 
 import android.annotation.NonNull;
+import android.annotation.Nullable;
 import android.annotation.UnsupportedAppUsage;
 import android.content.ComponentName;
 import android.os.Build;
@@ -174,4 +175,21 @@
                 in.readString(),
                 UserHandle.CREATOR.createFromParcel(in));
     }
+
+    /**
+     * Determines if two {@link PhoneAccountHandle}s are from the same package.
+     *
+     * @param a Phone account handle to check for same {@link ConnectionService} package.
+     * @param b Other phone account handle to check for same {@link ConnectionService} package.
+     * @return {@code true} if the two {@link PhoneAccountHandle}s passed in belong to the same
+     * {@link ConnectionService} / package, {@code false} otherwise.  Note: {@code null} phone
+     * account handles are considered equivalent to other {@code null} phone account handles.
+     * @hide
+     */
+    public static boolean areFromSamePackage(@Nullable PhoneAccountHandle a,
+            @Nullable PhoneAccountHandle b) {
+        String aPackageName = a != null ? a.getComponentName().getPackageName() : null;
+        String bPackageName = b != null ? b.getComponentName().getPackageName() : null;
+        return Objects.equals(aPackageName, bPackageName);
+    }
 }