Merge "Using the keyguard fading away duration for the scrim" into qt-r1-dev
diff --git a/cmds/statsd/src/atoms.proto b/cmds/statsd/src/atoms.proto
index f08be49..e7cce06 100644
--- a/cmds/statsd/src/atoms.proto
+++ b/cmds/statsd/src/atoms.proto
@@ -319,6 +319,8 @@
             217 [(log_from_module) = "permissioncontroller"];
         PermissionAppsFragmentViewed permission_apps_fragment_viewed =
             218  [(log_from_module) = "permissioncontroller"];
+        ExclusionRectStateChanged exclusion_rect_state_changed = 223;
+        BackGesture back_gesture_reported_reported = 224;
     }
 
     // Pulled events will start at field 10000.
@@ -2500,6 +2502,41 @@
     optional State state = 1;
 }
 
+message BackGesture {
+    enum BackType {
+          DEFAULT_BACK_TYPE = 0;
+          COMPLETED = 1;
+          COMPLETED_REJECTED = 2; // successful because coming from rejected area
+          INCOMPLETE_EXCLUDED = 3; // would have been successful but in the exclusion area
+          INCOMPLETE = 4;
+    }
+    optional BackType type = 1;
+
+    optional int32 y_coordinate = 2; // y coordinate for ACTION_DOWN event
+    enum WindowHorizontalLocation {
+        DEFAULT_LOCATION = 0;
+        LEFT = 1;
+        RIGHT = 2;
+    }
+    optional WindowHorizontalLocation x_location = 3;
+}
+
+message ExclusionRectStateChanged {
+    optional string component_name = 1;    // if not available, simply packageName
+    optional int32 requested_height = 2;   // px
+    optional int32 rejected_height = 3;    // px
+
+    enum WindowHorizontalLocation {
+        DEFAULT_LOCATION = 0;
+        LEFT = 1;
+        RIGHT = 2;
+    }
+    optional WindowHorizontalLocation x_location = 4;
+    optional bool landscape = 5;
+    optional bool splitscreen = 6;
+    optional int32 duration_millis = 7;
+}
+
 message LauncherUIChanged {
     optional android.stats.launcher.LauncherAction action = 1;
     optional android.stats.launcher.LauncherState src_state = 2;
diff --git a/core/java/android/app/Activity.java b/core/java/android/app/Activity.java
index dc52c52..f5b0b59 100644
--- a/core/java/android/app/Activity.java
+++ b/core/java/android/app/Activity.java
@@ -1547,7 +1547,9 @@
      * had previously been frozen by {@link #onSaveInstanceState}.
      *
      * <p>This method is called between {@link #onStart} and
-     * {@link #onPostCreate}.
+     * {@link #onPostCreate}. This method is called only when recreating
+     * an activity; the method isn't invoked if {@link #onStart} is called for
+     * any other reason.</p>
      *
      * @param savedInstanceState the data most recently supplied in {@link #onSaveInstanceState}.
      *
diff --git a/core/java/android/app/ActivityManagerInternal.java b/core/java/android/app/ActivityManagerInternal.java
index 8508c2c..1725db0 100644
--- a/core/java/android/app/ActivityManagerInternal.java
+++ b/core/java/android/app/ActivityManagerInternal.java
@@ -120,17 +120,6 @@
     public abstract void setHasOverlayUi(int pid, boolean hasOverlayUi);
 
     /**
-     * Sets if the given pid is currently running a remote animation, which is taken a signal for
-     * determining oom adjustment and scheduling behavior.
-     *
-     * @param pid The pid we are setting overlay UI for.
-     * @param runningRemoteAnimation True if the process is running a remote animation, false
-     *                               otherwise.
-     * @see RemoteAnimationAdapter
-     */
-    public abstract void setRunningRemoteAnimation(int pid, boolean runningRemoteAnimation);
-
-    /**
      * Called after the network policy rules are updated by
      * {@link com.android.server.net.NetworkPolicyManagerService} for a specific {@param uid} and
      * {@param procStateSeq}.
diff --git a/core/java/android/provider/ContactsContract.java b/core/java/android/provider/ContactsContract.java
index 81e1eb9..af3a16c 100644
--- a/core/java/android/provider/ContactsContract.java
+++ b/core/java/android/provider/ContactsContract.java
@@ -870,8 +870,8 @@
     protected interface ContactOptionsColumns {
         /**
          * The number of times a contact has been contacted.
-         * <p class="caution"><b>Caution: </b>As of January 7, 2019, this field is obsolete. For
-         * more information, see the
+         * <p class="caution"><b>Caution: </b>If you publish your app to the Google Play Store,
+         * this field is obsolete, regardless of Android version. For more information, see the
          * <a href="/guide/topics/providers/contacts-provider#ObsoleteData">Contacts Provider</a>
          * page.</p>
          * <P>Type: INTEGER</P>
@@ -885,8 +885,8 @@
 
         /**
          * The last time a contact was contacted.
-         * <p class="caution"><b>Caution: </b>As of January 7, 2019, this field is obsolete. For
-         * more information, see the
+         * <p class="caution"><b>Caution: </b>If you publish your app to the Google Play Store,
+         * this field is obsolete, regardless of Android version. For more information, see the
          * <a href="/guide/topics/providers/contacts-provider#ObsoleteData">Contacts Provider</a>
          * page.</p>
          * <P>Type: INTEGER</P>
@@ -1691,10 +1691,10 @@
          * TIMES_CONTACTED field is incremented by 1 and the LAST_TIME_CONTACTED
          * field is populated with the current system time.
          *
-         * <p class="caution"><b>Caution: </b>As of January 7, 2019, this method is obsolete. For
-         * more information, see the
+         * <p class="caution"><b>Caution: </b>If you publish your app to the Google Play Store,
+         * this field is obsolete, regardless of Android version. For more information, see the
          * <a href="/guide/topics/providers/contacts-provider#ObsoleteData">Contacts Provider</a>
-         * page.
+         * page.</p>
          *
          * @param resolver the ContentResolver to use
          * @param contactId the person who was contacted
@@ -1730,8 +1730,8 @@
          * Frequent contacts are no longer included in the result as of
          * Android version {@link android.os.Build.VERSION_CODES#Q}.
          *
-         * <p class="caution"><b>Caution: </b>As of January 7, 2019, this field no longer sorts
-         * results based on contacts frequency. For more information, see the
+         * <p class="caution"><b>Caution: </b>If you publish your app to the Google Play Store, this
+         * field doesn't sort results based on contacts frequency. For more information, see the
          * <a href="/guide/topics/providers/contacts-provider#ObsoleteData">Contacts Provider</a>
          * page.
          */
@@ -1745,8 +1745,8 @@
          * Android version {@link android.os.Build.VERSION_CODES#Q}.
          * This URI always returns an empty cursor.
          *
-         * <p class="caution"><b>Caution: </b>As of January 7, 2019, this field no longer sorts
-         * results based on contacts frequency. For more information, see the
+         * <p class="caution"><b>Caution: </b>If you publish your app to the Google Play Store, this
+         * field doesn't sort results based on contacts frequency. For more information, see the
          * <a href="/guide/topics/providers/contacts-provider#ObsoleteData">Contacts Provider</a>
          * page.
          */
@@ -1760,8 +1760,8 @@
          * various parts of the contact name. The filter argument should be passed
          * as an additional path segment after this URI.
          *
-         * <p class="caution"><b>Caution: </b>As of January 7, 2019, this field no longer sorts
-         * results based on contacts frequency. For more information, see the
+         * <p class="caution"><b>Caution: </b>If you publish your app to the Google Play Store, this
+         * field doesn't sort results based on contacts frequency. For more information, see the
          * <a href="/guide/topics/providers/contacts-provider#ObsoleteData">Contacts Provider</a>
          * page.
          */
@@ -4292,10 +4292,10 @@
          * Android version {@link android.os.Build.VERSION_CODES#Q}.
          * This column always contains 0.
          *
-         * <p class="caution"><b>Caution: </b>As of January 7, 2019, this field is obsolete.
-         * For more information, see the
+         * <p class="caution"><b>Caution: </b>If you publish your app to the Google Play Store,
+         * this field is obsolete, regardless of Android version. For more information, see the
          * <a href="/guide/topics/providers/contacts-provider#ObsoleteData">Contacts Provider</a>
-         * page.
+         * page.</p>
          */
         @Deprecated
         public static final String LAST_TIME_USED = "last_time_used";
@@ -4306,10 +4306,10 @@
          * Android version {@link android.os.Build.VERSION_CODES#Q}.
          * This column always contains 0.
          *
-         * <p class="caution"><b>Caution: </b>As of January 7, 2019, this field is obsolete.
-         * For more information, see the
+         * <p class="caution"><b>Caution: </b>If you publish your app to the Google Play Store,
+         * this field is obsolete, regardless of Android version. For more information, see the
          * <a href="/guide/topics/providers/contacts-provider#ObsoleteData">Contacts Provider</a>
-         * page.
+         * page.</p>
          */
         @Deprecated
         public static final String TIMES_USED = "times_used";
@@ -5259,8 +5259,8 @@
         /**
          * The content:// style URI for this table.
          *
-         * <p class="caution"><b>Caution: </b>As of January 7, 2019, this field no longer
-         * sorts results based on contacts frequency. For more information, see the
+         * <p class="caution"><b>Caution: </b>If you publish your app to the Google Play Store, this
+         * field doesn't sort results based on contacts frequency. For more information, see the
          * <a href="/guide/topics/providers/contacts-provider#ObsoleteData">Contacts Provider</a>
          * page.
          *
@@ -5277,8 +5277,8 @@
         /**
          * <p>URI used for the "enterprise caller-id".</p>
          *
-         * <p class="caution"><b>Caution: </b>As of January 7, 2019, this field no longer
-         * sorts results based on contacts frequency. For more information, see the
+         * <p class="caution"><b>Caution: </b>If you publish your app to the Google Play Store, this
+         * field doesn't sort results based on contacts frequency. For more information, see the
          * <a href="/guide/topics/providers/contacts-provider#ObsoleteData">Contacts Provider</a>
          * page.
          *
@@ -6079,8 +6079,8 @@
              * to display names as well as phone numbers. The filter argument should be passed
              * as an additional path segment after this URI.
              *
-             * <p class="caution"><b>Caution: </b>As of January 7, 2019, this field no longer
-             * sorts results based on contacts frequency. For more information, see the
+             * <p class="caution"><b>Caution: </b>This field deosn't sort results based on contacts
+             * frequency. For more information, see the
              * <a href="/guide/topics/providers/contacts-provider#ObsoleteData">Contacts Provider</a>
              * page.
              */
@@ -6092,8 +6092,9 @@
              * same columns. This URI requires {@link ContactsContract#DIRECTORY_PARAM_KEY} in
              * parameters, otherwise it will throw IllegalArgumentException.
              *
-             * <p class="caution"><b>Caution: </b>As of January 7, 2019, this field no longer sorts
-             * results based on contacts frequency. For more information, see the
+             * <p class="caution"><b>Caution: </b>If you publish your app to the Google Play Store,
+             * this field doesn't sort results based on contacts frequency. For more information,
+             * see the
              * <a href="/guide/topics/providers/contacts-provider#ObsoleteData">Contacts Provider</a>
              * page.
              */
@@ -6360,8 +6361,9 @@
              * as an additional path segment after this URI.
              * </p>
              *
-             * <p class="caution"><b>Caution: </b>As of January 7, 2019, this field no longer sorts
-             * results based on contacts frequency. For more information, see the
+             * <p class="caution"><b>Caution: </b>If you publish your app to the Google Play Store,
+             * this field doesn't sort results based on contacts frequency. For more information,
+             * see the
              * <a href="/guide/topics/providers/contacts-provider#ObsoleteData">Contacts Provider</a>
              * page.</p>
              *
@@ -6383,8 +6385,9 @@
              * same columns. This URI requires {@link ContactsContract#DIRECTORY_PARAM_KEY} in
              * parameters, otherwise it will throw IllegalArgumentException.
              *
-             * <p class="caution"><b>Caution: </b>As of January 7, 2019, this field no longer
-             * sorts results based on contacts frequency. For more information, see the
+             * <p class="caution"><b>Caution: </b>If you publish your app to the Google Play Store,
+             * this field doesn't sort results based on contacts frequency. For more information,
+             * see the
              * <a href="/guide/topics/providers/contacts-provider#ObsoleteData">Contacts Provider</a>
              * page.
              */
@@ -7602,8 +7605,8 @@
              * <p>Similar to {@link Phone#CONTENT_FILTER_URI}, but allows users to filter callable
              * data.
              *
-             * <p class="caution"><b>Caution: </b>As of January 7, 2019, this field no longer
-             * sorts results based on contacts frequency. For more information, see the
+             * <p class="caution"><b>Caution: </b>This field no longer sorts results based on
+             * contacts frequency. For more information, see the
              * <a href="/guide/topics/providers/contacts-provider#ObsoleteData">Contacts Provider</a>
              * page.
              */
@@ -7615,8 +7618,9 @@
              * callable data. This URI requires {@link ContactsContract#DIRECTORY_PARAM_KEY} in
              * parameters, otherwise it will throw IllegalArgumentException.
              *
-             * <p class="caution"><b>Caution: </b>As of January 7, 2019, this field no longer
-             * sorts results based on contacts frequency. For more information, see the
+             * <p class="caution"><b>Caution: </b>If you publish your app to the Google Play Store,
+             * this field doesn't sort results based on contacts frequency. For more information,
+             * see the
              * <a href="/guide/topics/providers/contacts-provider#ObsoleteData">Contacts Provider</a>
              * page.</p>
              */
@@ -7646,8 +7650,9 @@
              * <p>The content:// style URI for these data items, which allows for a query parameter
              * to be appended onto the end to filter for data items matching the query.
              *
-             * <p class="caution"><b>Caution: </b>As of January 7, 2019, this field no longer
-             * sorts results based on contacts frequency. For more information, see the
+             * <p class="caution"><b>Caution: </b>If you publish your app to the Google Play Store,
+             * this field doesn't sort results based on contacts frequency. For more information,
+             * see the
              * <a href="/guide/topics/providers/contacts-provider#ObsoleteData">Contacts Provider</a>
              * page.
              */
@@ -8298,15 +8303,14 @@
     }
 
     /**
-     * <p class="caution"><b>Caution: </b>As of January 7, 2019, this class is obsolete. For
-     * more information, see the
-     * <a href="/guide/topics/providers/contacts-provider#ObsoleteData">Contacts Provider</a>
-     * page.
-     * </p>
      * <p>
      * API allowing applications to send usage information for each {@link Data} row to the
      * Contacts Provider.  Applications can also clear all usage information.
      * </p>
+     * <p class="caution"><b>Caution: </b>If you publish your app to the Google Play Store,
+     * this field is obsolete, regardless of Android version. For more information, see the
+     * <a href="/guide/topics/providers/contacts-provider#ObsoleteData">Contacts Provider</a>
+     * page.</p>
      * <p>
      * With the feedback, Contacts Provider may return more contextually appropriate results for
      * Data listing, typically supplied with
diff --git a/core/java/android/provider/DeviceConfig.java b/core/java/android/provider/DeviceConfig.java
index 1fd212d..ea50ae8 100644
--- a/core/java/android/provider/DeviceConfig.java
+++ b/core/java/android/provider/DeviceConfig.java
@@ -338,6 +338,20 @@
                 "system_gestures_excluded_by_pre_q_sticky_immersive";
 
         /**
+         * The minimum duration between gesture exclusion logging for a given window in
+         * milliseconds.
+         *
+         * Events that happen in-between will be silently dropped.
+         *
+         * A non-positive value disables logging.
+         *
+         * @see android.provider.DeviceConfig#NAMESPACE_WINDOW_MANAGER
+         * @hide
+         */
+        String KEY_SYSTEM_GESTURE_EXCLUSION_LOG_DEBOUNCE_MILLIS =
+                "system_gesture_exclusion_log_debounce_millis";
+
+        /**
          * Key for controlling which packages are explicitly blocked from running at refresh rates
          * higher than 60hz.
          *
diff --git a/core/java/android/view/ISystemGestureExclusionListener.aidl b/core/java/android/view/ISystemGestureExclusionListener.aidl
index a032625..9c2f9a6 100644
--- a/core/java/android/view/ISystemGestureExclusionListener.aidl
+++ b/core/java/android/view/ISystemGestureExclusionListener.aidl
@@ -28,7 +28,14 @@
      * Called when the system gesture exclusion for the given display changed.
      * @param displayId the display whose system gesture exclusion changed
      * @param systemGestureExclusion a {@code Region} where the app would like priority over the
-     *                               system gestures, in display coordinates.
+     *                               system gestures, in display coordinates. Certain restrictions
+     *                               might be applied such that apps don't get all the exclusions
+     *                               they request.
+     * @param systemGestureExclusionUnrestricted a {@code Region} where the app would like priority
+     *                               over the system gestures, in display coordinates, without
+     *                               any restrictions applied. Null if no restrictions have been
+     *                               applied.
      */
-    void onSystemGestureExclusionChanged(int displayId, in Region systemGestureExclusion);
+    void onSystemGestureExclusionChanged(int displayId, in Region systemGestureExclusion,
+            in Region systemGestureExclusionUnrestricted);
 }
\ No newline at end of file
diff --git a/core/java/android/view/RemoteAnimationAdapter.java b/core/java/android/view/RemoteAnimationAdapter.java
index bc2fe54..c686440 100644
--- a/core/java/android/view/RemoteAnimationAdapter.java
+++ b/core/java/android/view/RemoteAnimationAdapter.java
@@ -55,6 +55,7 @@
 
     /** @see #getCallingPid */
     private int mCallingPid;
+    private int mCallingUid;
 
     /**
      * @param runner The interface that gets notified when we actually need to start the animation.
@@ -103,10 +104,11 @@
     }
 
     /**
-     * To be called by system_server to keep track which pid is running this animation.
+     * To be called by system_server to keep track which pid and uid is running this animation.
      */
-    public void setCallingPid(int pid) {
+    public void setCallingPidUid(int pid, int uid) {
         mCallingPid = pid;
+        mCallingUid = uid;
     }
 
     /**
@@ -116,6 +118,13 @@
         return mCallingPid;
     }
 
+    /**
+     * @return The uid of the process running the animation.
+     */
+    public int getCallingUid() {
+        return mCallingUid;
+    }
+
     @Override
     public int describeContents() {
         return 0;
diff --git a/core/java/android/view/RemoteAnimationDefinition.java b/core/java/android/view/RemoteAnimationDefinition.java
index 884cae4..da599ef 100644
--- a/core/java/android/view/RemoteAnimationDefinition.java
+++ b/core/java/android/view/RemoteAnimationDefinition.java
@@ -118,9 +118,9 @@
      * To be called by system_server to keep track which pid is running the remote animations inside
      * this definition.
      */
-    public void setCallingPid(int pid) {
+    public void setCallingPidUid(int pid, int uid) {
         for (int i = mTransitionAnimationMap.size() - 1; i >= 0; i--) {
-            mTransitionAnimationMap.valueAt(i).adapter.setCallingPid(pid);
+            mTransitionAnimationMap.valueAt(i).adapter.setCallingPidUid(pid, uid);
         }
     }
 
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index b2449d5..4e86e60 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -11085,6 +11085,13 @@
      *
      * <p>Do not modify the provided list after this method is called.</p>
      *
+     * <p>Note: the system will put a limit of <code>200dp</code> on the vertical extent of the
+     * exclusions it takes into account. The limit does not apply while the navigation
+     * bar is {@link #SYSTEM_UI_FLAG_IMMERSIVE_STICKY stickily} hidden, nor to the
+     * {@link android.inputmethodservice.InputMethodService input method} and
+     * {@link Intent#CATEGORY_HOME home activity}.
+     * </p>
+     *
      * @param rects A list of precision gesture regions that this view needs to function correctly
      */
     public void setSystemGestureExclusionRects(@NonNull List<Rect> rects) {
diff --git a/core/java/android/view/WindowInsets.java b/core/java/android/view/WindowInsets.java
index 9340b71..bcc6a55 100644
--- a/core/java/android/view/WindowInsets.java
+++ b/core/java/android/view/WindowInsets.java
@@ -35,6 +35,7 @@
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.annotation.UnsupportedAppUsage;
+import android.content.Intent;
 import android.graphics.Insets;
 import android.graphics.Rect;
 import android.util.SparseArray;
@@ -644,6 +645,14 @@
      * {@link View#setSystemGestureExclusionRects} outside of the
      * {@link #getMandatorySystemGestureInsets() mandatory system gesture insets}.
      *
+     * <p>Note: the system will put a limit of <code>200dp</code> on the vertical extent of the
+     * exclusions it takes into account. The limit does not apply while the navigation
+     * bar is {@link View#SYSTEM_UI_FLAG_IMMERSIVE_STICKY stickily} hidden, nor to the
+     * {@link android.inputmethodservice.InputMethodService input method} and
+     * {@link Intent#CATEGORY_HOME home activity}.
+     * </p>
+     *
+     *
      * <p>Simple taps are guaranteed to reach the window even within the system gesture insets,
      * as long as they are outside the {@link #getTappableElementInsets() system window insets}.
      *
diff --git a/core/java/android/widget/AbsSeekBar.java b/core/java/android/widget/AbsSeekBar.java
index 50bb688..1db9123 100644
--- a/core/java/android/widget/AbsSeekBar.java
+++ b/core/java/android/widget/AbsSeekBar.java
@@ -91,6 +91,7 @@
     @UnsupportedAppUsage
     private float mDisabledAlpha;
 
+    private int mThumbExclusionMaxSize;
     private int mScaledTouchSlop;
     private float mTouchDownX;
     @UnsupportedAppUsage
@@ -170,6 +171,8 @@
         applyTickMarkTint();
 
         mScaledTouchSlop = ViewConfiguration.get(context).getScaledTouchSlop();
+        mThumbExclusionMaxSize = getResources().getDimensionPixelSize(
+                com.android.internal.R.dimen.seekbar_thumb_exclusion_max_size);
     }
 
     /**
@@ -762,12 +765,30 @@
         }
         mGestureExclusionRects.clear();
         thumb.copyBounds(mThumbRect);
+        mThumbRect.offset(mPaddingLeft - mThumbOffset, mPaddingTop);
+        growRectTo(mThumbRect, Math.min(getHeight(), mThumbExclusionMaxSize));
         mGestureExclusionRects.add(mThumbRect);
         mGestureExclusionRects.addAll(mUserGestureExclusionRects);
         super.setSystemGestureExclusionRects(mGestureExclusionRects);
     }
 
     /**
+     * Grows {@code r} from its center such that each dimension is at least {@code minimumSize}.
+     */
+    private void growRectTo(Rect r, int minimumSize) {
+        int dy = (minimumSize - r.height()) / 2;
+        if (dy > 0) {
+            r.top -= dy;
+            r.bottom += dy;
+        }
+        int dx = (minimumSize - r.width()) / 2;
+        if (dx > 0) {
+            r.left -= dx;
+            r.right += dx;
+        }
+    }
+
+    /**
      * @hide
      */
     @Override
diff --git a/core/java/com/android/internal/widget/MediaNotificationView.java b/core/java/com/android/internal/widget/MediaNotificationView.java
index e7d240a..9bb4501 100644
--- a/core/java/com/android/internal/widget/MediaNotificationView.java
+++ b/core/java/com/android/internal/widget/MediaNotificationView.java
@@ -26,6 +26,8 @@
 import android.widget.ImageView;
 import android.widget.RemoteViews;
 
+import java.util.ArrayList;
+
 /**
  * A TextView that can float around an image on the end.
  *
@@ -42,6 +44,7 @@
     private View mMainColumn;
     private View mMediaContent;
     private int mImagePushIn;
+    private ArrayList<VisibilityChangeListener> mListeners;
 
     public MediaNotificationView(Context context) {
         this(context, null);
@@ -168,4 +171,50 @@
         mMainColumn = findViewById(com.android.internal.R.id.notification_main_column);
         mMediaContent = findViewById(com.android.internal.R.id.notification_media_content);
     }
+
+    @Override
+    public void onVisibilityAggregated(boolean isVisible) {
+        super.onVisibilityAggregated(isVisible);
+        if (mListeners != null) {
+            for (int i = 0; i < mListeners.size(); i++) {
+                mListeners.get(i).onAggregatedVisibilityChanged(isVisible);
+            }
+        }
+    }
+
+    /**
+     * Add a listener to receive updates on the visibility of this view
+     *
+     * @param listener The listener to add.
+     */
+    public void addVisibilityListener(VisibilityChangeListener listener) {
+        if (mListeners == null) {
+            mListeners = new ArrayList<>();
+        }
+        if (!mListeners.contains(listener)) {
+            mListeners.add(listener);
+        }
+    }
+
+    /**
+     * Remove the specified listener
+     *
+     * @param listener The listener to remove.
+     */
+    public void removeVisibilityListener(VisibilityChangeListener listener) {
+        if (mListeners != null) {
+            mListeners.remove(listener);
+        }
+    }
+
+    /**
+     * Interface for receiving updates when the view's visibility changes
+     */
+    public interface VisibilityChangeListener {
+        /**
+         * Method called when the visibility of this view has changed
+         * @param isVisible true if the view is now visible
+         */
+        void onAggregatedVisibilityChanged(boolean isVisible);
+    }
 }
diff --git a/core/java/com/android/internal/widget/PointerLocationView.java b/core/java/com/android/internal/widget/PointerLocationView.java
index 9084f62..d48034b 100644
--- a/core/java/com/android/internal/widget/PointerLocationView.java
+++ b/core/java/com/android/internal/widget/PointerLocationView.java
@@ -53,6 +53,12 @@
     // to plot alongside the default one.  Useful for testing and comparison purposes.
     private static final String ALT_STRATEGY_PROPERY_KEY = "debug.velocitytracker.alt";
 
+    /**
+     * If set to a positive value between 1-255, shows an overlay with the approved (red) and
+     * rejected (blue) exclusions.
+     */
+    private static final String GESTURE_EXCLUSION_PROP = "debug.pointerlocation.showexclusion";
+
     public static class PointerState {
         // Trace of previous points.
         private float[] mTraceX = new float[32];
@@ -138,8 +144,10 @@
     private final PointerCoords mTempCoords = new PointerCoords();
 
     private final Region mSystemGestureExclusion = new Region();
+    private final Region mSystemGestureExclusionRejected = new Region();
     private final Path mSystemGestureExclusionPath = new Path();
     private final Paint mSystemGestureExclusionPaint;
+    private final Paint mSystemGestureExclusionRejectedPaint;
 
     private final VelocityTracker mVelocity;
     private final VelocityTracker mAltVelocity;
@@ -190,6 +198,10 @@
         mSystemGestureExclusionPaint.setARGB(25, 255, 0, 0);
         mSystemGestureExclusionPaint.setStyle(Paint.Style.FILL_AND_STROKE);
 
+        mSystemGestureExclusionRejectedPaint = new Paint();
+        mSystemGestureExclusionRejectedPaint.setARGB(25, 0, 0, 255);
+        mSystemGestureExclusionRejectedPaint.setStyle(Paint.Style.FILL_AND_STROKE);
+
         PointerState ps = new PointerState();
         mPointers.add(ps);
         mActivePointerId = 0;
@@ -263,6 +275,12 @@
             canvas.drawPath(mSystemGestureExclusionPath, mSystemGestureExclusionPaint);
         }
 
+        if (!mSystemGestureExclusionRejected.isEmpty()) {
+            mSystemGestureExclusionPath.reset();
+            mSystemGestureExclusionRejected.getBoundaryPath(mSystemGestureExclusionPath);
+            canvas.drawPath(mSystemGestureExclusionPath, mSystemGestureExclusionRejectedPaint);
+        }
+
         // Labels
         if (mActivePointerId >= 0) {
             final PointerState ps = mPointers.get(mActivePointerId);
@@ -754,6 +772,9 @@
             } catch (RemoteException e) {
                 throw e.rethrowFromSystemServer();
             }
+            final int alpha = systemGestureExclusionOpacity();
+            mSystemGestureExclusionPaint.setAlpha(alpha);
+            mSystemGestureExclusionRejectedPaint.setAlpha(alpha);
         } else {
             mSystemGestureExclusion.setEmpty();
         }
@@ -805,7 +826,12 @@
     }
 
     private static boolean shouldShowSystemGestureExclusion() {
-        return SystemProperties.getBoolean("debug.pointerlocation.showexclusion", false);
+        return systemGestureExclusionOpacity() > 0;
+    }
+
+    private static int systemGestureExclusionOpacity() {
+        int x = SystemProperties.getInt(GESTURE_EXCLUSION_PROP, 0);
+        return x >= 0 && x <= 255 ? x : 0;
     }
 
     // HACK
@@ -928,12 +954,19 @@
     private ISystemGestureExclusionListener mSystemGestureExclusionListener =
             new ISystemGestureExclusionListener.Stub() {
         @Override
-        public void onSystemGestureExclusionChanged(int displayId, Region systemGestureExclusion) {
+        public void onSystemGestureExclusionChanged(int displayId, Region systemGestureExclusion,
+                Region systemGestureExclusionUnrestricted) {
             Region exclusion = Region.obtain(systemGestureExclusion);
+            Region rejected = Region.obtain();
+            if (systemGestureExclusionUnrestricted != null) {
+                rejected.set(systemGestureExclusionUnrestricted);
+                rejected.op(exclusion, Region.Op.DIFFERENCE);
+            }
             Handler handler = getHandler();
             if (handler != null) {
                 handler.post(() -> {
                     mSystemGestureExclusion.set(exclusion);
+                    mSystemGestureExclusionRejected.set(rejected);
                     exclusion.recycle();
                     invalidate();
                 });
diff --git a/core/res/res/values-as/strings.xml b/core/res/res/values-as/strings.xml
index e50f32a..c53af2b 100644
--- a/core/res/res/values-as/strings.xml
+++ b/core/res/res/values-as/strings.xml
@@ -95,8 +95,7 @@
     <string name="notification_channel_voice_mail" msgid="3954099424160511919">"ভইচমেইলৰ বাৰ্তাসমূহ"</string>
     <string name="notification_channel_wfc" msgid="2130802501654254801">"ৱাই-ফাই কলিং"</string>
     <string name="notification_channel_sim" msgid="4052095493875188564">"ছিমৰ স্থিতি"</string>
-    <!-- no translation found for notification_channel_sim_high_prio (1787666807724243207) -->
-    <skip />
+    <string name="notification_channel_sim_high_prio" msgid="1787666807724243207">"উচ্চ অগ্ৰাধিকাৰযুক্ত ছিমৰ স্থিতি"</string>
     <string name="peerTtyModeFull" msgid="6165351790010341421">"নেটৱৰ্ক পীয়েৰে TTY ম\'ড FULLলৈ সলনি কৰিবলৈ অনুৰোধ কৰিছে"</string>
     <string name="peerTtyModeHco" msgid="5728602160669216784">"নেটৱৰ্ক পীয়েৰে TTY ম\'ড HCOলৈ সলনি কৰিবলৈ অনুৰোধ কৰিছে"</string>
     <string name="peerTtyModeVco" msgid="1742404978686538049">"নেটৱৰ্ক পীয়েৰে TTY ম\'ড VCO লৈ সলনি কৰিবলৈ অনুৰোধ কৰিছে"</string>
diff --git a/core/res/res/values-bn/strings.xml b/core/res/res/values-bn/strings.xml
index b7f4d67..3d834d5 100644
--- a/core/res/res/values-bn/strings.xml
+++ b/core/res/res/values-bn/strings.xml
@@ -95,8 +95,7 @@
     <string name="notification_channel_voice_mail" msgid="3954099424160511919">"ভয়েসমেল মেসেজ"</string>
     <string name="notification_channel_wfc" msgid="2130802501654254801">"ওয়াই-ফাই কলিং"</string>
     <string name="notification_channel_sim" msgid="4052095493875188564">"সিম কার্ডের স্টাটাস"</string>
-    <!-- no translation found for notification_channel_sim_high_prio (1787666807724243207) -->
-    <skip />
+    <string name="notification_channel_sim_high_prio" msgid="1787666807724243207">"উচ্চ প্রায়রিটি সিম স্ট্যাটাস"</string>
     <string name="peerTtyModeFull" msgid="6165351790010341421">"পির TTY মোড FULL অনুরোধ করেছে"</string>
     <string name="peerTtyModeHco" msgid="5728602160669216784">"পির TTY মোড HCO অনুরোধ করেছে"</string>
     <string name="peerTtyModeVco" msgid="1742404978686538049">"পির TTY মোড VCO অনুরোধ করেছে"</string>
diff --git a/core/res/res/values-ca/strings.xml b/core/res/res/values-ca/strings.xml
index 46d17d3..f4b341c 100644
--- a/core/res/res/values-ca/strings.xml
+++ b/core/res/res/values-ca/strings.xml
@@ -573,9 +573,9 @@
     <string name="face_acquired_recalibrate" msgid="8077949502893707539">"Torna a registrar la teva cara."</string>
     <string name="face_acquired_too_different" msgid="7663983770123789694">"Ja no es reconeix la teva cara. Torna-ho a provar."</string>
     <string name="face_acquired_too_similar" msgid="1508776858407646460">"És massa semblant; canvia de postura."</string>
-    <string name="face_acquired_pan_too_extreme" msgid="4581629343077288178">"Inclina el cap una mica menys."</string>
-    <string name="face_acquired_tilt_too_extreme" msgid="4019954263012496468">"Inclina el cap una mica menys."</string>
-    <string name="face_acquired_roll_too_extreme" msgid="6312973147689664409">"No inclinis tant el cap."</string>
+    <string name="face_acquired_pan_too_extreme" msgid="4581629343077288178">"No giris tant el cap."</string>
+    <string name="face_acquired_tilt_too_extreme" msgid="4019954263012496468">"No inclinis tant el cap."</string>
+    <string name="face_acquired_roll_too_extreme" msgid="6312973147689664409">"No giris tant el cap."</string>
     <string name="face_acquired_obscured" msgid="5357207702967893283">"Suprimeix qualsevol cosa que amagui la teva cara."</string>
     <string name="face_acquired_sensor_dirty" msgid="7905138627046865579">"Neteja la part superior de la pantalla, inclosa la barra negra"</string>
   <string-array name="face_acquired_vendor">
@@ -1483,7 +1483,7 @@
     <string name="back_button_label" msgid="2300470004503343439">"Enrere"</string>
     <string name="next_button_label" msgid="1080555104677992408">"Següent"</string>
     <string name="skip_button_label" msgid="1275362299471631819">"Omet"</string>
-    <string name="no_matches" msgid="8129421908915840737">"Cap coincidència"</string>
+    <string name="no_matches" msgid="8129421908915840737">"No s\'ha trobat cap coincidència"</string>
     <string name="find_on_page" msgid="1946799233822820384">"Troba-ho a la pàgina"</string>
     <plurals name="matches_found" formatted="false" msgid="1210884353962081884">
       <item quantity="other"><xliff:g id="INDEX">%d</xliff:g> de <xliff:g id="TOTAL">%d</xliff:g></item>
diff --git a/core/res/res/values-ja/strings.xml b/core/res/res/values-ja/strings.xml
index 7b1d8a5..effa902 100644
--- a/core/res/res/values-ja/strings.xml
+++ b/core/res/res/values-ja/strings.xml
@@ -299,8 +299,8 @@
     <string name="permgroupdesc_microphone" msgid="4988812113943554584">"音声の録音"</string>
     <string name="permgrouprequest_microphone" msgid="9167492350681916038">"音声の録音を「&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt;」に許可しますか?"</string>
     <string name="permgrouplab_activityRecognition" msgid="1565108047054378642">"身体活動"</string>
-    <string name="permgroupdesc_activityRecognition" msgid="6949472038320473478">"運動データにアクセス"</string>
-    <string name="permgrouprequest_activityRecognition" msgid="7626438016904799383">"運動データへのアクセスを「&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt;」に許可しますか?"</string>
+    <string name="permgroupdesc_activityRecognition" msgid="6949472038320473478">"身体活動にアクセス"</string>
+    <string name="permgrouprequest_activityRecognition" msgid="7626438016904799383">"身体活動へのアクセスを「&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt;」に許可しますか?"</string>
     <string name="permgrouplab_camera" msgid="4820372495894586615">"カメラ"</string>
     <string name="permgroupdesc_camera" msgid="3250611594678347720">"写真と動画の撮影"</string>
     <string name="permgrouprequest_camera" msgid="1299833592069671756">"写真と動画の撮影を「&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt;」に許可しますか?"</string>
@@ -429,8 +429,8 @@
     <string name="permdesc_recordAudio" msgid="4245930455135321433">"このアプリは、いつでもマイクを使用して録音できます。"</string>
     <string name="permlab_sim_communication" msgid="2935852302216852065">"SIMへのコマンド送信"</string>
     <string name="permdesc_sim_communication" msgid="5725159654279639498">"SIMにコマンドを送信することをアプリに許可します。この許可は非常に危険です。"</string>
-    <string name="permlab_activityRecognition" msgid="3634590230567608356">"運動の認識"</string>
-    <string name="permdesc_activityRecognition" msgid="3143453925156552894">"このアプリで運動が認識されるようにします。"</string>
+    <string name="permlab_activityRecognition" msgid="3634590230567608356">"身体活動の認識"</string>
+    <string name="permdesc_activityRecognition" msgid="3143453925156552894">"このアプリで身体活動が認識されるようにします。"</string>
     <string name="permlab_camera" msgid="3616391919559751192">"写真と動画の撮影"</string>
     <string name="permdesc_camera" msgid="5392231870049240670">"このアプリは、いつでもカメラを使用して写真や動画を撮影できます。"</string>
     <string name="permlab_vibrate" msgid="7696427026057705834">"バイブレーションの制御"</string>
diff --git a/core/res/res/values-kn/strings.xml b/core/res/res/values-kn/strings.xml
index 0a7f6a0..8e5ea6a 100644
--- a/core/res/res/values-kn/strings.xml
+++ b/core/res/res/values-kn/strings.xml
@@ -95,8 +95,7 @@
     <string name="notification_channel_voice_mail" msgid="3954099424160511919">"ಧ್ವನಿಮೇಲ್ ಸಂದೇಶಗಳು"</string>
     <string name="notification_channel_wfc" msgid="2130802501654254801">"ವೈ-ಫೈ ಕರೆ ಮಾಡುವಿಕೆ"</string>
     <string name="notification_channel_sim" msgid="4052095493875188564">"ಸಿಮ್‌ ಸ್ಥಿತಿ"</string>
-    <!-- no translation found for notification_channel_sim_high_prio (1787666807724243207) -->
-    <skip />
+    <string name="notification_channel_sim_high_prio" msgid="1787666807724243207">"ಹೆಚ್ಚಿನ ಆದ್ಯತೆಯ ಸಿಮ್ ಸ್ಥಿತಿ"</string>
     <string name="peerTtyModeFull" msgid="6165351790010341421">"ಪೀರ್ ವಿನಂತಿಸಿಕೊಂಡ TTY ಮೋಡ್ ಪೂರ್ಣಗೊಂಡಿದೆ"</string>
     <string name="peerTtyModeHco" msgid="5728602160669216784">"ಪೀರ್ ವಿನಂತಿಸಿಕೊಂಡ TTY ಮೋಡ್ HCO"</string>
     <string name="peerTtyModeVco" msgid="1742404978686538049">"ಪೀರ್ ವಿನಂತಿಸಿಕೊಂಡ TTY ಮೋಡ್ VCO"</string>
diff --git a/core/res/res/values-ml/strings.xml b/core/res/res/values-ml/strings.xml
index 0026ddb..9ad8b13 100644
--- a/core/res/res/values-ml/strings.xml
+++ b/core/res/res/values-ml/strings.xml
@@ -95,8 +95,7 @@
     <string name="notification_channel_voice_mail" msgid="3954099424160511919">"വോയ്‌സ്‌മെയിൽ സന്ദേശങ്ങൾ"</string>
     <string name="notification_channel_wfc" msgid="2130802501654254801">"വൈഫൈ കോളിംഗ്"</string>
     <string name="notification_channel_sim" msgid="4052095493875188564">"സിം നില"</string>
-    <!-- no translation found for notification_channel_sim_high_prio (1787666807724243207) -->
-    <skip />
+    <string name="notification_channel_sim_high_prio" msgid="1787666807724243207">"ഉയർന്ന മുൻഗണനയുള്ള സിം നില"</string>
     <string name="peerTtyModeFull" msgid="6165351790010341421">"പിയർ അഭ്യർത്ഥിച്ച TTY മോഡ് \'ഫുൾ\'"</string>
     <string name="peerTtyModeHco" msgid="5728602160669216784">"പിയർ അഭ്യർത്ഥിച്ച TTY മോഡ് HCO"</string>
     <string name="peerTtyModeVco" msgid="1742404978686538049">"പിയർ അഭ്യർത്ഥിച്ച TTY മോഡ് VCO"</string>
diff --git a/core/res/res/values-mr/strings.xml b/core/res/res/values-mr/strings.xml
index 084b950..faafeb7 100644
--- a/core/res/res/values-mr/strings.xml
+++ b/core/res/res/values-mr/strings.xml
@@ -95,8 +95,7 @@
     <string name="notification_channel_voice_mail" msgid="3954099424160511919">"व्हॉइसमेल मेसेज"</string>
     <string name="notification_channel_wfc" msgid="2130802501654254801">"वाय-फाय कॉलिंग"</string>
     <string name="notification_channel_sim" msgid="4052095493875188564">"सिम स्थिती"</string>
-    <!-- no translation found for notification_channel_sim_high_prio (1787666807724243207) -->
-    <skip />
+    <string name="notification_channel_sim_high_prio" msgid="1787666807724243207">"उच्च प्राधान्य सिम स्थिती"</string>
     <string name="peerTtyModeFull" msgid="6165351790010341421">"समवयस्क व्यक्तीने TTY मोड पूर्ण ची विनंती केली"</string>
     <string name="peerTtyModeHco" msgid="5728602160669216784">"समवयस्क व्यक्तीने TTY मोड HCO ची विनंती केली"</string>
     <string name="peerTtyModeVco" msgid="1742404978686538049">"समवयस्क व्यक्तीने TTY मोड VCO ची विनंती केली"</string>
diff --git a/core/res/res/values-my/strings.xml b/core/res/res/values-my/strings.xml
index ec80088..ad5aaca 100644
--- a/core/res/res/values-my/strings.xml
+++ b/core/res/res/values-my/strings.xml
@@ -95,7 +95,7 @@
     <string name="notification_channel_voice_mail" msgid="3954099424160511919">"အသံမေးလ် မက်ဆေ့ဂျ်များ"</string>
     <string name="notification_channel_wfc" msgid="2130802501654254801">"Wi-Fi ခေါ်ဆိုမှု"</string>
     <string name="notification_channel_sim" msgid="4052095493875188564">"ဆင်းမ်ကဒ် အခြေအနေ"</string>
-    <string name="notification_channel_sim_high_prio" msgid="1787666807724243207">"အရေးကြီး ဆင်းမ်ကတ်အခြေအနေ"</string>
+    <string name="notification_channel_sim_high_prio" msgid="1787666807724243207">"အထူးဦးစားပေး ဆင်းမ်ကတ်အခြေအနေ"</string>
     <string name="peerTtyModeFull" msgid="6165351790010341421">"အခြားစက်မှ TTY မုဒ် FULL ပြုရန် တောင်းဆို၏"</string>
     <string name="peerTtyModeHco" msgid="5728602160669216784">"အခြားစက်မှ TTY မုဒ် HCO ပြုရန် တောင်းဆို၏"</string>
     <string name="peerTtyModeVco" msgid="1742404978686538049">"TTY မုဒ် VCO ပြုရန် အခြားစက်မှ တောင်းဆို၏"</string>
diff --git a/core/res/res/values-ne/strings.xml b/core/res/res/values-ne/strings.xml
index e554145..4739232 100644
--- a/core/res/res/values-ne/strings.xml
+++ b/core/res/res/values-ne/strings.xml
@@ -95,8 +95,7 @@
     <string name="notification_channel_voice_mail" msgid="3954099424160511919">"भ्वाइस मेल सन्देशहरू"</string>
     <string name="notification_channel_wfc" msgid="2130802501654254801">"Wi-Fi कल"</string>
     <string name="notification_channel_sim" msgid="4052095493875188564">"SIM को स्थिति"</string>
-    <!-- no translation found for notification_channel_sim_high_prio (1787666807724243207) -->
-    <skip />
+    <string name="notification_channel_sim_high_prio" msgid="1787666807724243207">"उच्च प्राथमिकता रहेको SIM को स्थिति"</string>
     <string name="peerTtyModeFull" msgid="6165351790010341421">"सहकर्मी अनुरोध गरियो। TTY मोड पूर्ण"</string>
     <string name="peerTtyModeHco" msgid="5728602160669216784">"सहकर्मी अनुरोध गरियो। TTY मोड HCO"</string>
     <string name="peerTtyModeVco" msgid="1742404978686538049">"सहकर्मी अनुरोध गरियो। TTY मोड VCO"</string>
diff --git a/core/res/res/values-or/strings.xml b/core/res/res/values-or/strings.xml
index e2d3176..ce40db3 100644
--- a/core/res/res/values-or/strings.xml
+++ b/core/res/res/values-or/strings.xml
@@ -95,8 +95,7 @@
     <string name="notification_channel_voice_mail" msgid="3954099424160511919">"ଭଏସମେଲ୍‍ ମେସେଜ୍‍"</string>
     <string name="notification_channel_wfc" msgid="2130802501654254801">"ୱାଇ-ଫାଇ କଲିଙ୍ଗ"</string>
     <string name="notification_channel_sim" msgid="4052095493875188564">"SIM ଷ୍ଟାଟସ୍"</string>
-    <!-- no translation found for notification_channel_sim_high_prio (1787666807724243207) -->
-    <skip />
+    <string name="notification_channel_sim_high_prio" msgid="1787666807724243207">"ଉଚ୍ଚ ପ୍ରାଥମିକତା SIM ସ୍ଥିତି"</string>
     <string name="peerTtyModeFull" msgid="6165351790010341421">"ପୀଆର୍‌ ଅନୁରୋଧ କରିଥିବା TTY ମୋଡ୍‍ FULL ଅଟେ"</string>
     <string name="peerTtyModeHco" msgid="5728602160669216784">"ପୀଅର୍‌ ଅନୁରୋଧ କରିଥିବା TTY ମୋଡ୍‍ HCO ଅଟେ"</string>
     <string name="peerTtyModeVco" msgid="1742404978686538049">"ପୀଅର୍‌ ଅନୁରୋଧ କରିଥିବା TTY ମୋଡ୍‍ VCO ଅଟେ"</string>
diff --git a/core/res/res/values-pa/strings.xml b/core/res/res/values-pa/strings.xml
index 370db7d7..591ba0a 100644
--- a/core/res/res/values-pa/strings.xml
+++ b/core/res/res/values-pa/strings.xml
@@ -95,8 +95,7 @@
     <string name="notification_channel_voice_mail" msgid="3954099424160511919">"ਵੌਇਸਮੇਲ ਸੁਨੇਹੇ"</string>
     <string name="notification_channel_wfc" msgid="2130802501654254801">"ਵਾਈ-ਫਾਈ ਕਾਲਿੰਗ"</string>
     <string name="notification_channel_sim" msgid="4052095493875188564">"ਸਿਮ ਅਵਸਥਾ"</string>
-    <!-- no translation found for notification_channel_sim_high_prio (1787666807724243207) -->
-    <skip />
+    <string name="notification_channel_sim_high_prio" msgid="1787666807724243207">"ਉੱਚ ਤਰਜੀਹੀ ਸਿਮ ਸਥਿਤੀ"</string>
     <string name="peerTtyModeFull" msgid="6165351790010341421">"ਪੀਅਰ ਨੇ TTY Mode FULL ਦੀ ਬੇਨਤੀ ਕੀਤੀ"</string>
     <string name="peerTtyModeHco" msgid="5728602160669216784">"ਪੀਅਰ ਨੇ TTY Mode HCO ਦੀ ਬੇਨਤੀ ਕੀਤੀ"</string>
     <string name="peerTtyModeVco" msgid="1742404978686538049">"ਪੀਅਰ ਨੇ TTY Mode VCO ਦੀ ਬੇਨਤੀ ਕੀਤੀ"</string>
diff --git a/core/res/res/values-ro/strings.xml b/core/res/res/values-ro/strings.xml
index 50dae75..245864c 100644
--- a/core/res/res/values-ro/strings.xml
+++ b/core/res/res/values-ro/strings.xml
@@ -96,7 +96,7 @@
     <string name="notification_channel_voice_mail" msgid="3954099424160511919">"Mesaje din mesageria vocală"</string>
     <string name="notification_channel_wfc" msgid="2130802501654254801">"Apelare prin Wi-Fi"</string>
     <string name="notification_channel_sim" msgid="4052095493875188564">"Starea cardului SIM"</string>
-    <string name="notification_channel_sim_high_prio" msgid="1787666807724243207">"Stare SIM cu prioritate ridicată"</string>
+    <string name="notification_channel_sim_high_prio" msgid="1787666807724243207">"Notificări de la SIM cu prioritate ridicată"</string>
     <string name="peerTtyModeFull" msgid="6165351790010341421">"Cealaltă persoană a solicitat modul TTY cu setarea COMPLET"</string>
     <string name="peerTtyModeHco" msgid="5728602160669216784">"Cealaltă persoană a solicitat modul TTY cu setarea HCO"</string>
     <string name="peerTtyModeVco" msgid="1742404978686538049">"Cealaltă persoană a solicitat modul TTY cu setarea VCO"</string>
diff --git a/core/res/res/values-sw/strings.xml b/core/res/res/values-sw/strings.xml
index 8adc187..cded9f1 100644
--- a/core/res/res/values-sw/strings.xml
+++ b/core/res/res/values-sw/strings.xml
@@ -364,7 +364,7 @@
     <string name="permlab_enableCarMode" msgid="5684504058192921098">"Wezesha mtindo wa gari"</string>
     <string name="permdesc_enableCarMode" msgid="4853187425751419467">"Inaruhusu programu kuwawezesha mtindo wa gari."</string>
     <string name="permlab_killBackgroundProcesses" msgid="3914026687420177202">"funga programu zingine"</string>
-    <string name="permdesc_killBackgroundProcesses" msgid="4593353235959733119">"Inaruhusu programu kukamilisha michakato ya usuli ya programu nyingine. Hii inaweza kusababisha programu nyingine kukoma kufanyakazi."</string>
+    <string name="permdesc_killBackgroundProcesses" msgid="4593353235959733119">"Huruhusu programu kukamilisha michakato ya chinichini ya programu nyingine. Hii inaweza kusababisha programu nyingine kuacha kufanya kazi."</string>
     <string name="permlab_systemAlertWindow" msgid="7238805243128138690">"Programu hii inaweza kuonekana juu ya programu zingine"</string>
     <string name="permdesc_systemAlertWindow" msgid="2393776099672266188">"Programu hii inaweza kuonekana juu ya programu zingine au sehemu zingine za skrini. Hii huenda ikaathiri matumizi ya kawaida ya programu na kubadilisha jinsi ambavyo programu zingine zinavyoonekana."</string>
     <string name="permlab_runInBackground" msgid="7365290743781858803">"tumia chini chini"</string>
diff --git a/core/res/res/values-te/strings.xml b/core/res/res/values-te/strings.xml
index 574e3cd..776d39e 100644
--- a/core/res/res/values-te/strings.xml
+++ b/core/res/res/values-te/strings.xml
@@ -95,8 +95,7 @@
     <string name="notification_channel_voice_mail" msgid="3954099424160511919">"వాయిస్ మెయిల్ సందేశాలు"</string>
     <string name="notification_channel_wfc" msgid="2130802501654254801">"Wi-Fi కాలింగ్"</string>
     <string name="notification_channel_sim" msgid="4052095493875188564">"SIM స్థితి"</string>
-    <!-- no translation found for notification_channel_sim_high_prio (1787666807724243207) -->
-    <skip />
+    <string name="notification_channel_sim_high_prio" msgid="1787666807724243207">"అధిక ప్రాధాన్యత గల SIM స్థితి"</string>
     <string name="peerTtyModeFull" msgid="6165351790010341421">"అవతలి వారు FULL TTY మోడ్‌ని అభ్యర్థించారు"</string>
     <string name="peerTtyModeHco" msgid="5728602160669216784">"అవతలి వారు HCO TTY మోడ్‌ని అభ్యర్థించారు"</string>
     <string name="peerTtyModeVco" msgid="1742404978686538049">"అవతలి వారు VCO TTY మోడ్‌ని అభ్యర్థించారు"</string>
diff --git a/core/res/res/values-uk/strings.xml b/core/res/res/values-uk/strings.xml
index 37ff895..13c8929 100644
--- a/core/res/res/values-uk/strings.xml
+++ b/core/res/res/values-uk/strings.xml
@@ -97,7 +97,7 @@
     <string name="notification_channel_voice_mail" msgid="3954099424160511919">"Повідомлення голосової пошти"</string>
     <string name="notification_channel_wfc" msgid="2130802501654254801">"Дзвінки через Wi-Fi"</string>
     <string name="notification_channel_sim" msgid="4052095493875188564">"Статус SIM-карти"</string>
-    <string name="notification_channel_sim_high_prio" msgid="1787666807724243207">"Статус високопріоритетних сповіщень для SIM-карти"</string>
+    <string name="notification_channel_sim_high_prio" msgid="1787666807724243207">"Високопріоритетні сповіщення із SIM-карти"</string>
     <string name="peerTtyModeFull" msgid="6165351790010341421">"Пристрій змінив режим TTY на FULL"</string>
     <string name="peerTtyModeHco" msgid="5728602160669216784">"Пристрій змінив режим TTY на HCO"</string>
     <string name="peerTtyModeVco" msgid="1742404978686538049">"Пристрій змінив режим TTY на VCO"</string>
diff --git a/core/res/res/values-ur/strings.xml b/core/res/res/values-ur/strings.xml
index 70072d5..dba7f8f 100644
--- a/core/res/res/values-ur/strings.xml
+++ b/core/res/res/values-ur/strings.xml
@@ -95,8 +95,7 @@
     <string name="notification_channel_voice_mail" msgid="3954099424160511919">"صوتی میل پیغامات"</string>
     <string name="notification_channel_wfc" msgid="2130802501654254801">"‏Wi-Fi کالنگ"</string>
     <string name="notification_channel_sim" msgid="4052095493875188564">"‏SIM کا اسٹیٹس"</string>
-    <!-- no translation found for notification_channel_sim_high_prio (1787666807724243207) -->
-    <skip />
+    <string name="notification_channel_sim_high_prio" msgid="1787666807724243207">"‏اعلی ترجیحی SIM کی صورتحال"</string>
     <string name="peerTtyModeFull" msgid="6165351790010341421">"‏ہمسر نے TTY وضع مکمل کی درخواست کی"</string>
     <string name="peerTtyModeHco" msgid="5728602160669216784">"‏ہمسر نے TTY وضع HCO کی درخواست کی"</string>
     <string name="peerTtyModeVco" msgid="1742404978686538049">"‏ہمسر نے TTY وضع VCO کی درخواست کی"</string>
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index 4eee1db..df87981 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -4241,6 +4241,10 @@
          one bar higher than they actually are -->
     <bool name="config_inflateSignalStrength">false</bool>
 
+    <!-- Contains a blacklist of apps that should not get pre-installed carrier app permission
+         grants, even if the UICC claims that the app should be privileged. See b/138150105 -->
+    <string-array name="config_restrictedPreinstalledCarrierApps" translatable="false"/>
+
     <!-- Sharesheet: define a max number of targets per application for new shortcuts-based direct share introduced in Q -->
     <integer name="config_maxShortcutTargetsPerApp">3</integer>
 
diff --git a/core/res/res/values/dimens.xml b/core/res/res/values/dimens.xml
index 6653879..609659b 100644
--- a/core/res/res/values/dimens.xml
+++ b/core/res/res/values/dimens.xml
@@ -748,6 +748,8 @@
     <!-- Line spacing modifier for the message field of the harmful app dialog -->
     <item name="harmful_app_message_line_spacing_modifier" type="dimen">1.22</item>
 
+    <dimen name="seekbar_thumb_exclusion_max_size">48dp</dimen>
+
     <!-- chooser (sharesheet) spacing -->
     <dimen name="chooser_corner_radius">8dp</dimen>
     <dimen name="chooser_row_text_option_translate">25dp</dimen>
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index d275a37..92c5d2c 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -3817,6 +3817,7 @@
   <java-symbol type="color" name="chooser_gradient_highlight" />
   <java-symbol type="drawable" name="chooser_direct_share_label_placeholder" />
   <java-symbol type="dimen" name="chooser_direct_share_label_placeholder_max_width" />
+  <java-symbol type="dimen" name="seekbar_thumb_exclusion_max_size" />
   <java-symbol type="layout" name="chooser_az_label_row" />
   <java-symbol type="string" name="chooser_all_apps_button_label" />
   <java-symbol type="anim" name="resolver_launch_anim" />
@@ -3826,6 +3827,7 @@
 
   <java-symbol type="string" name="config_defaultSupervisionProfileOwnerComponent" />
   <java-symbol type="bool" name="config_inflateSignalStrength" />
+  <java-symbol type="array" name="config_restrictedPreinstalledCarrierApps" />
 
   <java-symbol type="array" name="config_highRefreshRateBlacklist" />
 
diff --git a/core/tests/coretests/src/android/widget/AbsSeekBarTest.java b/core/tests/coretests/src/android/widget/AbsSeekBarTest.java
new file mode 100644
index 0000000..aec6096
--- /dev/null
+++ b/core/tests/coretests/src/android/widget/AbsSeekBarTest.java
@@ -0,0 +1,136 @@
+/*
+ * 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.widget;
+
+import static android.view.View.MeasureSpec.EXACTLY;
+import static android.view.View.MeasureSpec.makeMeasureSpec;
+
+import static org.hamcrest.Matchers.hasItem;
+import static org.hamcrest.Matchers.hasSize;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertThat;
+
+import android.content.Context;
+import android.graphics.Point;
+import android.graphics.Rect;
+import android.graphics.drawable.ShapeDrawable;
+import android.graphics.drawable.shapes.RectShape;
+import android.platform.test.annotations.Presubmit;
+import android.view.View;
+
+import androidx.test.filters.SmallTest;
+import androidx.test.platform.app.InstrumentationRegistry;
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.util.Arrays;
+import java.util.List;
+
+@RunWith(AndroidJUnit4.class)
+@SmallTest
+@Presubmit
+public class AbsSeekBarTest {
+
+    private Context mContext;
+    private AbsSeekBar mBar;
+
+    @Before
+    public void setUp() throws Exception {
+        mContext = InstrumentationRegistry.getInstrumentation().getContext();
+        mBar = new SeekBar(mContext);
+    }
+
+    @Test
+    public void testExclusionForThumb_limitedTo48dp() {
+        mBar.setPadding(10, 10, 10, 10);
+        mBar.setThumb(newThumb(dpToPx(20)));
+        mBar.setMin(0);
+        mBar.setMax(100);
+        mBar.setProgress(50);
+        measureAndLayout(dpToPx(200), dpToPx(100));
+        List<Rect> exclusions = mBar.getSystemGestureExclusionRects();
+
+        assertEquals("exclusions should be size 1, but was " + exclusions, 1, exclusions.size());
+        assertEquals("exclusion should be centered on thumb",
+                center(mBar), center(exclusions.get(0)));
+        assertEquals("exclusion should be 48dp high", dpToPx(48), exclusions.get(0).height());
+        assertEquals("exclusion should be 48dp wide", dpToPx(48), exclusions.get(0).width());
+    }
+
+    @Test
+    public void testExclusionForThumb_limitedToHeight() {
+        mBar.setPadding(10, 10, 10, 10);
+        mBar.setThumb(newThumb(dpToPx(20)));
+        mBar.setMin(0);
+        mBar.setMax(100);
+        mBar.setProgress(50);
+        measureAndLayout(dpToPx(200), dpToPx(32));
+        List<Rect> exclusions = mBar.getSystemGestureExclusionRects();
+
+        assertEquals("exclusions should be size 1, but was " + exclusions, 1, exclusions.size());
+        assertEquals("exclusion should be centered on thumb",
+                center(mBar), center(exclusions.get(0)));
+        assertEquals("exclusion should be 32dp high", dpToPx(32), exclusions.get(0).height());
+        assertEquals("exclusion should be 32dp wide", dpToPx(32), exclusions.get(0).width());
+    }
+
+    @Test
+    public void testExclusionForThumb_passesThroughUserExclusions() {
+        mBar.setSystemGestureExclusionRects(Arrays.asList(new Rect(1, 2, 3, 4)));
+
+        mBar.setPadding(10, 10, 10, 10);
+        mBar.setThumb(newThumb(dpToPx(20)));
+        mBar.setMin(0);
+        mBar.setMax(100);
+        mBar.setProgress(50);
+        measureAndLayout(dpToPx(200), dpToPx(32));
+
+        assertThat(mBar.getSystemGestureExclusionRects(), hasItem(new Rect(1, 2, 3, 4)));
+        assertThat(mBar.getSystemGestureExclusionRects(), hasSize(2));
+
+        mBar.setSystemGestureExclusionRects(Arrays.asList(new Rect(3, 4, 5, 6)));
+        assertThat(mBar.getSystemGestureExclusionRects(), hasItem(new Rect(3, 4, 5, 6)));
+        assertThat(mBar.getSystemGestureExclusionRects(), hasSize(2));
+    }
+
+    private Point center(Rect rect) {
+        return new Point(rect.centerX(), rect.centerY());
+    }
+
+    private Point center(View view) {
+        return center(new Rect(view.getLeft(), view.getTop(), view.getRight(), view.getBottom()));
+    }
+
+    private ShapeDrawable newThumb(int size) {
+        final ShapeDrawable thumb = new ShapeDrawable(new RectShape());
+        thumb.setIntrinsicWidth(size);
+        thumb.setIntrinsicHeight(size);
+        return thumb;
+    }
+
+    private void measureAndLayout(int wPx, int hPx) {
+        mBar.measure(makeMeasureSpec(wPx, EXACTLY), makeMeasureSpec(hPx, EXACTLY));
+        mBar.layout(0, 0, wPx, hPx);
+    }
+
+    private int dpToPx(int dp) {
+        return (int) (mContext.getResources().getDisplayMetrics().density * dp);
+    }
+}
diff --git a/packages/MtpDocumentsProvider/res/values-hi/strings.xml b/packages/MtpDocumentsProvider/res/values-hi/strings.xml
index bbd0ae7..e469fc0 100644
--- a/packages/MtpDocumentsProvider/res/values-hi/strings.xml
+++ b/packages/MtpDocumentsProvider/res/values-hi/strings.xml
@@ -19,7 +19,7 @@
     <string name="app_label" msgid="6271216747302322594">"MTP होस्ट"</string>
     <string name="downloads_app_label" msgid="7120690641874849726">"डाउनलोड"</string>
     <string name="root_name" msgid="5819495383921089536">"<xliff:g id="DEVICE_MODEL">%1$s</xliff:g> <xliff:g id="STORAGE_NAME">%2$s</xliff:g>"</string>
-    <string name="accessing_notification_title" msgid="3030133609230917944">"<xliff:g id="DEVICE_MODEL">%1$s</xliff:g> से फ़ाइलें एक्सेस कर रहा है"</string>
+    <string name="accessing_notification_title" msgid="3030133609230917944">"<xliff:g id="DEVICE_MODEL">%1$s</xliff:g> से फ़ाइलें ऐक्सेस कर रहा है"</string>
     <string name="error_busy_device" msgid="3997316850357386589">"दूसरा डिवाइस व्यस्त है. आप उसके उपलब्ध हो जाने तक फ़ाइलें ट्रांसफ़र नहीं कर सकते."</string>
     <string name="error_locked_device" msgid="7557872102188356147">"कोई फ़ाइल नहीं मिली. हो सकता है कि दूसरा डिवाइस लॉक हो. अगर ऐसा है, तो उसे अनलॉक करें और दोबारा कोशिश करें."</string>
 </resources>
diff --git a/packages/SystemUI/res-keyguard/values-de/strings.xml b/packages/SystemUI/res-keyguard/values-de/strings.xml
index 7f39a19..d44bfbc 100644
--- a/packages/SystemUI/res-keyguard/values-de/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-de/strings.xml
@@ -152,6 +152,6 @@
       <item quantity="one">Die SIM-Karte ist jetzt deaktiviert. Gib den PUK-Code ein, um fortzufahren. Du hast noch <xliff:g id="_NUMBER_0">%d</xliff:g> Versuch, bevor die SIM-Karte endgültig gesperrt wird. Weitere Informationen erhältst du von deinem Mobilfunkanbieter.</item>
     </plurals>
     <string name="clock_title_default" msgid="6645600990069154049">"Standard"</string>
-    <string name="clock_title_bubble" msgid="1286365278681892114">"Blase"</string>
+    <string name="clock_title_bubble" msgid="1286365278681892114">"Bubble"</string>
     <string name="clock_title_analog" msgid="4047401488577315053">"Analog"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-de/strings.xml b/packages/SystemUI/res/values-de/strings.xml
index 408254f..9b3974b 100644
--- a/packages/SystemUI/res/values-de/strings.xml
+++ b/packages/SystemUI/res/values-de/strings.xml
@@ -656,7 +656,7 @@
     <string name="notification_silence_title" msgid="5763240612242137433">"Lautlos"</string>
     <string name="notification_alert_title" msgid="8031196611815490340">"Benachrichtigen"</string>
     <string name="notification_channel_summary_low" msgid="3387466082089715555">"Benachrichtigungen werden ohne Ton oder Vibration angekündigt, um deine Konzentration nicht zu stören."</string>
-    <string name="notification_channel_summary_default" msgid="5994062840431965586">"Benachrichtigungen werden mit einem Ton oder einer Vibration angekündigt, um dich auf sie aufmerksam zu machen."</string>
+    <string name="notification_channel_summary_default" msgid="5994062840431965586">"Benachrichtigungen werden mit einem Ton oder einer Vibration angekündigt."</string>
     <string name="notification_unblockable_desc" msgid="4556908766584964102">"Diese Benachrichtigungen können nicht geändert werden."</string>
     <string name="notification_multichannel_desc" msgid="4695920306092240550">"Die Benachrichtigungsgruppe kann hier nicht konfiguriert werden"</string>
     <string name="notification_delegate_header" msgid="2857691673814814270">"Weitergeleitete Benachrichtigung"</string>
diff --git a/packages/SystemUI/res/values-es-rUS/strings.xml b/packages/SystemUI/res/values-es-rUS/strings.xml
index 37aae55..d6c8d09 100644
--- a/packages/SystemUI/res/values-es-rUS/strings.xml
+++ b/packages/SystemUI/res/values-es-rUS/strings.xml
@@ -553,7 +553,7 @@
     <string name="quick_settings_reset_confirmation_button" msgid="2660339101868367515">"Ocultar"</string>
     <string name="stream_voice_call" msgid="4410002696470423714">"Llamada"</string>
     <string name="stream_system" msgid="7493299064422163147">"Sistema"</string>
-    <string name="stream_ring" msgid="8213049469184048338">"Hacer sonar"</string>
+    <string name="stream_ring" msgid="8213049469184048338">"Timbre"</string>
     <string name="stream_music" msgid="9086982948697544342">"Multimedia"</string>
     <string name="stream_alarm" msgid="5209444229227197703">"Alarma"</string>
     <string name="stream_notification" msgid="2563720670905665031">"Notificación"</string>
@@ -561,7 +561,7 @@
     <string name="stream_dtmf" msgid="2447177903892477915">"Multifrecuencia de tono doble"</string>
     <string name="stream_accessibility" msgid="301136219144385106">"Accesibilidad"</string>
     <string name="ring_toggle_title" msgid="3281244519428819576">"Llamadas"</string>
-    <string name="volume_ringer_status_normal" msgid="4273142424125855384">"Hacer sonar"</string>
+    <string name="volume_ringer_status_normal" msgid="4273142424125855384">"Timbre"</string>
     <string name="volume_ringer_status_vibrate" msgid="1825615171021346557">"Vibrar"</string>
     <string name="volume_ringer_status_silent" msgid="6896394161022916369">"Silenciar"</string>
     <string name="qs_status_phone_vibrate" msgid="204362991135761679">"Teléfono en vibración"</string>
diff --git a/packages/SystemUI/res/values-sq/strings.xml b/packages/SystemUI/res/values-sq/strings.xml
index 83a7aaa..1f75490 100644
--- a/packages/SystemUI/res/values-sq/strings.xml
+++ b/packages/SystemUI/res/values-sq/strings.xml
@@ -544,7 +544,7 @@
     <string name="screen_pinning_description_recents_invisible_accessible" msgid="6134833683151189507">"Kjo e ruan në pamje deri sa ta heqësh nga gozhdimi. Prek dhe mbaj të shtypur \"Kreu\" për ta hequr nga gozhdimi."</string>
     <string name="screen_pinning_toast" msgid="2266705122951934150">"Për të hequr gozhdimin e këtij ekrani, prek dhe mbaj butonat \"Prapa\" dhe \"Përmbledhja\"."</string>
     <string name="screen_pinning_toast_recents_invisible" msgid="8252402309499161281">"Për të hequr gozhdimin e këtij ekrani, prek dhe mbaj butonat \"Prapa\" dhe \"Kreu\"."</string>
-    <string name="screen_pinning_positive" msgid="3783985798366751226">"E kuptova!"</string>
+    <string name="screen_pinning_positive" msgid="3783985798366751226">"E kuptova"</string>
     <string name="screen_pinning_negative" msgid="3741602308343880268">"Jo, faleminderit!"</string>
     <string name="screen_pinning_start" msgid="1022122128489278317">"Ekrani u gozhdua"</string>
     <string name="screen_pinning_exit" msgid="5187339744262325372">"Ekrani u hoq nga gozhdimi"</string>
diff --git a/packages/SystemUI/res/values-sw/strings.xml b/packages/SystemUI/res/values-sw/strings.xml
index 182caa4..640bbda 100644
--- a/packages/SystemUI/res/values-sw/strings.xml
+++ b/packages/SystemUI/res/values-sw/strings.xml
@@ -416,7 +416,7 @@
     <string name="keyguard_indication_charging_time_wireless" msgid="6959284458466962592">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Inachaji bila kutumia waya (imebakisha <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g> ili ijae)"</string>
     <string name="keyguard_indication_charging_time" msgid="2056340799276374421">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Inachaji (Imebakisha <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g> ili ijae)"</string>
     <string name="keyguard_indication_charging_time_fast" msgid="7767562163577492332">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Inachaji kwa kasi (Imebakisha <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g> ili ijae)"</string>
-    <string name="keyguard_indication_charging_time_slowly" msgid="3769655133567307069">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Inachaji pole pole (Imebakisha <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g> ili ijae)"</string>
+    <string name="keyguard_indication_charging_time_slowly" msgid="3769655133567307069">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Inachaji pole pole (Imebakisha <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g> ijae)"</string>
     <string name="accessibility_multi_user_switch_switcher" msgid="7305948938141024937">"Badili mtumiaji"</string>
     <string name="accessibility_multi_user_switch_switcher_with_current" msgid="8434880595284601601">"Badili mtumiaji, mtumiaji wa sasa <xliff:g id="CURRENT_USER_NAME">%s</xliff:g>"</string>
     <string name="accessibility_multi_user_switch_inactive" msgid="1424081831468083402">"Mtumiaji wa sasa <xliff:g id="CURRENT_USER_NAME">%s</xliff:g>"</string>
diff --git a/packages/SystemUI/res/values-ta/strings.xml b/packages/SystemUI/res/values-ta/strings.xml
index 9f8f45e..6e8b097 100644
--- a/packages/SystemUI/res/values-ta/strings.xml
+++ b/packages/SystemUI/res/values-ta/strings.xml
@@ -761,7 +761,7 @@
     <item msgid="8175437057325747277">"ஏதுமில்லை"</item>
   </string-array>
   <string-array name="nav_bar_layouts">
-    <item msgid="8077901629964902399">"இயல்பானது"</item>
+    <item msgid="8077901629964902399">"சராசரி"</item>
     <item msgid="8256205964297588988">"சுருக்கமானது"</item>
     <item msgid="8719936228094005878">"இடப்புறம் சாய்ந்தது"</item>
     <item msgid="586019486955594690">"வலப்புறம் சாய்ந்தது"</item>
diff --git a/packages/SystemUI/res/values-vi/strings.xml b/packages/SystemUI/res/values-vi/strings.xml
index affca3d..025efac 100644
--- a/packages/SystemUI/res/values-vi/strings.xml
+++ b/packages/SystemUI/res/values-vi/strings.xml
@@ -741,7 +741,7 @@
     <string name="battery" msgid="7498329822413202973">"Pin"</string>
     <string name="clock" msgid="7416090374234785905">"Đồng hồ"</string>
     <string name="headset" msgid="4534219457597457353">"Tai nghe"</string>
-    <string name="accessibility_long_click_tile" msgid="6687350750091842525">"Mở cài đặt"</string>
+    <string name="accessibility_long_click_tile" msgid="6687350750091842525">"Mở phần cài đặt"</string>
     <string name="accessibility_status_bar_headphones" msgid="9156307120060559989">"Đã kết nối tai nghe"</string>
     <string name="accessibility_status_bar_headset" msgid="8666419213072449202">"Đã kết nối tai nghe"</string>
     <string name="data_saver" msgid="5037565123367048522">"Trình tiết kiệm dữ liệu"</string>
@@ -817,7 +817,7 @@
     <string name="dock_non_resizeble_failed_to_dock_text" msgid="3871617304250207291">"Ứng dụng không hỗ trợ chia đôi màn hình."</string>
     <string name="forced_resizable_secondary_display" msgid="4230857851756391925">"Ứng dụng có thể không hoạt động trên màn hình phụ."</string>
     <string name="activity_launch_on_secondary_display_failed_text" msgid="7793821742158306742">"Ứng dụng không hỗ trợ khởi chạy trên màn hình phụ."</string>
-    <string name="accessibility_quick_settings_settings" msgid="6132460890024942157">"Mở cài đặt."</string>
+    <string name="accessibility_quick_settings_settings" msgid="6132460890024942157">"Mở phần cài đặt."</string>
     <string name="accessibility_quick_settings_expand" msgid="2375165227880477530">"Mở cài đặt nhanh."</string>
     <string name="accessibility_quick_settings_collapse" msgid="1792625797142648105">"Đóng cài đặt nhanh."</string>
     <string name="accessibility_quick_settings_alarm_set" msgid="1863000242431528676">"Đã đặt báo thức."</string>
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/system/SystemGestureExclusionListenerCompat.java b/packages/SystemUI/shared/src/com/android/systemui/shared/system/SystemGestureExclusionListenerCompat.java
index 9fdecfb..aeb0415 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/system/SystemGestureExclusionListenerCompat.java
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/system/SystemGestureExclusionListenerCompat.java
@@ -34,9 +34,11 @@
             new ISystemGestureExclusionListener.Stub() {
                 @Override
                 public void onSystemGestureExclusionChanged(int displayId,
-                        Region systemGestureExclusion) {
+                        Region systemGestureExclusion, Region unrestrictedOrNull) {
                     if (displayId == mDisplayId) {
-                        onExclusionChanged(systemGestureExclusion);
+                        Region unrestricted = (unrestrictedOrNull == null)
+                                ? systemGestureExclusion : unrestrictedOrNull;
+                        onExclusionChanged(systemGestureExclusion, unrestricted);
                     }
                 }
             };
@@ -47,11 +49,29 @@
     }
 
     /**
-     * Called when the exclusion region has changed
+     * Called when the exclusion region has changed.
+     *
+     * TODO: remove, once all subclasses have migrated to
+     *       {@link #onExclusionChanged(Region, Region)}.
      */
     public abstract void onExclusionChanged(Region systemGestureExclusion);
 
     /**
+     * Called when the exclusion region has changed.
+     *
+     * @param systemGestureExclusion the system gesture exclusion to be applied
+     * @param systemGestureExclusionUnrestricted what would be the system gesture exclusion, if
+     *           there were no restrictions being applied. For logging purposes only.
+     *
+     */
+    public void onExclusionChanged(Region systemGestureExclusion,
+            Region systemGestureExclusionUnrestricted) {
+        // TODO: make abstract, once all subclasses have migrated away from
+        //       onExclusionChanged(Region)
+        onExclusionChanged(systemGestureExclusion);
+    }
+
+    /**
      * Registers the listener for getting exclusion rect changes.
      */
     public void register() {
diff --git a/packages/SystemUI/src/com/android/keyguard/CarrierTextController.java b/packages/SystemUI/src/com/android/keyguard/CarrierTextController.java
index 11d093f..10d132a 100644
--- a/packages/SystemUI/src/com/android/keyguard/CarrierTextController.java
+++ b/packages/SystemUI/src/com/android/keyguard/CarrierTextController.java
@@ -400,8 +400,11 @@
             }
         }
 
+        if (TextUtils.isEmpty(displayText)) displayText = joinNotEmpty(mSeparator, carrierNames);
+
         displayText = updateCarrierTextWithSimIoError(displayText, carrierNames, subOrderBySlot,
                 allSimsMissing);
+
         boolean airplaneMode = false;
         // APM (airplane mode) != no carrier state. There are carrier services
         // (e.g. WFC = Wi-Fi calling) which may operate in APM.
@@ -410,9 +413,6 @@
             airplaneMode = true;
         }
 
-        if (TextUtils.isEmpty(displayText) && !airplaneMode) {
-            displayText = joinNotEmpty(mSeparator, carrierNames);
-        }
         final CarrierTextCallbackInfo info = new CarrierTextCallbackInfo(
                 displayText,
                 carrierNames,
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardSimPinView.java b/packages/SystemUI/src/com/android/keyguard/KeyguardSimPinView.java
index fb3a586..69da990 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardSimPinView.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardSimPinView.java
@@ -123,7 +123,7 @@
             msg = rez.getString(R.string.kg_sim_lock_esim_instructions, msg);
         }
 
-        if (mSecurityMessageDisplay != null) {
+        if (mSecurityMessageDisplay != null && getVisibility() == VISIBLE) {
             mSecurityMessageDisplay.setMessage(msg);
         }
         mSimImageView.setImageTintList(ColorStateList.valueOf(color));
diff --git a/packages/SystemUI/src/com/android/systemui/assist/AssistManager.java b/packages/SystemUI/src/com/android/systemui/assist/AssistManager.java
index 0b00b91..4a4fead 100644
--- a/packages/SystemUI/src/com/android/systemui/assist/AssistManager.java
+++ b/packages/SystemUI/src/com/android/systemui/assist/AssistManager.java
@@ -82,7 +82,7 @@
         void processBundle(Bundle hints);
 
         /**
-         * Hides the UI.
+         * Hides any SysUI for the assistant, but _does not_ close the assistant itself.
          */
         void hide();
     }
diff --git a/packages/SystemUI/src/com/android/systemui/assist/ui/DefaultUiController.java b/packages/SystemUI/src/com/android/systemui/assist/ui/DefaultUiController.java
index 662de3a..0c4f051 100644
--- a/packages/SystemUI/src/com/android/systemui/assist/ui/DefaultUiController.java
+++ b/packages/SystemUI/src/com/android/systemui/assist/ui/DefaultUiController.java
@@ -118,7 +118,6 @@
 
     @Override // AssistManager.UiController
     public void hide() {
-        Dependency.get(AssistManager.class).hideAssist();
         detach();
         if (mInvocationAnimator.isRunning()) {
             mInvocationAnimator.cancel();
diff --git a/packages/SystemUI/src/com/android/systemui/classifier/FalsingManagerProxy.java b/packages/SystemUI/src/com/android/systemui/classifier/FalsingManagerProxy.java
index 128cc61..ee79e6b 100644
--- a/packages/SystemUI/src/com/android/systemui/classifier/FalsingManagerProxy.java
+++ b/packages/SystemUI/src/com/android/systemui/classifier/FalsingManagerProxy.java
@@ -26,6 +26,7 @@
 import android.view.MotionEvent;
 
 import com.android.internal.annotations.VisibleForTesting;
+import com.android.keyguard.KeyguardUpdateMonitor;
 import com.android.systemui.Dependency;
 import com.android.systemui.classifier.brightline.BrightLineFalsingManager;
 import com.android.systemui.classifier.brightline.FalsingDataProvider;
@@ -102,7 +103,8 @@
         } else {
             mInternalFalsingManager = new BrightLineFalsingManager(
                     new FalsingDataProvider(context.getResources().getDisplayMetrics()),
-                    Dependency.get(AsyncSensorManager.class)
+                    Dependency.get(AsyncSensorManager.class),
+                    KeyguardUpdateMonitor.getInstance(context)
             );
         }
 
diff --git a/packages/SystemUI/src/com/android/systemui/classifier/brightline/BrightLineFalsingManager.java b/packages/SystemUI/src/com/android/systemui/classifier/brightline/BrightLineFalsingManager.java
index ce82bbf..9e0b702 100644
--- a/packages/SystemUI/src/com/android/systemui/classifier/brightline/BrightLineFalsingManager.java
+++ b/packages/SystemUI/src/com/android/systemui/classifier/brightline/BrightLineFalsingManager.java
@@ -23,11 +23,14 @@
 import android.hardware.SensorEvent;
 import android.hardware.SensorEventListener;
 import android.hardware.SensorManager;
+import android.hardware.biometrics.BiometricSourceType;
 import android.net.Uri;
 import android.util.Log;
 import android.view.MotionEvent;
 
 import com.android.internal.logging.MetricsLogger;
+import com.android.keyguard.KeyguardUpdateMonitor;
+import com.android.keyguard.KeyguardUpdateMonitorCallback;
 import com.android.systemui.classifier.Classifier;
 import com.android.systemui.plugins.FalsingManager;
 
@@ -47,11 +50,13 @@
 
     private final SensorManager mSensorManager;
     private final FalsingDataProvider mDataProvider;
+    private final KeyguardUpdateMonitor mKeyguardUpdateMonitor;
     private boolean mSessionStarted;
     private MetricsLogger mMetricsLogger;
     private int mIsFalseTouchCalls;
     private boolean mShowingAod;
     private boolean mScreenOn;
+    private boolean mJustUnlockedWithFace;
 
     private final ExecutorService mBackgroundExecutor = Executors.newSingleThreadExecutor();
 
@@ -68,10 +73,27 @@
         }
     };
 
-    public BrightLineFalsingManager(FalsingDataProvider falsingDataProvider,
-            SensorManager sensorManager) {
+    private final KeyguardUpdateMonitorCallback mKeyguardUpdateCallback =
+            new KeyguardUpdateMonitorCallback() {
+                @Override
+                public void onBiometricAuthenticated(int userId,
+                        BiometricSourceType biometricSourceType) {
+                    if (userId == KeyguardUpdateMonitor.getCurrentUser()
+                            && biometricSourceType == BiometricSourceType.FACE) {
+                        mJustUnlockedWithFace = true;
+                    }
+                }
+            };
+
+    public BrightLineFalsingManager(
+            FalsingDataProvider falsingDataProvider,
+            SensorManager sensorManager,
+            KeyguardUpdateMonitor keyguardUpdateMonitor) {
+        mKeyguardUpdateMonitor = keyguardUpdateMonitor;
         mDataProvider = falsingDataProvider;
         mSensorManager = sensorManager;
+        mKeyguardUpdateMonitor.registerCallback(mKeyguardUpdateCallback);
+
         mMetricsLogger = new MetricsLogger();
         mClassifiers = new ArrayList<>();
         DistanceClassifier distanceClassifier = new DistanceClassifier(mDataProvider);
@@ -110,6 +132,7 @@
         if (!mSessionStarted && !mShowingAod && mScreenOn) {
             logDebug("Starting Session");
             mSessionStarted = true;
+            mJustUnlockedWithFace = false;
             registerSensors();
             mClassifiers.forEach(FalsingClassifier::onSessionStarted);
         }
@@ -141,7 +164,7 @@
 
     @Override
     public boolean isFalseTouch() {
-        boolean r = mClassifiers.stream().anyMatch(falsingClassifier -> {
+        boolean r = !mJustUnlockedWithFace && mClassifiers.stream().anyMatch(falsingClassifier -> {
             boolean result = falsingClassifier.isFalseTouch();
             if (result) {
                 logInfo(falsingClassifier.getClass().getName() + ": true");
@@ -335,6 +358,7 @@
     @Override
     public void cleanup() {
         unregisterSensors();
+        mKeyguardUpdateMonitor.removeCallback(mKeyguardUpdateCallback);
     }
 
     static void logDebug(String msg) {
diff --git a/packages/SystemUI/src/com/android/systemui/power/PowerUI.java b/packages/SystemUI/src/com/android/systemui/power/PowerUI.java
index fb8b6c7..75dc397 100644
--- a/packages/SystemUI/src/com/android/systemui/power/PowerUI.java
+++ b/packages/SystemUI/src/com/android/systemui/power/PowerUI.java
@@ -64,6 +64,8 @@
     private static final int CHARGE_CYCLE_PERCENT_RESET = 45;
     private static final long SIX_HOURS_MILLIS = Duration.ofHours(6).toMillis();
     public static final int NO_ESTIMATE_AVAILABLE = -1;
+    private static final String BOOT_COUNT_KEY = "boot_count";
+    private static final String PREFS = "powerui_prefs";
 
     private final Handler mHandler = new Handler();
     @VisibleForTesting
@@ -118,7 +120,7 @@
 
         // Check to see if we need to let the user know that the phone previously shut down due
         // to the temperature being too high.
-        showThermalShutdownDialog();
+        showWarnOnThermalShutdown();
 
         // Register an observer to configure mEnableSkinTemperatureWarning and perform the
         // registration of skin thermal event listener upon Settings change.
@@ -542,10 +544,23 @@
         }
     }
 
-    private void showThermalShutdownDialog() {
-        if (mPowerManager.getLastShutdownReason()
-                == PowerManager.SHUTDOWN_REASON_THERMAL_SHUTDOWN) {
-            mWarnings.showThermalShutdownWarning();
+    private void showWarnOnThermalShutdown() {
+        int bootCount = -1;
+        int lastReboot = mContext.getSharedPreferences(PREFS, 0).getInt(BOOT_COUNT_KEY, -1);
+        try {
+            bootCount = Settings.Global.getInt(mContext.getContentResolver(),
+                    Settings.Global.BOOT_COUNT);
+        } catch (Settings.SettingNotFoundException e) {
+            Slog.e(TAG, "Failed to read system boot count from Settings.Global.BOOT_COUNT");
+        }
+        // Only show the thermal shutdown warning when there is a thermal reboot.
+        if (bootCount > lastReboot) {
+            mContext.getSharedPreferences(PREFS, 0).edit().putInt(BOOT_COUNT_KEY,
+                    bootCount).apply();
+            if (mPowerManager.getLastShutdownReason()
+                    == PowerManager.SHUTDOWN_REASON_THERMAL_SHUTDOWN) {
+                mWarnings.showThermalShutdownWarning();
+            }
         }
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotificationData.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotificationData.java
index 1ce4934..0009292 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotificationData.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotificationData.java
@@ -420,7 +420,14 @@
             }
         }
 
-        Collections.sort(mSortedAndFiltered, mRankingComparator);
+        if (mSortedAndFiltered.size() == 1) {
+            // HACK: We need the comparator to run on all children in order to set the
+            // isHighPriority field. If there is only one child, then the comparison won't be run,
+            // so we have to trigger it manually. Get rid of this code as soon as possible.
+            mRankingComparator.compare(mSortedAndFiltered.get(0), mSortedAndFiltered.get(0));
+        } else {
+            Collections.sort(mSortedAndFiltered, mRankingComparator);
+        }
     }
 
     public void dump(PrintWriter pw, String indent) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java
index a8327f6..ea31be4 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java
@@ -1367,7 +1367,9 @@
         if (isChildInGroup()) {
             mTranslationWhenRemoved += getNotificationParent().getTranslationY();
         }
-        mPrivateLayout.setRemoved();
+        for (NotificationContentView l : mLayouts) {
+            l.setRemoved();
+        }
     }
 
     public boolean wasChildInGroupWhenRemoved() {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationContentView.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationContentView.java
index 90f6324..0c5b27b 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationContentView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationContentView.java
@@ -1542,6 +1542,15 @@
         if (mHeadsUpRemoteInput != null) {
             mHeadsUpRemoteInput.setRemoved();
         }
+        if (mExpandedWrapper != null) {
+            mExpandedWrapper.setRemoved();
+        }
+        if (mContractedWrapper != null) {
+            mContractedWrapper.setRemoved();
+        }
+        if (mHeadsUpWrapper != null) {
+            mHeadsUpWrapper.setRemoved();
+        }
     }
 
     public void setContentHeightAnimating(boolean animating) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationMediaTemplateViewWrapper.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationMediaTemplateViewWrapper.java
index 20e8b73..1116106 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationMediaTemplateViewWrapper.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationMediaTemplateViewWrapper.java
@@ -39,6 +39,7 @@
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.logging.MetricsLogger;
 import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
+import com.android.internal.widget.MediaNotificationView;
 import com.android.systemui.Dependency;
 import com.android.systemui.statusbar.NotificationMediaManager;
 import com.android.systemui.statusbar.TransformableView;
@@ -67,6 +68,7 @@
     private View mSeekBarView;
     private Context mContext;
     private MetricsLogger mMetricsLogger;
+    private boolean mIsViewVisible;
 
     @VisibleForTesting
     protected SeekBar.OnSeekBarChangeListener mSeekListener =
@@ -88,11 +90,46 @@
         }
     };
 
+    private MediaNotificationView.VisibilityChangeListener mVisibilityListener =
+            new MediaNotificationView.VisibilityChangeListener() {
+        @Override
+        public void onAggregatedVisibilityChanged(boolean isVisible) {
+            mIsViewVisible = isVisible;
+            if (isVisible && mMediaController != null) {
+                // Restart timer if we're currently playing and didn't already have one going
+                PlaybackState state = mMediaController.getPlaybackState();
+                if (state != null && state.getState() == PlaybackState.STATE_PLAYING
+                        && mSeekBarTimer == null && mSeekBarView != null
+                        && mSeekBarView.getVisibility() != View.GONE) {
+                    startTimer();
+                }
+            } else {
+                clearTimer();
+            }
+        }
+    };
+
+    private View.OnAttachStateChangeListener mAttachStateListener =
+            new View.OnAttachStateChangeListener() {
+        @Override
+        public void onViewAttachedToWindow(View v) {
+        }
+
+        @Override
+        public void onViewDetachedFromWindow(View v) {
+            mIsViewVisible = false;
+        }
+    };
+
     private MediaController.Callback mMediaCallback = new MediaController.Callback() {
         @Override
         public void onSessionDestroyed() {
             clearTimer();
             mMediaController.unregisterCallback(this);
+            if (mView instanceof MediaNotificationView) {
+                ((MediaNotificationView) mView).removeVisibilityListener(mVisibilityListener);
+                mView.removeOnAttachStateChangeListener(mAttachStateListener);
+            }
         }
 
         @Override
@@ -126,10 +163,17 @@
         mContext = ctx;
         mMediaManager = Dependency.get(NotificationMediaManager.class);
         mMetricsLogger = Dependency.get(MetricsLogger.class);
+
+        if (mView instanceof MediaNotificationView) {
+            MediaNotificationView mediaView = (MediaNotificationView) mView;
+            mediaView.addVisibilityListener(mVisibilityListener);
+            mView.addOnAttachStateChangeListener(mAttachStateListener);
+        }
     }
 
     private void resolveViews() {
         mActions = mView.findViewById(com.android.internal.R.id.media_actions);
+        mIsViewVisible = mView.isShown();
 
         final MediaSession.Token token = mRow.getEntry().notification.getNotification().extras
                 .getParcelable(Notification.EXTRA_MEDIA_SESSION);
@@ -208,24 +252,37 @@
 
     private void startTimer() {
         clearTimer();
-        mSeekBarTimer = new Timer(true /* isDaemon */);
-        mSeekBarTimer.schedule(new TimerTask() {
-            @Override
-            public void run() {
-                mHandler.post(mOnUpdateTimerTick);
-            }
-        }, 0, PROGRESS_UPDATE_INTERVAL);
+        if (mIsViewVisible) {
+            mSeekBarTimer = new Timer(true /* isDaemon */);
+            mSeekBarTimer.schedule(new TimerTask() {
+                @Override
+                public void run() {
+                    mHandler.post(mOnUpdateTimerTick);
+                }
+            }, 0, PROGRESS_UPDATE_INTERVAL);
+        }
     }
 
     private void clearTimer() {
         if (mSeekBarTimer != null) {
-            // TODO: also trigger this when the notification panel is collapsed
             mSeekBarTimer.cancel();
             mSeekBarTimer.purge();
             mSeekBarTimer = null;
         }
     }
 
+    @Override
+    public void setRemoved() {
+        clearTimer();
+        if (mMediaController != null) {
+            mMediaController.unregisterCallback(mMediaCallback);
+        }
+        if (mView instanceof MediaNotificationView) {
+            ((MediaNotificationView) mView).removeVisibilityListener(mVisibilityListener);
+            mView.removeOnAttachStateChangeListener(mAttachStateListener);
+        }
+    }
+
     private boolean canSeekMedia(@Nullable PlaybackState state) {
         if (state == null) {
             return false;
@@ -261,7 +318,6 @@
         public void run() {
             if (mMediaController != null && mSeekBar != null) {
                 PlaybackState playbackState = mMediaController.getPlaybackState();
-
                 if (playbackState != null) {
                     updatePlaybackUi(playbackState);
                 } else {
@@ -274,6 +330,10 @@
     };
 
     private void updatePlaybackUi(PlaybackState state) {
+        if (mSeekBar == null || mSeekBarElapsedTime == null) {
+            return;
+        }
+
         long position = state.getPosition();
         mSeekBar.setProgress((int) position);
 
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationViewWrapper.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationViewWrapper.java
index 47906a7..3950003 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationViewWrapper.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationViewWrapper.java
@@ -261,6 +261,12 @@
         mView.setVisibility(visible ? View.VISIBLE : View.INVISIBLE);
     }
 
+    /**
+     * Called to indicate this view is removed
+     */
+    public void setRemoved() {
+    }
+
     public int getCustomBackgroundColor() {
         // Parent notifications should always use the normal background color
         return mRow.isSummaryWithChildren() ? 0 : mBackgroundColor;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/EdgeBackGestureHandler.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/EdgeBackGestureHandler.java
index f9cdde8..6a74779 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/EdgeBackGestureHandler.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/EdgeBackGestureHandler.java
@@ -31,6 +31,7 @@
 import android.os.Looper;
 import android.os.RemoteException;
 import android.os.SystemClock;
+import android.os.SystemProperties;
 import android.util.Log;
 import android.util.MathUtils;
 import android.view.Gravity;
@@ -66,7 +67,8 @@
 public class EdgeBackGestureHandler implements DisplayListener {
 
     private static final String TAG = "EdgeBackGestureHandler";
-    private static final int MAX_LONG_PRESS_TIMEOUT = 250;
+    private static final int MAX_LONG_PRESS_TIMEOUT = SystemProperties.getInt(
+            "gestures.back_timeout", 250);
 
     private final IPinnedStackListener.Stub mImeChangedListener = new IPinnedStackListener.Stub() {
         @Override
@@ -103,7 +105,7 @@
             new ISystemGestureExclusionListener.Stub() {
                 @Override
                 public void onSystemGestureExclusionChanged(int displayId,
-                        Region systemGestureExclusion) {
+                        Region systemGestureExclusion, Region unrestrictedOrNull) {
                     if (displayId == mDisplayId) {
                         mMainExecutor.execute(() -> mExcludeRegion.set(systemGestureExclusion));
                     }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java
index 6bfa048..f689a3e 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java
@@ -619,6 +619,10 @@
         // Always disable recents when alternate car mode UI is active and for secondary displays.
         boolean disableRecent = isRecentsButtonDisabled();
 
+        // Disable the home handle if both hone and recents are disabled
+        boolean disableHomeHandle = disableRecent
+                && ((mDisabledFlags & View.STATUS_BAR_DISABLE_HOME) != 0);
+
         boolean disableBack = !useAltBack && (isGesturalMode(mNavBarMode)
                 || ((mDisabledFlags & View.STATUS_BAR_DISABLE_BACK) != 0));
 
@@ -649,6 +653,7 @@
         getBackButton().setVisibility(disableBack      ? View.INVISIBLE : View.VISIBLE);
         getHomeButton().setVisibility(disableHome      ? View.INVISIBLE : View.VISIBLE);
         getRecentsButton().setVisibility(disableRecent ? View.INVISIBLE : View.VISIBLE);
+        getHomeHandle().setVisibility(disableHomeHandle ? View.INVISIBLE : View.VISIBLE);
     }
 
     @VisibleForTesting
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimState.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimState.java
index d28dadd..9fdd3b8 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimState.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimState.java
@@ -133,6 +133,12 @@
             mBlankScreen = mDisplayRequiresBlanking;
             mAnimationDuration = mWakeLockScreenSensorActive
                     ? ScrimController.ANIMATION_DURATION_LONG : ScrimController.ANIMATION_DURATION;
+
+            // Wake sensor will show the wallpaper, let's fade from black. Otherwise it will
+            // feel like the screen is flashing if the wallpaper is light.
+            if (mWakeLockScreenSensorActive && previousState == AOD) {
+                updateScrimColor(mScrimBehind, 1f /* alpha */, Color.BLACK);
+            }
         }
 
         @Override
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/CarrierTextControllerTest.java b/packages/SystemUI/tests/src/com/android/keyguard/CarrierTextControllerTest.java
index db45ad78..0044ca7 100644
--- a/packages/SystemUI/tests/src/com/android/keyguard/CarrierTextControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/keyguard/CarrierTextControllerTest.java
@@ -36,6 +36,7 @@
 import android.net.ConnectivityManager;
 import android.net.wifi.WifiManager;
 import android.os.Handler;
+import android.provider.Settings;
 import android.telephony.SubscriptionInfo;
 import android.telephony.SubscriptionManager;
 import android.telephony.TelephonyManager;
@@ -65,6 +66,8 @@
 public class CarrierTextControllerTest extends SysuiTestCase {
 
     private static final CharSequence SEPARATOR = " \u2014 ";
+    private static final CharSequence INVALID_CARD_TEXT = "Invalid card";
+    private static final CharSequence AIRPLANE_MODE_TEXT = "Airplane mode";
     private static final String TEST_CARRIER = "TEST_CARRIER";
     private static final String TEST_CARRIER_2 = "TEST_CARRIER_2";
     private static final String TEST_GROUP_UUID = "59b5c870-fc4c-47a4-a99e-9db826b48b24";
@@ -106,6 +109,10 @@
         mContext.addMockSystemService(ConnectivityManager.class, mConnectivityManager);
         mContext.addMockSystemService(TelephonyManager.class, mTelephonyManager);
         mContext.addMockSystemService(SubscriptionManager.class, mSubscriptionManager);
+        mContext.getOrCreateTestableResources().addOverride(
+                R.string.keyguard_sim_error_message_short, INVALID_CARD_TEXT);
+        mContext.getOrCreateTestableResources().addOverride(
+                R.string.airplane_mode, AIRPLANE_MODE_TEXT);
         mDependency.injectMockDependency(WakefulnessLifecycle.class);
         mDependency.injectTestDependency(Dependency.MAIN_HANDLER,
                 new Handler(mTestableLooper.getLooper()));
@@ -122,6 +129,53 @@
     }
 
     @Test
+    public void testAirplaneMode() {
+        Settings.Global.putInt(mContext.getContentResolver(), Settings.Global.AIRPLANE_MODE_ON, 1);
+        reset(mCarrierTextCallback);
+        List<SubscriptionInfo> list = new ArrayList<>();
+        list.add(TEST_SUBSCRIPTION);
+        when(mKeyguardUpdateMonitor.getSubscriptionInfo(anyBoolean())).thenReturn(list);
+        when(mKeyguardUpdateMonitor.getSimState(0)).thenReturn(IccCardConstants.State.READY);
+        mKeyguardUpdateMonitor.mServiceStates = new HashMap<>();
+
+        mCarrierTextController.updateCarrierText();
+
+        ArgumentCaptor<CarrierTextController.CarrierTextCallbackInfo> captor =
+                ArgumentCaptor.forClass(
+                        CarrierTextController.CarrierTextCallbackInfo.class);
+
+        mTestableLooper.processAllMessages();
+        verify(mCarrierTextCallback).updateCarrierInfo(captor.capture());
+        assertEquals(AIRPLANE_MODE_TEXT, captor.getValue().carrierText);
+    }
+
+    @Test
+    public void testCardIOError() {
+        reset(mCarrierTextCallback);
+        List<SubscriptionInfo> list = new ArrayList<>();
+        list.add(TEST_SUBSCRIPTION);
+        when(mKeyguardUpdateMonitor.getSubscriptionInfo(anyBoolean())).thenReturn(list);
+        when(mKeyguardUpdateMonitor.getSimState(0)).thenReturn(IccCardConstants.State.READY);
+        when(mKeyguardUpdateMonitor.getSimState(1)).thenReturn(
+                IccCardConstants.State.CARD_IO_ERROR);
+        mKeyguardUpdateMonitor.mServiceStates = new HashMap<>();
+
+        mCarrierTextController.mCallback.onSimStateChanged(3, 1,
+                IccCardConstants.State.CARD_IO_ERROR);
+
+        ArgumentCaptor<CarrierTextController.CarrierTextCallbackInfo> captor =
+                ArgumentCaptor.forClass(
+                        CarrierTextController.CarrierTextCallbackInfo.class);
+
+        mTestableLooper.processAllMessages();
+        verify(mCarrierTextCallback).updateCarrierInfo(captor.capture());
+        assertEquals("TEST_CARRIER" + SEPARATOR + INVALID_CARD_TEXT, captor.getValue().carrierText);
+        // There's only one subscription in the list
+        assertEquals(1, captor.getValue().listOfCarriers.length);
+        assertEquals(TEST_CARRIER, captor.getValue().listOfCarriers[0]);
+    }
+
+    @Test
     public void testWrongSlots() {
         reset(mCarrierTextCallback);
         when(mKeyguardUpdateMonitor.getSubscriptionInfo(anyBoolean())).thenReturn(
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/NotificationDataTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/NotificationDataTest.java
index 260555f..e2d8e56 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/NotificationDataTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/NotificationDataTest.java
@@ -23,6 +23,7 @@
 import static android.app.Notification.CATEGORY_EVENT;
 import static android.app.Notification.CATEGORY_MESSAGE;
 import static android.app.Notification.CATEGORY_REMINDER;
+import static android.app.NotificationManager.IMPORTANCE_DEFAULT;
 import static android.app.NotificationManager.IMPORTANCE_LOW;
 import static android.app.NotificationManager.IMPORTANCE_MIN;
 
@@ -62,6 +63,8 @@
 import android.testing.TestableLooper.RunWithLooper;
 import android.util.ArraySet;
 
+import androidx.test.filters.SmallTest;
+
 import com.android.systemui.Dependency;
 import com.android.systemui.ForegroundServiceController;
 import com.android.systemui.InitController;
@@ -85,8 +88,6 @@
 import java.util.List;
 import java.util.Map;
 
-import androidx.test.filters.SmallTest;
-
 @SmallTest
 @RunWith(AndroidTestingRunner.class)
 @RunWithLooper
@@ -114,6 +115,7 @@
         MockitoAnnotations.initMocks(this);
         when(mMockStatusBarNotification.getUid()).thenReturn(UID_NORMAL);
         when(mMockStatusBarNotification.cloneLight()).thenReturn(mMockStatusBarNotification);
+        when(mMockStatusBarNotification.getKey()).thenReturn("mock_key");
 
         when(mMockPackageManager.checkUidPermission(
                 eq(Manifest.permission.NOTIFICATION_DURING_SETUP),
@@ -232,6 +234,7 @@
         Notification n = mMockStatusBarNotification.getNotification();
         n.flags = Notification.FLAG_FOREGROUND_SERVICE;
         NotificationEntry entry = new NotificationEntry(mMockStatusBarNotification);
+        entry.setRow(mRow);
         mNotificationData.add(entry);
         Bundle override = new Bundle();
         override.putInt(OVERRIDE_VIS_EFFECTS, 255);
@@ -250,6 +253,7 @@
         n = nb.build();
         when(mMockStatusBarNotification.getNotification()).thenReturn(n);
         NotificationEntry entry = new NotificationEntry(mMockStatusBarNotification);
+        entry.setRow(mRow);
         mNotificationData.add(entry);
         Bundle override = new Bundle();
         override.putInt(OVERRIDE_VIS_EFFECTS, 255);
@@ -263,6 +267,7 @@
     public void testIsExemptFromDndVisualSuppression_system() {
         initStatusBarNotification(false);
         NotificationEntry entry = new NotificationEntry(mMockStatusBarNotification);
+        entry.setRow(mRow);
         entry.mIsSystemNotification = true;
         mNotificationData.add(entry);
         Bundle override = new Bundle();
@@ -277,6 +282,7 @@
     public void testIsNotExemptFromDndVisualSuppression_hiddenCategories() {
         initStatusBarNotification(false);
         NotificationEntry entry = new NotificationEntry(mMockStatusBarNotification);
+        entry.setRow(mRow);
         entry.mIsSystemNotification = true;
         Bundle override = new Bundle();
         override.putInt(OVERRIDE_VIS_EFFECTS, NotificationManager.Policy.SUPPRESSED_EFFECT_AMBIENT);
@@ -529,6 +535,62 @@
         assertEquals(-1, mNotificationData.mRankingComparator.compare(a, b));
     }
 
+    @Test
+    public void testSort_properlySetsIsTopBucket() {
+
+        Notification notification = new Notification.Builder(mContext, "test")
+                .build();
+        StatusBarNotification sbn = new StatusBarNotification(
+                "pkg",
+                "pkg",
+                0,
+                "tag",
+                0,
+                0,
+                notification,
+                mContext.getUser(),
+                "",
+                0);
+
+        Bundle override = new Bundle();
+        override.putInt(OVERRIDE_IMPORTANCE, IMPORTANCE_DEFAULT);
+        mNotificationData.rankingOverrides.put(sbn.getKey(), override);
+
+        NotificationEntry entry = new NotificationEntry(sbn);
+        entry.setRow(mRow);
+        mNotificationData.add(entry);
+
+        assertTrue(entry.isTopBucket());
+    }
+
+    @Test
+    public void testSort_properlySetsIsNotTopBucket() {
+        Notification notification = new Notification.Builder(mContext, "test")
+                .build();
+        StatusBarNotification sbn = new StatusBarNotification(
+                "pkg",
+                "pkg",
+                0,
+                "tag",
+                0,
+                0,
+                notification,
+                mContext.getUser(),
+                "",
+                0);
+
+        Bundle override = new Bundle();
+        override.putInt(OVERRIDE_IMPORTANCE, IMPORTANCE_LOW);
+        mNotificationData.rankingOverrides.put(sbn.getKey(), override);
+
+        NotificationEntry entry = new NotificationEntry(sbn);
+        entry.setRow(mRow);
+
+        mNotificationData.add(entry);
+
+        assertFalse(entry.isTopBucket());
+    }
+
     private void initStatusBarNotification(boolean allowDuringSetup) {
         Bundle bundle = new Bundle();
         bundle.putBoolean(Notification.EXTRA_ALLOW_DURING_SETUP, allowDuringSetup);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutTest.java
index 9ecb8d5..c851c91 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutTest.java
@@ -137,7 +137,7 @@
         mDependency.injectTestDependency(
                 NotificationBlockingHelperManager.class,
                 mBlockingHelperManager);
-        mDependency.injectTestDependency(StatusBarStateController.class, mBarState);
+        mDependency.injectTestDependency(SysuiStatusBarStateController.class, mBarState);
         mDependency.injectTestDependency(MetricsLogger.class, mMetricsLogger);
         mDependency.injectTestDependency(NotificationRemoteInputManager.class,
                 mRemoteInputManager);
@@ -163,7 +163,7 @@
                 mock(DynamicPrivacyController.class),
                 mock(ConfigurationController.class),
                 mock(ActivityStarterDelegate.class),
-                mock(StatusBarStateController.class),
+                mock(SysuiStatusBarStateController.class),
                 mHeadsUpManager,
                 mKeyguardBypassController);
         mStackScroller = spy(mStackScrollerInternal);
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index 91ae156..2ddc7259 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -8467,32 +8467,6 @@
         }
     }
 
-    void setRunningRemoteAnimation(int pid, boolean runningRemoteAnimation) {
-        if (pid == Process.myPid()) {
-            Slog.wtf(TAG, "system can't run remote animation");
-            return;
-        }
-        synchronized (ActivityManagerService.this) {
-            final ProcessRecord pr;
-            synchronized (mPidsSelfLocked) {
-                pr = mPidsSelfLocked.get(pid);
-                if (pr == null) {
-                    Slog.w(TAG, "setRunningRemoteAnimation called on unknown pid: " + pid);
-                    return;
-                }
-            }
-            if (pr.runningRemoteAnimation == runningRemoteAnimation) {
-                return;
-            }
-            pr.runningRemoteAnimation = runningRemoteAnimation;
-            if (DEBUG_OOM_ADJ) {
-                Slog.i(TAG, "Setting runningRemoteAnimation=" + pr.runningRemoteAnimation
-                        + " for pid=" + pid);
-            }
-            updateOomAdjLocked(pr, true, OomAdjuster.OOM_ADJ_REASON_UI_VISIBILITY);
-        }
-    }
-
     public final void enterSafeMode() {
         synchronized(this) {
             // It only makes sense to do this before the system is ready
@@ -17971,11 +17945,6 @@
         }
 
         @Override
-        public void setRunningRemoteAnimation(int pid, boolean runningRemoteAnimation) {
-            ActivityManagerService.this.setRunningRemoteAnimation(pid, runningRemoteAnimation);
-        }
-
-        @Override
         public List<ProcessMemoryState> getMemoryStateForProcesses() {
             List<ProcessMemoryState> processMemoryStates = new ArrayList<>();
             synchronized (mPidsSelfLocked) {
diff --git a/services/core/java/com/android/server/am/ProcessRecord.java b/services/core/java/com/android/server/am/ProcessRecord.java
index 563b2f3..ea30842 100644
--- a/services/core/java/com/android/server/am/ProcessRecord.java
+++ b/services/core/java/com/android/server/am/ProcessRecord.java
@@ -20,6 +20,7 @@
 
 import static com.android.server.Watchdog.NATIVE_STACKS_OF_INTEREST;
 import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_ANR;
+import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_OOM_ADJ;
 import static com.android.server.am.ActivityManagerDebugConfig.TAG_AM;
 import static com.android.server.am.ActivityManagerDebugConfig.TAG_WITH_CLASS_NAME;
 import static com.android.server.am.ActivityManagerService.MY_PID;
@@ -1348,6 +1349,25 @@
         }
     }
 
+    @Override
+    public void setRunningRemoteAnimation(boolean runningRemoteAnimation) {
+        if (pid == Process.myPid()) {
+            Slog.wtf(TAG, "system can't run remote animation");
+            return;
+        }
+        synchronized (mService) {
+            if (this.runningRemoteAnimation == runningRemoteAnimation) {
+                return;
+            }
+            this.runningRemoteAnimation = runningRemoteAnimation;
+            if (DEBUG_OOM_ADJ) {
+                Slog.i(TAG, "Setting runningRemoteAnimation=" + runningRemoteAnimation
+                        + " for pid=" + pid);
+            }
+            mService.updateOomAdjLocked(this, true, OomAdjuster.OOM_ADJ_REASON_UI_VISIBILITY);
+        }
+    }
+
     public long getInputDispatchingTimeout() {
         return mWindowProcessController.getInputDispatchingTimeout();
     }
diff --git a/services/core/java/com/android/server/camera/CameraServiceProxy.java b/services/core/java/com/android/server/camera/CameraServiceProxy.java
index 8de2595..b46f034 100644
--- a/services/core/java/com/android/server/camera/CameraServiceProxy.java
+++ b/services/core/java/com/android/server/camera/CameraServiceProxy.java
@@ -15,6 +15,7 @@
  */
 package com.android.server.camera;
 
+import android.annotation.IntDef;
 import android.content.BroadcastReceiver;
 import android.content.Context;
 import android.content.Intent;
@@ -44,6 +45,8 @@
 import com.android.server.SystemService;
 import com.android.server.wm.WindowManagerInternal;
 
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
 import java.util.ArrayList;
 import java.util.Collection;
 import java.util.Collections;
@@ -100,7 +103,26 @@
     private static final String NFC_SERVICE_BINDER_NAME = "nfc";
     private static final IBinder nfcInterfaceToken = new Binder();
 
-    private final boolean mNotifyNfc;
+    // Valid values for NFC_NOTIFICATION_PROP
+    // Do not disable active NFC for any camera use
+    private static final int NFC_NOTIFY_NONE = 0;
+    // Always disable active NFC for any camera use
+    private static final int NFC_NOTIFY_ALL = 1;
+     // Disable active NFC only for back-facing cameras
+    private static final int NFC_NOTIFY_BACK = 2;
+    // Disable active NFC only for front-facing cameras
+    private static final int NFC_NOTIFY_FRONT = 3;
+
+    @Retention(RetentionPolicy.SOURCE)
+    @IntDef(prefix = {"NFC_"}, value =
+         {NFC_NOTIFY_NONE,
+          NFC_NOTIFY_ALL,
+          NFC_NOTIFY_BACK,
+          NFC_NOTIFY_FRONT})
+    private @interface NfcNotifyState {};
+
+    private final @NfcNotifyState int mNotifyNfc;
+    private boolean mLastNfcPollState = true;
 
     /**
      * Structure to track camera usage
@@ -202,8 +224,12 @@
         mHandlerThread.start();
         mHandler = new Handler(mHandlerThread.getLooper(), this);
 
-        mNotifyNfc = SystemProperties.getInt(NFC_NOTIFICATION_PROP, 0) > 0;
-        if (DEBUG) Slog.v(TAG, "Notify NFC behavior is " + (mNotifyNfc ? "active" : "disabled"));
+        int notifyNfc = SystemProperties.getInt(NFC_NOTIFICATION_PROP, 0);
+        if (notifyNfc < NFC_NOTIFY_NONE || notifyNfc > NFC_NOTIFY_FRONT) {
+            notifyNfc = NFC_NOTIFY_NONE;
+        }
+        mNotifyNfc = notifyNfc;
+        if (DEBUG) Slog.v(TAG, "Notify NFC state is " + nfcNotifyToString(mNotifyNfc));
     }
 
     @Override
@@ -270,12 +296,10 @@
             mCameraServiceRaw = null;
 
             // All cameras reset to idle on camera service death
-            boolean wasEmpty = mActiveCameraUsage.isEmpty();
             mActiveCameraUsage.clear();
 
-            if ( mNotifyNfc && !wasEmpty ) {
-                notifyNfcService(/*enablePolling*/ true);
-            }
+            // Ensure NFC is back on
+            notifyNfcService(/*enablePolling*/ true);
         }
     }
 
@@ -474,14 +498,32 @@
 
                     break;
             }
-            boolean isEmpty = mActiveCameraUsage.isEmpty();
-            if ( mNotifyNfc && (wasEmpty != isEmpty) ) {
-                notifyNfcService(isEmpty);
+            switch (mNotifyNfc) {
+                case NFC_NOTIFY_NONE:
+                    break;
+                case NFC_NOTIFY_ALL:
+                    notifyNfcService(mActiveCameraUsage.isEmpty());
+                    break;
+                case NFC_NOTIFY_BACK:
+                case NFC_NOTIFY_FRONT:
+                    boolean enablePolling = true;
+                    int targetFacing = mNotifyNfc == NFC_NOTIFY_BACK
+                            ? ICameraServiceProxy.CAMERA_FACING_BACK :
+                              ICameraServiceProxy.CAMERA_FACING_FRONT;
+                    for (int i = 0; i < mActiveCameraUsage.size(); i++) {
+                        if (mActiveCameraUsage.valueAt(i).mCameraFacing == targetFacing) {
+                            enablePolling = false;
+                            break;
+                        }
+                    }
+                    notifyNfcService(enablePolling);
+                    break;
             }
         }
     }
 
     private void notifyNfcService(boolean enablePolling) {
+        if (enablePolling == mLastNfcPollState) return;
 
         IBinder nfcServiceBinder = getBinderService(NFC_SERVICE_BINDER_NAME);
         if (nfcServiceBinder == null) {
@@ -490,9 +532,14 @@
         }
         INfcAdapter nfcAdapterRaw = INfcAdapter.Stub.asInterface(nfcServiceBinder);
         int flags = enablePolling ? ENABLE_POLLING_FLAGS : DISABLE_POLLING_FLAGS;
-        if (DEBUG) Slog.v(TAG, "Setting NFC reader mode to flags " + flags);
+        if (DEBUG) {
+            Slog.v(TAG, "Setting NFC reader mode to flags " + flags
+                    + " to turn polling " + enablePolling);
+        }
+
         try {
             nfcAdapterRaw.setReaderMode(nfcInterfaceToken, null, flags, null);
+            mLastNfcPollState = enablePolling;
         } catch (RemoteException e) {
             Slog.w(TAG, "Could not notify NFC service, remote exception: " + e);
         }
@@ -529,4 +576,13 @@
         return "CAMERA_FACING_UNKNOWN";
     }
 
+    private static String nfcNotifyToString(@NfcNotifyState int nfcNotifyState) {
+        switch (nfcNotifyState) {
+            case NFC_NOTIFY_NONE: return "NFC_NOTIFY_NONE";
+            case NFC_NOTIFY_ALL: return "NFC_NOTIFY_ALL";
+            case NFC_NOTIFY_BACK: return "NFC_NOTIFY_BACK";
+            case NFC_NOTIFY_FRONT: return "NFC_NOTIFY_FRONT";
+        }
+        return "UNKNOWN_NFC_NOTIFY";
+    }
 }
diff --git a/services/core/java/com/android/server/connectivity/Tethering.java b/services/core/java/com/android/server/connectivity/Tethering.java
index 4957eed..73d160d 100644
--- a/services/core/java/com/android/server/connectivity/Tethering.java
+++ b/services/core/java/com/android/server/connectivity/Tethering.java
@@ -772,7 +772,6 @@
                     case WifiManager.WIFI_AP_STATE_FAILED:
                     default:
                         disableWifiIpServingLocked(ifname, curState);
-                        mEntitlementMgr.stopProvisioningIfNeeded(TETHERING_WIFI);
                         break;
                 }
             }
diff --git a/services/core/java/com/android/server/display/DisplayModeDirector.java b/services/core/java/com/android/server/display/DisplayModeDirector.java
index 78a48da..c45a314 100644
--- a/services/core/java/com/android/server/display/DisplayModeDirector.java
+++ b/services/core/java/com/android/server/display/DisplayModeDirector.java
@@ -728,6 +728,7 @@
 
         private SensorManager mSensorManager;
         private Sensor mLightSensor;
+        private LightSensorEventListener mLightSensorListener = new LightSensorEventListener();
         // Take it as low brightness before valid sensor data comes
         private float mAmbientLux = -1.0f;
         private AmbientFilter mAmbientFilter;
@@ -907,19 +908,40 @@
                 mSensorManager.registerListener(mLightSensorListener,
                         mLightSensor, LIGHT_SENSOR_RATE_MS * 1000, mHandler);
             } else {
+                mLightSensorListener.removeCallbacks();
                 mSensorManager.unregisterListener(mLightSensorListener);
             }
         }
 
-        private final SensorEventListener mLightSensorListener = new SensorEventListener() {
+        private final class LightSensorEventListener implements SensorEventListener {
+            final private static int INJECT_EVENTS_INTERVAL_MS = LIGHT_SENSOR_RATE_MS;
+            private float mLastSensorData;
+
             @Override
             public void onSensorChanged(SensorEvent event) {
-                long now = SystemClock.uptimeMillis();
-                mAmbientFilter.addValue(now, event.values[0]);
-                mAmbientLux = mAmbientFilter.getEstimate(now);
+                mLastSensorData = event.values[0];
+                if (DEBUG) {
+                    Slog.d(TAG, "On sensor changed: " + mLastSensorData);
+                }
 
-                synchronized (mLock) {
-                    onBrightnessChangedLocked();
+                boolean zoneChanged = isDifferentZone(mLastSensorData, mAmbientLux);
+                if (zoneChanged && mLastSensorData < mAmbientLux) {
+                    // Easier to see flicker at lower brightness environment. Forget the history to
+                    // get immediate response.
+                    mAmbientFilter.clear();
+                }
+
+                long now = SystemClock.uptimeMillis();
+                mAmbientFilter.addValue(now, mLastSensorData);
+
+                mHandler.removeCallbacks(mInjectSensorEventRunnable);
+                processSensorData(now);
+
+                if (zoneChanged && mLastSensorData > mAmbientLux) {
+                    // Sensor may not report new event if there is no brightness change.
+                    // Need to keep querying the temporal filter for the latest estimation,
+                    // until enter in higher lux zone or is interrupted by a new sensor event.
+                    mHandler.postDelayed(mInjectSensorEventRunnable, INJECT_EVENTS_INTERVAL_MS);
                 }
             }
 
@@ -927,6 +949,47 @@
             public void onAccuracyChanged(Sensor sensor, int accuracy) {
                 // Not used.
             }
+
+            public void removeCallbacks() {
+                mHandler.removeCallbacks(mInjectSensorEventRunnable);
+            }
+
+            private void processSensorData(long now) {
+                mAmbientLux = mAmbientFilter.getEstimate(now);
+
+                synchronized (mLock) {
+                    onBrightnessChangedLocked();
+                }
+            }
+
+            private boolean isDifferentZone(float lux1, float lux2) {
+                for (int z = 0; z < mAmbientBrightnessThresholds.length; z++) {
+                    final float boundary = mAmbientBrightnessThresholds[z];
+
+                    // Test each boundary. See if the current value and the new value are at
+                    // different sides.
+                    if ((lux1 <= boundary && lux2 > boundary)
+                            || (lux1 > boundary && lux2 <= boundary)) {
+                        return true;
+                    }
+                }
+
+                return false;
+            }
+
+            private Runnable mInjectSensorEventRunnable = new Runnable() {
+                @Override
+                public void run() {
+                    long now = SystemClock.uptimeMillis();
+                    // No need to really inject the last event into a temporal filter.
+                    processSensorData(now);
+
+                    // Inject next event if there is a possible zone change.
+                    if (isDifferentZone(mLastSensorData, mAmbientLux)) {
+                        mHandler.postDelayed(mInjectSensorEventRunnable, INJECT_EVENTS_INTERVAL_MS);
+                    }
+                }
+            };
         };
 
         private final class ScreenStateReceiver extends BroadcastReceiver {
diff --git a/services/core/java/com/android/server/om/IdmapDaemon.java b/services/core/java/com/android/server/om/IdmapDaemon.java
new file mode 100644
index 0000000..91824c3
--- /dev/null
+++ b/services/core/java/com/android/server/om/IdmapDaemon.java
@@ -0,0 +1,194 @@
+/*
+ * 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 com.android.server.om;
+
+import static android.content.Context.IDMAP_SERVICE;
+
+import static com.android.server.om.OverlayManagerService.DEBUG;
+import static com.android.server.om.OverlayManagerService.TAG;
+
+import android.os.IBinder;
+import android.os.IIdmap2;
+import android.os.RemoteException;
+import android.os.ServiceManager;
+import android.os.SystemProperties;
+import android.util.Slog;
+
+import com.android.server.FgThread;
+
+import java.util.concurrent.FutureTask;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.atomic.AtomicInteger;
+
+/**
+ * To prevent idmap2d from continuously running, the idmap daemon will terminate after 10
+ * seconds without a transaction.
+ **/
+class IdmapDaemon {
+    // The amount of time in milliseconds to wait after a transaction to the idmap service is made
+    // before stopping the service.
+    private static final int SERVICE_TIMEOUT_MS = 10000;
+
+    // The amount of time in milliseconds to wait when attempting to connect to idmap service.
+    private static final int SERVICE_CONNECT_TIMEOUT_MS = 5000;
+
+    private static final Object IDMAP_TOKEN = new Object();
+    private static final String IDMAP_DAEMON = "idmap2d";
+
+    private static IdmapDaemon sInstance;
+    private volatile IIdmap2 mService;
+    private final AtomicInteger mOpenedCount = new AtomicInteger();
+
+    /**
+     * An {@link AutoCloseable} connection to the idmap service. When the connection is closed or
+     * finalized, the idmap service will be stopped after a period of time unless another connection
+     * to the service is open.
+     **/
+    private class Connection implements AutoCloseable {
+        private boolean mOpened = true;
+
+        private Connection() {
+            synchronized (IDMAP_TOKEN) {
+                mOpenedCount.incrementAndGet();
+            }
+        }
+
+        @Override
+        public void close() {
+            synchronized (IDMAP_TOKEN) {
+                if (!mOpened) {
+                    return;
+                }
+
+                mOpened = false;
+                if (mOpenedCount.decrementAndGet() != 0) {
+                    // Only post the callback to stop the service if the service does not have an
+                    // open connection.
+                    return;
+                }
+
+                FgThread.getHandler().postDelayed(() -> {
+                    synchronized (IDMAP_TOKEN) {
+                        // Only stop the service if the service does not have an open connection.
+                        if (mService == null || mOpenedCount.get() != 0) {
+                            return;
+                        }
+
+                        stopIdmapService();
+                        mService = null;
+                    }
+                }, IDMAP_TOKEN, SERVICE_TIMEOUT_MS);
+            }
+        }
+    }
+
+    static IdmapDaemon getInstance() {
+        if (sInstance == null) {
+            sInstance = new IdmapDaemon();
+        }
+        return sInstance;
+    }
+
+    String createIdmap(String targetPath, String overlayPath, int policies, boolean enforce,
+            int userId) throws Exception {
+        try (Connection connection = connect()) {
+            return mService.createIdmap(targetPath, overlayPath, policies, enforce, userId);
+        }
+    }
+
+    boolean removeIdmap(String overlayPath, int userId) throws Exception {
+        try (Connection connection = connect()) {
+            return mService.removeIdmap(overlayPath, userId);
+        }
+    }
+
+    boolean verifyIdmap(String overlayPath, int policies, boolean enforce, int userId)
+            throws Exception {
+        try (Connection connection = connect()) {
+            return mService.verifyIdmap(overlayPath, policies, enforce, userId);
+        }
+    }
+
+    String getIdmapPath(String overlayPath, int userId) throws Exception {
+        try (Connection connection = connect()) {
+            return mService.getIdmapPath(overlayPath, userId);
+        }
+    }
+
+    static void startIdmapService() {
+        SystemProperties.set("ctl.start", IDMAP_DAEMON);
+    }
+
+    static void stopIdmapService() {
+        SystemProperties.set("ctl.stop", IDMAP_DAEMON);
+    }
+
+    private Connection connect() throws Exception {
+        synchronized (IDMAP_TOKEN) {
+            FgThread.getHandler().removeCallbacksAndMessages(IDMAP_TOKEN);
+            if (mService != null) {
+                // Not enough time has passed to stop the idmap service. Reuse the existing
+                // interface.
+                return new Connection();
+            }
+
+            // Start the idmap service if it is not currently running.
+            startIdmapService();
+
+            // Block until the service is found.
+            FutureTask<IBinder> bindIdmap = new FutureTask<>(() -> {
+                while (true) {
+                    try {
+                        IBinder binder = ServiceManager.getService(IDMAP_SERVICE);
+                        if (binder != null) {
+                            return binder;
+                        }
+                    } catch (Exception e) {
+                        Slog.e(TAG, "service '" + IDMAP_SERVICE + "' not retrieved; "
+                                + e.getMessage());
+                    }
+                    Thread.sleep(100);
+                }
+            });
+
+            IBinder binder;
+            try {
+                FgThread.getHandler().postAtFrontOfQueue(bindIdmap);
+                binder = bindIdmap.get(SERVICE_CONNECT_TIMEOUT_MS, TimeUnit.MILLISECONDS);
+            } catch (Exception rethrow) {
+                Slog.e(TAG, "service '" + IDMAP_SERVICE + "' not found;");
+                throw rethrow;
+            }
+
+            try {
+                binder.linkToDeath(() -> {
+                    Slog.w(TAG, "service '" + IDMAP_SERVICE + "' died");
+                }, 0);
+            } catch (RemoteException rethrow) {
+                Slog.e(TAG, "service '" + IDMAP_SERVICE + "' failed to be bound");
+                throw rethrow;
+            }
+
+            mService = IIdmap2.Stub.asInterface(binder);
+            if (DEBUG) {
+                Slog.d(TAG, "service '" + IDMAP_SERVICE + "' connected");
+            }
+
+            return new Connection();
+        }
+    }
+}
diff --git a/services/core/java/com/android/server/om/IdmapManager.java b/services/core/java/com/android/server/om/IdmapManager.java
index b604aa8..9b6d986 100644
--- a/services/core/java/com/android/server/om/IdmapManager.java
+++ b/services/core/java/com/android/server/om/IdmapManager.java
@@ -16,9 +16,6 @@
 
 package com.android.server.om;
 
-import static android.content.Context.IDMAP_SERVICE;
-import static android.text.format.DateUtils.SECOND_IN_MILLIS;
-
 import static com.android.server.om.OverlayManagerService.DEBUG;
 import static com.android.server.om.OverlayManagerService.TAG;
 
@@ -27,15 +24,11 @@
 import android.content.pm.ApplicationInfo;
 import android.content.pm.PackageInfo;
 import android.os.Build.VERSION_CODES;
-import android.os.IBinder;
 import android.os.IIdmap2;
-import android.os.RemoteException;
-import android.os.ServiceManager;
 import android.os.SystemProperties;
 import android.os.UserHandle;
 import android.util.Slog;
 
-import com.android.internal.os.BackgroundThread;
 import com.android.server.om.OverlayManagerServiceImpl.PackageManagerHelper;
 import com.android.server.pm.Installer;
 
@@ -51,11 +44,6 @@
  */
 class IdmapManager {
     private static final boolean FEATURE_FLAG_IDMAP2 = true;
-
-    private final Installer mInstaller;
-    private final PackageManagerHelper mPackageManager;
-    private IIdmap2 mIdmap2Service;
-
     private static final boolean VENDOR_IS_Q_OR_LATER;
     static {
         final String value = SystemProperties.get("ro.vndk.version", "29");
@@ -70,12 +58,14 @@
         VENDOR_IS_Q_OR_LATER = isQOrLater;
     }
 
+    private final Installer mInstaller;
+    private final PackageManagerHelper mPackageManager;
+    private final IdmapDaemon mIdmapDaemon;
+
     IdmapManager(final Installer installer, final PackageManagerHelper packageManager) {
         mInstaller = installer;
         mPackageManager = packageManager;
-        if (FEATURE_FLAG_IDMAP2) {
-            connectToIdmap2d();
-        }
+        mIdmapDaemon = IdmapDaemon.getInstance();
     }
 
     boolean createIdmap(@NonNull final PackageInfo targetPackage,
@@ -91,11 +81,11 @@
             if (FEATURE_FLAG_IDMAP2) {
                 int policies = calculateFulfilledPolicies(targetPackage, overlayPackage, userId);
                 boolean enforce = enforceOverlayable(overlayPackage);
-                if (mIdmap2Service.verifyIdmap(overlayPath, policies, enforce, userId)) {
+                if (mIdmapDaemon.verifyIdmap(overlayPath, policies, enforce, userId)) {
                     return true;
                 }
-                return mIdmap2Service.createIdmap(targetPath, overlayPath, policies, enforce,
-                    userId) != null;
+                return mIdmapDaemon.createIdmap(targetPath, overlayPath, policies,
+                        enforce, userId) != null;
             } else {
                 mInstaller.idmap(targetPath, overlayPath, sharedGid);
                 return true;
@@ -113,7 +103,7 @@
         }
         try {
             if (FEATURE_FLAG_IDMAP2) {
-                return mIdmap2Service.removeIdmap(oi.baseCodePath, userId);
+                return mIdmapDaemon.removeIdmap(oi.baseCodePath, userId);
             } else {
                 mInstaller.removeIdmap(oi.baseCodePath);
                 return true;
@@ -137,7 +127,7 @@
             final int userId) {
         if (FEATURE_FLAG_IDMAP2) {
             try {
-                return mIdmap2Service.getIdmapPath(overlayPackagePath, userId);
+                return mIdmapDaemon.getIdmapPath(overlayPackagePath, userId);
             } catch (Exception e) {
                 Slog.w(TAG, "failed to get idmap path for " + overlayPackagePath + ": "
                         + e.getMessage());
@@ -151,35 +141,6 @@
         }
     }
 
-    private void connectToIdmap2d() {
-        IBinder binder = ServiceManager.getService(IDMAP_SERVICE);
-        if (binder != null) {
-            try {
-                binder.linkToDeath(new IBinder.DeathRecipient() {
-                    @Override
-                    public void binderDied() {
-                        Slog.w(TAG, "service '" + IDMAP_SERVICE + "' died; reconnecting...");
-                        connectToIdmap2d();
-                    }
-
-                }, 0);
-            } catch (RemoteException e) {
-                binder = null;
-            }
-        }
-        if (binder != null) {
-            mIdmap2Service = IIdmap2.Stub.asInterface(binder);
-            if (DEBUG) {
-                Slog.d(TAG, "service '" + IDMAP_SERVICE + "' connected");
-            }
-        } else {
-            Slog.w(TAG, "service '" + IDMAP_SERVICE + "' not found; trying again...");
-            BackgroundThread.getHandler().postDelayed(() -> {
-                connectToIdmap2d();
-            }, SECOND_IN_MILLIS);
-        }
-    }
-
     /**
      * Checks if overlayable and policies should be enforced on the specified overlay for backwards
      * compatibility with pre-Q overlays.
diff --git a/services/core/java/com/android/server/om/OverlayManagerService.java b/services/core/java/com/android/server/om/OverlayManagerService.java
index da69986..ce95181 100644
--- a/services/core/java/com/android/server/om/OverlayManagerService.java
+++ b/services/core/java/com/android/server/om/OverlayManagerService.java
@@ -262,6 +262,7 @@
 
             initIfNeeded();
             onSwitchUser(UserHandle.USER_SYSTEM);
+            IdmapDaemon.stopIdmapService();
 
             publishBinderService(Context.OVERLAY_SERVICE, mService);
             publishLocalService(OverlayManagerService.class, this);
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index 7cbf919..a7d436a 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -320,7 +320,6 @@
 import com.android.server.pm.permission.PermissionManagerServiceInternal.PermissionCallback;
 import com.android.server.pm.permission.PermissionsState;
 import com.android.server.policy.PermissionPolicyInternal;
-import com.android.server.policy.PermissionPolicyInternal.OnInitializedCallback;
 import com.android.server.security.VerityUtils;
 import com.android.server.storage.DeviceStorageMonitorInternal;
 import com.android.server.wm.ActivityTaskManagerInternal;
@@ -11033,14 +11032,15 @@
         final String realPkgName = request.realPkgName;
         final List<String> changedAbiCodePath = result.changedAbiCodePath;
         final PackageSetting pkgSetting;
+        if (request.pkgSetting != null && request.pkgSetting.sharedUser != null
+                && request.pkgSetting.sharedUser != result.pkgSetting.sharedUser) {
+            // shared user changed, remove from old shared user
+            request.pkgSetting.sharedUser.removePackage(request.pkgSetting);
+        }
         if (result.existingSettingCopied) {
             pkgSetting = request.pkgSetting;
             pkgSetting.updateFrom(result.pkgSetting);
             pkg.mExtras = pkgSetting;
-            if (pkgSetting.sharedUser != null
-                    && pkgSetting.sharedUser.removePackage(result.pkgSetting)) {
-                pkgSetting.sharedUser.addPackage(pkgSetting);
-            }
         } else {
             pkgSetting = result.pkgSetting;
             if (originalPkgSetting != null) {
@@ -11050,6 +11050,9 @@
                 mTransferedPackages.add(originalPkgSetting.name);
             }
         }
+        if (pkgSetting.sharedUser != null) {
+            pkgSetting.sharedUser.addPackage(pkgSetting);
+        }
         // TODO(toddke): Consider a method specifically for modifying the Package object
         // post scan; or, moving this stuff out of the Package object since it has nothing
         // to do with the package on disk.
diff --git a/services/core/java/com/android/server/pm/permission/PermissionManagerService.java b/services/core/java/com/android/server/pm/permission/PermissionManagerService.java
index 8884821..899f802 100644
--- a/services/core/java/com/android/server/pm/permission/PermissionManagerService.java
+++ b/services/core/java/com/android/server/pm/permission/PermissionManagerService.java
@@ -2098,7 +2098,8 @@
 
         final PackageParser.Package pkg = mPackageManagerInt.getPackage(packageName);
         if (pkg == null || pkg.mExtras == null) {
-            throw new IllegalArgumentException("Unknown package: " + packageName);
+            Log.e(TAG, "Unknown package: " + packageName);
+            return;
         }
         final BasePermission bp;
         synchronized(mLock) {
@@ -2239,7 +2240,8 @@
 
         final PackageParser.Package pkg = mPackageManagerInt.getPackage(packageName);
         if (pkg == null || pkg.mExtras == null) {
-            throw new IllegalArgumentException("Unknown package: " + packageName);
+            Log.e(TAG, "Unknown package: " + packageName);
+            return;
         }
         if (mPackageManagerInt.filterAppAccess(pkg, Binder.getCallingUid(), userId)) {
             throw new IllegalArgumentException("Unknown package: " + packageName);
diff --git a/services/core/java/com/android/server/power/AttentionDetector.java b/services/core/java/com/android/server/power/AttentionDetector.java
index 56d8396..4e9b724 100644
--- a/services/core/java/com/android/server/power/AttentionDetector.java
+++ b/services/core/java/com/android/server/power/AttentionDetector.java
@@ -161,7 +161,7 @@
 
         context.getContentResolver().registerContentObserver(Settings.System.getUriFor(
                 Settings.System.ADAPTIVE_SLEEP),
-                false, new ContentObserver(new Handler()) {
+                false, new ContentObserver(new Handler(context.getMainLooper())) {
                     @Override
                     public void onChange(boolean selfChange) {
                         updateEnabledFromSettings(context);
diff --git a/services/core/java/com/android/server/power/PowerManagerService.java b/services/core/java/com/android/server/power/PowerManagerService.java
index cfd3ae6..aa49ba6 100644
--- a/services/core/java/com/android/server/power/PowerManagerService.java
+++ b/services/core/java/com/android/server/power/PowerManagerService.java
@@ -2724,6 +2724,14 @@
                 return true;
             }
         }
+
+        if (mDisplayPowerRequest.policy == DisplayPowerRequest.POLICY_DOZE
+                && mDisplayPowerRequest.dozeScreenState == Display.STATE_ON) {
+            // Although we are in DOZE and would normally allow the device to suspend,
+            // the doze service has explicitly requested the display to remain in the ON
+            // state which means we should hold the display suspend blocker.
+            return true;
+        }
         if (mScreenBrightnessBoostInProgress) {
             return true;
         }
@@ -4858,7 +4866,8 @@
         }
     }
 
-    private final class LocalService extends PowerManagerInternal {
+    @VisibleForTesting
+    final class LocalService extends PowerManagerInternal {
         @Override
         public void setScreenBrightnessOverrideFromWindowManager(int screenBrightness) {
             if (screenBrightness < PowerManager.BRIGHTNESS_DEFAULT
diff --git a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
index 8a9dfc7..747837b 100644
--- a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
+++ b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
@@ -1462,16 +1462,18 @@
             @Nullable IRecentsAnimationRunner recentsAnimationRunner) {
         enforceCallerIsRecentsOrHasPermission(MANAGE_ACTIVITY_STACKS, "startRecentsActivity()");
         final int callingPid = Binder.getCallingPid();
+        final int callingUid = Binder.getCallingUid();
         final long origId = Binder.clearCallingIdentity();
         try {
             synchronized (mGlobalLock) {
                 final ComponentName recentsComponent = mRecentTasks.getRecentsComponent();
                 final int recentsUid = mRecentTasks.getRecentsComponentUid();
+                final WindowProcessController caller = getProcessController(callingPid, callingUid);
 
                 // Start a new recents animation
                 final RecentsAnimation anim = new RecentsAnimation(this, mStackSupervisor,
                         getActivityStartController(), mWindowManager, intent, recentsComponent,
-                        recentsUid, callingPid);
+                        recentsUid, caller);
                 if (recentsAnimationRunner == null) {
                     anim.preloadRecentsActivity();
                 } else {
@@ -4650,7 +4652,7 @@
     public void registerRemoteAnimations(IBinder token, RemoteAnimationDefinition definition) {
         mAmInternal.enforceCallingPermission(CONTROL_REMOTE_APP_TRANSITION_ANIMATIONS,
                 "registerRemoteAnimations");
-        definition.setCallingPid(Binder.getCallingPid());
+        definition.setCallingPidUid(Binder.getCallingPid(), Binder.getCallingUid());
         synchronized (mGlobalLock) {
             final ActivityRecord r = ActivityRecord.isInStackLocked(token);
             if (r == null) {
@@ -4670,7 +4672,7 @@
             RemoteAnimationAdapter adapter) {
         mAmInternal.enforceCallingPermission(CONTROL_REMOTE_APP_TRANSITION_ANIMATIONS,
                 "registerRemoteAnimationForNextActivityStart");
-        adapter.setCallingPid(Binder.getCallingPid());
+        adapter.setCallingPidUid(Binder.getCallingPid(), Binder.getCallingUid());
         synchronized (mGlobalLock) {
             final long origId = Binder.clearCallingIdentity();
             try {
@@ -4687,7 +4689,7 @@
             RemoteAnimationDefinition definition) {
         mAmInternal.enforceCallingPermission(CONTROL_REMOTE_APP_TRANSITION_ANIMATIONS,
                 "registerRemoteAnimations");
-        definition.setCallingPid(Binder.getCallingPid());
+        definition.setCallingPidUid(Binder.getCallingPid(), Binder.getCallingUid());
         synchronized (mGlobalLock) {
             final ActivityDisplay display = mRootActivityContainer.getActivityDisplay(displayId);
             if (display == null) {
diff --git a/services/core/java/com/android/server/wm/AppWindowToken.java b/services/core/java/com/android/server/wm/AppWindowToken.java
index 6c577e1..f1a9e60 100644
--- a/services/core/java/com/android/server/wm/AppWindowToken.java
+++ b/services/core/java/com/android/server/wm/AppWindowToken.java
@@ -206,6 +206,7 @@
     boolean removed;
 
     // Information about an application starting window if displayed.
+    // Note: these are de-referenced before the starting window animates away.
     StartingData mStartingData;
     WindowState startingWindow;
     StartingSurface startingSurface;
@@ -1243,6 +1244,21 @@
         return true;
     }
 
+    /**
+     * @return {@code true} if starting window is in app's hierarchy.
+     */
+    boolean hasStartingWindow() {
+        if (startingDisplayed || mStartingData != null) {
+            return true;
+        }
+        for (int i = mChildren.size() - 1; i >= 0; i--) {
+            if (getChildAt(i).mAttrs.type == TYPE_APPLICATION_STARTING) {
+                return true;
+            }
+        }
+        return false;
+    }
+
     @Override
     void addWindow(WindowState w) {
         super.addWindow(w);
diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java
index a1b8760..e099a4f 100644
--- a/services/core/java/com/android/server/wm/DisplayContent.java
+++ b/services/core/java/com/android/server/wm/DisplayContent.java
@@ -67,6 +67,7 @@
 import static android.view.WindowManager.LayoutParams.TYPE_DREAM;
 import static android.view.WindowManager.LayoutParams.TYPE_INPUT_METHOD;
 import static android.view.WindowManager.LayoutParams.TYPE_INPUT_METHOD_DIALOG;
+import static android.view.WindowManager.LayoutParams.TYPE_NAVIGATION_BAR;
 import static android.view.WindowManager.LayoutParams.TYPE_STATUS_BAR;
 import static android.view.WindowManager.LayoutParams.TYPE_SYSTEM_DIALOG;
 import static android.view.WindowManager.LayoutParams.TYPE_SYSTEM_ERROR;
@@ -137,6 +138,8 @@
 import static com.android.server.wm.WindowManagerService.WINDOW_FREEZE_TIMEOUT_DURATION;
 import static com.android.server.wm.WindowManagerService.dipToPixel;
 import static com.android.server.wm.WindowManagerService.logSurface;
+import static com.android.server.wm.WindowState.EXCLUSION_LEFT;
+import static com.android.server.wm.WindowState.EXCLUSION_RIGHT;
 import static com.android.server.wm.WindowState.RESIZE_HANDLE_WIDTH_IN_DP;
 import static com.android.server.wm.WindowStateAnimator.DRAW_PENDING;
 import static com.android.server.wm.WindowStateAnimator.READY_TO_SHOW;
@@ -330,6 +333,8 @@
     private final RemoteCallbackList<ISystemGestureExclusionListener>
             mSystemGestureExclusionListeners = new RemoteCallbackList<>();
     private final Region mSystemGestureExclusion = new Region();
+    private boolean mSystemGestureExclusionWasRestricted = false;
+    private final Region mSystemGestureExclusionUnrestricted = new Region();
     private int mSystemGestureExclusionLimit;
 
     /**
@@ -4845,9 +4850,13 @@
         //
         // In the case where we have no IME target we assign it where it's base layer would
         // place it in the AboveAppWindowContainers.
-        if (imeTarget != null && !(imeTarget.inSplitScreenWindowingMode()
-                || imeTarget.mToken.isAppAnimating())
-                && (imeTarget.getSurfaceControl() != null)) {
+        //
+        // Keep IME window in mAboveAppWindowsContainers as long as app's starting window exists
+        // so it get's layered above the starting window.
+        if (imeTarget != null
+                && !(imeTarget.mAppToken != null && imeTarget.mAppToken.hasStartingWindow())
+                && (!(imeTarget.inSplitScreenWindowingMode() || imeTarget.mToken.isAppAnimating())
+                && (imeTarget.getSurfaceControl() != null))) {
             mImeWindowsContainers.assignRelativeLayer(t, imeTarget.getSurfaceControl(),
                     // TODO: We need to use an extra level on the app surface to ensure
                     // this is always above SurfaceView but always below attached window.
@@ -5135,16 +5144,21 @@
             return false;
         }
 
-        final Region systemGestureExclusion = calculateSystemGestureExclusion();
+        final Region systemGestureExclusion = Region.obtain();
+        mSystemGestureExclusionWasRestricted = calculateSystemGestureExclusion(
+                systemGestureExclusion, mSystemGestureExclusionUnrestricted);
         try {
             if (mSystemGestureExclusion.equals(systemGestureExclusion)) {
                 return false;
             }
             mSystemGestureExclusion.set(systemGestureExclusion);
+            final Region unrestrictedOrNull = mSystemGestureExclusionWasRestricted
+                    ? mSystemGestureExclusionUnrestricted : null;
             for (int i = mSystemGestureExclusionListeners.beginBroadcast() - 1; i >= 0; --i) {
                 try {
                     mSystemGestureExclusionListeners.getBroadcastItem(i)
-                            .onSystemGestureExclusionChanged(mDisplayId, systemGestureExclusion);
+                            .onSystemGestureExclusionChanged(mDisplayId, systemGestureExclusion,
+                                    unrestrictedOrNull);
                 } catch (RemoteException e) {
                     Slog.e(TAG, "Failed to notify SystemGestureExclusionListener", e);
                 }
@@ -5156,8 +5170,22 @@
         }
     }
 
+    /**
+     * Calculates the system gesture exclusion.
+     *
+     * @param outExclusion will be set to the gesture exclusion region
+     * @param outExclusionUnrestricted will be set to the gesture exclusion region without
+     *                                 any restrictions applied.
+     * @return whether any restrictions were applied, i.e. outExclusion and outExclusionUnrestricted
+     *         differ.
+     */
     @VisibleForTesting
-    Region calculateSystemGestureExclusion() {
+    boolean calculateSystemGestureExclusion(Region outExclusion, @Nullable
+            Region outExclusionUnrestricted) {
+        outExclusion.setEmpty();
+        if (outExclusionUnrestricted != null) {
+            outExclusionUnrestricted.setEmpty();
+        }
         final Region unhandled = Region.obtain();
         unhandled.set(0, 0, mDisplayFrames.mDisplayWidth, mDisplayFrames.mDisplayHeight);
 
@@ -5166,7 +5194,6 @@
         final Rect rightEdge = mInsetsStateController.getSourceProvider(TYPE_RIGHT_GESTURES)
                 .getSource().getFrame();
 
-        final Region global = Region.obtain();
         final Region touchableRegion = Region.obtain();
         final Region local = Region.obtain();
         final int[] remainingLeftRight =
@@ -5204,28 +5231,39 @@
             if (needsGestureExclusionRestrictions(w, mLastDispatchedSystemUiVisibility)) {
 
                 // Processes the region along the left edge.
-                remainingLeftRight[0] = addToGlobalAndConsumeLimit(local, global, leftEdge,
-                        remainingLeftRight[0]);
+                remainingLeftRight[0] = addToGlobalAndConsumeLimit(local, outExclusion, leftEdge,
+                        remainingLeftRight[0], w, EXCLUSION_LEFT);
 
                 // Processes the region along the right edge.
-                remainingLeftRight[1] = addToGlobalAndConsumeLimit(local, global, rightEdge,
-                        remainingLeftRight[1]);
+                remainingLeftRight[1] = addToGlobalAndConsumeLimit(local, outExclusion, rightEdge,
+                        remainingLeftRight[1], w, EXCLUSION_RIGHT);
 
                 // Adds the middle (unrestricted area)
                 final Region middle = Region.obtain(local);
                 middle.op(leftEdge, Op.DIFFERENCE);
                 middle.op(rightEdge, Op.DIFFERENCE);
-                global.op(middle, Op.UNION);
+                outExclusion.op(middle, Op.UNION);
                 middle.recycle();
             } else {
-                global.op(local, Op.UNION);
+                boolean loggable = needsGestureExclusionRestrictions(w, 0 /* lastSysUiVis */);
+                if (loggable) {
+                    addToGlobalAndConsumeLimit(local, outExclusion, leftEdge,
+                            Integer.MAX_VALUE, w, EXCLUSION_LEFT);
+                    addToGlobalAndConsumeLimit(local, outExclusion, rightEdge,
+                            Integer.MAX_VALUE, w, EXCLUSION_RIGHT);
+                }
+                outExclusion.op(local, Op.UNION);
+            }
+            if (outExclusionUnrestricted != null) {
+                outExclusionUnrestricted.op(local, Op.UNION);
             }
             unhandled.op(touchableRegion, Op.DIFFERENCE);
         }, true /* topToBottom */);
         local.recycle();
         touchableRegion.recycle();
         unhandled.recycle();
-        return global;
+        return remainingLeftRight[0] < mSystemGestureExclusionLimit
+                || remainingLeftRight[1] < mSystemGestureExclusionLimit;
     }
 
     /**
@@ -5243,31 +5281,57 @@
     }
 
     /**
+     * @return Whether gesture exclusion area should be logged for the given window
+     */
+    static boolean logsGestureExclusionRestrictions(WindowState win) {
+        if (win.mWmService.mSystemGestureExclusionLogDebounceTimeoutMillis <= 0) {
+            return false;
+        }
+        final WindowManager.LayoutParams attrs = win.getAttrs();
+        final int type = attrs.type;
+        return type != TYPE_WALLPAPER
+                && type != TYPE_APPLICATION_STARTING
+                && type != TYPE_NAVIGATION_BAR
+                && (attrs.flags & FLAG_NOT_TOUCHABLE) == 0
+                && needsGestureExclusionRestrictions(win, 0 /* sysUiVisibility */)
+                && win.getDisplayContent().mDisplayPolicy.hasSideGestures();
+    }
+
+    /**
      * Adds a local gesture exclusion area to the global area while applying a limit per edge.
      *
      * @param local The gesture exclusion area to add.
      * @param global The destination.
      * @param edge Only processes the part in that region.
      * @param limit How much limit in pixels we have.
-     * @return How much of the limit are remaining.
+     * @param win The WindowState that is being processed
+     * @param side The side that is being processed, either {@link WindowState#EXCLUSION_LEFT} or
+     *             {@link WindowState#EXCLUSION_RIGHT}
+     * @return How much of the limit is remaining.
      */
     private static int addToGlobalAndConsumeLimit(Region local, Region global, Rect edge,
-            int limit) {
+            int limit, WindowState win, int side) {
         final Region r = Region.obtain(local);
         r.op(edge, Op.INTERSECT);
 
         final int[] remaining = {limit};
+        final int[] requestedExclusion = {0};
         forEachRectReverse(r, rect -> {
             if (remaining[0] <= 0) {
                 return;
             }
             final int height = rect.height();
+            requestedExclusion[0] += height;
             if (height > remaining[0]) {
                 rect.top = rect.bottom - remaining[0];
             }
             remaining[0] -= height;
             global.op(rect, Op.UNION);
         });
+
+        final int grantedExclusion = limit - remaining[0];
+        win.setLastExclusionHeights(side, requestedExclusion[0], grantedExclusion);
+
         r.recycle();
         return remaining[0];
     }
@@ -5282,10 +5346,13 @@
         }
 
         if (!changed) {
+            final Region unrestrictedOrNull = mSystemGestureExclusionWasRestricted
+                    ? mSystemGestureExclusionUnrestricted : null;
             // If updateSystemGestureExclusion changed the exclusion, it will already have
             // notified the listener. Otherwise, we'll do it here.
             try {
-                listener.onSystemGestureExclusionChanged(mDisplayId, mSystemGestureExclusion);
+                listener.onSystemGestureExclusionChanged(mDisplayId, mSystemGestureExclusion,
+                        unrestrictedOrNull);
             } catch (RemoteException e) {
                 Slog.e(TAG, "Failed to notify SystemGestureExclusionListener during register", e);
             }
diff --git a/services/core/java/com/android/server/wm/DisplayPolicy.java b/services/core/java/com/android/server/wm/DisplayPolicy.java
index cf87203..ed7dbd0 100644
--- a/services/core/java/com/android/server/wm/DisplayPolicy.java
+++ b/services/core/java/com/android/server/wm/DisplayPolicy.java
@@ -478,9 +478,10 @@
 
                     @Override
                     public void onSwipeFromRight() {
-                        final Region excludedRegion;
+                        final Region excludedRegion = Region.obtain();
                         synchronized (mLock) {
-                            excludedRegion = mDisplayContent.calculateSystemGestureExclusion();
+                            mDisplayContent.calculateSystemGestureExclusion(
+                                    excludedRegion, null /* outUnrestricted */);
                         }
                         final boolean sideAllowed = mNavigationBarAlwaysShowOnSideGesture
                                 || mNavigationBarPosition == NAV_BAR_RIGHT;
@@ -488,13 +489,15 @@
                                 && !mSystemGestures.currentGestureStartedInRegion(excludedRegion)) {
                             requestTransientBars(mNavigationBar);
                         }
+                        excludedRegion.recycle();
                     }
 
                     @Override
                     public void onSwipeFromLeft() {
-                        final Region excludedRegion;
+                        final Region excludedRegion = Region.obtain();
                         synchronized (mLock) {
-                            excludedRegion = mDisplayContent.calculateSystemGestureExclusion();
+                            mDisplayContent.calculateSystemGestureExclusion(
+                                    excludedRegion, null /* outUnrestricted */);
                         }
                         final boolean sideAllowed = mNavigationBarAlwaysShowOnSideGesture
                                 || mNavigationBarPosition == NAV_BAR_LEFT;
@@ -502,6 +505,7 @@
                                 && !mSystemGestures.currentGestureStartedInRegion(excludedRegion)) {
                             requestTransientBars(mNavigationBar);
                         }
+                        excludedRegion.recycle();
                     }
 
                     @Override
@@ -674,6 +678,10 @@
         return mHasStatusBar;
     }
 
+    boolean hasSideGestures() {
+        return mHasNavigationBar && mSideGestureInset > 0;
+    }
+
     public boolean navigationBarCanMove() {
         return mNavigationBarCanMove;
     }
diff --git a/services/core/java/com/android/server/wm/RecentsAnimation.java b/services/core/java/com/android/server/wm/RecentsAnimation.java
index 0a3e7a4..036bef7 100644
--- a/services/core/java/com/android/server/wm/RecentsAnimation.java
+++ b/services/core/java/com/android/server/wm/RecentsAnimation.java
@@ -33,6 +33,7 @@
 import static com.android.server.wm.RecentsAnimationController.REORDER_MOVE_TO_TOP;
 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_RECENTS_ANIMATIONS;
 
+import android.annotation.Nullable;
 import android.app.ActivityOptions;
 import android.content.ComponentName;
 import android.content.Intent;
@@ -60,7 +61,7 @@
     private final Intent mTargetIntent;
     private final ComponentName mRecentsComponent;
     private final int mRecentsUid;
-    private final int mCallingPid;
+    private final @Nullable WindowProcessController mCaller;
     private final int mUserId;
     private final int mTargetActivityType;
 
@@ -76,7 +77,8 @@
 
     RecentsAnimation(ActivityTaskManagerService atm, ActivityStackSupervisor stackSupervisor,
             ActivityStartController activityStartController, WindowManagerService wm,
-            Intent targetIntent, ComponentName recentsComponent, int recentsUid, int callingPid) {
+            Intent targetIntent, ComponentName recentsComponent, int recentsUid,
+            @Nullable WindowProcessController caller) {
         mService = atm;
         mStackSupervisor = stackSupervisor;
         mDefaultDisplay = mService.mRootActivityContainer.getDefaultDisplay();
@@ -85,7 +87,7 @@
         mTargetIntent = targetIntent;
         mRecentsComponent = recentsComponent;
         mRecentsUid = recentsUid;
-        mCallingPid = callingPid;
+        mCaller = caller;
         mUserId = atm.getCurrentUserId();
         mTargetActivityType = targetIntent.getComponent() != null
                 && recentsComponent.equals(targetIntent.getComponent())
@@ -190,7 +192,9 @@
 
         mStackSupervisor.getActivityMetricsLogger().notifyActivityLaunching(mTargetIntent);
 
-        mService.mH.post(() -> mService.mAmInternal.setRunningRemoteAnimation(mCallingPid, true));
+        if (mCaller != null) {
+            mCaller.setRunningRecentsAnimation(true);
+        }
 
         mWindowManager.deferSurfaceLayout();
         try {
@@ -286,8 +290,9 @@
                 mService.stopAppSwitches();
             }
 
-            mService.mH.post(
-                    () -> mService.mAmInternal.setRunningRemoteAnimation(mCallingPid, false));
+            if (mCaller != null) {
+                mCaller.setRunningRecentsAnimation(false);
+            }
 
             mWindowManager.inSurfaceTransaction(() -> {
                 Trace.traceBegin(TRACE_TAG_ACTIVITY_MANAGER,
@@ -453,7 +458,7 @@
     /**
      * Called only when the animation should be canceled prior to starting.
      */
-    private void notifyAnimationCancelBeforeStart(IRecentsAnimationRunner recentsAnimationRunner) {
+    static void notifyAnimationCancelBeforeStart(IRecentsAnimationRunner recentsAnimationRunner) {
         try {
             recentsAnimationRunner.onAnimationCanceled(false /* deferredWithScreenshot */);
         } catch (RemoteException e) {
diff --git a/services/core/java/com/android/server/wm/RemoteAnimationController.java b/services/core/java/com/android/server/wm/RemoteAnimationController.java
index b4bfedd..a1bc406 100644
--- a/services/core/java/com/android/server/wm/RemoteAnimationController.java
+++ b/services/core/java/com/android/server/wm/RemoteAnimationController.java
@@ -129,7 +129,7 @@
                 writeStartDebugStatement();
             }
         });
-        sendRunningRemoteAnimation(true);
+        setRunningRemoteAnimation(true);
     }
 
     void cancelAnimation(String reason) {
@@ -216,7 +216,7 @@
                 mService.closeSurfaceTransaction("RemoteAnimationController#finished");
             }
         }
-        sendRunningRemoteAnimation(false);
+        setRunningRemoteAnimation(false);
         if (DEBUG_REMOTE_ANIMATIONS) Slog.i(TAG, "Finishing remote animation");
     }
 
@@ -235,12 +235,18 @@
         }
     }
 
-    private void sendRunningRemoteAnimation(boolean running) {
+    private void setRunningRemoteAnimation(boolean running) {
         final int pid = mRemoteAnimationAdapter.getCallingPid();
+        final int uid = mRemoteAnimationAdapter.getCallingUid();
         if (pid == 0) {
             throw new RuntimeException("Calling pid of remote animation was null");
         }
-        mService.sendSetRunningRemoteAnimation(pid, running);
+        final WindowProcessController wpc = mService.mAtmService.getProcessController(pid, uid);
+        if (wpc == null) {
+            Slog.w(TAG, "Unable to find process with pid=" + pid + " uid=" + uid);
+            return;
+        }
+        wpc.setRunningRemoteAnimation(running);
     }
 
     private void linkToDeathOfRunner() throws RemoteException {
@@ -417,7 +423,7 @@
                 mHandler.removeCallbacks(mTimeoutRunnable);
                 releaseFinishedCallback();
                 invokeAnimationCancelled();
-                sendRunningRemoteAnimation(false);
+                setRunningRemoteAnimation(false);
             }
         }
 
diff --git a/services/core/java/com/android/server/wm/SafeActivityOptions.java b/services/core/java/com/android/server/wm/SafeActivityOptions.java
index ac90283..a7b5368 100644
--- a/services/core/java/com/android/server/wm/SafeActivityOptions.java
+++ b/services/core/java/com/android/server/wm/SafeActivityOptions.java
@@ -122,17 +122,20 @@
         if (mOriginalOptions != null) {
             checkPermissions(intent, aInfo, callerApp, supervisor, mOriginalOptions,
                     mOriginalCallingPid, mOriginalCallingUid);
-            setCallingPidForRemoteAnimationAdapter(mOriginalOptions, mOriginalCallingPid);
+            setCallingPidUidForRemoteAnimationAdapter(mOriginalOptions, mOriginalCallingPid,
+                    mOriginalCallingUid);
         }
         if (mCallerOptions != null) {
             checkPermissions(intent, aInfo, callerApp, supervisor, mCallerOptions,
                     mRealCallingPid, mRealCallingUid);
-            setCallingPidForRemoteAnimationAdapter(mCallerOptions, mRealCallingPid);
+            setCallingPidUidForRemoteAnimationAdapter(mCallerOptions, mRealCallingPid,
+                    mRealCallingUid);
         }
         return mergeActivityOptions(mOriginalOptions, mCallerOptions);
     }
 
-    private void setCallingPidForRemoteAnimationAdapter(ActivityOptions options, int callingPid) {
+    private void setCallingPidUidForRemoteAnimationAdapter(ActivityOptions options,
+            int callingPid, int callingUid) {
         final RemoteAnimationAdapter adapter = options.getRemoteAnimationAdapter();
         if (adapter == null) {
             return;
@@ -141,7 +144,7 @@
             Slog.wtf(TAG, "Safe activity options constructed after clearing calling id");
             return;
         }
-        adapter.setCallingPid(callingPid);
+        adapter.setCallingPidUid(callingPid, callingUid);
     }
 
     /**
diff --git a/services/core/java/com/android/server/wm/TaskLaunchParamsModifier.java b/services/core/java/com/android/server/wm/TaskLaunchParamsModifier.java
index 14585c5..19fbfed 100644
--- a/services/core/java/com/android/server/wm/TaskLaunchParamsModifier.java
+++ b/services/core/java/com/android/server/wm/TaskLaunchParamsModifier.java
@@ -292,6 +292,10 @@
 
     private int getPreferredLaunchDisplay(@Nullable TaskRecord task,
             @Nullable ActivityOptions options, ActivityRecord source, LaunchParams currentParams) {
+        if (!mSupervisor.mService.mSupportsMultiDisplay) {
+            return DEFAULT_DISPLAY;
+        }
+
         int displayId = INVALID_DISPLAY;
         final int optionLaunchId = options != null ? options.getLaunchDisplayId() : INVALID_DISPLAY;
         if (optionLaunchId != INVALID_DISPLAY) {
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index 57f402c..c108752 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -34,6 +34,7 @@
 import static android.os.Trace.TRACE_TAG_WINDOW_MANAGER;
 import static android.provider.DeviceConfig.WindowManager.KEY_SYSTEM_GESTURES_EXCLUDED_BY_PRE_Q_STICKY_IMMERSIVE;
 import static android.provider.DeviceConfig.WindowManager.KEY_SYSTEM_GESTURE_EXCLUSION_LIMIT_DP;
+import static android.provider.DeviceConfig.WindowManager.KEY_SYSTEM_GESTURE_EXCLUSION_LOG_DEBOUNCE_MILLIS;
 import static android.provider.Settings.Global.DEVELOPMENT_FORCE_DESKTOP_MODE_ON_EXTERNAL_DISPLAYS;
 import static android.view.Display.DEFAULT_DISPLAY;
 import static android.view.Display.INVALID_DISPLAY;
@@ -847,6 +848,16 @@
     int mSystemGestureExclusionLimitDp;
     boolean mSystemGestureExcludedByPreQStickyImmersive;
 
+    /**
+     * The minimum duration between gesture exclusion logging for a given window in
+     * milliseconds.
+     *
+     * Events that happen in-between will be silently dropped.
+     *
+     * A non-positive value disables logging.
+     */
+    public long mSystemGestureExclusionLogDebounceTimeoutMillis;
+
     public interface WindowChangeListener {
         public void windowsChanged();
         public void focusChanged();
@@ -1146,6 +1157,9 @@
         mSystemGestureExclusionLimitDp = Math.max(MIN_GESTURE_EXCLUSION_LIMIT_DP,
                 DeviceConfig.getInt(DeviceConfig.NAMESPACE_WINDOW_MANAGER,
                         KEY_SYSTEM_GESTURE_EXCLUSION_LIMIT_DP, 0));
+        mSystemGestureExclusionLogDebounceTimeoutMillis =
+                DeviceConfig.getInt(DeviceConfig.NAMESPACE_WINDOW_MANAGER,
+                        KEY_SYSTEM_GESTURE_EXCLUSION_LOG_DEBOUNCE_MILLIS, 0);
         mSystemGestureExcludedByPreQStickyImmersive =
                 DeviceConfig.getBoolean(DeviceConfig.NAMESPACE_WINDOW_MANAGER,
                         KEY_SYSTEM_GESTURES_EXCLUDED_BY_PRE_Q_STICKY_IMMERSIVE, false);
@@ -1163,6 +1177,10 @@
                             mSystemGestureExcludedByPreQStickyImmersive = excludedByPreQSticky;
                             mRoot.forAllDisplays(DisplayContent::updateSystemGestureExclusionLimit);
                         }
+
+                        mSystemGestureExclusionLogDebounceTimeoutMillis =
+                                DeviceConfig.getInt(DeviceConfig.NAMESPACE_WINDOW_MANAGER,
+                                        KEY_SYSTEM_GESTURE_EXCLUSION_LOG_DEBOUNCE_MILLIS, 0);
                     }
                 });
 
@@ -4556,7 +4574,6 @@
         public static final int SEAMLESS_ROTATION_TIMEOUT = 54;
         public static final int RESTORE_POINTER_ICON = 55;
         public static final int SET_HAS_OVERLAY_UI = 58;
-        public static final int SET_RUNNING_REMOTE_ANIMATION = 59;
         public static final int ANIMATION_FAILSAFE = 60;
         public static final int RECOMPUTE_FOCUS = 61;
         public static final int ON_POINTER_DOWN_OUTSIDE_FOCUS = 62;
@@ -4935,10 +4952,6 @@
                     mAmInternal.setHasOverlayUi(msg.arg1, msg.arg2 == 1);
                     break;
                 }
-                case SET_RUNNING_REMOTE_ANIMATION: {
-                    mAmInternal.setRunningRemoteAnimation(msg.arg1, msg.arg2 == 1);
-                    break;
-                }
                 case ANIMATION_FAILSAFE: {
                     synchronized (mGlobalLock) {
                         if (mRecentsAnimationController != null) {
@@ -7625,11 +7638,6 @@
         return mSurfaceBuilderFactory.make(s);
     }
 
-    void sendSetRunningRemoteAnimation(int pid, boolean runningRemoteAnimation) {
-        mH.obtainMessage(H.SET_RUNNING_REMOTE_ANIMATION, pid, runningRemoteAnimation ? 1 : 0)
-                .sendToTarget();
-    }
-
     void startSeamlessRotation() {
         // We are careful to reset this in case a window was removed before it finished
         // seamless rotation.
diff --git a/services/core/java/com/android/server/wm/WindowProcessController.java b/services/core/java/com/android/server/wm/WindowProcessController.java
index b6960f0..4cb546f 100644
--- a/services/core/java/com/android/server/wm/WindowProcessController.java
+++ b/services/core/java/com/android/server/wm/WindowProcessController.java
@@ -56,6 +56,7 @@
 import android.util.Log;
 import android.util.Slog;
 import android.util.proto.ProtoOutputStream;
+import android.view.IRemoteAnimationRunner;
 
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.app.HeavyWeightSwitcherActivity;
@@ -176,6 +177,12 @@
     // Registered display id as a listener to override config change
     private int mDisplayId;
 
+    /** Whether our process is currently running a {@link RecentsAnimation} */
+    private boolean mRunningRecentsAnimation;
+
+    /** Whether our process is currently running a {@link IRemoteAnimationRunner} */
+    private boolean mRunningRemoteAnimation;
+
     public WindowProcessController(ActivityTaskManagerService atm, ApplicationInfo info,
             String name, int uid, int userId, Object owner, WindowProcessListener listener) {
         mInfo = info;
@@ -1079,6 +1086,30 @@
         }
     }
 
+    void setRunningRecentsAnimation(boolean running) {
+        if (mRunningRecentsAnimation == running) {
+            return;
+        }
+        mRunningRecentsAnimation = running;
+        updateRunningRemoteOrRecentsAnimation();
+    }
+
+    void setRunningRemoteAnimation(boolean running) {
+        if (mRunningRemoteAnimation == running) {
+            return;
+        }
+        mRunningRemoteAnimation = running;
+        updateRunningRemoteOrRecentsAnimation();
+    }
+
+    private void updateRunningRemoteOrRecentsAnimation() {
+
+        // Posting on handler so WM lock isn't held when we call into AM.
+        mAtm.mH.sendMessage(PooledLambda.obtainMessage(
+                WindowProcessListener::setRunningRemoteAnimation, mListener,
+                mRunningRecentsAnimation || mRunningRemoteAnimation));
+    }
+
     @Override
     public String toString() {
         return mOwner != null ? mOwner.toString() : null;
diff --git a/services/core/java/com/android/server/wm/WindowProcessListener.java b/services/core/java/com/android/server/wm/WindowProcessListener.java
index 527d54a..23d7a6a 100644
--- a/services/core/java/com/android/server/wm/WindowProcessListener.java
+++ b/services/core/java/com/android/server/wm/WindowProcessListener.java
@@ -17,6 +17,8 @@
 package com.android.server.wm;
 
 import android.util.proto.ProtoOutputStream;
+import android.view.IRemoteAnimationRunner;
+import android.view.RemoteAnimationAdapter;
 
 /**
  * Interface used by the owner/creator of a process that owns windows to listen to changes from the
@@ -60,4 +62,14 @@
     /** App died :(...oh well */
     void appDied();
     void writeToProto(ProtoOutputStream proto, long fieldId);
+
+    /**
+     * Sets if the process is currently running a remote animation, which is taken a signal for
+     * determining oom adjustment and scheduling behavior.
+     *
+     * @param runningRemoteAnimation True if the process is running a remote animation, false
+     *                               otherwise.
+     * @see RemoteAnimationAdapter
+     */
+    void setRunningRemoteAnimation(boolean runningRemoteAnimation);
 }
diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java
index f68d7c0..18cdc94 100644
--- a/services/core/java/com/android/server/wm/WindowState.java
+++ b/services/core/java/com/android/server/wm/WindowState.java
@@ -20,6 +20,8 @@
 import static android.app.AppOpsManager.MODE_ALLOWED;
 import static android.app.AppOpsManager.MODE_DEFAULT;
 import static android.app.AppOpsManager.OP_NONE;
+import static android.app.WindowConfiguration.isSplitScreenWindowingMode;
+import static android.content.res.Configuration.ORIENTATION_LANDSCAPE;
 import static android.os.PowerManager.DRAW_WAKE_LOCK;
 import static android.os.Trace.TRACE_TAG_WINDOW_MANAGER;
 import static android.view.Display.DEFAULT_DISPLAY;
@@ -80,6 +82,7 @@
 import static com.android.server.policy.WindowManagerPolicy.TRANSIT_EXIT;
 import static com.android.server.policy.WindowManagerPolicy.TRANSIT_PREVIEW_DONE;
 import static com.android.server.wm.AnimationSpecProto.MOVE;
+import static com.android.server.wm.DisplayContent.logsGestureExclusionRestrictions;
 import static com.android.server.wm.DragResizeMode.DRAG_RESIZE_MODE_DOCKED_DIVIDER;
 import static com.android.server.wm.DragResizeMode.DRAG_RESIZE_MODE_FREEFORM;
 import static com.android.server.wm.IdentifierProto.HASH_CODE;
@@ -174,6 +177,7 @@
 import android.util.DisplayMetrics;
 import android.util.MergedConfiguration;
 import android.util.Slog;
+import android.util.StatsLog;
 import android.util.TimeUtils;
 import android.util.proto.ProtoOutputStream;
 import android.view.Display;
@@ -227,6 +231,9 @@
     // to capture touch events in that area.
     static final int RESIZE_HANDLE_WIDTH_IN_DP = 30;
 
+    static final int EXCLUSION_LEFT = 0;
+    static final int EXCLUSION_RIGHT = 1;
+
     final WindowManagerPolicy mPolicy;
     final Context mContext;
     final Session mSession;
@@ -397,6 +404,13 @@
      */
     private final List<Rect> mExclusionRects = new ArrayList<>();
 
+    // 0 = left, 1 = right
+    private final int[] mLastRequestedExclusionHeight = {0, 0};
+    private final int[] mLastGrantedExclusionHeight = {0, 0};
+    private final long[] mLastExclusionLogUptimeMillis = {0, 0};
+
+    private boolean mLastShownChangedReported;
+
     // If a window showing a wallpaper: the requested offset for the
     // wallpaper; if a wallpaper window: the currently applied offset.
     float mWallpaperX = -1;
@@ -679,6 +693,20 @@
                 && mAppToken != null && mAppToken.mTargetSdk < Build.VERSION_CODES.Q;
     }
 
+    void setLastExclusionHeights(int side, int requested, int granted) {
+        boolean changed = mLastGrantedExclusionHeight[side] != granted
+                || mLastRequestedExclusionHeight[side] != requested;
+
+        if (changed) {
+            if (mLastShownChangedReported) {
+                logExclusionRestrictions(side);
+            }
+
+            mLastGrantedExclusionHeight[side] = granted;
+            mLastRequestedExclusionHeight[side] = requested;
+        }
+    }
+
     interface PowerManagerWrapper {
         void wakeUp(long time, @WakeReason int reason, String details);
 
@@ -2957,6 +2985,49 @@
         mAnimatingExit = false;
     }
 
+    void onSurfaceShownChanged(boolean shown) {
+        if (mLastShownChangedReported == shown) {
+            return;
+        }
+        mLastShownChangedReported = shown;
+
+        if (shown) {
+            initExclusionRestrictions();
+        } else {
+            logExclusionRestrictions(EXCLUSION_LEFT);
+            logExclusionRestrictions(EXCLUSION_RIGHT);
+        }
+    }
+
+    private void logExclusionRestrictions(int side) {
+        if (!logsGestureExclusionRestrictions(this)
+                || SystemClock.uptimeMillis() < mLastExclusionLogUptimeMillis[side]
+                + mWmService.mSystemGestureExclusionLogDebounceTimeoutMillis) {
+            // Drop the log if we have just logged; this is okay, because what we would have logged
+            // was true only for a short duration.
+            return;
+        }
+
+        final long now = SystemClock.uptimeMillis();
+        final long duration = now - mLastExclusionLogUptimeMillis[side];
+        mLastExclusionLogUptimeMillis[side] = now;
+
+        final int requested = mLastRequestedExclusionHeight[side];
+        final int granted = mLastGrantedExclusionHeight[side];
+
+        StatsLog.write(StatsLog.EXCLUSION_RECT_STATE_CHANGED,
+                mAttrs.packageName, requested, requested - granted /* rejected */,
+                side + 1 /* Sides are 1-indexed in atoms.proto */,
+                (getConfiguration().orientation == ORIENTATION_LANDSCAPE),
+                isSplitScreenWindowingMode(getWindowingMode()), (int) duration);
+    }
+
+    private void initExclusionRestrictions() {
+        final long now = SystemClock.uptimeMillis();
+        mLastExclusionLogUptimeMillis[EXCLUSION_LEFT] = now;
+        mLastExclusionLogUptimeMillis[EXCLUSION_RIGHT] = now;
+    }
+
     @Override
     public boolean isDefaultDisplay() {
         final DisplayContent displayContent = getDisplayContent();
diff --git a/services/core/java/com/android/server/wm/WindowSurfaceController.java b/services/core/java/com/android/server/wm/WindowSurfaceController.java
index bef0f81..53bbd70 100644
--- a/services/core/java/com/android/server/wm/WindowSurfaceController.java
+++ b/services/core/java/com/android/server/wm/WindowSurfaceController.java
@@ -507,6 +507,8 @@
 
         mService.updateNonSystemOverlayWindowsVisibilityIfNeeded(mAnimator.mWin, surfaceShown);
 
+        mAnimator.mWin.onSurfaceShownChanged(surfaceShown);
+
         if (mWindowSession != null) {
             mWindowSession.onWindowSurfaceVisibilityChanged(this, mSurfaceShown, mWindowType);
         }
diff --git a/services/tests/servicestests/src/com/android/server/power/PowerManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/power/PowerManagerServiceTest.java
index 1bda412..88de250 100644
--- a/services/tests/servicestests/src/com/android/server/power/PowerManagerServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/power/PowerManagerServiceTest.java
@@ -23,7 +23,10 @@
 
 import static com.google.common.truth.Truth.assertThat;
 
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
 import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyBoolean;
 import static org.mockito.ArgumentMatchers.anyInt;
 import static org.mockito.ArgumentMatchers.anyString;
 import static org.mockito.ArgumentMatchers.argThat;
@@ -59,6 +62,7 @@
 import android.os.SystemProperties;
 import android.os.UserHandle;
 import android.provider.Settings;
+import android.view.Display;
 
 import androidx.test.InstrumentationRegistry;
 
@@ -157,6 +161,10 @@
         mResourcesSpy = spy(mContextSpy.getResources());
         when(mContextSpy.getResources()).thenReturn(mResourcesSpy);
 
+        when(mDisplayManagerInternalMock.requestPowerState(any(), anyBoolean())).thenReturn(true);
+    }
+
+    private PowerManagerService createService() {
         mService = new PowerManagerService(mContextSpy, new Injector() {
             @Override
             Notifier createNotifier(Looper looper, Context context, IBatteryStats batteryStats,
@@ -166,7 +174,7 @@
 
             @Override
             SuspendBlocker createSuspendBlocker(PowerManagerService service, String name) {
-                return mock(SuspendBlocker.class);
+                return super.createSuspendBlocker(service, name);
             }
 
             @Override
@@ -191,6 +199,7 @@
                 return mAmbientDisplayConfigurationMock;
             }
         });
+        return mService;
     }
 
     @After
@@ -262,6 +271,7 @@
 
     @Test
     public void testUpdatePowerScreenPolicy_UpdateDisplayPowerRequest() {
+        createService();
         mService.updatePowerRequestFromBatterySaverPolicy(mDisplayPowerRequest);
         assertThat(mDisplayPowerRequest.lowPowerMode).isEqualTo(BATTERY_SAVER_ENABLED);
         assertThat(mDisplayPowerRequest.screenLowPowerBrightnessFactor)
@@ -270,6 +280,7 @@
 
     @Test
     public void testGetLastShutdownReasonInternal() {
+        createService();
         SystemProperties.set(TEST_LAST_REBOOT_PROPERTY, "shutdown,thermal");
         int reason = mService.getLastShutdownReasonInternal(TEST_LAST_REBOOT_PROPERTY);
         SystemProperties.set(TEST_LAST_REBOOT_PROPERTY, "");
@@ -278,6 +289,7 @@
 
     @Test
     public void testGetDesiredScreenPolicy_WithVR() throws Exception {
+        createService();
         // Brighten up the screen
         mService.setWakefulnessLocked(WAKEFULNESS_AWAKE, PowerManager.WAKE_REASON_UNKNOWN, 0);
         assertThat(mService.getDesiredScreenPolicyLocked()).isEqualTo(
@@ -307,11 +319,13 @@
 
     @Test
     public void testWakefulnessAwake_InitialValue() throws Exception {
+        createService();
         assertThat(mService.getWakefulness()).isEqualTo(WAKEFULNESS_AWAKE);
     }
 
     @Test
     public void testWakefulnessSleep_NoDozeSleepFlag() throws Exception {
+        createService();
         // Start with AWAKE state
         startSystem();
         assertThat(mService.getWakefulness()).isEqualTo(WAKEFULNESS_AWAKE);
@@ -324,6 +338,7 @@
 
     @Test
     public void testWakefulnessAwake_AcquireCausesWakeup() throws Exception {
+        createService();
         startSystem();
         forceSleep();
 
@@ -355,6 +370,7 @@
 
     @Test
     public void testWakefulnessAwake_IPowerManagerWakeUp() throws Exception {
+        createService();
         startSystem();
         forceSleep();
         mService.getBinderServiceInstance().wakeUp(SystemClock.uptimeMillis(),
@@ -369,6 +385,8 @@
     @Test
     public void testWakefulnessAwake_ShouldWakeUpWhenPluggedIn() throws Exception {
         boolean powerState;
+
+        createService();
         startSystem();
         forceSleep();
 
@@ -444,6 +462,7 @@
 
     @Test
     public void testWakefulnessDoze_goToSleep() throws Exception {
+        createService();
         // Start with AWAKE state
         startSystem();
         assertThat(mService.getWakefulness()).isEqualTo(WAKEFULNESS_AWAKE);
@@ -457,6 +476,7 @@
     @Test
     public void testWasDeviceIdleFor_true() {
         int interval = 1000;
+        createService();
         mService.onUserActivity();
         SystemClock.sleep(interval + 1 /* just a little more */);
         assertThat(mService.wasDeviceIdleForInternal(interval)).isTrue();
@@ -465,12 +485,14 @@
     @Test
     public void testWasDeviceIdleFor_false() {
         int interval = 1000;
+        createService();
         mService.onUserActivity();
         assertThat(mService.wasDeviceIdleForInternal(interval)).isFalse();
     }
 
     @Test
     public void testForceSuspend_putsDeviceToSleep() {
+        createService();
         mService.systemReady(null);
         mService.onBootPhase(SystemService.PHASE_BOOT_COMPLETED);
 
@@ -497,6 +519,8 @@
         final int flags = PowerManager.PARTIAL_WAKE_LOCK;
         final String pkg = mContextSpy.getOpPackageName();
 
+        createService();
+
         // Set up the Notification mock to keep track of the wakelocks that are currently
         // active or disabled. We'll use this to verify that wakelocks are disabled when
         // they should be.
@@ -541,7 +565,54 @@
 
     @Test
     public void testForceSuspend_forceSuspendFailurePropogated() {
+        createService();
         when(mNativeWrapperMock.nativeForceSuspend()).thenReturn(false);
         assertThat(mService.getBinderServiceInstance().forceSuspend()).isFalse();
     }
+
+    @Test
+    public void testSetDozeOverrideFromDreamManager_triggersSuspendBlocker() throws Exception {
+        final String suspendBlockerName = "PowerManagerService.Display";
+        final String tag = "acq_causes_wakeup";
+        final String packageName = "pkg.name";
+        final IBinder token = new Binder();
+
+        final boolean[] isAcquired = new boolean[1];
+        doAnswer(inv -> {
+            if (suspendBlockerName.equals(inv.getArguments()[0])) {
+                isAcquired[0] = false;
+            }
+            return null;
+        }).when(mNativeWrapperMock).nativeReleaseSuspendBlocker(any());
+
+        doAnswer(inv -> {
+            if (suspendBlockerName.equals(inv.getArguments()[0])) {
+                isAcquired[0] = true;
+            }
+            return null;
+        }).when(mNativeWrapperMock).nativeAcquireSuspendBlocker(any());
+
+        // Need to create the service after we stub the mocks for this test because some of the
+        // mocks are used during the constructor.
+        createService();
+
+        // Start with AWAKE state
+        startSystem();
+        assertThat(mService.getWakefulness()).isEqualTo(WAKEFULNESS_AWAKE);
+        assertTrue(isAcquired[0]);
+
+        // Take a nap and verify we no longer hold the blocker
+        int flags = PowerManager.DOZE_WAKE_LOCK;
+        mService.getBinderServiceInstance().acquireWakeLock(token, flags, tag, packageName,
+                null /* workSource */, null /* historyTag */);
+        mService.getBinderServiceInstance().goToSleep(SystemClock.uptimeMillis(),
+                PowerManager.GO_TO_SLEEP_REASON_APPLICATION, 0);
+        assertThat(mService.getWakefulness()).isEqualTo(WAKEFULNESS_DOZING);
+        assertFalse(isAcquired[0]);
+
+        // Override the display state by DreamManager and verify is reacquires the blocker.
+        mService.getLocalServiceInstance()
+                .setDozeOverrideFromDreamManager(Display.STATE_ON, PowerManager.BRIGHTNESS_DEFAULT);
+        assertTrue(isAcquired[0]);
+    }
 }
diff --git a/services/tests/wmtests/src/com/android/server/wm/AppTransitionTests.java b/services/tests/wmtests/src/com/android/server/wm/AppTransitionTests.java
index f602418..d1dc382 100644
--- a/services/tests/wmtests/src/com/android/server/wm/AppTransitionTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/AppTransitionTests.java
@@ -207,7 +207,7 @@
         final RemoteAnimationAdapter adapter = new RemoteAnimationAdapter(
                 runner, 100, 50, true /* changeNeedsSnapshot */);
         // RemoteAnimationController will tracking RemoteAnimationAdapter's caller with calling pid.
-        adapter.setCallingPid(123);
+        adapter.setCallingPidUid(123, 456);
 
         // Simulate activity finish flows to prepare app transition & set visibility,
         // make sure transition is set as expected.
diff --git a/services/tests/wmtests/src/com/android/server/wm/AppWindowTokenTests.java b/services/tests/wmtests/src/com/android/server/wm/AppWindowTokenTests.java
index 7f35dac..d9566a3 100644
--- a/services/tests/wmtests/src/com/android/server/wm/AppWindowTokenTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/AppWindowTokenTests.java
@@ -504,6 +504,21 @@
         assertEquals(stackBounds, mToken.getAnimationBounds(STACK_CLIP_BEFORE_ANIM));
     }
 
+    @Test
+    public void testHasStartingWindow() {
+        final WindowManager.LayoutParams attrs =
+                new WindowManager.LayoutParams(TYPE_APPLICATION_STARTING);
+        final WindowTestUtils.TestWindowState startingWindow = createWindowState(attrs, mToken);
+        mToken.startingDisplayed = true;
+        mToken.addWindow(startingWindow);
+        assertTrue("Starting window should be present", mToken.hasStartingWindow());
+        mToken.startingDisplayed = false;
+        assertTrue("Starting window should be present", mToken.hasStartingWindow());
+
+        mToken.removeChild(startingWindow);
+        assertFalse("Starting window should not be present", mToken.hasStartingWindow());
+    }
+
     private void assertHasStartingWindow(AppWindowToken atoken) {
         assertNotNull(atoken.startingSurface);
         assertNotNull(atoken.mStartingData);
diff --git a/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java b/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java
index 7cd097e..6889086 100644
--- a/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java
@@ -756,7 +756,8 @@
         final ISystemGestureExclusionListener.Stub verifier =
                 new ISystemGestureExclusionListener.Stub() {
             @Override
-            public void onSystemGestureExclusionChanged(int displayId, Region actual) {
+            public void onSystemGestureExclusionChanged(int displayId, Region actual,
+                    Region unrestricted) {
                 Region expected = Region.obtain();
                 expected.set(10, 20, 30, 40);
                 assertEquals(expected, actual);
@@ -790,7 +791,14 @@
 
         final Region expected = Region.obtain();
         expected.set(20, 30, 40, 50);
-        assertEquals(expected, dc.calculateSystemGestureExclusion());
+        assertEquals(expected, calculateSystemGestureExclusion(dc));
+    }
+
+    private Region calculateSystemGestureExclusion(DisplayContent dc) {
+        Region out = Region.obtain();
+        Region unrestricted = Region.obtain();
+        dc.calculateSystemGestureExclusion(out, unrestricted);
+        return out;
     }
 
     @Test
@@ -814,7 +822,7 @@
         win2.setHasSurface(true);
 
         final Region expected = Region.obtain();
-        assertEquals(expected, dc.calculateSystemGestureExclusion());
+        assertEquals(expected, calculateSystemGestureExclusion(dc));
     }
 
     @Test
@@ -839,7 +847,7 @@
 
             final Region expected = Region.obtain();
             expected.set(dc.getBounds());
-            assertEquals(expected, dc.calculateSystemGestureExclusion());
+            assertEquals(expected, calculateSystemGestureExclusion(dc));
 
             win.setHasSurface(false);
         }
diff --git a/services/tests/wmtests/src/com/android/server/wm/RemoteAnimationControllerTest.java b/services/tests/wmtests/src/com/android/server/wm/RemoteAnimationControllerTest.java
index cb74c3e..74791e2 100644
--- a/services/tests/wmtests/src/com/android/server/wm/RemoteAnimationControllerTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/RemoteAnimationControllerTest.java
@@ -79,7 +79,7 @@
 
         when(mMockRunner.asBinder()).thenReturn(new Binder());
         mAdapter = new RemoteAnimationAdapter(mMockRunner, 100, 50, true /* changeNeedsSnapshot */);
-        mAdapter.setCallingPid(123);
+        mAdapter.setCallingPidUid(123, 456);
         mWm.mH.runWithScissors(() -> mHandler = new TestHandler(null, mClock), 0);
         mController = new RemoteAnimationController(mWm, mAdapter, mHandler);
     }
diff --git a/services/tests/wmtests/src/com/android/server/wm/TaskLaunchParamsModifierTests.java b/services/tests/wmtests/src/com/android/server/wm/TaskLaunchParamsModifierTests.java
index f918149..58614c6 100644
--- a/services/tests/wmtests/src/com/android/server/wm/TaskLaunchParamsModifierTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/TaskLaunchParamsModifierTests.java
@@ -1225,6 +1225,22 @@
         assertEquals(startingBounds, adjustedBounds);
     }
 
+    @Test
+    public void testNoMultiDisplaySupports() {
+        final boolean orgValue = mService.mSupportsMultiDisplay;
+        final TestActivityDisplay display = createNewActivityDisplay(WINDOWING_MODE_FULLSCREEN);
+        mCurrent.mPreferredDisplayId = display.mDisplayId;
+
+        try {
+            mService.mSupportsMultiDisplay = false;
+            assertEquals(RESULT_CONTINUE, mTarget.onCalculate(/* task */ null, /* layout */ null,
+                    mActivity, /* source */ null, /* options */ null, mCurrent, mResult));
+            assertEquals(DEFAULT_DISPLAY, mResult.mPreferredDisplayId);
+        } finally {
+            mService.mSupportsMultiDisplay = orgValue;
+        }
+    }
+
     private TestActivityDisplay createNewActivityDisplay(int windowingMode) {
         final TestActivityDisplay display = addNewActivityDisplayAt(ActivityDisplay.POSITION_TOP);
         display.setWindowingMode(windowingMode);
diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowProcessControllerTests.java b/services/tests/wmtests/src/com/android/server/wm/WindowProcessControllerTests.java
index a7c84a1..8c56ffa 100644
--- a/services/tests/wmtests/src/com/android/server/wm/WindowProcessControllerTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/WindowProcessControllerTests.java
@@ -23,12 +23,18 @@
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertTrue;
+import static org.mockito.ArgumentMatchers.eq;
 import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
 
 import android.content.pm.ApplicationInfo;
 import android.platform.test.annotations.Presubmit;
 
+import org.junit.Before;
 import org.junit.Test;
+import org.mockito.InOrder;
+import org.mockito.Mockito;
 
 /**
  * Tests for the {@link WindowProcessController} class.
@@ -39,43 +45,89 @@
 @Presubmit
 public class WindowProcessControllerTests extends ActivityTestsBase {
 
+    WindowProcessController mWpc;
+    WindowProcessListener mMockListener;
+
+    @Before
+    public void setUp() {
+        mMockListener = mock(WindowProcessListener.class);
+        mWpc = new WindowProcessController(
+                mService, mock(ApplicationInfo.class), null, 0, -1, null, mMockListener);
+    }
+
     @Test
     public void testDisplayConfigurationListener() {
-        final WindowProcessController wpc = new WindowProcessController(
-                        mService, mock(ApplicationInfo.class), null, 0, -1, null, null);
+
         //By default, the process should not listen to any display.
-        assertEquals(INVALID_DISPLAY, wpc.getDisplayId());
+        assertEquals(INVALID_DISPLAY, mWpc.getDisplayId());
 
         // Register to display 1 as a listener.
         TestActivityDisplay testActivityDisplay1 = createTestActivityDisplayInContainer();
-        wpc.registerDisplayConfigurationListenerLocked(testActivityDisplay1);
-        assertTrue(testActivityDisplay1.containsListener(wpc));
-        assertEquals(testActivityDisplay1.mDisplayId, wpc.getDisplayId());
+        mWpc.registerDisplayConfigurationListenerLocked(testActivityDisplay1);
+        assertTrue(testActivityDisplay1.containsListener(mWpc));
+        assertEquals(testActivityDisplay1.mDisplayId, mWpc.getDisplayId());
 
         // Move to display 2.
         TestActivityDisplay testActivityDisplay2 = createTestActivityDisplayInContainer();
-        wpc.registerDisplayConfigurationListenerLocked(testActivityDisplay2);
-        assertFalse(testActivityDisplay1.containsListener(wpc));
-        assertTrue(testActivityDisplay2.containsListener(wpc));
-        assertEquals(testActivityDisplay2.mDisplayId, wpc.getDisplayId());
+        mWpc.registerDisplayConfigurationListenerLocked(testActivityDisplay2);
+        assertFalse(testActivityDisplay1.containsListener(mWpc));
+        assertTrue(testActivityDisplay2.containsListener(mWpc));
+        assertEquals(testActivityDisplay2.mDisplayId, mWpc.getDisplayId());
 
         // Null ActivityDisplay will not change anything.
-        wpc.registerDisplayConfigurationListenerLocked(null);
-        assertTrue(testActivityDisplay2.containsListener(wpc));
-        assertEquals(testActivityDisplay2.mDisplayId, wpc.getDisplayId());
+        mWpc.registerDisplayConfigurationListenerLocked(null);
+        assertTrue(testActivityDisplay2.containsListener(mWpc));
+        assertEquals(testActivityDisplay2.mDisplayId, mWpc.getDisplayId());
 
         // Unregister listener will remove the wpc from registered displays.
-        wpc.unregisterDisplayConfigurationListenerLocked();
-        assertFalse(testActivityDisplay1.containsListener(wpc));
-        assertFalse(testActivityDisplay2.containsListener(wpc));
-        assertEquals(INVALID_DISPLAY, wpc.getDisplayId());
+        mWpc.unregisterDisplayConfigurationListenerLocked();
+        assertFalse(testActivityDisplay1.containsListener(mWpc));
+        assertFalse(testActivityDisplay2.containsListener(mWpc));
+        assertEquals(INVALID_DISPLAY, mWpc.getDisplayId());
 
         // Unregistration still work even if the display was removed.
-        wpc.registerDisplayConfigurationListenerLocked(testActivityDisplay1);
-        assertEquals(testActivityDisplay1.mDisplayId, wpc.getDisplayId());
+        mWpc.registerDisplayConfigurationListenerLocked(testActivityDisplay1);
+        assertEquals(testActivityDisplay1.mDisplayId, mWpc.getDisplayId());
         mRootActivityContainer.removeChild(testActivityDisplay1);
-        wpc.unregisterDisplayConfigurationListenerLocked();
-        assertEquals(INVALID_DISPLAY, wpc.getDisplayId());
+        mWpc.unregisterDisplayConfigurationListenerLocked();
+        assertEquals(INVALID_DISPLAY, mWpc.getDisplayId());
+    }
+
+    @Test
+    public void testSetRunningRecentsAnimation() {
+        mWpc.setRunningRecentsAnimation(true);
+        mWpc.setRunningRecentsAnimation(false);
+        mService.mH.runWithScissors(() -> {}, 0);
+
+        InOrder orderVerifier = Mockito.inOrder(mMockListener);
+        orderVerifier.verify(mMockListener).setRunningRemoteAnimation(eq(true));
+        orderVerifier.verify(mMockListener).setRunningRemoteAnimation(eq(false));
+    }
+
+    @Test
+    public void testSetRunningRemoteAnimation() {
+        mWpc.setRunningRemoteAnimation(true);
+        mWpc.setRunningRemoteAnimation(false);
+        mService.mH.runWithScissors(() -> {}, 0);
+
+        InOrder orderVerifier = Mockito.inOrder(mMockListener);
+        orderVerifier.verify(mMockListener).setRunningRemoteAnimation(eq(true));
+        orderVerifier.verify(mMockListener).setRunningRemoteAnimation(eq(false));
+    }
+
+    @Test
+    public void testSetRunningBothAnimations() {
+        mWpc.setRunningRemoteAnimation(true);
+        mWpc.setRunningRecentsAnimation(true);
+
+        mWpc.setRunningRecentsAnimation(false);
+        mWpc.setRunningRemoteAnimation(false);
+        mService.mH.runWithScissors(() -> {}, 0);
+
+        InOrder orderVerifier = Mockito.inOrder(mMockListener);
+        orderVerifier.verify(mMockListener, times(3)).setRunningRemoteAnimation(eq(true));
+        orderVerifier.verify(mMockListener, times(1)).setRunningRemoteAnimation(eq(false));
+        orderVerifier.verifyNoMoreInteractions();
     }
 
     private TestActivityDisplay createTestActivityDisplayInContainer() {
diff --git a/telephony/java/android/telephony/CarrierConfigManager.java b/telephony/java/android/telephony/CarrierConfigManager.java
index cea4faf..56a6d61 100755
--- a/telephony/java/android/telephony/CarrierConfigManager.java
+++ b/telephony/java/android/telephony/CarrierConfigManager.java
@@ -468,6 +468,14 @@
             "notify_handover_video_from_wifi_to_lte_bool";
 
     /**
+     * Flag specifying whether the carrier supports merging a RTT call with a voice call,
+     * downgrading the call in the process.
+     * @hide
+     */
+    public static final String KEY_ALLOW_MERGING_RTT_CALLS_BOOL =
+             "allow_merging_rtt_calls_bool";
+
+    /**
      * Flag specifying whether the carrier wants to notify the user when a VT call has been handed
      * over from LTE to WIFI.
      * <p>
@@ -3057,6 +3065,7 @@
         sDefaults.putBoolean(KEY_CARRIER_VOLTE_AVAILABLE_BOOL, false);
         sDefaults.putBoolean(KEY_CARRIER_VT_AVAILABLE_BOOL, false);
         sDefaults.putBoolean(KEY_NOTIFY_HANDOVER_VIDEO_FROM_WIFI_TO_LTE_BOOL, false);
+        sDefaults.putBoolean(KEY_ALLOW_MERGING_RTT_CALLS_BOOL, false);
         sDefaults.putBoolean(KEY_NOTIFY_HANDOVER_VIDEO_FROM_LTE_TO_WIFI_BOOL, false);
         sDefaults.putBoolean(KEY_SUPPORT_DOWNGRADE_VT_TO_AUDIO_BOOL, true);
         sDefaults.putString(KEY_DEFAULT_VM_NUMBER_STRING, "");
diff --git a/telephony/java/android/telephony/TelephonyManager.java b/telephony/java/android/telephony/TelephonyManager.java
index 976cd0c..7477c3e 100644
--- a/telephony/java/android/telephony/TelephonyManager.java
+++ b/telephony/java/android/telephony/TelephonyManager.java
@@ -2417,6 +2417,10 @@
      * registered operator or the cell nearby, if available.
      * .
      * <p>
+     * Note: In multi-sim, this returns a shared emergency network country iso from other
+     * subscription if the subscription used to create the TelephonyManager doesn't camp on
+     * a network due to some reason (e.g. pin/puk locked), or sim is absent in the corresponding
+     * slot.
      * Note: Result may be unreliable on CDMA networks (use {@link #getPhoneType()} to determine
      * if on a CDMA network).
      */
diff --git a/telephony/java/android/telephony/emergency/EmergencyNumber.java b/telephony/java/android/telephony/emergency/EmergencyNumber.java
index 511adf6..19d0724 100644
--- a/telephony/java/android/telephony/emergency/EmergencyNumber.java
+++ b/telephony/java/android/telephony/emergency/EmergencyNumber.java
@@ -22,6 +22,7 @@
 import android.hardware.radio.V1_4.EmergencyServiceCategory;
 import android.os.Parcel;
 import android.os.Parcelable;
+import android.telephony.CarrierConfigManager;
 import android.telephony.PhoneNumberUtils;
 import android.telephony.Rlog;
 
@@ -301,6 +302,9 @@
      * The character in the number string is only the dial pad
      * character('0'-'9', '*', '+', or '#'). For example: 911.
      *
+     * If the number starts with carrier prefix, the carrier prefix is configured in
+     * {@link CarrierConfigManager#KEY_EMERGENCY_NUMBER_PREFIX_STRING_ARRAY}.
+     *
      * @return the dialing number.
      */
     public @NonNull String getNumber() {
diff --git a/telephony/java/com/android/internal/telephony/CarrierAppUtils.java b/telephony/java/com/android/internal/telephony/CarrierAppUtils.java
index a1bea4d..d4ed923 100644
--- a/telephony/java/com/android/internal/telephony/CarrierAppUtils.java
+++ b/telephony/java/com/android/internal/telephony/CarrierAppUtils.java
@@ -21,6 +21,7 @@
 import android.content.pm.ApplicationInfo;
 import android.content.pm.IPackageManager;
 import android.content.pm.PackageManager;
+import android.content.res.Resources;
 import android.os.RemoteException;
 import android.provider.Settings;
 import android.telephony.TelephonyManager;
@@ -28,7 +29,9 @@
 import android.util.ArraySet;
 import android.util.Slog;
 
+import com.android.internal.R;
 import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.util.ArrayUtils;
 import com.android.server.SystemConfig;
 
 import java.util.ArrayList;
@@ -140,9 +143,12 @@
         try {
             for (ApplicationInfo ai : candidates) {
                 String packageName = ai.packageName;
-                boolean hasPrivileges = telephonyManager != null &&
-                        telephonyManager.checkCarrierPrivilegesForPackageAnyPhone(packageName) ==
-                                TelephonyManager.CARRIER_PRIVILEGE_STATUS_HAS_ACCESS;
+                String[] restrictedCarrierApps = Resources.getSystem().getStringArray(
+                        R.array.config_restrictedPreinstalledCarrierApps);
+                boolean hasPrivileges = telephonyManager != null
+                        && telephonyManager.checkCarrierPrivilegesForPackageAnyPhone(packageName)
+                                == TelephonyManager.CARRIER_PRIVILEGE_STATUS_HAS_ACCESS
+                        && !ArrayUtils.contains(restrictedCarrierApps, packageName);
 
                 // add hiddenUntilInstalled flag for carrier apps and associated apps
                 packageManager.setSystemAppHiddenUntilInstalled(packageName, true);