Merge "Remove libhwbinder/libhidltransport deps" am: 32f968b767
am: 350e380ced

Change-Id: I918bc5573f6f0efa676573209ce1874b02462576
diff --git a/api/Android.bp b/api/Android.bp
new file mode 100644
index 0000000..54ff82c
--- /dev/null
+++ b/api/Android.bp
@@ -0,0 +1,7 @@
+genrule {
+    name: "current-api-xml",
+    tools: ["metalava"],
+    srcs: ["current.txt"],
+    out: ["current.api"],
+    cmd: "$(location metalava) --no-banner -convert2xmlnostrip $(in) $(out)",
+}
diff --git a/api/test-current.txt b/api/test-current.txt
index 077abe0..9fa7f99 100644
--- a/api/test-current.txt
+++ b/api/test-current.txt
@@ -54,6 +54,7 @@
     method @RequiresPermission(android.Manifest.permission.PACKAGE_USAGE_STATS) public int getPackageImportance(String);
     method public long getTotalRam();
     method @RequiresPermission(android.Manifest.permission.PACKAGE_USAGE_STATS) public int getUidImportance(int);
+    method public static boolean isHighEndGfx();
     method @RequiresPermission(android.Manifest.permission.PACKAGE_USAGE_STATS) public void removeOnUidImportanceListener(android.app.ActivityManager.OnUidImportanceListener);
     method public static void resumeAppSwitches() throws android.os.RemoteException;
     method @RequiresPermission(android.Manifest.permission.CHANGE_CONFIGURATION) public void scheduleApplicationInfoChanged(java.util.List<java.lang.String>, int);
@@ -3262,10 +3263,13 @@
   }
 
   @UiThread public class View implements android.view.accessibility.AccessibilityEventSource android.graphics.drawable.Drawable.Callback android.view.KeyEvent.Callback {
+    method @android.view.ViewDebug.ExportedProperty(mapping={@android.view.ViewDebug.IntToString(from=android.view.View.IMPORTANT_FOR_CONTENT_CAPTURE_AUTO, to="auto"), @android.view.ViewDebug.IntToString(from=android.view.View.IMPORTANT_FOR_CONTENT_CAPTURE_YES, to="yes"), @android.view.ViewDebug.IntToString(from=android.view.View.IMPORTANT_FOR_CONTENT_CAPTURE_NO, to="no"), @android.view.ViewDebug.IntToString(from=android.view.View.IMPORTANT_FOR_CONTENT_CAPTURE_YES_EXCLUDE_DESCENDANTS, to="yesExcludeDescendants"), @android.view.ViewDebug.IntToString(from=android.view.View.IMPORTANT_FOR_CONTENT_CAPTURE_NO_EXCLUDE_DESCENDANTS, to="noExcludeDescendants")}) public int getImportantForContentCapture();
     method public android.view.View getTooltipView();
     method public boolean isAutofilled();
     method public static boolean isDefaultFocusHighlightEnabled();
     method public boolean isDefaultFocusHighlightNeeded(android.graphics.drawable.Drawable, android.graphics.drawable.Drawable);
+    method public final boolean isImportantForContentCapture();
+    method public void onProvideContentCaptureStructure(@NonNull android.view.ViewStructure, int);
     method protected void resetResolvedDrawables();
     method public void resetResolvedLayoutDirection();
     method public void resetResolvedPadding();
@@ -3276,7 +3280,13 @@
     method public boolean restoreFocusNotInCluster();
     method public void setAutofilled(boolean);
     method public final void setFocusedInCluster();
+    method public void setImportantForContentCapture(int);
     method public void setIsRootNamespace(boolean);
+    field public static final int IMPORTANT_FOR_CONTENT_CAPTURE_AUTO = 0; // 0x0
+    field public static final int IMPORTANT_FOR_CONTENT_CAPTURE_NO = 2; // 0x2
+    field public static final int IMPORTANT_FOR_CONTENT_CAPTURE_NO_EXCLUDE_DESCENDANTS = 8; // 0x8
+    field public static final int IMPORTANT_FOR_CONTENT_CAPTURE_YES = 1; // 0x1
+    field public static final int IMPORTANT_FOR_CONTENT_CAPTURE_YES_EXCLUDE_DESCENDANTS = 4; // 0x4
   }
 
   public class ViewConfiguration {
diff --git a/cmds/bootanimation/bootanim.rc b/cmds/bootanimation/bootanim.rc
index 469c964..9f4f314 100644
--- a/cmds/bootanimation/bootanim.rc
+++ b/cmds/bootanimation/bootanim.rc
@@ -4,4 +4,5 @@
     group graphics audio
     disabled
     oneshot
+    ioprio rt 0
     writepid /dev/stune/top-app/tasks
diff --git a/cmds/statsd/src/atoms.proto b/cmds/statsd/src/atoms.proto
index 52b7d4b..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;
@@ -3291,6 +3328,8 @@
     optional int32 error_info_vendor = 7;
     // Dictates if this message should trigger additional debugging.
     optional bool debug = 8;
+    // Time spent during the authentication attempt.
+    optional int64 latency_millis = 9;
 }
 
 /**
diff --git a/cmds/statsd/src/external/PowerStatsPuller.cpp b/cmds/statsd/src/external/PowerStatsPuller.cpp
index c56f9a2..b142cac 100644
--- a/cmds/statsd/src/external/PowerStatsPuller.cpp
+++ b/cmds/statsd/src/external/PowerStatsPuller.cpp
@@ -85,7 +85,6 @@
     std::lock_guard<std::mutex> lock(gPowerStatsHalMutex);
 
     if (!getPowerStatsHalLocked()) {
-        ALOGE("power.stats Hal not loaded");
         return false;
     }
 
@@ -116,6 +115,7 @@
         if (gRailInfo.empty()) {
             ALOGE("power.stats has no rail information");
             gPowerStatsExist = false; // No rail info, so never try again.
+            gPowerStatsHal = nullptr;
             return false;
         }
     }
diff --git a/core/java/android/accessibilityservice/AccessibilityService.java b/core/java/android/accessibilityservice/AccessibilityService.java
index cebe6e12..90b80e7 100644
--- a/core/java/android/accessibilityservice/AccessibilityService.java
+++ b/core/java/android/accessibilityservice/AccessibilityService.java
@@ -309,7 +309,7 @@
      * Name under which an AccessibilityService component publishes information
      * about itself. This meta-data must reference an XML resource containing an
      * <code>&lt;{@link android.R.styleable#AccessibilityService accessibility-service}&gt;</code>
-     * tag. This is a a sample XML file configuring an accessibility service:
+     * tag. This is a sample XML file configuring an accessibility service:
      * <pre> &lt;accessibility-service
      *     android:accessibilityEventTypes="typeViewClicked|typeViewFocused"
      *     android:packageNames="foo.bar, foo.baz"
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/ActivityManager.java b/core/java/android/app/ActivityManager.java
index 17368b7..91b98c7 100644
--- a/core/java/android/app/ActivityManager.java
+++ b/core/java/android/app/ActivityManager.java
@@ -925,7 +925,7 @@
      * (which tends to consume a lot more RAM).
      * @hide
      */
-    @UnsupportedAppUsage
+    @TestApi
     static public boolean isHighEndGfx() {
         return !isLowRamDeviceStatic()
                 && !RoSystemProperties.CONFIG_AVOID_GFX_ACCEL
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/app/ActivityThread.java b/core/java/android/app/ActivityThread.java
index d780b09..1b51573 100644
--- a/core/java/android/app/ActivityThread.java
+++ b/core/java/android/app/ActivityThread.java
@@ -1005,8 +1005,7 @@
                 boolean isRestrictedBackupMode, boolean persistent, Configuration config,
                 CompatibilityInfo compatInfo, Map services, Bundle coreSettings,
                 String buildSerial, AutofillOptions autofillOptions,
-                ContentCaptureOptions contentCaptureOptions,
-                long[] disabledCompatChanges) {
+                ContentCaptureOptions contentCaptureOptions, long[] disabledCompatChanges) {
             if (services != null) {
                 if (false) {
                     // Test code to make sure the app could see the passed-in services.
@@ -1052,6 +1051,8 @@
             data.compatInfo = compatInfo;
             data.initProfilerInfo = profilerInfo;
             data.buildSerial = buildSerial;
+            data.autofillOptions = autofillOptions;
+            data.contentCaptureOptions = contentCaptureOptions;
             data.disabledCompatChanges = disabledCompatChanges;
             sendMessage(H.BIND_APPLICATION, data);
         }
@@ -6133,7 +6134,6 @@
         if (data.trackAllocation) {
             DdmVmInternal.enableRecentAllocations(true);
         }
-
         // Note when this process has started.
         Process.setStartTimes(SystemClock.elapsedRealtime(), SystemClock.uptimeMillis());
 
diff --git a/core/java/android/app/ActivityView.java b/core/java/android/app/ActivityView.java
index 4771f9f..3bf659b 100644
--- a/core/java/android/app/ActivityView.java
+++ b/core/java/android/app/ActivityView.java
@@ -120,6 +120,7 @@
 
         mActivityTaskManager = ActivityTaskManager.getService();
         mSurfaceView = new SurfaceView(context);
+        mSurfaceView.setAlpha(0f);
         mSurfaceCallback = new SurfaceCallback();
         mSurfaceView.getHolder().addCallback(mSurfaceCallback);
         addView(mSurfaceView);
@@ -347,6 +348,16 @@
     }
 
     @Override
+    public void setAlpha(float alpha) {
+        mSurfaceView.setAlpha(alpha);
+    }
+
+    @Override
+    public float getAlpha() {
+        return mSurfaceView.getAlpha();
+    }
+
+    @Override
     public boolean gatherTransparentRegion(Region region) {
         // The tap exclude region may be affected by any view on top of it, so we detect the
         // possible change by monitoring this function.
diff --git a/core/java/android/app/AppOpsManager.java b/core/java/android/app/AppOpsManager.java
index da4c038..8cae56d 100644
--- a/core/java/android/app/AppOpsManager.java
+++ b/core/java/android/app/AppOpsManager.java
@@ -240,7 +240,8 @@
     public @interface UidState {}
 
     /**
-     * Uid state: The UID is a foreground persistent app.
+     * Uid state: The UID is a foreground persistent app. The lower the UID
+     * state the more important the UID is for the user.
      * @hide
      */
     @TestApi
@@ -248,7 +249,8 @@
     public static final int UID_STATE_PERSISTENT = 100;
 
     /**
-     * Uid state: The UID is top foreground app.
+     * Uid state: The UID is top foreground app. The lower the UID
+     * state the more important the UID is for the user.
      * @hide
      */
     @TestApi
@@ -257,6 +259,7 @@
 
     /**
      * Uid state: The UID is running a foreground service of location type.
+     * The lower the UID state the more important the UID is for the user.
      * @hide
      */
     @TestApi
@@ -264,7 +267,8 @@
     public static final int UID_STATE_FOREGROUND_SERVICE_LOCATION = 300;
 
     /**
-     * Uid state: The UID is running a foreground service.
+     * Uid state: The UID is running a foreground service. The lower the UID
+     * state the more important the UID is for the user.
      * @hide
      */
     @TestApi
@@ -279,7 +283,8 @@
     public static final int UID_STATE_MAX_LAST_NON_RESTRICTED = UID_STATE_FOREGROUND_SERVICE;
 
     /**
-     * Uid state: The UID is a foreground app.
+     * Uid state: The UID is a foreground app. The lower the UID
+     * state the more important the UID is for the user.
      * @hide
      */
     @TestApi
@@ -287,7 +292,8 @@
     public static final int UID_STATE_FOREGROUND = 500;
 
     /**
-     * Uid state: The UID is a background app.
+     * Uid state: The UID is a background app. The lower the UID
+     * state the more important the UID is for the user.
      * @hide
      */
     @TestApi
@@ -295,7 +301,8 @@
     public static final int UID_STATE_BACKGROUND = 600;
 
     /**
-     * Uid state: The UID is a cached app.
+     * Uid state: The UID is a cached app. The lower the UID
+     * state the more important the UID is for the user.
      * @hide
      */
     @TestApi
diff --git a/core/java/android/app/ITaskStackListener.aidl b/core/java/android/app/ITaskStackListener.aidl
index 0df3bbe..650147b 100644
--- a/core/java/android/app/ITaskStackListener.aidl
+++ b/core/java/android/app/ITaskStackListener.aidl
@@ -170,6 +170,14 @@
      */
     void onBackPressedOnTaskRoot(in ActivityManager.RunningTaskInfo taskInfo);
 
+    /*
+     * Called when contents are drawn for the first time on a display which can only contain one
+     * task.
+     *
+     * @param displayId the id of the display on which contents are drawn.
+     */
+    void onSingleTaskDisplayDrawn(int displayId);
+
     /**
      * Called when a task is reparented to a stack on a different display.
      *
diff --git a/core/java/android/app/Notification.java b/core/java/android/app/Notification.java
index 789351e..ceadd85 100644
--- a/core/java/android/app/Notification.java
+++ b/core/java/android/app/Notification.java
@@ -3386,11 +3386,7 @@
          */
         private int mCachedContrastColor = COLOR_INVALID;
         private int mCachedContrastColorIsFor = COLOR_INVALID;
-        /**
-         * Caches a ambient version of {@link #mCachedAmbientColorIsFor}.
-         */
-        private int mCachedAmbientColor = COLOR_INVALID;
-        private int mCachedAmbientColorIsFor = COLOR_INVALID;
+
         /**
          * A neutral color color that can be used for icons.
          */
@@ -5441,26 +5437,14 @@
         /**
          * Construct a RemoteViews for the display in public contexts like on the lockscreen.
          *
+         * @param isLowPriority is this notification low priority
          * @hide
          */
         @UnsupportedAppUsage
-        public RemoteViews makePublicContentView() {
-            return makePublicView(false /* ambient */);
-        }
-
-        /**
-         * Construct a RemoteViews for the display in public contexts like on the lockscreen.
-         *
-         * @hide
-         */
-        public RemoteViews makePublicAmbientNotification() {
-            return makePublicView(true /* ambient */);
-        }
-
-        private RemoteViews makePublicView(boolean ambient) {
+        public RemoteViews makePublicContentView(boolean isLowPriority) {
             if (mN.publicVersion != null) {
                 final Builder builder = recoverBuilder(mContext, mN.publicVersion);
-                return ambient ? builder.makeAmbientNotification() : builder.createContentView();
+                return builder.createContentView();
             }
             Bundle savedBundle = mN.extras;
             Style style = mStyle;
@@ -5484,7 +5468,11 @@
             }
             mN.extras = publicExtras;
             RemoteViews view;
-            view = makeNotificationHeader();
+            StandardTemplateParams params = mParams.reset().fillTextsFrom(this);
+            if (isLowPriority) {
+                params.forceDefaultColor();
+            }
+            view = makeNotificationHeader(params);
             view.setBoolean(R.id.notification_header, "setExpandOnlyOnButton", true);
             mN.extras = savedBundle;
             mN.mLargeIcon = largeIcon;
@@ -8118,8 +8106,7 @@
          */
         @Override
         public RemoteViews makeHeadsUpContentView(boolean increasedHeight) {
-            RemoteViews expanded = makeMediaBigContentView();
-            return expanded != null ? expanded : makeMediaContentView();
+            return makeMediaContentView();
         }
 
         /** @hide */
diff --git a/core/java/android/app/StatusBarManager.java b/core/java/android/app/StatusBarManager.java
index d9e8763..28413be 100644
--- a/core/java/android/app/StatusBarManager.java
+++ b/core/java/android/app/StatusBarManager.java
@@ -433,6 +433,9 @@
         private boolean mNotificationPeeking;
         private boolean mRecents;
         private boolean mSearch;
+        private boolean mSystemIcons;
+        private boolean mClock;
+        private boolean mNotificationIcons;
 
         /** @hide */
         public DisableInfo(int flags1, int flags2) {
@@ -441,6 +444,9 @@
             mNotificationPeeking = (flags1 & DISABLE_NOTIFICATION_ALERTS) != 0;
             mRecents = (flags1 & DISABLE_RECENT) != 0;
             mSearch = (flags1 & DISABLE_SEARCH) != 0;
+            mSystemIcons = (flags1 & DISABLE_SYSTEM_INFO) != 0;
+            mClock = (flags1 & DISABLE_CLOCK) != 0;
+            mNotificationIcons = (flags1 & DISABLE_NOTIFICATION_ICONS) != 0;
         }
 
         /** @hide */
@@ -527,6 +533,48 @@
         }
 
         /**
+         * @return {@code true} if system icons are disabled
+         *
+         * @hide
+         */
+        public boolean areSystemIconsDisabled() {
+            return mSystemIcons;
+        }
+
+        /** * @hide */
+        public void setSystemIconsDisabled(boolean disabled) {
+            mSystemIcons = disabled;
+        }
+
+        /**
+         * @return {@code true} if the clock icon is disabled
+         *
+         * @hide
+         */
+        public boolean isClockDisabled() {
+            return mClock;
+        }
+
+        /** * @hide */
+        public void setClockDisabled(boolean disabled) {
+            mClock = disabled;
+        }
+
+        /**
+         * @return {@code true} if notification icons are disabled
+         *
+         * @hide
+         */
+        public boolean areNotificationIconsDisabled() {
+            return mNotificationIcons;
+        }
+
+        /** * @hide */
+        public void setNotificationIconsDisabled(boolean disabled) {
+            mNotificationIcons = disabled;
+        }
+
+        /**
          * @return {@code true} if no components are disabled (default state)
          *
          * @hide
@@ -535,7 +583,7 @@
         @TestApi
         public boolean areAllComponentsEnabled() {
             return !mStatusBarExpansion && !mNavigateHome && !mNotificationPeeking && !mRecents
-                    && !mSearch;
+                    && !mSearch && !mSystemIcons && !mClock && !mNotificationIcons;
         }
 
         /** @hide */
@@ -545,6 +593,9 @@
             mNotificationPeeking = false;
             mRecents = false;
             mSearch = false;
+            mSystemIcons = false;
+            mClock = false;
+            mNotificationIcons = false;
         }
 
         /**
@@ -554,7 +605,7 @@
          */
         public boolean areAllComponentsDisabled() {
             return mStatusBarExpansion && mNavigateHome && mNotificationPeeking
-                    && mRecents && mSearch;
+                    && mRecents && mSearch && mSystemIcons && mClock && mNotificationIcons;
         }
 
         /** @hide */
@@ -564,6 +615,9 @@
             mNotificationPeeking = true;
             mRecents = true;
             mSearch = true;
+            mSystemIcons = true;
+            mClock = true;
+            mNotificationIcons = true;
         }
 
         @NonNull
@@ -577,6 +631,9 @@
                     .append(mNotificationPeeking ? "disabled" : "enabled");
             sb.append(" mRecents=").append(mRecents ? "disabled" : "enabled");
             sb.append(" mSearch=").append(mSearch ? "disabled" : "enabled");
+            sb.append(" mSystemIcons=").append(mSystemIcons ? "disabled" : "enabled");
+            sb.append(" mClock=").append(mClock ? "disabled" : "enabled");
+            sb.append(" mNotificationIcons=").append(mNotificationIcons ? "disabled" : "enabled");
 
             return sb.toString();
 
@@ -597,6 +654,9 @@
             if (mNotificationPeeking) disable1 |= DISABLE_NOTIFICATION_ALERTS;
             if (mRecents) disable1 |= DISABLE_RECENT;
             if (mSearch) disable1 |= DISABLE_SEARCH;
+            if (mSystemIcons) disable1 |= DISABLE_SYSTEM_INFO;
+            if (mClock) disable1 |= DISABLE_CLOCK;
+            if (mNotificationIcons) disable1 |= DISABLE_NOTIFICATION_ICONS;
 
             return new Pair<Integer, Integer>(disable1, disable2);
         }
diff --git a/core/java/android/app/TaskStackListener.java b/core/java/android/app/TaskStackListener.java
index 73fc7a3..b63feb5 100644
--- a/core/java/android/app/TaskStackListener.java
+++ b/core/java/android/app/TaskStackListener.java
@@ -176,6 +176,10 @@
     }
 
     @Override
+    public void onSingleTaskDisplayDrawn(int displayId) throws RemoteException {
+    }
+
+    @Override
     public void onTaskDisplayChanged(int taskId, int newDisplayId) throws RemoteException {
     }
 }
diff --git a/core/java/android/app/slice/SliceProvider.java b/core/java/android/app/slice/SliceProvider.java
index 0ccd49f..5e530ee 100644
--- a/core/java/android/app/slice/SliceProvider.java
+++ b/core/java/android/app/slice/SliceProvider.java
@@ -355,7 +355,8 @@
     @Override
     public Bundle call(String method, String arg, Bundle extras) {
         if (method.equals(METHOD_SLICE)) {
-            Uri uri = getUriWithoutUserId(extras.getParcelable(EXTRA_BIND_URI));
+            Uri uri = getUriWithoutUserId(validateIncomingUriOrNull(
+                    extras.getParcelable(EXTRA_BIND_URI)));
             List<SliceSpec> supportedSpecs = extras.getParcelableArrayList(EXTRA_SUPPORTED_SPECS);
 
             String callingPackage = getCallingPackage();
@@ -369,7 +370,7 @@
         } else if (method.equals(METHOD_MAP_INTENT)) {
             Intent intent = extras.getParcelable(EXTRA_INTENT);
             if (intent == null) return null;
-            Uri uri = onMapIntentToUri(intent);
+            Uri uri = validateIncomingUriOrNull(onMapIntentToUri(intent));
             List<SliceSpec> supportedSpecs = extras.getParcelableArrayList(EXTRA_SUPPORTED_SPECS);
             Bundle b = new Bundle();
             if (uri != null) {
@@ -383,24 +384,27 @@
         } else if (method.equals(METHOD_MAP_ONLY_INTENT)) {
             Intent intent = extras.getParcelable(EXTRA_INTENT);
             if (intent == null) return null;
-            Uri uri = onMapIntentToUri(intent);
+            Uri uri = validateIncomingUriOrNull(onMapIntentToUri(intent));
             Bundle b = new Bundle();
             b.putParcelable(EXTRA_SLICE, uri);
             return b;
         } else if (method.equals(METHOD_PIN)) {
-            Uri uri = getUriWithoutUserId(extras.getParcelable(EXTRA_BIND_URI));
+            Uri uri = getUriWithoutUserId(validateIncomingUriOrNull(
+                    extras.getParcelable(EXTRA_BIND_URI)));
             if (Binder.getCallingUid() != Process.SYSTEM_UID) {
                 throw new SecurityException("Only the system can pin/unpin slices");
             }
             handlePinSlice(uri);
         } else if (method.equals(METHOD_UNPIN)) {
-            Uri uri = getUriWithoutUserId(extras.getParcelable(EXTRA_BIND_URI));
+            Uri uri = getUriWithoutUserId(validateIncomingUriOrNull(
+                    extras.getParcelable(EXTRA_BIND_URI)));
             if (Binder.getCallingUid() != Process.SYSTEM_UID) {
                 throw new SecurityException("Only the system can pin/unpin slices");
             }
             handleUnpinSlice(uri);
         } else if (method.equals(METHOD_GET_DESCENDANTS)) {
-            Uri uri = getUriWithoutUserId(extras.getParcelable(EXTRA_BIND_URI));
+            Uri uri = getUriWithoutUserId(
+                    validateIncomingUriOrNull(extras.getParcelable(EXTRA_BIND_URI)));
             Bundle b = new Bundle();
             b.putParcelableArrayList(EXTRA_SLICE_DESCENDANTS,
                     new ArrayList<>(handleGetDescendants(uri)));
@@ -416,6 +420,10 @@
         return super.call(method, arg, extras);
     }
 
+    private Uri validateIncomingUriOrNull(Uri uri) {
+        return uri == null ? null : validateIncomingUri(uri);
+    }
+
     private Collection<Uri> handleGetDescendants(Uri uri) {
         mCallback = "onGetSliceDescendants";
         return onGetSliceDescendants(uri);
diff --git a/core/java/android/content/Context.java b/core/java/android/content/Context.java
index a6b95a9..4a5ea03 100644
--- a/core/java/android/content/Context.java
+++ b/core/java/android/content/Context.java
@@ -854,11 +854,16 @@
      * to any callers for the same name, meaning they will see each other's
      * edits as soon as they are made.
      *
-     * This method is thead-safe.
+     * <p>This method is thread-safe.
      *
-     * @param name Desired preferences file. If a preferences file by this name
-     * does not exist, it will be created when you retrieve an
-     * editor (SharedPreferences.edit()) and then commit changes (Editor.commit()).
+     * <p>If the preferences directory does not already exist, it will be created when this method
+     * is called.
+     *
+     * <p>If a preferences file by this name does not exist, it will be created when you retrieve an
+     * editor ({@link SharedPreferences#edit()}) and then commit changes ({@link
+     * SharedPreferences.Editor#commit()} or {@link SharedPreferences.Editor#apply()}).
+     *
+     * @param name Desired preferences file.
      * @param mode Operating mode.
      *
      * @return The single {@link SharedPreferences} instance that can be used
diff --git a/core/java/android/content/pm/LauncherApps.java b/core/java/android/content/pm/LauncherApps.java
index 037a149..c74daa8 100644
--- a/core/java/android/content/pm/LauncherApps.java
+++ b/core/java/android/content/pm/LauncherApps.java
@@ -503,9 +503,38 @@
     }
 
     /**
-     * Retrieves a list of launchable activities that match {@link Intent#ACTION_MAIN} and
-     * {@link Intent#CATEGORY_LAUNCHER}, for a specified user. Result may include
-     * synthesized activities like app details Activity injected by system.
+     * Retrieves a list of activities that specify {@link Intent#ACTION_MAIN} and
+     * {@link Intent#CATEGORY_LAUNCHER}, across all apps, for a specified user. If an app doesn't
+     * have any activities that specify <code>ACTION_MAIN</code> or <code>CATEGORY_LAUNCHER</code>,
+     * the system adds a synthesized activity to the list. This synthesized activity represents the
+     * app's details page within system settings.
+     *
+     * <p class="note"><b>Note: </b>It's possible for system apps, such as app stores, to prevent
+     * the system from adding synthesized activities to the returned list.</p>
+     *
+     * <p>As of <a href="/reference/android/os/Build.VERSION_CODES.html#Q">Android Q</a>, at least
+     * one of the app's activities or synthesized activities appears in the returned list unless the
+     * app satisfies at least one of the following conditions:</p>
+     * <ul>
+     * <li>The app is a system app.</li>
+     * <li>The app doesn't request any <a href="/guide/topics/permissions/overview">permissions</a>.
+     * </li>
+     * <li>The <code>&lt;application&gt;</code> tag in the app's manifest doesn't contain any child
+     * elements that represent
+     * <a href="/guide/components/fundamentals#DeclaringComponents">app components</a>.</li>
+     * </ul>
+     *
+     * <p>Additionally, the system hides synthesized activities for some or all apps in the
+     * following enterprise-related cases:</p>
+     * <ul>
+     * <li>If the device is a
+     * <a href="https://developers.google.com/android/work/overview#company-owned-devices-for-knowledge-workers">fully
+     * managed device</a>, no synthesized activities for any app appear in the returned list.</li>
+     * <li>If the current user has a
+     * <a href="https://developers.google.com/android/work/overview#employee-owned-devices-byod">work
+     * profile</a>, no synthesized activities for the user's work apps appear in the returned
+     * list.</li>
+     * </ul>
      *
      * @param packageName The specific package to query. If null, it checks all installed packages
      *            in the profile.
diff --git a/core/java/android/content/res/Configuration.java b/core/java/android/content/res/Configuration.java
index 861ae7b..9cf54f4 100644
--- a/core/java/android/content/res/Configuration.java
+++ b/core/java/android/content/res/Configuration.java
@@ -1222,7 +1222,15 @@
                                                         .setVariant(variant)
                                                         .setScript(script)
                                                         .build();
-                                list.add(locale);
+                                // Log a WTF here if a repeated locale is found to avoid throwing an
+                                // exception in system server when LocaleList is created below
+                                final int inListIndex = list.indexOf(locale);
+                                if (inListIndex != -1) {
+                                    Slog.wtf(TAG, "Repeated locale (" + list.get(inListIndex) + ")"
+                                            + " found when trying to add: " + locale.toString());
+                                } else {
+                                    list.add(locale);
+                                }
                             } catch (IllformedLocaleException e) {
                                 Slog.e(TAG, "readFromProto error building locale with: "
                                         + "language-" + language + ";country-" + country
diff --git a/core/java/android/hardware/Sensor.java b/core/java/android/hardware/Sensor.java
index 099ae29..e78fb7f 100644
--- a/core/java/android/hardware/Sensor.java
+++ b/core/java/android/hardware/Sensor.java
@@ -339,6 +339,8 @@
      * for {@link #TYPE_STEP_COUNTER} instead. It is defined as a
      * {@link Sensor#REPORTING_MODE_SPECIAL_TRIGGER} sensor.
      * <p>
+     * This sensor requires permission {@code android.permission.ACTIVITY_RECOGNITION}.
+     * <p>
      * See {@link android.hardware.SensorEvent#values SensorEvent.values} for more details.
      */
     public static final int TYPE_STEP_DETECTOR = 18;
@@ -384,8 +386,6 @@
      * gyroscope. This sensor uses lower power than the other rotation vectors, because it doesn't
      * use the gyroscope. However, it is more noisy and will work best outdoors.
      * <p>
-     * This sensor requires permission {@code android.permission.ACTIVITY_RECOGNITION}.
-     * <p>
      * See {@link android.hardware.SensorEvent#values SensorEvent.values} for more details.
      */
     public static final int TYPE_GEOMAGNETIC_ROTATION_VECTOR = 20;
diff --git a/core/java/android/hardware/biometrics/BiometricManager.java b/core/java/android/hardware/biometrics/BiometricManager.java
index 6c497d4..d8110f3 100644
--- a/core/java/android/hardware/biometrics/BiometricManager.java
+++ b/core/java/android/hardware/biometrics/BiometricManager.java
@@ -104,9 +104,17 @@
      */
     @RequiresPermission(USE_BIOMETRIC)
     public @BiometricError int canAuthenticate() {
+        return canAuthenticate(mContext.getUserId());
+    }
+
+    /**
+     * @hide
+     */
+    @RequiresPermission(USE_BIOMETRIC_INTERNAL)
+    public @BiometricError int canAuthenticate(int userId) {
         if (mService != null) {
             try {
-                return mService.canAuthenticate(mContext.getOpPackageName());
+                return mService.canAuthenticate(mContext.getOpPackageName(), userId);
             } catch (RemoteException e) {
                 throw e.rethrowFromSystemServer();
             }
@@ -121,6 +129,25 @@
     }
 
     /**
+     * @hide
+     * @param userId
+     * @return
+     */
+    @RequiresPermission(USE_BIOMETRIC_INTERNAL)
+    public boolean hasEnrolledBiometrics(int userId) {
+        if (mService != null) {
+            try {
+                return mService.hasEnrolledBiometrics(userId);
+            } catch (RemoteException e) {
+                Slog.w(TAG, "Remote exception in hasEnrolledBiometrics(): " + e);
+                return false;
+            }
+        } else {
+            return false;
+        }
+    }
+
+    /**
      * Listens for changes to biometric eligibility on keyguard from user settings.
      * @param callback
      * @hide
diff --git a/core/java/android/hardware/biometrics/IBiometricEnabledOnKeyguardCallback.aidl b/core/java/android/hardware/biometrics/IBiometricEnabledOnKeyguardCallback.aidl
index d22e7e2..62d727c 100644
--- a/core/java/android/hardware/biometrics/IBiometricEnabledOnKeyguardCallback.aidl
+++ b/core/java/android/hardware/biometrics/IBiometricEnabledOnKeyguardCallback.aidl
@@ -22,5 +22,5 @@
  * @hide
  */
 oneway interface IBiometricEnabledOnKeyguardCallback {
-    void onChanged(in BiometricSourceType type, boolean enabled);
+    void onChanged(in BiometricSourceType type, boolean enabled, int userId);
 }
\ No newline at end of file
diff --git a/core/java/android/hardware/biometrics/IBiometricService.aidl b/core/java/android/hardware/biometrics/IBiometricService.aidl
index 90d4921..f0a0b2f 100644
--- a/core/java/android/hardware/biometrics/IBiometricService.aidl
+++ b/core/java/android/hardware/biometrics/IBiometricService.aidl
@@ -40,7 +40,10 @@
     void cancelAuthentication(IBinder token, String opPackageName);
 
     // Checks if biometrics can be used.
-    int canAuthenticate(String opPackageName);
+    int canAuthenticate(String opPackageName, int userId);
+
+    // Checks if any biometrics are enrolled.
+    boolean hasEnrolledBiometrics(int userId);
 
     // Register callback for when keyguard biometric eligibility changes.
     void registerEnabledOnKeyguardCallback(IBiometricEnabledOnKeyguardCallback callback);
diff --git a/core/java/android/hardware/display/AmbientDisplayConfiguration.java b/core/java/android/hardware/display/AmbientDisplayConfiguration.java
index c45b8ed..3e995b6 100644
--- a/core/java/android/hardware/display/AmbientDisplayConfiguration.java
+++ b/core/java/android/hardware/display/AmbientDisplayConfiguration.java
@@ -48,7 +48,8 @@
         return pulseOnNotificationEnabled(user)
                 || pulseOnLongPressEnabled(user)
                 || alwaysOnEnabled(user)
-                || wakeScreenGestureEnabled(user)
+                || wakeLockScreenGestureEnabled(user)
+                || wakeDisplayGestureEnabled(user)
                 || pickupGestureEnabled(user)
                 || tapGestureEnabled(user)
                 || doubleTapGestureEnabled(user);
@@ -105,8 +106,14 @@
     }
 
     /** {@hide} */
-    public boolean wakeScreenGestureEnabled(int user) {
-        return boolSettingDefaultOn(Settings.Secure.DOZE_WAKE_SCREEN_GESTURE, user)
+    public boolean wakeLockScreenGestureEnabled(int user) {
+        return boolSettingDefaultOn(Settings.Secure.DOZE_WAKE_LOCK_SCREEN_GESTURE, user)
+                && wakeScreenGestureAvailable();
+    }
+
+    /** {@hide} */
+    public boolean wakeDisplayGestureEnabled(int user) {
+        return boolSettingDefaultOn(Settings.Secure.DOZE_WAKE_DISPLAY_GESTURE, user)
                 && wakeScreenGestureAvailable();
     }
 
diff --git a/core/java/android/hardware/display/DisplayManager.java b/core/java/android/hardware/display/DisplayManager.java
index 8a0a9c7..0b25dbd 100644
--- a/core/java/android/hardware/display/DisplayManager.java
+++ b/core/java/android/hardware/display/DisplayManager.java
@@ -820,4 +820,64 @@
          */
         void onDisplayChanged(int displayId);
     }
+
+    /**
+     * Interface for accessing keys belonging to {@link
+     * android.provider.DeviceConfig#NAMESPACE_DISPLAY_MANAGER}.
+     * @hide
+     */
+    public interface DeviceConfig {
+
+        /**
+         * Key for refresh rate in the zone defined by thresholds.
+         *
+         * @see android.provider.DeviceConfig#NAMESPACE_DISPLAY_MANAGER
+         * @see android.R.integer#config_defaultZoneBehavior
+         */
+        String KEY_REFRESH_RATE_IN_ZONE = "refresh_rate_in_zone";
+
+        /**
+         * Key for accessing the display brightness thresholds for the configured refresh rate zone.
+         * The value will be a pair of comma separated integers representing the minimum and maximum
+         * thresholds of the zone, respectively, in display backlight units (i.e. [0, 255]).
+         *
+         * @see android.provider.DeviceConfig#NAMESPACE_DISPLAY_MANAGER
+         * @see android.R.array#config_brightnessThresholdsOfPeakRefreshRate
+         * @hide
+         */
+        String KEY_PEAK_REFRESH_RATE_DISPLAY_BRIGHTNESS_THRESHOLDS =
+                "peak_refresh_rate_brightness_thresholds";
+
+        /**
+         * Key for accessing the ambient brightness thresholds for the configured refresh rate zone.
+         * The value will be a pair of comma separated integers representing the minimum and maximum
+         * thresholds of the zone, respectively, in lux.
+         *
+         * @see android.provider.DeviceConfig#NAMESPACE_DISPLAY_MANAGER
+         * @see android.R.array#config_ambientThresholdsOfPeakRefreshRate
+         * @hide
+         */
+        String KEY_PEAK_REFRESH_RATE_AMBIENT_BRIGHTNESS_THRESHOLDS =
+                "peak_refresh_rate_ambient_thresholds";
+
+        /**
+         * Key for default peak refresh rate
+         *
+         * @see android.provider.DeviceConfig#NAMESPACE_DISPLAY_MANAGER
+         * @see android.R.integer#config_defaultPeakRefreshRate
+         * @hide
+         */
+        String KEY_PEAK_REFRESH_RATE_DEFAULT = "peak_refresh_rate_default";
+
+        /**
+         * Key for controlling which packages are explicitly blocked from running at refresh rates
+         * higher than 60hz. An app may be added to this list if they exhibit performance issues at
+         * higher refresh rates.
+         *
+         * @see android.provider.DeviceConfig#NAMESPACE_DISPLAY_MANAGER
+         * @see android.R.array#config_highRefreshRateBlacklist
+         * @hide
+         */
+        String KEY_HIGH_REFRESH_RATE_BLACKLIST = "high_refresh_rate_blacklist";
+    }
 }
diff --git a/core/java/android/hardware/face/FaceManager.java b/core/java/android/hardware/face/FaceManager.java
index 8596af10..12b285a 100644
--- a/core/java/android/hardware/face/FaceManager.java
+++ b/core/java/android/hardware/face/FaceManager.java
@@ -262,7 +262,7 @@
      * @hide
      */
     @RequiresPermission(MANAGE_BIOMETRIC)
-    public void enroll(byte[] token, CancellationSignal cancel,
+    public void enroll(int userId, byte[] token, CancellationSignal cancel,
             EnrollmentCallback callback, int[] disabledFeatures) {
         if (callback == null) {
             throw new IllegalArgumentException("Must supply an enrollment callback");
@@ -281,7 +281,7 @@
             try {
                 mEnrollmentCallback = callback;
                 Trace.beginSection("FaceManager#enroll");
-                mService.enroll(mToken, token, mServiceReceiver,
+                mService.enroll(userId, mToken, token, mServiceReceiver,
                         mContext.getOpPackageName(), disabledFeatures);
             } catch (RemoteException e) {
                 Log.w(TAG, "Remote exception in enroll: ", e);
@@ -339,12 +339,13 @@
      * @hide
      */
     @RequiresPermission(MANAGE_BIOMETRIC)
-    public void setFeature(int feature, boolean enabled, byte[] token,
+    public void setFeature(int userId, int feature, boolean enabled, byte[] token,
             SetFeatureCallback callback) {
         if (mService != null) {
             try {
                 mSetFeatureCallback = callback;
-                mService.setFeature(feature, enabled, token, mServiceReceiver);
+                mService.setFeature(userId, feature, enabled, token, mServiceReceiver,
+                        mContext.getOpPackageName());
             } catch (RemoteException e) {
                 throw e.rethrowFromSystemServer();
             }
@@ -355,11 +356,11 @@
      * @hide
      */
     @RequiresPermission(MANAGE_BIOMETRIC)
-    public void getFeature(int feature, GetFeatureCallback callback) {
+    public void getFeature(int userId, int feature, GetFeatureCallback callback) {
         if (mService != null) {
             try {
                 mGetFeatureCallback = callback;
-                mService.getFeature(feature, mServiceReceiver);
+                mService.getFeature(userId, feature, mServiceReceiver, mContext.getOpPackageName());
             } catch (RemoteException e) {
                 throw e.rethrowFromSystemServer();
             }
@@ -414,7 +415,8 @@
             try {
                 mRemovalCallback = callback;
                 mRemovalFace = face;
-                mService.remove(mToken, face.getBiometricId(), userId, mServiceReceiver);
+                mService.remove(mToken, face.getBiometricId(), userId, mServiceReceiver,
+                        mContext.getOpPackageName());
             } catch (RemoteException e) {
                 Log.w(TAG, "Remote exception in remove: ", e);
                 if (callback != null) {
@@ -637,7 +639,7 @@
             }
         }
         Slog.w(TAG, "Invalid error message: " + errMsg + ", " + vendorCode);
-        return null;
+        return "";
     }
 
     /**
diff --git a/core/java/android/hardware/face/IFaceService.aidl b/core/java/android/hardware/face/IFaceService.aidl
index 601be75..b6a0afb 100644
--- a/core/java/android/hardware/face/IFaceService.aidl
+++ b/core/java/android/hardware/face/IFaceService.aidl
@@ -50,14 +50,15 @@
             int callingUid, int callingPid, int callingUserId, boolean fromClient);
 
     // Start face enrollment
-    void enroll(IBinder token, in byte [] cryptoToken, IFaceServiceReceiver receiver,
+    void enroll(int userId, IBinder token, in byte [] cryptoToken, IFaceServiceReceiver receiver,
             String opPackageName, in int [] disabledFeatures);
 
     // Cancel enrollment in progress
     void cancelEnrollment(IBinder token);
 
     // Any errors resulting from this call will be returned to the listener
-    void remove(IBinder token, int faceId, int userId, IFaceServiceReceiver receiver);
+    void remove(IBinder token, int faceId, int userId, IFaceServiceReceiver receiver,
+            String opPackageName);
 
     // Rename the face specified by faceId to the given name
     void rename(int faceId, String name);
@@ -98,10 +99,10 @@
     // Enumerate all faces
     void enumerate(IBinder token, int userId, IFaceServiceReceiver receiver);
 
-    void setFeature(int feature, boolean enabled, in byte [] token,
-            IFaceServiceReceiver receiver);
+    void setFeature(int userId, int feature, boolean enabled, in byte [] token,
+            IFaceServiceReceiver receiver, String opPackageName);
 
-    void getFeature(int feature, IFaceServiceReceiver receiver);
+    void getFeature(int userId, int feature, IFaceServiceReceiver receiver, String opPackageName);
 
     void userActivity();
 }
diff --git a/core/java/android/net/NetworkTemplate.java b/core/java/android/net/NetworkTemplate.java
index ae421a4..87c7118 100644
--- a/core/java/android/net/NetworkTemplate.java
+++ b/core/java/android/net/NetworkTemplate.java
@@ -48,6 +48,7 @@
 import java.io.DataOutputStream;
 import java.io.IOException;
 import java.util.Arrays;
+import java.util.List;
 import java.util.Objects;
 
 /**
@@ -481,17 +482,39 @@
      * For example, given an incoming template matching B, and the currently
      * active merge set [A,B], we'd return a new template that primarily matches
      * A, but also matches B.
+     * TODO: remove and use {@link #normalize(NetworkTemplate, List)}.
      */
     @UnsupportedAppUsage
     public static NetworkTemplate normalize(NetworkTemplate template, String[] merged) {
-        if (template.isMatchRuleMobile() && ArrayUtils.contains(merged, template.mSubscriberId)) {
-            // Requested template subscriber is part of the merge group; return
-            // a template that matches all merged subscribers.
-            return new NetworkTemplate(template.mMatchRule, merged[0], merged,
-                    template.mNetworkId);
-        } else {
-            return template;
+        return normalize(template, Arrays.<String[]>asList(merged));
+    }
+
+    /**
+     * Examine the given template and normalize if it refers to a "merged"
+     * mobile subscriber. We pick the "lowest" merged subscriber as the primary
+     * for key purposes, and expand the template to match all other merged
+     * subscribers.
+     *
+     * There can be multiple merged subscriberIds for multi-SIM devices.
+     *
+     * <p>
+     * For example, given an incoming template matching B, and the currently
+     * active merge set [A,B], we'd return a new template that primarily matches
+     * A, but also matches B.
+     */
+    public static NetworkTemplate normalize(NetworkTemplate template, List<String[]> mergedList) {
+        if (!template.isMatchRuleMobile()) return template;
+
+        for (String[] merged : mergedList) {
+            if (ArrayUtils.contains(merged, template.mSubscriberId)) {
+                // Requested template subscriber is part of the merge group; return
+                // a template that matches all merged subscribers.
+                return new NetworkTemplate(template.mMatchRule, merged[0], merged,
+                        template.mNetworkId);
+            }
         }
+
+        return template;
     }
 
     @UnsupportedAppUsage
diff --git a/core/java/android/os/IVibratorService.aidl b/core/java/android/os/IVibratorService.aidl
index e8b3ca6..1456ff7 100644
--- a/core/java/android/os/IVibratorService.aidl
+++ b/core/java/android/os/IVibratorService.aidl
@@ -16,6 +16,7 @@
 
 package android.os;
 
+import android.media.AudioAttributes;
 import android.os.VibrationEffect;
 
 /** {@hide} */
@@ -23,8 +24,8 @@
 {
     boolean hasVibrator();
     boolean hasAmplitudeControl();
-    void vibrate(int uid, String opPkg, in VibrationEffect effect, int usageHint, String reason,
-            IBinder token);
+    void vibrate(int uid, String opPkg, in VibrationEffect effect, in AudioAttributes attributes,
+            String reason, IBinder token);
     void cancelVibrate(IBinder token);
 }
 
diff --git a/core/java/android/os/RecoverySystem.java b/core/java/android/os/RecoverySystem.java
index 53298d8..48fc2a6 100644
--- a/core/java/android/os/RecoverySystem.java
+++ b/core/java/android/os/RecoverySystem.java
@@ -31,6 +31,8 @@
 import android.content.IntentFilter;
 import android.content.pm.PackageManager;
 import android.provider.Settings;
+import android.telephony.SubscriptionInfo;
+import android.telephony.SubscriptionManager;
 import android.telephony.euicc.EuiccManager;
 import android.text.TextUtils;
 import android.text.format.DateFormat;
@@ -56,10 +58,12 @@
 import java.util.ArrayList;
 import java.util.Enumeration;
 import java.util.HashSet;
+import java.util.List;
 import java.util.Locale;
 import java.util.concurrent.CountDownLatch;
 import java.util.concurrent.TimeUnit;
 import java.util.concurrent.atomic.AtomicBoolean;
+import java.util.concurrent.atomic.AtomicInteger;
 import java.util.zip.ZipEntry;
 import java.util.zip.ZipFile;
 import java.util.zip.ZipInputStream;
@@ -87,11 +91,14 @@
     private static final long PUBLISH_PROGRESS_INTERVAL_MS = 500;
 
     private static final long DEFAULT_EUICC_FACTORY_RESET_TIMEOUT_MILLIS = 30000L; // 30 s
-
     private static final long MIN_EUICC_FACTORY_RESET_TIMEOUT_MILLIS = 5000L; // 5 s
-
     private static final long MAX_EUICC_FACTORY_RESET_TIMEOUT_MILLIS = 60000L; // 60 s
 
+    private static final long DEFAULT_EUICC_REMOVING_INVISIBLE_PROFILES_TIMEOUT_MILLIS =
+            45000L; // 45 s
+    private static final long MIN_EUICC_REMOVING_INVISIBLE_PROFILES_TIMEOUT_MILLIS = 15000L; // 15 s
+    private static final long MAX_EUICC_REMOVING_INVISIBLE_PROFILES_TIMEOUT_MILLIS = 90000L; // 90 s
+
     /** Used to communicate with recovery.  See bootable/recovery/recovery.cpp. */
     private static final File RECOVERY_DIR = new File("/cache/recovery");
     private static final File LOG_FILE = new File(RECOVERY_DIR, "log");
@@ -99,9 +106,14 @@
     private static final String LAST_PREFIX = "last_";
     private static final String ACTION_EUICC_FACTORY_RESET =
             "com.android.internal.action.EUICC_FACTORY_RESET";
+    private static final String ACTION_EUICC_REMOVE_INVISIBLE_SUBSCRIPTIONS =
+            "com.android.internal.action.EUICC_REMOVE_INVISIBLE_SUBSCRIPTIONS";
 
-    /** used in {@link #wipeEuiccData} as package name of callback intent */
-    private static final String PACKAGE_NAME_WIPING_EUICC_DATA_CALLBACK = "android";
+    /**
+     * Used in {@link #wipeEuiccData} & {@link #removeEuiccInvisibleSubs} as package name of
+     * callback intent.
+     */
+    private static final String PACKAGE_NAME_EUICC_DATA_MANAGEMENT_CALLBACK = "android";
 
     /**
      * The recovery image uses this file to identify the location (i.e. blocks)
@@ -754,8 +766,11 @@
         // Block until the ordered broadcast has completed.
         condition.block();
 
+        EuiccManager euiccManager = context.getSystemService(EuiccManager.class);
         if (wipeEuicc) {
-            wipeEuiccData(context, PACKAGE_NAME_WIPING_EUICC_DATA_CALLBACK);
+            wipeEuiccData(context, PACKAGE_NAME_EUICC_DATA_MANAGEMENT_CALLBACK);
+        } else {
+            removeEuiccInvisibleSubs(context, euiccManager);
         }
 
         String shutdownArg = null;
@@ -851,6 +866,110 @@
         return false;
     }
 
+    private static void removeEuiccInvisibleSubs(
+            Context context, EuiccManager euiccManager) {
+        ContentResolver cr = context.getContentResolver();
+        if (Settings.Global.getInt(cr, Settings.Global.EUICC_PROVISIONED, 0) == 0) {
+            // If the eUICC isn't provisioned, there's no need to remove euicc invisible profiles,
+            // as there's nothing to be removed.
+            Log.i(TAG, "Skip removing eUICC invisible profiles as it is not provisioned.");
+            return;
+        } else if (euiccManager == null || !euiccManager.isEnabled()) {
+            Log.i(TAG, "Skip removing eUICC invisible profiles as eUICC manager is not available.");
+            return;
+        }
+        SubscriptionManager subscriptionManager =
+                context.getSystemService(SubscriptionManager.class);
+        List<SubscriptionInfo> availableSubs =
+                subscriptionManager.getAvailableSubscriptionInfoList();
+        if (availableSubs == null || availableSubs.isEmpty()) {
+            Log.i(TAG, "Skip removing eUICC invisible profiles as no available profiles found.");
+            return;
+        }
+        List<SubscriptionInfo> invisibleSubs = new ArrayList<>();
+        for (SubscriptionInfo sub : availableSubs) {
+            if (sub.isEmbedded() && !subscriptionManager.isSubscriptionVisible(sub)) {
+                invisibleSubs.add(sub);
+            }
+        }
+        removeEuiccInvisibleSubs(context, invisibleSubs, euiccManager);
+    }
+
+    private static boolean removeEuiccInvisibleSubs(
+            Context context, List<SubscriptionInfo> subscriptionInfos, EuiccManager euiccManager) {
+        if (subscriptionInfos == null || subscriptionInfos.isEmpty()) {
+            Log.i(TAG, "There are no eUICC invisible profiles needed to be removed.");
+            return true;
+        }
+        CountDownLatch removeSubsLatch = new CountDownLatch(subscriptionInfos.size());
+        final AtomicInteger removedSubsCount = new AtomicInteger(0);
+
+        BroadcastReceiver removeEuiccSubsReceiver = new BroadcastReceiver() {
+            @Override
+            public void onReceive(Context context, Intent intent) {
+                if (ACTION_EUICC_REMOVE_INVISIBLE_SUBSCRIPTIONS.equals(intent.getAction())) {
+                    if (getResultCode() != EuiccManager.EMBEDDED_SUBSCRIPTION_RESULT_OK) {
+                        int detailedCode = intent.getIntExtra(
+                                EuiccManager.EXTRA_EMBEDDED_SUBSCRIPTION_DETAILED_CODE, 0);
+                        Log.e(TAG, "Error removing euicc opportunistic profile, Detailed code = "
+                                + detailedCode);
+                    } else {
+                        Log.e(TAG, "Successfully remove euicc opportunistic profile.");
+                        removedSubsCount.incrementAndGet();
+                    }
+                    removeSubsLatch.countDown();
+                }
+            }
+        };
+
+        Intent intent = new Intent(ACTION_EUICC_REMOVE_INVISIBLE_SUBSCRIPTIONS);
+        intent.setPackage(PACKAGE_NAME_EUICC_DATA_MANAGEMENT_CALLBACK);
+        PendingIntent callbackIntent = PendingIntent.getBroadcastAsUser(
+                context, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT, UserHandle.SYSTEM);
+        IntentFilter intentFilter = new IntentFilter();
+        intentFilter.addAction(ACTION_EUICC_REMOVE_INVISIBLE_SUBSCRIPTIONS);
+        HandlerThread euiccHandlerThread =
+                new HandlerThread("euiccRemovingSubsReceiverThread");
+        euiccHandlerThread.start();
+        Handler euiccHandler = new Handler(euiccHandlerThread.getLooper());
+        context.getApplicationContext()
+                .registerReceiver(
+                        removeEuiccSubsReceiver, intentFilter, null, euiccHandler);
+        for (SubscriptionInfo subscriptionInfo : subscriptionInfos) {
+            Log.i(
+                    TAG,
+                    "Remove invisible subscription " + subscriptionInfo.getSubscriptionId()
+                            + " from card " + subscriptionInfo.getCardId());
+            euiccManager.createForCardId(subscriptionInfo.getCardId())
+                    .deleteSubscription(subscriptionInfo.getSubscriptionId(), callbackIntent);
+        }
+        try {
+            long waitingTimeMillis = Settings.Global.getLong(
+                    context.getContentResolver(),
+                    Settings.Global.EUICC_REMOVING_INVISIBLE_PROFILES_TIMEOUT_MILLIS,
+                    DEFAULT_EUICC_REMOVING_INVISIBLE_PROFILES_TIMEOUT_MILLIS);
+            if (waitingTimeMillis < MIN_EUICC_REMOVING_INVISIBLE_PROFILES_TIMEOUT_MILLIS) {
+                waitingTimeMillis = MIN_EUICC_REMOVING_INVISIBLE_PROFILES_TIMEOUT_MILLIS;
+            } else if (waitingTimeMillis > MAX_EUICC_REMOVING_INVISIBLE_PROFILES_TIMEOUT_MILLIS) {
+                waitingTimeMillis = MAX_EUICC_REMOVING_INVISIBLE_PROFILES_TIMEOUT_MILLIS;
+            }
+            if (!removeSubsLatch.await(waitingTimeMillis, TimeUnit.MILLISECONDS)) {
+                Log.e(TAG, "Timeout removing invisible euicc profiles.");
+                return false;
+            }
+        } catch (InterruptedException e) {
+            Thread.currentThread().interrupt();
+            Log.e(TAG, "Removing invisible euicc profiles interrupted", e);
+            return false;
+        } finally {
+            context.getApplicationContext().unregisterReceiver(removeEuiccSubsReceiver);
+            if (euiccHandlerThread != null) {
+                euiccHandlerThread.quit();
+            }
+        }
+        return removedSubsCount.get() == subscriptionInfos.size();
+    }
+
     /** {@hide} */
     public static void rebootPromptAndWipeUserData(Context context, String reason)
             throws IOException {
diff --git a/core/java/android/os/SharedMemory.java b/core/java/android/os/SharedMemory.java
index 7df4b5d..57a8801 100644
--- a/core/java/android/os/SharedMemory.java
+++ b/core/java/android/os/SharedMemory.java
@@ -25,8 +25,6 @@
 
 import dalvik.system.VMRuntime;
 
-import libcore.io.IoUtils;
-
 import java.io.Closeable;
 import java.io.FileDescriptor;
 import java.nio.ByteBuffer;
@@ -64,7 +62,7 @@
 
         mMemoryRegistration = new MemoryRegistration(mSize);
         mCleaner = Cleaner.create(mFileDescriptor,
-                new Closer(mFileDescriptor.getInt$(), mMemoryRegistration));
+                new Closer(mFileDescriptor, mMemoryRegistration));
     }
 
     /**
@@ -261,9 +259,6 @@
             mCleaner.clean();
             mCleaner = null;
         }
-
-        // Cleaner.clean doesn't clear the value of the file descriptor.
-        mFileDescriptor.setInt$(-1);
     }
 
     @Override
@@ -295,24 +290,19 @@
      * Cleaner that closes the FD
      */
     private static final class Closer implements Runnable {
-        // This is a copy of the FileDescriptor we're attached to, in order to avoid a reference
-        // cycle.
         private FileDescriptor mFd;
         private MemoryRegistration mMemoryReference;
 
-        private Closer(int fd, MemoryRegistration memoryReference) {
-            mFd = new FileDescriptor();
-            mFd.setInt$(fd);
-            IoUtils.setFdOwner(mFd, this);
-
+        private Closer(FileDescriptor fd, MemoryRegistration memoryReference) {
+            mFd = fd;
             mMemoryReference = memoryReference;
         }
 
         @Override
         public void run() {
-            IoUtils.closeQuietly(mFd);
-            mFd = null;
-
+            try {
+                Os.close(mFd);
+            } catch (ErrnoException e) { /* swallow error */ }
             mMemoryReference.release();
             mMemoryReference = null;
         }
diff --git a/core/java/android/os/SystemVibrator.java b/core/java/android/os/SystemVibrator.java
index 4af514a..a5188e7 100644
--- a/core/java/android/os/SystemVibrator.java
+++ b/core/java/android/os/SystemVibrator.java
@@ -77,16 +77,12 @@
             return;
         }
         try {
-            mService.vibrate(uid, opPkg, effect, usageForAttributes(attributes), reason, mToken);
+            mService.vibrate(uid, opPkg, effect, attributes, reason, mToken);
         } catch (RemoteException e) {
             Log.w(TAG, "Failed to vibrate.", e);
         }
     }
 
-    private static int usageForAttributes(AudioAttributes attributes) {
-        return attributes != null ? attributes.getUsage() : AudioAttributes.USAGE_UNKNOWN;
-    }
-
     @Override
     public void cancel() {
         if (mService == null) {
diff --git a/core/java/android/os/VibrationEffect.java b/core/java/android/os/VibrationEffect.java
index 702b41b..26da0a0 100644
--- a/core/java/android/os/VibrationEffect.java
+++ b/core/java/android/os/VibrationEffect.java
@@ -53,7 +53,7 @@
     public static final int MAX_AMPLITUDE = 255;
 
     /**
-     * A click effect.
+     * A click effect. Use this effect as a baseline, as it's the most common type of click effect.
      *
      * @see #get(int)
      */
@@ -67,7 +67,7 @@
     public static final int EFFECT_DOUBLE_CLICK = Effect.DOUBLE_CLICK;
 
     /**
-     * A tick effect.
+     * A tick effect. This effect is less strong compared to {@link #EFFECT_CLICK}.
      * @see #get(int)
      */
     public static final int EFFECT_TICK = Effect.TICK;
@@ -89,7 +89,7 @@
     public static final int EFFECT_POP = Effect.POP;
 
     /**
-     * A heavy click effect.
+     * A heavy click effect. This effect is stronger than {@link #EFFECT_CLICK}.
      * @see #get(int)
      */
     public static final int EFFECT_HEAVY_CLICK = Effect.HEAVY_CLICK;
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 e30ba38..c837b93 100644
--- a/core/java/android/provider/DeviceConfig.java
+++ b/core/java/android/provider/DeviceConfig.java
@@ -136,6 +136,14 @@
     public static final String NAMESPACE_DEX_BOOT = "dex_boot";
 
     /**
+     * Namespace for display manager related features. The names to access the properties in this
+     * namespace should be defined in {@link android.hardware.display.DisplayManager}.
+     *
+     * @hide
+     */
+    public static final String NAMESPACE_DISPLAY_MANAGER = "display_manager";
+
+    /**
      * Namespace for all Game Driver features.
      *
      * @hide
@@ -336,6 +344,20 @@
         @TestApi
         String KEY_SYSTEM_GESTURES_EXCLUDED_BY_PRE_Q_STICKY_IMMERSIVE =
                 "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";
     }
 
     private static final Object sLock = new Object();
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index 383d8db..209a364 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -88,6 +88,7 @@
 import android.util.ArraySet;
 import android.util.Log;
 import android.util.MemoryIntArray;
+import android.view.Display;
 import android.view.inputmethod.InputMethodSystemProperty;
 
 import com.android.internal.annotations.GuardedBy;
@@ -3476,6 +3477,14 @@
         };
 
         /**
+         * The user selected min refresh rate in frames per second.
+         *
+         * If this isn't set, 0 will be used.
+         * @hide
+         */
+        public static final String MIN_REFRESH_RATE = "min_refresh_rate";
+
+        /**
          * The user selected peak refresh rate in frames per second.
          *
          * If this isn't set, the system falls back to a device specific default.
@@ -4073,7 +4082,7 @@
          * preference, this rotation value will be used. Must be one of the
          * {@link android.view.Surface#ROTATION_0 Surface rotation constants}.
          *
-         * @see android.view.Display#getRotation
+         * @see Display#getRotation
          */
         public static final String USER_ROTATION = "user_rotation";
 
@@ -5948,6 +5957,18 @@
         public static final String DEVICE_PROVISIONED = Global.DEVICE_PROVISIONED;
 
         /**
+         * Indicates whether a DPC has been downloaded during provisioning.
+         *
+         * <p>Type: int (0 for false, 1 for true)
+         *
+         * <p>If this is true, then any attempts to begin setup again should result in factory reset
+         *
+         * @hide
+         */
+        public static final String MANAGED_PROVISIONING_DPC_DOWNLOADED =
+                "managed_provisioning_dpc_downloaded";
+
+        /**
          * Indicates whether the current user has completed setup via the setup wizard.
          * <p>
          * Type: int (0 for false, 1 for true)
@@ -6321,13 +6342,15 @@
                 "lock_screen_allow_remote_input";
 
         /**
-         * Indicates which clock face to show on lock screen and AOD.
+         * Indicates which clock face to show on lock screen and AOD formatted as a serialized
+         * {@link org.json.JSONObject} with the format:
+         *     {"clock": id, "_applied_timestamp": timestamp}
          * @hide
          */
         public static final String LOCK_SCREEN_CUSTOM_CLOCK_FACE = "lock_screen_custom_clock_face";
 
         private static final Validator LOCK_SCREEN_CUSTOM_CLOCK_FACE_VALIDATOR =
-                ANY_STRING_VALIDATOR;
+                SettingsValidators.JSON_OBJECT_VALIDATOR;
 
         /**
          * Indicates which clock face to show on lock screen and AOD while docked.
@@ -7731,12 +7754,21 @@
         private static final Validator DOZE_TAP_SCREEN_GESTURE_VALIDATOR = BOOLEAN_VALIDATOR;
 
         /**
-         * Gesture that wakes up the display, showing the ambient version of the status bar.
+         * Gesture that wakes up the display, showing some version of the lock screen.
          * @hide
          */
-        public static final String DOZE_WAKE_SCREEN_GESTURE = "doze_wake_screen_gesture";
+        public static final String DOZE_WAKE_LOCK_SCREEN_GESTURE = "doze_wake_screen_gesture";
 
-        private static final Validator DOZE_WAKE_SCREEN_GESTURE_VALIDATOR = BOOLEAN_VALIDATOR;
+        private static final Validator DOZE_WAKE_LOCK_SCREEN_GESTURE_VALIDATOR = BOOLEAN_VALIDATOR;
+
+        /**
+         * Gesture that wakes up the display, toggling between {@link Display.STATE_OFF} and
+         * {@link Display.STATE_DOZE}.
+         * @hide
+         */
+        public static final String DOZE_WAKE_DISPLAY_GESTURE = "doze_wake_display_gesture";
+
+        private static final Validator DOZE_WAKE_DISPLAY_GESTURE_VALIDATOR = BOOLEAN_VALIDATOR;
 
         /**
          * Gesture that skips media.
@@ -7752,10 +7784,30 @@
          */
         public static final String SKIP_GESTURE_COUNT = "skip_gesture_count";
 
+        /**
+         * Count of non-gesture interaction.
+         * @hide
+         */
+        public static final String SKIP_TOUCH_COUNT = "skip_touch_count";
+
         private static final Validator SKIP_GESTURE_COUNT_VALIDATOR =
                 NON_NEGATIVE_INTEGER_VALIDATOR;
 
         /**
+         * Direction to advance media for skip gesture
+         * @hide
+         */
+        public static final String SKIP_DIRECTION = "skip_gesture_direction";
+
+        /**
+         * Only used if FeatureFlag "settings_skip_direction_mutable" is enabled.
+         * If feature flag is disabled, should assume SKIP_DIRECTION = 0.
+         *      0 / false = right to left to advance to next
+         *      1 / true = left to right to advance to next
+         */
+        private static final Validator SKIP_DIRECTION_VALIDATOR = BOOLEAN_VALIDATOR;
+
+        /**
          * Gesture that silences sound (alarms, notification, calls).
          * @hide
          */
@@ -7782,11 +7834,22 @@
         public static final String SILENCE_CALL_GESTURE_COUNT = "silence_call_gesture_count";
 
         /**
-         * Count of successful silence notification gestures.
+         * Count of non-gesture interaction.
          * @hide
          */
-        public static final String SILENCE_NOTIFICATION_GESTURE_COUNT =
-                "silence_notification_gesture_count";
+        public static final String SILENCE_ALARMS_TOUCH_COUNT = "silence_alarms_touch_count";
+
+        /**
+         * Count of non-gesture interaction.
+         * @hide
+         */
+        public static final String SILENCE_TIMER_TOUCH_COUNT = "silence_timer_touch_count";
+
+        /**
+         * Count of non-gesture interaction.
+         * @hide
+         */
+        public static final String SILENCE_CALL_TOUCH_COUNT = "silence_call_touch_count";
 
         private static final Validator SILENCE_GESTURE_COUNT_VALIDATOR =
                 NON_NEGATIVE_INTEGER_VALIDATOR;
@@ -8250,6 +8313,16 @@
                 BOOLEAN_VALIDATOR;
 
         /**
+         * Whether or not media is shown automatically when bypassing as a heads up.
+         * @hide
+         */
+        public static final String SHOW_MEDIA_WHEN_BYPASSING =
+                "show_media_when_bypassing";
+
+        private static final Validator SHOW_MEDIA_WHEN_BYPASSING_VALIDATOR =
+                BOOLEAN_VALIDATOR;
+
+        /**
          * Whether or not face unlock requires attention. This is a cached value, the source of
          * truth is obtained through the HAL.
          * @hide
@@ -8289,16 +8362,6 @@
                 BOOLEAN_VALIDATOR;
 
         /**
-         * Whether or not the face unlock education screen has been shown to the user.
-         * @hide
-         */
-        public static final String FACE_UNLOCK_EDUCATION_INFO_DISPLAYED =
-                "face_unlock_education_info_displayed";
-
-        private static final Validator FACE_UNLOCK_EDUCATION_INFO_DISPLAYED_VALIDATOR =
-                BOOLEAN_VALIDATOR;
-
-        /**
          * Whether or not debugging is enabled.
          * @hide
          */
@@ -8948,10 +9011,12 @@
             DOZE_PICK_UP_GESTURE,
             DOZE_DOUBLE_TAP_GESTURE,
             DOZE_TAP_SCREEN_GESTURE,
-            DOZE_WAKE_SCREEN_GESTURE,
+            DOZE_WAKE_LOCK_SCREEN_GESTURE,
+            DOZE_WAKE_DISPLAY_GESTURE,
             NFC_PAYMENT_DEFAULT_COMPONENT,
             AUTOMATIC_STORAGE_MANAGER_DAYS_TO_RETAIN,
             FACE_UNLOCK_KEYGUARD_ENABLED,
+            SHOW_MEDIA_WHEN_BYPASSING,
             FACE_UNLOCK_DISMISSES_KEYGUARD,
             FACE_UNLOCK_APP_ENABLED,
             FACE_UNLOCK_ALWAYS_REQUIRE_CONFIRMATION,
@@ -8992,15 +9057,19 @@
             UI_NIGHT_MODE,
             LOCK_SCREEN_WHEN_TRUST_LOST,
             SKIP_GESTURE,
+            SKIP_DIRECTION,
             SILENCE_GESTURE,
             THEME_CUSTOMIZATION_OVERLAY_PACKAGES,
             NAVIGATION_MODE,
             AWARE_ENABLED,
             SKIP_GESTURE_COUNT,
+            SKIP_TOUCH_COUNT,
             SILENCE_ALARMS_GESTURE_COUNT,
-            SILENCE_NOTIFICATION_GESTURE_COUNT,
             SILENCE_CALL_GESTURE_COUNT,
             SILENCE_TIMER_GESTURE_COUNT,
+            SILENCE_ALARMS_TOUCH_COUNT,
+            SILENCE_CALL_TOUCH_COUNT,
+            SILENCE_TIMER_TOUCH_COUNT,
             DARK_MODE_DIALOG_SEEN,
             GLOBAL_ACTIONS_PANEL_ENABLED,
             AWARE_LOCK_ENABLED
@@ -9119,18 +9188,18 @@
             VALIDATORS.put(DOZE_PICK_UP_GESTURE, DOZE_PICK_UP_GESTURE_VALIDATOR);
             VALIDATORS.put(DOZE_DOUBLE_TAP_GESTURE, DOZE_DOUBLE_TAP_GESTURE_VALIDATOR);
             VALIDATORS.put(DOZE_TAP_SCREEN_GESTURE, DOZE_TAP_SCREEN_GESTURE_VALIDATOR);
-            VALIDATORS.put(DOZE_WAKE_SCREEN_GESTURE, DOZE_WAKE_SCREEN_GESTURE_VALIDATOR);
+            VALIDATORS.put(DOZE_WAKE_LOCK_SCREEN_GESTURE, DOZE_WAKE_LOCK_SCREEN_GESTURE_VALIDATOR);
+            VALIDATORS.put(DOZE_WAKE_DISPLAY_GESTURE, DOZE_WAKE_DISPLAY_GESTURE_VALIDATOR);
             VALIDATORS.put(NFC_PAYMENT_DEFAULT_COMPONENT, NFC_PAYMENT_DEFAULT_COMPONENT_VALIDATOR);
             VALIDATORS.put(AUTOMATIC_STORAGE_MANAGER_DAYS_TO_RETAIN,
                     AUTOMATIC_STORAGE_MANAGER_DAYS_TO_RETAIN_VALIDATOR);
             VALIDATORS.put(FACE_UNLOCK_KEYGUARD_ENABLED, FACE_UNLOCK_KEYGUARD_ENABLED_VALIDATOR);
             VALIDATORS.put(FACE_UNLOCK_DISMISSES_KEYGUARD,
                     FACE_UNLOCK_DISMISSES_KEYGUARD_VALIDATOR);
+            VALIDATORS.put(SHOW_MEDIA_WHEN_BYPASSING, SHOW_MEDIA_WHEN_BYPASSING_VALIDATOR);
             VALIDATORS.put(FACE_UNLOCK_APP_ENABLED, FACE_UNLOCK_APP_ENABLED_VALIDATOR);
             VALIDATORS.put(FACE_UNLOCK_ALWAYS_REQUIRE_CONFIRMATION,
                     FACE_UNLOCK_ALWAYS_REQUIRE_CONFIRMATION_VALIDATOR);
-            VALIDATORS.put(FACE_UNLOCK_EDUCATION_INFO_DISPLAYED,
-                    FACE_UNLOCK_EDUCATION_INFO_DISPLAYED_VALIDATOR);
             VALIDATORS.put(ASSIST_GESTURE_ENABLED, ASSIST_GESTURE_ENABLED_VALIDATOR);
             VALIDATORS.put(ASSIST_GESTURE_SILENCE_ALERTS_ENABLED,
                     ASSIST_GESTURE_SILENCE_ALERTS_ENABLED_VALIDATOR);
@@ -9178,16 +9247,21 @@
             VALIDATORS.put(LOCK_SCREEN_CUSTOM_CLOCK_FACE, LOCK_SCREEN_CUSTOM_CLOCK_FACE_VALIDATOR);
             VALIDATORS.put(LOCK_SCREEN_WHEN_TRUST_LOST, LOCK_SCREEN_WHEN_TRUST_LOST_VALIDATOR);
             VALIDATORS.put(SKIP_GESTURE, SKIP_GESTURE_VALIDATOR);
+            VALIDATORS.put(SKIP_DIRECTION, SKIP_DIRECTION_VALIDATOR);
+            VALIDATORS.put(SKIP_DIRECTION, SKIP_DIRECTION_VALIDATOR);
             VALIDATORS.put(SILENCE_GESTURE, SILENCE_GESTURE_VALIDATOR);
             VALIDATORS.put(THEME_CUSTOMIZATION_OVERLAY_PACKAGES,
                     THEME_CUSTOMIZATION_OVERLAY_PACKAGES_VALIDATOR);
             VALIDATORS.put(NAVIGATION_MODE, NAVIGATION_MODE_VALIDATOR);
             VALIDATORS.put(AWARE_ENABLED, AWARE_ENABLED_VALIDATOR);
             VALIDATORS.put(SKIP_GESTURE_COUNT, SKIP_GESTURE_COUNT_VALIDATOR);
+            VALIDATORS.put(SKIP_TOUCH_COUNT, SKIP_GESTURE_COUNT_VALIDATOR);
             VALIDATORS.put(SILENCE_ALARMS_GESTURE_COUNT, SILENCE_GESTURE_COUNT_VALIDATOR);
             VALIDATORS.put(SILENCE_TIMER_GESTURE_COUNT, SILENCE_GESTURE_COUNT_VALIDATOR);
             VALIDATORS.put(SILENCE_CALL_GESTURE_COUNT, SILENCE_GESTURE_COUNT_VALIDATOR);
-            VALIDATORS.put(SILENCE_NOTIFICATION_GESTURE_COUNT, SILENCE_GESTURE_COUNT_VALIDATOR);
+            VALIDATORS.put(SILENCE_ALARMS_TOUCH_COUNT, SILENCE_GESTURE_COUNT_VALIDATOR);
+            VALIDATORS.put(SILENCE_TIMER_TOUCH_COUNT, SILENCE_GESTURE_COUNT_VALIDATOR);
+            VALIDATORS.put(SILENCE_CALL_TOUCH_COUNT, SILENCE_GESTURE_COUNT_VALIDATOR);
             VALIDATORS.put(ODI_CAPTIONS_ENABLED, ODI_CAPTIONS_ENABLED_VALIDATOR);
             VALIDATORS.put(DARK_MODE_DIALOG_SEEN, BOOLEAN_VALIDATOR);
             VALIDATORS.put(UI_NIGHT_MODE, UI_NIGHT_MODE_VALIDATOR);
@@ -13549,6 +13623,16 @@
                 "location_settings_link_to_permissions_enabled";
 
         /**
+         * Flag to set the waiting time for removing invisible euicc profiles inside System >
+         * Settings.
+         * Type: long
+         *
+         * @hide
+         */
+        public static final String EUICC_REMOVING_INVISIBLE_PROFILES_TIMEOUT_MILLIS =
+                "euicc_removing_invisible_profiles_timeout_millis";
+
+        /**
          * Flag to set the waiting time for euicc factory reset inside System > Settings
          * Type: long
          *
diff --git a/core/java/android/util/FeatureFlagUtils.java b/core/java/android/util/FeatureFlagUtils.java
index 324e02c..0e0c676 100644
--- a/core/java/android/util/FeatureFlagUtils.java
+++ b/core/java/android/util/FeatureFlagUtils.java
@@ -57,6 +57,7 @@
         DEFAULT_FLAGS.put(SCREENRECORD_LONG_PRESS, "false");
         DEFAULT_FLAGS.put(PIXEL_WALLPAPER_CATEGORY_SWITCH, "false");
         DEFAULT_FLAGS.put("settings_wifi_details_datausage_header", "false");
+        DEFAULT_FLAGS.put("settings_skip_direction_mutable", "true");
     }
 
     /**
diff --git a/core/java/android/view/AccessibilityInteractionController.java b/core/java/android/view/AccessibilityInteractionController.java
index bbd44c8..4b92968 100644
--- a/core/java/android/view/AccessibilityInteractionController.java
+++ b/core/java/android/view/AccessibilityInteractionController.java
@@ -830,6 +830,32 @@
         return false;
     }
 
+    private void adjustBoundsInScreenIfNeeded(List<AccessibilityNodeInfo> infos) {
+        if (infos == null || shouldBypassAdjustBoundsInScreen()) {
+            return;
+        }
+        final int infoCount = infos.size();
+        for (int i = 0; i < infoCount; i++) {
+            final AccessibilityNodeInfo info = infos.get(i);
+            adjustBoundsInScreenIfNeeded(info);
+        }
+    }
+
+    private void adjustBoundsInScreenIfNeeded(AccessibilityNodeInfo info) {
+        if (info == null || shouldBypassAdjustBoundsInScreen()) {
+            return;
+        }
+        final Rect boundsInScreen = mTempRect;
+        info.getBoundsInScreen(boundsInScreen);
+        boundsInScreen.offset(mViewRootImpl.mAttachInfo.mLocationInParentDisplay.x,
+                mViewRootImpl.mAttachInfo.mLocationInParentDisplay.y);
+        info.setBoundsInScreen(boundsInScreen);
+    }
+
+    private boolean shouldBypassAdjustBoundsInScreen() {
+        return mViewRootImpl.mAttachInfo.mLocationInParentDisplay.equals(0, 0);
+    }
+
     private void applyAppScaleAndMagnificationSpecIfNeeded(AccessibilityNodeInfo info,
             MagnificationSpec spec) {
         if (info == null) {
@@ -921,6 +947,7 @@
             MagnificationSpec spec, Region interactiveRegion) {
         try {
             mViewRootImpl.mAttachInfo.mAccessibilityFetchFlags = 0;
+            adjustBoundsInScreenIfNeeded(infos);
             applyAppScaleAndMagnificationSpecIfNeeded(infos, spec);
             adjustIsVisibleToUserIfNeeded(infos, interactiveRegion);
             callback.setFindAccessibilityNodeInfosResult(infos, interactionId);
@@ -939,6 +966,7 @@
             MagnificationSpec spec, Region interactiveRegion) {
         try {
             mViewRootImpl.mAttachInfo.mAccessibilityFetchFlags = 0;
+            adjustBoundsInScreenIfNeeded(info);
             applyAppScaleAndMagnificationSpecIfNeeded(info, spec);
             adjustIsVisibleToUserIfNeeded(info, interactiveRegion);
             callback.setFindAccessibilityNodeInfoResult(info, interactionId);
diff --git a/core/java/android/view/Choreographer.java b/core/java/android/view/Choreographer.java
index c64386e..e95b5ca 100644
--- a/core/java/android/view/Choreographer.java
+++ b/core/java/android/view/Choreographer.java
@@ -16,6 +16,7 @@
 
 package android.view;
 
+import static android.view.DisplayEventReceiver.CONFIG_CHANGED_EVENT_SUPPRESS;
 import static android.view.DisplayEventReceiver.VSYNC_SOURCE_APP;
 import static android.view.DisplayEventReceiver.VSYNC_SOURCE_SURFACE_FLINGER;
 
@@ -910,7 +911,7 @@
         private int mFrame;
 
         public FrameDisplayEventReceiver(Looper looper, int vsyncSource) {
-            super(looper, vsyncSource);
+            super(looper, vsyncSource, CONFIG_CHANGED_EVENT_SUPPRESS);
         }
 
         // TODO(b/116025192): physicalDisplayId is ignored because SF only emits VSYNC events for
diff --git a/core/java/android/view/DisplayEventReceiver.java b/core/java/android/view/DisplayEventReceiver.java
index 60daddd..91acc46 100644
--- a/core/java/android/view/DisplayEventReceiver.java
+++ b/core/java/android/view/DisplayEventReceiver.java
@@ -53,6 +53,20 @@
      */
     public static final int VSYNC_SOURCE_SURFACE_FLINGER = 1;
 
+    /**
+     * Specifies to suppress config changed events from being generated from Surface Flinger.
+     * <p>
+     * Needs to be kept in sync with frameworks/native/include/gui/ISurfaceComposer.h
+     */
+    public static final int CONFIG_CHANGED_EVENT_SUPPRESS = 0;
+
+    /**
+     * Specifies to generate config changed events from Surface Flinger.
+     * <p>
+     * Needs to be kept in sync with frameworks/native/include/gui/ISurfaceComposer.h
+     */
+    public static final int CONFIG_CHANGED_EVENT_DISPATCH = 1;
+
     private static final String TAG = "DisplayEventReceiver";
 
     private final CloseGuard mCloseGuard = CloseGuard.get();
@@ -65,7 +79,7 @@
     private MessageQueue mMessageQueue;
 
     private static native long nativeInit(WeakReference<DisplayEventReceiver> receiver,
-            MessageQueue messageQueue, int vsyncSource);
+            MessageQueue messageQueue, int vsyncSource, int configChanged);
     private static native void nativeDispose(long receiverPtr);
     @FastNative
     private static native void nativeScheduleVsync(long receiverPtr);
@@ -77,7 +91,7 @@
      */
     @UnsupportedAppUsage
     public DisplayEventReceiver(Looper looper) {
-        this(looper, VSYNC_SOURCE_APP);
+        this(looper, VSYNC_SOURCE_APP, CONFIG_CHANGED_EVENT_SUPPRESS);
     }
 
     /**
@@ -85,15 +99,17 @@
      *
      * @param looper The looper to use when invoking callbacks.
      * @param vsyncSource The source of the vsync tick. Must be on of the VSYNC_SOURCE_* values.
+     * @param configChanged Whether to dispatch config changed events. Must be one of the
+     * CONFIG_CHANGED_EVENT_* values.
      */
-    public DisplayEventReceiver(Looper looper, int vsyncSource) {
+    public DisplayEventReceiver(Looper looper, int vsyncSource, int configChanged) {
         if (looper == null) {
             throw new IllegalArgumentException("looper must not be null");
         }
 
         mMessageQueue = looper.getQueue();
         mReceiverPtr = nativeInit(new WeakReference<DisplayEventReceiver>(this), mMessageQueue,
-                vsyncSource);
+                vsyncSource, configChanged);
 
         mCloseGuard.open("dispose");
     }
diff --git a/core/java/android/view/IRecentsAnimationController.aidl b/core/java/android/view/IRecentsAnimationController.aidl
index 956161a..955be8d 100644
--- a/core/java/android/view/IRecentsAnimationController.aidl
+++ b/core/java/android/view/IRecentsAnimationController.aidl
@@ -77,23 +77,9 @@
     void hideCurrentInputMethod();
 
     /**
-     * Set a state for controller whether would like to cancel recents animations with deferred
-     * task screenshot presentation.
-     *
-     * When we cancel the recents animation due to a stack order change, we can't just cancel it
-     * immediately as it would lead to a flicker in Launcher if we just remove the task from the
-     * leash. Instead we screenshot the previous task and replace the child of the leash with the
-     * screenshot, so that Launcher can still control the leash lifecycle & make the next app
-     * transition animate smoothly without flickering.
-     *
-     * @param screenshot When set {@code true}, means recents animation will be canceled when the
-     *                   next app launch. System will take previous task's screenshot when the next
-     *                   app transition starting, and skip previous task's animation.
-     *                   Set {@code false} means will not take screenshot & skip animation
-     *                   for previous task.
-     *
-     * @see #cleanupScreenshot()
-     * @see IRecentsAnimationRunner#onCancelled
+     * This call is deprecated, use #setDeferCancelUntilNextTransition() instead
+     * TODO(138144750): Remove this method once there are no callers
+     * @deprecated
      */
     void setCancelWithDeferredScreenshot(boolean screenshot);
 
@@ -104,4 +90,34 @@
      * @see {@link IRecentsAnimationRunner#onAnimationCanceled}
      */
     void cleanupScreenshot();
+
+    /**
+     * Set a state for controller whether would like to cancel recents animations with deferred
+     * task screenshot presentation.
+     *
+     * When we cancel the recents animation due to a stack order change, we can't just cancel it
+     * immediately as it would lead to a flicker in Launcher if we just remove the task from the
+     * leash. Instead we screenshot the previous task and replace the child of the leash with the
+     * screenshot, so that Launcher can still control the leash lifecycle & make the next app
+     * transition animate smoothly without flickering.
+     *
+     * @param defer When set {@code true}, means that the recents animation will defer canceling the
+     *              animation when a stack order change is triggered until the subsequent app
+     *              transition start and skip previous task's animation.
+     *              When set to {@code false}, means that the recents animation will be canceled
+     *              immediately when the stack order changes.
+     * @param screenshot When set {@code true}, means that the system will take previous task's
+     *                   screenshot and replace the contents of the leash with it when the next app
+     *                   transition starting. The runner must call #cleanupScreenshot() to end the
+     *                   recents animation.
+     *                   When set to {@code false}, means that the system will simply wait for the
+     *                   next app transition start to immediately cancel the recents animation. This
+     *                   can be useful when you want an immediate transition into a state where the
+     *                   task is shown in the home/recents activity (without waiting for a
+     *                   screenshot).
+     *
+     * @see #cleanupScreenshot()
+     * @see IRecentsAnimationRunner#onCancelled
+     */
+    void setDeferCancelUntilNextTransition(boolean defer, boolean screenshot);
 }
diff --git a/core/java/android/view/IRecentsAnimationRunner.aidl b/core/java/android/view/IRecentsAnimationRunner.aidl
index 9c652a8..6cda60c 100644
--- a/core/java/android/view/IRecentsAnimationRunner.aidl
+++ b/core/java/android/view/IRecentsAnimationRunner.aidl
@@ -36,7 +36,7 @@
      * @param deferredWithScreenshot If set to {@code true}, the contents of the task will be
      *                               replaced with a screenshot, such that the runner's leash is
      *                               still active. As soon as the runner doesn't need the leash
-     *                               anymore, it can call
+     *                               anymore, it must call
      *                               {@link IRecentsAnimationController#cleanupScreenshot).
      *
      * @see {@link RecentsAnimationController#cleanupScreenshot}
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/IWindow.aidl b/core/java/android/view/IWindow.aidl
index 699e795..f34f9e6 100644
--- a/core/java/android/view/IWindow.aidl
+++ b/core/java/android/view/IWindow.aidl
@@ -17,6 +17,7 @@
 
 package android.view;
 
+import android.graphics.Point;
 import android.graphics.Rect;
 import android.os.Bundle;
 import android.os.ParcelFileDescriptor;
@@ -57,6 +58,12 @@
             in DisplayCutout.ParcelableWrapper displayCutout);
 
     /**
+     * Called when the window location in parent display has changed. The offset will only be a
+     * nonzero value if the window is on an embedded display that is re-parented to another window.
+     */
+    void locationInParentDisplayChanged(in Point offset);
+
+    /**
      * Called when the window insets configuration has changed.
      */
     void insetsChanged(in InsetsState insetsState);
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/Surface.java b/core/java/android/view/Surface.java
index cb64ab1..17f07b5 100644
--- a/core/java/android/view/Surface.java
+++ b/core/java/android/view/Surface.java
@@ -21,6 +21,7 @@
 import android.annotation.UnsupportedAppUsage;
 import android.content.res.CompatibilityInfo.Translator;
 import android.graphics.Canvas;
+import android.graphics.ColorSpace;
 import android.graphics.GraphicBuffer;
 import android.graphics.Matrix;
 import android.graphics.RecordingCanvas;
@@ -80,7 +81,8 @@
     private static native long nativeGetNextFrameNumber(long nativeObject);
     private static native int nativeSetScalingMode(long nativeObject, int scalingMode);
     private static native int nativeForceScopedDisconnect(long nativeObject);
-    private static native int nativeAttachAndQueueBuffer(long nativeObject, GraphicBuffer buffer);
+    private static native int nativeAttachAndQueueBufferWithColorSpace(long nativeObject,
+            GraphicBuffer buffer, int colorSpaceId);
 
     private static native int nativeSetSharedBufferModeEnabled(long nativeObject, boolean enabled);
     private static native int nativeSetAutoRefreshEnabled(long nativeObject, boolean enabled);
@@ -699,18 +701,35 @@
     }
 
     /**
+     * Transfer ownership of buffer with a color space and present it on the Surface.
+     * The supported color spaces are SRGB and Display P3, other color spaces will be
+     * treated as SRGB.
+     * @hide
+     */
+    public void attachAndQueueBufferWithColorSpace(GraphicBuffer buffer, ColorSpace colorSpace) {
+        synchronized (mLock) {
+            checkNotReleasedLocked();
+            if (colorSpace == null) {
+                colorSpace = ColorSpace.get(ColorSpace.Named.SRGB);
+            }
+            int err = nativeAttachAndQueueBufferWithColorSpace(mNativeObject, buffer,
+                    colorSpace.getId());
+            if (err != 0) {
+                throw new RuntimeException(
+                        "Failed to attach and queue buffer to Surface (bad object?), "
+                        + "native error: " + err);
+            }
+        }
+    }
+
+    /**
+     * Deprecated, use attachAndQueueBufferWithColorSpace instead.
      * Transfer ownership of buffer and present it on the Surface.
+     * The color space of the buffer is treated as SRGB.
      * @hide
      */
     public void attachAndQueueBuffer(GraphicBuffer buffer) {
-        synchronized (mLock) {
-            checkNotReleasedLocked();
-            int err = nativeAttachAndQueueBuffer(mNativeObject, buffer);
-            if (err != 0) {
-                throw new RuntimeException(
-                        "Failed to attach and queue buffer to Surface (bad object?)");
-            }
-        }
+        attachAndQueueBufferWithColorSpace(buffer, ColorSpace.get(ColorSpace.Named.SRGB));
     }
 
     /**
diff --git a/core/java/android/view/SurfaceControl.java b/core/java/android/view/SurfaceControl.java
index 63e1485..3c045f4 100644
--- a/core/java/android/view/SurfaceControl.java
+++ b/core/java/android/view/SurfaceControl.java
@@ -1866,7 +1866,8 @@
         final ScreenshotGraphicBuffer buffer = screenshotToBuffer(display, sourceCrop, width,
                 height, useIdentityTransform, rotation);
         try {
-            consumer.attachAndQueueBuffer(buffer.getGraphicBuffer());
+            consumer.attachAndQueueBufferWithColorSpace(buffer.getGraphicBuffer(),
+                    buffer.getColorSpace());
         } catch (RuntimeException e) {
             Log.w(TAG, "Failed to take screenshot - " + e.getMessage());
         }
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index 1275e46..4e86e60 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -1390,6 +1390,74 @@
      */
     public static final int AUTOFILL_FLAG_INCLUDE_NOT_IMPORTANT_VIEWS = 0x1;
 
+    /** @hide */
+    @IntDef(prefix = { "IMPORTANT_FOR_CONTENT_CAPTURE_" }, value = {
+            IMPORTANT_FOR_CONTENT_CAPTURE_AUTO,
+            IMPORTANT_FOR_CONTENT_CAPTURE_YES,
+            IMPORTANT_FOR_CONTENT_CAPTURE_NO,
+            IMPORTANT_FOR_CONTENT_CAPTURE_YES_EXCLUDE_DESCENDANTS,
+            IMPORTANT_FOR_CONTENT_CAPTURE_NO_EXCLUDE_DESCENDANTS
+    })
+    @Retention(RetentionPolicy.SOURCE)
+    public @interface ContentCaptureImportance {}
+
+    /**
+     * Automatically determine whether a view is important for content capture.
+     *
+     * @see #isImportantForContentCapture()
+     * @see #setImportantForContentCapture(int)
+     *
+     * @hide
+     */
+    @TestApi
+    public static final int IMPORTANT_FOR_CONTENT_CAPTURE_AUTO = 0x0;
+
+    /**
+     * The view is important for content capture, and its children (if any) will be traversed.
+     *
+     * @see #isImportantForContentCapture()
+     * @see #setImportantForContentCapture(int)
+     *
+     * @hide
+     */
+    @TestApi
+    public static final int IMPORTANT_FOR_CONTENT_CAPTURE_YES = 0x1;
+
+    /**
+     * The view is not important for content capture, but its children (if any) will be traversed.
+     *
+     * @see #isImportantForContentCapture()
+     * @see #setImportantForContentCapture(int)
+     *
+     * @hide
+     */
+    @TestApi
+    public static final int IMPORTANT_FOR_CONTENT_CAPTURE_NO = 0x2;
+
+    /**
+     * The view is important for content capture, but its children (if any) will not be traversed.
+     *
+     * @see #isImportantForContentCapture()
+     * @see #setImportantForContentCapture(int)
+     *
+     * @hide
+     */
+    @TestApi
+    public static final int IMPORTANT_FOR_CONTENT_CAPTURE_YES_EXCLUDE_DESCENDANTS = 0x4;
+
+    /**
+     * The view is not important for content capture, and its children (if any) will not be
+     * traversed.
+     *
+     * @see #isImportantForContentCapture()
+     * @see #setImportantForContentCapture(int)
+     *
+     * @hide
+     */
+    @TestApi
+    public static final int IMPORTANT_FOR_CONTENT_CAPTURE_NO_EXCLUDE_DESCENDANTS = 0x8;
+
+
     /**
      * This view is enabled. Interpretation varies by subclass.
      * Use with ENABLED_MASK when calling setFlags.
@@ -3362,6 +3430,55 @@
 
     /* End of masks for mPrivateFlags3 */
 
+    /*
+     * Masks for mPrivateFlags4, as generated by dumpFlags():
+     *
+     * |-------|-------|-------|-------|
+     *                             1111 PFLAG4_IMPORTANT_FOR_CONTENT_CAPTURE_MASK
+     *                            1     PFLAG4_NOTIFIED_CONTENT_CAPTURE_APPEARED
+     *                           1      PFLAG4_NOTIFIED_CONTENT_CAPTURE_DISAPPEARED
+     *                          1       PFLAG4_CONTENT_CAPTURE_IMPORTANCE_IS_CACHED
+     *                         1        PFLAG4_CONTENT_CAPTURE_IMPORTANCE_CACHED_VALUE
+     *                         11       PFLAG4_CONTENT_CAPTURE_IMPORTANCE_MASK
+     * |-------|-------|-------|-------|
+     */
+
+    /**
+     * Mask for obtaining the bits which specify how to determine
+     * whether a view is important for autofill.
+     *
+     * <p>NOTE: the important for content capture values were the first flags added and are set in
+     * the rightmost position, so we don't need to shift them
+     */
+    private static final int PFLAG4_IMPORTANT_FOR_CONTENT_CAPTURE_MASK =
+            IMPORTANT_FOR_CONTENT_CAPTURE_AUTO | IMPORTANT_FOR_CONTENT_CAPTURE_YES
+            | IMPORTANT_FOR_CONTENT_CAPTURE_NO
+            | IMPORTANT_FOR_CONTENT_CAPTURE_YES_EXCLUDE_DESCENDANTS
+            | IMPORTANT_FOR_CONTENT_CAPTURE_NO_EXCLUDE_DESCENDANTS;
+
+    /*
+     * Variables used to control when the IntelligenceManager.notifyNodeAdded()/removed() methods
+     * should be called.
+     *
+     * The idea is to call notifyAppeared() after the view is layout and visible, then call
+     * notifyDisappeared() when it's gone (without known when it was removed from the parent).
+     */
+    private static final int PFLAG4_NOTIFIED_CONTENT_CAPTURE_APPEARED = 0x10;
+    private static final int PFLAG4_NOTIFIED_CONTENT_CAPTURE_DISAPPEARED = 0x20;
+
+    /*
+     * Flags used to cache the value returned by isImportantForContentCapture while the view
+     * hierarchy is being traversed.
+     */
+    private static final int PFLAG4_CONTENT_CAPTURE_IMPORTANCE_IS_CACHED = 0x40;
+    private static final int PFLAG4_CONTENT_CAPTURE_IMPORTANCE_CACHED_VALUE = 0x80;
+
+    private static final int PFLAG4_CONTENT_CAPTURE_IMPORTANCE_MASK =
+            PFLAG4_CONTENT_CAPTURE_IMPORTANCE_IS_CACHED
+            | PFLAG4_CONTENT_CAPTURE_IMPORTANCE_CACHED_VALUE;
+
+    /* End of masks for mPrivateFlags4 */
+
     /** @hide */
     protected static final int VIEW_STRUCTURE_FOR_ASSIST = 0;
     /** @hide */
@@ -3985,6 +4102,8 @@
     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 129147060)
     int mPrivateFlags3;
 
+    private int mPrivateFlags4;
+
     /**
      * This view's request for the visibility of the status bar.
      * @hide
@@ -8442,6 +8561,65 @@
         onProvideStructure(structure, VIEW_STRUCTURE_FOR_AUTOFILL, flags);
     }
 
+    /**
+     * Populates a {@link ViewStructure} for content capture.
+     *
+     * <p>This method is called after a view is that is eligible for content capture
+     * (for example, if it {@link #isImportantForAutofill()}, an intelligence service is enabled for
+     * the user, and the activity rendering the view is enabled for content capture) is laid out and
+     * is visible.
+     *
+     * <p>The populated structure is then passed to the service through
+     * {@link ContentCaptureSession#notifyViewAppeared(ViewStructure)}.
+     *
+     * <p><b>Note: </b>views that manage a virtual structure under this view must populate just
+     * the node representing this view and return right away, then asynchronously report (not
+     * necessarily in the UI thread) when the children nodes appear, disappear or have their text
+     * changed by calling
+     * {@link ContentCaptureSession#notifyViewAppeared(ViewStructure)},
+     * {@link ContentCaptureSession#notifyViewDisappeared(AutofillId)}, and
+     * {@link ContentCaptureSession#notifyViewTextChanged(AutofillId, CharSequence)}
+     * respectively. The structure for the a child must be created using
+     * {@link ContentCaptureSession#newVirtualViewStructure(AutofillId, long)}, and the
+     * {@code autofillId} for a child can be obtained either through
+     * {@code childStructure.getAutofillId()} or
+     * {@link ContentCaptureSession#newAutofillId(AutofillId, long)}.
+     *
+     * <p>When the virtual view hierarchy represents a web page, you should also:
+     *
+     * <ul>
+     *   <li>Call {@link ContentCaptureManager#getContentCaptureConditions()} to infer content
+     *   capture events should be generate for that URL.
+     *   <li>Create a new {@link ContentCaptureSession} child for every HTML element that
+     *   renders a new URL (like an {@code IFRAME}) and use that session to notify events from
+     *   that subtree.
+     * </ul>
+     *
+     * <p><b>Note: </b>the following methods of the {@code structure} will be ignored:
+     * <ul>
+     *   <li>{@link ViewStructure#setChildCount(int)}
+     *   <li>{@link ViewStructure#addChildCount(int)}
+     *   <li>{@link ViewStructure#getChildCount()}
+     *   <li>{@link ViewStructure#newChild(int)}
+     *   <li>{@link ViewStructure#asyncNewChild(int)}
+     *   <li>{@link ViewStructure#asyncCommit()}
+     *   <li>{@link ViewStructure#setWebDomain(String)}
+     *   <li>{@link ViewStructure#newHtmlInfoBuilder(String)}
+     *   <li>{@link ViewStructure#setHtmlInfo(android.view.ViewStructure.HtmlInfo)}
+     *   <li>{@link ViewStructure#setDataIsSensitive(boolean)}
+     *   <li>{@link ViewStructure#setAlpha(float)}
+     *   <li>{@link ViewStructure#setElevation(float)}
+     *   <li>{@link ViewStructure#setTransformation(Matrix)}
+     *
+     * </ul>
+     *
+     * @hide
+     */
+    @TestApi
+    public void onProvideContentCaptureStructure(@NonNull ViewStructure structure, int flags) {
+        onProvideStructure(structure, VIEW_STRUCTURE_FOR_CONTENT_CAPTURE, flags);
+    }
+
     /** @hide */
     protected void onProvideStructure(@NonNull ViewStructure structure,
             @ViewStructureType int viewFor, int flags) {
@@ -9080,6 +9258,280 @@
     }
 
     /**
+     * Gets the mode for determining whether this view is important for content capture.
+     *
+     * <p>See {@link #setImportantForContentCapture(int)} and
+     * {@link #isImportantForContentCapture()} for more info about this mode.
+     *
+     * @return {@link #IMPORTANT_FOR_CONTENT_CAPTURE_AUTO} by default, or value passed to
+     * {@link #setImportantForContentCapture(int)}.
+     *
+     * @attr ref android.R.styleable#View_importantForContentCapture
+     *
+     * @hide
+     */
+    @ViewDebug.ExportedProperty(mapping = {
+            @ViewDebug.IntToString(from = IMPORTANT_FOR_CONTENT_CAPTURE_AUTO, to = "auto"),
+            @ViewDebug.IntToString(from = IMPORTANT_FOR_CONTENT_CAPTURE_YES, to = "yes"),
+            @ViewDebug.IntToString(from = IMPORTANT_FOR_CONTENT_CAPTURE_NO, to = "no"),
+            @ViewDebug.IntToString(from = IMPORTANT_FOR_CONTENT_CAPTURE_YES_EXCLUDE_DESCENDANTS,
+                to = "yesExcludeDescendants"),
+            @ViewDebug.IntToString(from = IMPORTANT_FOR_CONTENT_CAPTURE_NO_EXCLUDE_DESCENDANTS,
+                to = "noExcludeDescendants")})
+//    @InspectableProperty(enumMapping = {
+//            @EnumEntry(value = IMPORTANT_FOR_CONTENT_CAPTURE_AUTO, name = "auto"),
+//            @EnumEntry(value = IMPORTANT_FOR_CONTENT_CAPTURE_YES, name = "yes"),
+//            @EnumEntry(value = IMPORTANT_FOR_CONTENT_CAPTURE_NO, name = "no"),
+//            @EnumEntry(value = IMPORTANT_FOR_CONTENT_CAPTURE_YES_EXCLUDE_DESCENDANTS,
+//                    name = "yesExcludeDescendants"),
+//            @EnumEntry(value = IMPORTANT_FOR_CONTENT_CAPTURE_NO_EXCLUDE_DESCENDANTS,
+//                    name = "noExcludeDescendants"),
+//    })
+    @TestApi
+    public @ContentCaptureImportance int getImportantForContentCapture() {
+        // NOTE: the important for content capture values were the first flags added and are set in
+        // the rightmost position, so we don't need to shift them
+        return mPrivateFlags4 & PFLAG4_IMPORTANT_FOR_CONTENT_CAPTURE_MASK;
+    }
+
+    /**
+     * Sets the mode for determining whether this view is considered important for content capture.
+     *
+     * <p>The platform determines the importance for autofill automatically but you
+     * can use this method to customize the behavior. Typically, a view that provides text should
+     * be marked as {@link #IMPORTANT_FOR_CONTENT_CAPTURE_YES}.
+     *
+     * @param mode {@link #IMPORTANT_FOR_CONTENT_CAPTURE_AUTO},
+     * {@link #IMPORTANT_FOR_CONTENT_CAPTURE_YES}, {@link #IMPORTANT_FOR_CONTENT_CAPTURE_NO},
+     * {@link #IMPORTANT_FOR_CONTENT_CAPTURE_YES_EXCLUDE_DESCENDANTS},
+     * or {@link #IMPORTANT_FOR_CONTENT_CAPTURE_NO_EXCLUDE_DESCENDANTS}.
+     *
+     * @attr ref android.R.styleable#View_importantForContentCapture
+     *
+     * @hide
+     */
+    @TestApi
+    public void setImportantForContentCapture(@ContentCaptureImportance int mode) {
+        // Reset first
+        mPrivateFlags4 &= ~PFLAG4_IMPORTANT_FOR_CONTENT_CAPTURE_MASK;
+        // Then set again
+        // NOTE: the important for content capture values were the first flags added and are set in
+        // the rightmost position, so we don't need to shift them
+        mPrivateFlags4 |= (mode & PFLAG4_IMPORTANT_FOR_CONTENT_CAPTURE_MASK);
+    }
+
+    /**
+     * Hints the Android System whether this view is considered important for content capture, based
+     * on the value explicitly set by {@link #setImportantForContentCapture(int)} and heuristics
+     * when it's {@link #IMPORTANT_FOR_CONTENT_CAPTURE_AUTO}.
+     *
+     * <p>See {@link ContentCaptureManager} for more info about content capture.
+     *
+     * @return whether the view is considered important for content capture.
+     *
+     * @see #setImportantForContentCapture(int)
+     * @see #IMPORTANT_FOR_CONTENT_CAPTURE_AUTO
+     * @see #IMPORTANT_FOR_CONTENT_CAPTURE_YES
+     * @see #IMPORTANT_FOR_CONTENT_CAPTURE_NO
+     * @see #IMPORTANT_FOR_CONTENT_CAPTURE_YES_EXCLUDE_DESCENDANTS
+     * @see #IMPORTANT_FOR_CONTENT_CAPTURE_NO_EXCLUDE_DESCENDANTS
+     *
+     * @hide
+     */
+    @TestApi
+    public final boolean isImportantForContentCapture() {
+        boolean isImportant;
+        if ((mPrivateFlags4 & PFLAG4_CONTENT_CAPTURE_IMPORTANCE_IS_CACHED) != 0) {
+            isImportant = (mPrivateFlags4 & PFLAG4_CONTENT_CAPTURE_IMPORTANCE_CACHED_VALUE) != 0;
+            return isImportant;
+        }
+
+        isImportant = calculateIsImportantForContentCapture();
+
+        mPrivateFlags4 &= ~PFLAG4_CONTENT_CAPTURE_IMPORTANCE_CACHED_VALUE;
+        if (isImportant) {
+            mPrivateFlags4 |= PFLAG4_CONTENT_CAPTURE_IMPORTANCE_CACHED_VALUE;
+        }
+        mPrivateFlags4 |= PFLAG4_CONTENT_CAPTURE_IMPORTANCE_IS_CACHED;
+        return isImportant;
+    }
+
+    /**
+     * Calculates whether the flag is important for content capture so it can be used by
+     * {@link #isImportantForContentCapture()} while the tree is traversed.
+     */
+    private boolean calculateIsImportantForContentCapture() {
+        // Check parent mode to ensure we're important
+        ViewParent parent = mParent;
+        while (parent instanceof View) {
+            final int parentImportance = ((View) parent).getImportantForContentCapture();
+            if (parentImportance == IMPORTANT_FOR_CONTENT_CAPTURE_NO_EXCLUDE_DESCENDANTS
+                    || parentImportance == IMPORTANT_FOR_CONTENT_CAPTURE_YES_EXCLUDE_DESCENDANTS) {
+                if (Log.isLoggable(CONTENT_CAPTURE_LOG_TAG, Log.VERBOSE)) {
+                    Log.v(CONTENT_CAPTURE_LOG_TAG, "View (" +  this + ") is not important for "
+                            + "content capture because parent " + parent + "'s importance is "
+                            + parentImportance);
+                }
+                return false;
+            }
+            parent = parent.getParent();
+        }
+
+        final int importance = getImportantForContentCapture();
+
+        // First, check the explicit states.
+        if (importance == IMPORTANT_FOR_CONTENT_CAPTURE_YES_EXCLUDE_DESCENDANTS
+                || importance == IMPORTANT_FOR_CONTENT_CAPTURE_YES) {
+            return true;
+        }
+        if (importance == IMPORTANT_FOR_CONTENT_CAPTURE_NO_EXCLUDE_DESCENDANTS
+                || importance == IMPORTANT_FOR_CONTENT_CAPTURE_NO) {
+            if (Log.isLoggable(CONTENT_CAPTURE_LOG_TAG, Log.VERBOSE)) {
+                Log.v(CONTENT_CAPTURE_LOG_TAG, "View (" +  this + ") is not important for content "
+                        + "capture because its importance is " + importance);
+            }
+            return false;
+        }
+
+        // Then use some heuristics to handle AUTO.
+        if (importance != IMPORTANT_FOR_CONTENT_CAPTURE_AUTO) {
+            Log.w(CONTENT_CAPTURE_LOG_TAG, "invalid content capture importance (" + importance
+                    + " on view " + this);
+            return false;
+        }
+
+        // View group is important if at least one children also is
+        if (this instanceof ViewGroup) {
+            final ViewGroup group = (ViewGroup) this;
+            for (int i = 0; i < group.getChildCount(); i++) {
+                final View child = group.getChildAt(i);
+                if (child.isImportantForContentCapture()) {
+                    return true;
+                }
+            }
+        }
+
+        // If the app developer explicitly set hints or autofill hintsfor it, it's important.
+        if (getAutofillHints() != null) {
+            return true;
+        }
+
+        // Otherwise, assume it's not important...
+        return false;
+    }
+
+    /**
+     * Helper used to notify the {@link ContentCaptureManager} when the view is removed or
+     * added, based on whether it's laid out and visible, and without knowing if the parent removed
+     * it from the view hierarchy.
+     *
+     * <p>This method is called from many places (visibility changed, view laid out, view attached
+     * or detached to/from window, etc...) and hence must contain the logic to call the manager, as
+     * described below:
+     *
+     * <ol>
+     *   <li>It should only be called when content capture is enabled for the view.
+     *   <li>It must call viewAppeared() before viewDisappeared()
+     *   <li>viewAppearead() can only be called when the view is visible and laidout
+     *   <li>It should not call the same event twice.
+     * </ol>
+     */
+    private void notifyAppearedOrDisappearedForContentCaptureIfNeeded(boolean appeared) {
+        AttachInfo ai = mAttachInfo;
+        // Skip it while the view is being laided out for the first time
+        if (ai != null && !ai.mReadyForContentCaptureUpdates) return;
+
+        if (Trace.isTagEnabled(Trace.TRACE_TAG_VIEW)) {
+            Trace.traceBegin(Trace.TRACE_TAG_VIEW,
+                    "notifyContentCapture(" + appeared + ") for " + getClass().getSimpleName());
+        }
+        try {
+            notifyAppearedOrDisappearedForContentCaptureIfNeededNoTrace(appeared);
+        } finally {
+            Trace.traceEnd(Trace.TRACE_TAG_VIEW);
+        }
+    }
+
+    private void notifyAppearedOrDisappearedForContentCaptureIfNeededNoTrace(boolean appeared) {
+        AttachInfo ai = mAttachInfo;
+
+        // First check if context has client, so it saves a service lookup when it doesn't
+        if (mContext.getContentCaptureOptions() == null) return;
+
+        // Then check if it's enabled in the context...
+        final ContentCaptureManager ccm = ai != null ? ai.getContentCaptureManager(mContext)
+                : mContext.getSystemService(ContentCaptureManager.class);
+        if (ccm == null || !ccm.isContentCaptureEnabled()) return;
+
+        // ... and finally at the view level
+        // NOTE: isImportantForContentCapture() is more expensive than cm.isContentCaptureEnabled()
+        if (!isImportantForContentCapture()) return;
+
+        ContentCaptureSession session = getContentCaptureSession();
+        if (session == null) return;
+
+        if (appeared) {
+            if (!isLaidOut() || getVisibility() != VISIBLE
+                    || (mPrivateFlags4 & PFLAG4_NOTIFIED_CONTENT_CAPTURE_APPEARED) != 0) {
+                if (DEBUG_CONTENT_CAPTURE) {
+                    Log.v(CONTENT_CAPTURE_LOG_TAG, "Ignoring 'appeared' on " + this + ": laid="
+                            + isLaidOut() + ", visibleToUser=" + isVisibleToUser()
+                            + ", visible=" + (getVisibility() == VISIBLE)
+                            + ": alreadyNotifiedAppeared=" + ((mPrivateFlags4
+                                    & PFLAG4_NOTIFIED_CONTENT_CAPTURE_APPEARED) != 0)
+                            + ", alreadyNotifiedDisappeared=" + ((mPrivateFlags4
+                                    & PFLAG4_NOTIFIED_CONTENT_CAPTURE_DISAPPEARED) != 0));
+                }
+                return;
+            }
+            setNotifiedContentCaptureAppeared();
+
+            if (ai != null) {
+                ai.delayNotifyContentCaptureEvent(session, this, appeared);
+            } else {
+                if (DEBUG_CONTENT_CAPTURE) {
+                    Log.w(CONTENT_CAPTURE_LOG_TAG, "no AttachInfo on appeared for " + this);
+                }
+            }
+        } else {
+            if ((mPrivateFlags4 & PFLAG4_NOTIFIED_CONTENT_CAPTURE_APPEARED) == 0
+                    || (mPrivateFlags4 & PFLAG4_NOTIFIED_CONTENT_CAPTURE_DISAPPEARED) != 0) {
+                if (DEBUG_CONTENT_CAPTURE) {
+                    Log.v(CONTENT_CAPTURE_LOG_TAG, "Ignoring 'disappeared' on " + this + ": laid="
+                            + isLaidOut() + ", visibleToUser=" + isVisibleToUser()
+                            + ", visible=" + (getVisibility() == VISIBLE)
+                            + ": alreadyNotifiedAppeared=" + ((mPrivateFlags4
+                                    & PFLAG4_NOTIFIED_CONTENT_CAPTURE_APPEARED) != 0)
+                            + ", alreadyNotifiedDisappeared=" + ((mPrivateFlags4
+                                    & PFLAG4_NOTIFIED_CONTENT_CAPTURE_DISAPPEARED) != 0));
+                }
+                return;
+            }
+            mPrivateFlags4 |= PFLAG4_NOTIFIED_CONTENT_CAPTURE_DISAPPEARED;
+            mPrivateFlags4 &= ~PFLAG4_NOTIFIED_CONTENT_CAPTURE_APPEARED;
+
+            if (ai != null) {
+                ai.delayNotifyContentCaptureEvent(session, this, appeared);
+            } else {
+                if (DEBUG_CONTENT_CAPTURE) {
+                    Log.v(CONTENT_CAPTURE_LOG_TAG, "no AttachInfo on disappeared for " + this);
+                }
+            }
+        }
+    }
+
+    private void setNotifiedContentCaptureAppeared() {
+        mPrivateFlags4 |= PFLAG4_NOTIFIED_CONTENT_CAPTURE_APPEARED;
+        mPrivateFlags4 &= ~PFLAG4_NOTIFIED_CONTENT_CAPTURE_DISAPPEARED;
+    }
+
+    /** @hide */
+    protected boolean getNotifiedContentCaptureAppeared() {
+        return (mPrivateFlags4 & PFLAG4_NOTIFIED_CONTENT_CAPTURE_APPEARED) != 0;
+    }
+
+
+    /**
      * Sets the (optional) {@link ContentCaptureSession} associated with this view.
      *
      * <p>This method should be called when you need to associate a {@link ContentCaptureContext} to
@@ -9332,6 +9784,68 @@
     }
 
     /**
+     * Dispatches the initial content capture events for a view structure.
+     *
+     * @hide
+     */
+    public void dispatchInitialProvideContentCaptureStructure() {
+        AttachInfo ai = mAttachInfo;
+        if (ai == null) {
+            Log.w(CONTENT_CAPTURE_LOG_TAG,
+                    "dispatchProvideContentCaptureStructure(): no AttachInfo for " + this);
+            return;
+        }
+        ContentCaptureManager ccm = ai.mContentCaptureManager;
+        if (ccm == null) {
+            Log.w(CONTENT_CAPTURE_LOG_TAG, "dispatchProvideContentCaptureStructure(): "
+                    + "no ContentCaptureManager for " + this);
+            return;
+        }
+
+        // We must set it before checkign if the view itself is important, because it might
+        // initially not be (for example, if it's empty), although that might change later (for
+        // example, if important views are added)
+        ai.mReadyForContentCaptureUpdates = true;
+
+        if (!isImportantForContentCapture()) {
+            if (Log.isLoggable(CONTENT_CAPTURE_LOG_TAG, Log.DEBUG)) {
+                Log.d(CONTENT_CAPTURE_LOG_TAG,
+                        "dispatchProvideContentCaptureStructure(): decorView is not important");
+            }
+            return;
+        }
+
+        ai.mContentCaptureManager = ccm;
+
+        ContentCaptureSession session = getContentCaptureSession();
+        if (session == null) {
+            if (Log.isLoggable(CONTENT_CAPTURE_LOG_TAG, Log.DEBUG)) {
+                Log.d(CONTENT_CAPTURE_LOG_TAG,
+                        "dispatchProvideContentCaptureStructure(): no session for " + this);
+            }
+            return;
+        }
+
+        session.internalNotifyViewTreeEvent(/* started= */ true);
+        try {
+            dispatchProvideContentCaptureStructure();
+        } finally {
+            session.internalNotifyViewTreeEvent(/* started= */ false);
+        }
+    }
+
+    /** @hide */
+    void dispatchProvideContentCaptureStructure() {
+        ContentCaptureSession session = getContentCaptureSession();
+        if (session != null) {
+            ViewStructure structure = session.newViewStructure(this);
+            onProvideContentCaptureStructure(structure, /* flags= */ 0);
+            setNotifiedContentCaptureAppeared();
+            session.notifyViewAppeared(structure);
+        }
+    }
+
+    /**
      * @see #onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo)
      *
      * Note: Called from the default {@link AccessibilityDelegate}.
@@ -10571,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) {
@@ -13281,6 +13802,7 @@
     public void dispatchStartTemporaryDetach() {
         mPrivateFlags3 |= PFLAG3_TEMPORARY_DETACH;
         notifyEnterOrExitForAutoFillIfNeeded(false);
+        notifyAppearedOrDisappearedForContentCaptureIfNeeded(false);
         onStartTemporaryDetach();
     }
 
@@ -13307,6 +13829,7 @@
             notifyFocusChangeToInputMethodManager(true /* hasFocus */);
         }
         notifyEnterOrExitForAutoFillIfNeeded(true);
+        notifyAppearedOrDisappearedForContentCaptureIfNeeded(true);
     }
 
     /**
@@ -13898,6 +14421,8 @@
                         : AccessibilityEvent.CONTENT_CHANGE_TYPE_PANE_DISAPPEARED);
             }
         }
+
+        notifyAppearedOrDisappearedForContentCaptureIfNeeded(isVisible);
     }
 
     /**
@@ -17593,6 +18118,7 @@
         }
 
         // Reset content capture caches
+        mPrivateFlags4 &= ~PFLAG4_CONTENT_CAPTURE_IMPORTANCE_MASK;
         mCachedContentCaptureSession = null;
 
         if ((mPrivateFlags & (PFLAG_DRAWN | PFLAG_HAS_BOUNDS)) == (PFLAG_DRAWN | PFLAG_HAS_BOUNDS)
@@ -19602,6 +20128,7 @@
         needGlobalAttributesUpdate(false);
 
         notifyEnterOrExitForAutoFillIfNeeded(true);
+        notifyAppearedOrDisappearedForContentCaptureIfNeeded(true);
     }
 
     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P)
@@ -19651,6 +20178,7 @@
         }
 
         notifyEnterOrExitForAutoFillIfNeeded(false);
+        notifyAppearedOrDisappearedForContentCaptureIfNeeded(false);
     }
 
     /**
@@ -21985,6 +22513,8 @@
             mPrivateFlags3 &= ~PFLAG3_NOTIFY_AUTOFILL_ENTER_ON_LAYOUT;
             notifyEnterOrExitForAutoFillIfNeeded(true);
         }
+
+        notifyAppearedOrDisappearedForContentCaptureIfNeeded(true);
     }
 
     private boolean hasParentWantsFocus() {
@@ -28050,6 +28580,12 @@
         boolean mHandlingPointerEvent;
 
         /**
+         * The offset of this view's window when it's on an embedded display that is re-parented
+         * to another window.
+         */
+        final Point mLocationInParentDisplay = new Point();
+
+        /**
          * Global to the view hierarchy used as a temporary for dealing with
          * x/y points in the transparent region computations.
          */
@@ -28196,6 +28732,23 @@
         View mTooltipHost;
 
         /**
+         * The initial structure has been reported so the view is ready to report updates.
+         */
+        boolean mReadyForContentCaptureUpdates;
+
+        /**
+         * Map(keyed by session) of content capture events that need to be notified after the view
+         * hierarchy is traversed: value is either the view itself for appearead events, or its
+         * autofill id for disappeared.
+         */
+        SparseArray<ArrayList<Object>> mContentCaptureEvents;
+
+        /**
+         * Cached reference to the {@link ContentCaptureManager}.
+         */
+        ContentCaptureManager mContentCaptureManager;
+
+        /**
          * Creates a new set of attachment information with the specified
          * events handler and thread.
          *
@@ -28213,6 +28766,31 @@
             mRootCallbacks = effectPlayer;
             mTreeObserver = new ViewTreeObserver(context);
         }
+
+        private void delayNotifyContentCaptureEvent(@NonNull ContentCaptureSession session,
+                @NonNull View view, boolean appeared) {
+            if (mContentCaptureEvents == null) {
+                // Most of the time there will be just one session, so intial capacity is 1
+                mContentCaptureEvents = new SparseArray<>(1);
+            }
+            int sessionId = session.getId();
+            // TODO: life would be much easier if we provided a MultiMap implementation somwhere...
+            ArrayList<Object> events = mContentCaptureEvents.get(sessionId);
+            if (events == null) {
+                events = new ArrayList<>();
+                mContentCaptureEvents.put(sessionId, events);
+            }
+            events.add(appeared ? view : view.getAutofillId());
+        }
+
+        @Nullable
+        ContentCaptureManager getContentCaptureManager(@NonNull Context context) {
+            if (mContentCaptureManager != null) {
+                return mContentCaptureManager;
+            }
+            mContentCaptureManager = context.getSystemService(ContentCaptureManager.class);
+            return mContentCaptureManager;
+        }
     }
 
     /**
diff --git a/core/java/android/view/ViewGroup.java b/core/java/android/view/ViewGroup.java
index d362024..937bd1b 100644
--- a/core/java/android/view/ViewGroup.java
+++ b/core/java/android/view/ViewGroup.java
@@ -3606,7 +3606,7 @@
             return;
         }
 
-        final ChildListForAutofill children = getChildrenForAutofill(flags);
+        final ChildListForAutoFillOrContentCapture children = getChildrenForAutofill(flags);
         final int childrenCount = children.size();
         structure.setChildCount(childrenCount);
         for (int i = 0; i < childrenCount; i++) {
@@ -3617,14 +3617,30 @@
         children.recycle();
     }
 
+    /** @hide */
+    @Override
+    public void dispatchProvideContentCaptureStructure() {
+        super.dispatchProvideContentCaptureStructure();
+
+        if (!isLaidOut()) return;
+
+        final ChildListForAutoFillOrContentCapture children = getChildrenForContentCapture();
+        final int childrenCount = children.size();
+        for (int i = 0; i < childrenCount; i++) {
+            final View child = children.get(i);
+            child.dispatchProvideContentCaptureStructure();
+        }
+        children.recycle();
+    }
+
     /**
      * Gets the children for autofill. Children for autofill are the first
      * level descendants that are important for autofill. The returned
      * child list object is pooled and the caller must recycle it once done.
      * @hide */
-    private @NonNull ChildListForAutofill getChildrenForAutofill(
+    private @NonNull ChildListForAutoFillOrContentCapture getChildrenForAutofill(
             @AutofillFlags int flags) {
-        final ChildListForAutofill children = ChildListForAutofill
+        final ChildListForAutoFillOrContentCapture children = ChildListForAutoFillOrContentCapture
                 .obtain();
         populateChildrenForAutofill(children, flags);
         return children;
@@ -3652,6 +3668,34 @@
         }
     }
 
+    private @NonNull ChildListForAutoFillOrContentCapture getChildrenForContentCapture() {
+        final ChildListForAutoFillOrContentCapture children = ChildListForAutoFillOrContentCapture
+                .obtain();
+        populateChildrenForContentCapture(children);
+        return children;
+    }
+
+    /** @hide */
+    private void populateChildrenForContentCapture(ArrayList<View> list) {
+        final int childrenCount = mChildrenCount;
+        if (childrenCount <= 0) {
+            return;
+        }
+        final ArrayList<View> preorderedList = buildOrderedChildList();
+        final boolean customOrder = preorderedList == null
+                && isChildrenDrawingOrderEnabled();
+        for (int i = 0; i < childrenCount; i++) {
+            final int childIndex = getAndVerifyPreorderedIndex(childrenCount, i, customOrder);
+            final View child = (preorderedList == null)
+                    ? mChildren[childIndex] : preorderedList.get(childIndex);
+            if (child.isImportantForContentCapture()) {
+                list.add(child);
+            } else if (child instanceof ViewGroup) {
+                ((ViewGroup) child).populateChildrenForContentCapture(list);
+            }
+        }
+    }
+
     private static View getAndVerifyPreorderedView(ArrayList<View> preorderedList, View[] children,
             int childIndex) {
         final View child;
@@ -8634,16 +8678,16 @@
     /**
      * Pooled class that to hold the children for autifill.
      */
-    private static class ChildListForAutofill extends ArrayList<View> {
+    private static class ChildListForAutoFillOrContentCapture extends ArrayList<View> {
         private static final int MAX_POOL_SIZE = 32;
 
-        private static final Pools.SimplePool<ChildListForAutofill> sPool =
+        private static final Pools.SimplePool<ChildListForAutoFillOrContentCapture> sPool =
                 new Pools.SimplePool<>(MAX_POOL_SIZE);
 
-        public static ChildListForAutofill obtain() {
-            ChildListForAutofill list = sPool.acquire();
+        public static ChildListForAutoFillOrContentCapture obtain() {
+            ChildListForAutoFillOrContentCapture list = sPool.acquire();
             if (list == null) {
-                list = new ChildListForAutofill();
+                list = new ChildListForAutoFillOrContentCapture();
             }
             return list;
         }
diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java
index aceb276..440df89 100644
--- a/core/java/android/view/ViewRootImpl.java
+++ b/core/java/android/view/ViewRootImpl.java
@@ -105,7 +105,11 @@
 import android.view.accessibility.IAccessibilityInteractionConnectionCallback;
 import android.view.animation.AccelerateDecelerateInterpolator;
 import android.view.animation.Interpolator;
+import android.view.autofill.AutofillId;
 import android.view.autofill.AutofillManager;
+import android.view.contentcapture.ContentCaptureManager;
+import android.view.contentcapture.ContentCaptureSession;
+import android.view.contentcapture.MainContentCaptureSession;
 import android.view.inputmethod.InputMethodManager;
 import android.widget.Scroller;
 
@@ -220,6 +224,21 @@
      */
     static final int MAX_TRACKBALL_DELAY = 250;
 
+    /**
+     * Initial value for {@link #mContentCaptureEnabled}.
+     */
+    private static final int CONTENT_CAPTURE_ENABLED_NOT_CHECKED = 0;
+
+    /**
+     * Value for {@link #mContentCaptureEnabled} when it was checked and set to {@code true}.
+     */
+    private static final int CONTENT_CAPTURE_ENABLED_TRUE = 1;
+
+    /**
+     * Value for {@link #mContentCaptureEnabled} when it was checked and set to {@code false}.
+     */
+    private static final int CONTENT_CAPTURE_ENABLED_FALSE = 2;
+
     @UnsupportedAppUsage
     static final ThreadLocal<HandlerActionQueue> sRunQueues = new ThreadLocal<HandlerActionQueue>();
 
@@ -410,6 +429,10 @@
     boolean mLayoutRequested;
     boolean mFirst;
 
+    @Nullable
+    int mContentCaptureEnabled = CONTENT_CAPTURE_ENABLED_NOT_CHECKED;
+    boolean mPerformContentCapture;
+
     boolean mReportNextDraw;
     boolean mFullRedrawNeeded;
     boolean mNewSurfaceNeeded;
@@ -607,6 +630,7 @@
         mTransparentRegion = new Region();
         mPreviousTransparentRegion = new Region();
         mFirst = true; // true for the first time the view is added
+        mPerformContentCapture = true; // also true for the first time the view is added
         mAdded = false;
         mAttachInfo = new View.AttachInfo(mWindowSession, mWindow, display, this, mHandler, this,
                 context);
@@ -2765,9 +2789,55 @@
             }
         }
 
+        if (mAttachInfo.mContentCaptureEvents != null) {
+            notifyContentCatpureEvents();
+        }
+
         mIsInTraversal = false;
     }
 
+    private void notifyContentCatpureEvents() {
+        Trace.traceBegin(Trace.TRACE_TAG_VIEW, "notifyContentCaptureEvents");
+        try {
+            MainContentCaptureSession mainSession = mAttachInfo.mContentCaptureManager
+                    .getMainContentCaptureSession();
+            for (int i = 0; i < mAttachInfo.mContentCaptureEvents.size(); i++) {
+                int sessionId = mAttachInfo.mContentCaptureEvents.keyAt(i);
+                mainSession.notifyViewTreeEvent(sessionId, /* started= */ true);
+                ArrayList<Object> events = mAttachInfo.mContentCaptureEvents
+                        .valueAt(i);
+                for_each_event: for (int j = 0; j < events.size(); j++) {
+                    Object event = events.get(j);
+                    if (event instanceof AutofillId) {
+                        mainSession.notifyViewDisappeared(sessionId, (AutofillId) event);
+                    } else if (event instanceof View) {
+                        View view = (View) event;
+                        ContentCaptureSession session = view.getContentCaptureSession();
+                        if (session == null) {
+                            Log.w(mTag, "no content capture session on view: " + view);
+                            continue for_each_event;
+                        }
+                        int actualId = session.getId();
+                        if (actualId != sessionId) {
+                            Log.w(mTag, "content capture session mismatch for view (" + view
+                                    + "): was " + sessionId + " before, it's " + actualId + " now");
+                            continue for_each_event;
+                        }
+                        ViewStructure structure = session.newViewStructure(view);
+                        view.onProvideContentCaptureStructure(structure, /* flags= */ 0);
+                        session.notifyViewAppeared(structure);
+                    } else {
+                        Log.w(mTag, "invalid content capture event: " + event);
+                    }
+                }
+                mainSession.notifyViewTreeEvent(sessionId, /* started= */ false);
+            }
+            mAttachInfo.mContentCaptureEvents = null;
+        } finally {
+            Trace.traceEnd(Trace.TRACE_TAG_VIEW);
+        }
+    }
+
     private void notifySurfaceDestroyed() {
         mSurfaceHolder.ungetCallbacks();
         SurfaceHolder.Callback[] callbacks = mSurfaceHolder.getCallbacks();
@@ -2902,6 +2972,13 @@
             }
         }
         mFirstInputStage.onWindowFocusChanged(hasWindowFocus);
+
+        // NOTE: there's no view visibility (appeared / disapparead) events when the windows focus
+        // is lost, so we don't need to to force a flush - there might be other events such as
+        // text changes, but these should be flushed independently.
+        if (hasWindowFocus) {
+            handleContentCaptureFlush();
+        }
     }
 
     private void fireAccessibilityFocusEventIfHasFocusedNode() {
@@ -3468,6 +3545,86 @@
                 pendingDrawFinished();
             }
         }
+        if (mPerformContentCapture) {
+            performContentCaptureInitialReport();
+        }
+    }
+
+    /**
+     * Checks (and caches) if content capture is enabled for this context.
+     */
+    private boolean isContentCaptureEnabled() {
+        switch (mContentCaptureEnabled) {
+            case CONTENT_CAPTURE_ENABLED_TRUE:
+                return true;
+            case CONTENT_CAPTURE_ENABLED_FALSE:
+                return false;
+            case CONTENT_CAPTURE_ENABLED_NOT_CHECKED:
+                final boolean reallyEnabled = isContentCaptureReallyEnabled();
+                mContentCaptureEnabled = reallyEnabled ? CONTENT_CAPTURE_ENABLED_TRUE
+                        : CONTENT_CAPTURE_ENABLED_FALSE;
+                return reallyEnabled;
+            default:
+                Log.w(TAG, "isContentCaptureEnabled(): invalid state " + mContentCaptureEnabled);
+                return false;
+        }
+
+    }
+
+    /**
+     * Checks (without caching) if content capture is enabled for this context.
+     */
+    private boolean isContentCaptureReallyEnabled() {
+        // First check if context supports it, so it saves a service lookup when it doesn't
+        if (mContext.getContentCaptureOptions() == null) return false;
+
+        final ContentCaptureManager ccm = mAttachInfo.getContentCaptureManager(mContext);
+        // Then check if it's enabled in the contex itself.
+        if (ccm == null || !ccm.isContentCaptureEnabled()) return false;
+
+        return true;
+    }
+
+    private void performContentCaptureInitialReport() {
+        mPerformContentCapture = false; // One-time offer!
+        final View rootView = mView;
+        if (DEBUG_CONTENT_CAPTURE) {
+            Log.v(mTag, "performContentCaptureInitialReport() on " + rootView);
+        }
+        if (Trace.isTagEnabled(Trace.TRACE_TAG_VIEW)) {
+            Trace.traceBegin(Trace.TRACE_TAG_VIEW, "dispatchContentCapture() for "
+                    + getClass().getSimpleName());
+        }
+        try {
+            if (!isContentCaptureEnabled()) return;
+
+            // Content capture is a go!
+            rootView.dispatchInitialProvideContentCaptureStructure();
+        } finally {
+            Trace.traceEnd(Trace.TRACE_TAG_VIEW);
+        }
+    }
+
+    private void handleContentCaptureFlush() {
+        if (DEBUG_CONTENT_CAPTURE) {
+            Log.v(mTag, "handleContentCaptureFlush()");
+        }
+        if (Trace.isTagEnabled(Trace.TRACE_TAG_VIEW)) {
+            Trace.traceBegin(Trace.TRACE_TAG_VIEW, "flushContentCapture for "
+                    + getClass().getSimpleName());
+        }
+        try {
+            if (!isContentCaptureEnabled()) return;
+
+            final ContentCaptureManager ccm = mAttachInfo.mContentCaptureManager;
+            if (ccm == null) {
+                Log.w(TAG, "No ContentCapture on AttachInfo");
+                return;
+            }
+            ccm.flush(ContentCaptureSession.FLUSH_REASON_VIEW_ROOT_ENTERED);
+        } finally {
+            Trace.traceEnd(Trace.TRACE_TAG_VIEW);
+        }
     }
 
     private boolean draw(boolean fullRedrawNeeded) {
@@ -3834,6 +3991,13 @@
         }
     }
 
+    void updateLocationInParentDisplay(int x, int y) {
+        if (mAttachInfo != null
+                && !mAttachInfo.mLocationInParentDisplay.equals(x, y)) {
+            mAttachInfo.mLocationInParentDisplay.set(x, y);
+        }
+    }
+
     /**
      * Set the root-level system gesture exclusion rects. These are added to those provided by
      * the root's view hierarchy.
@@ -4338,6 +4502,7 @@
     private static final int MSG_INSETS_CHANGED = 30;
     private static final int MSG_INSETS_CONTROL_CHANGED = 31;
     private static final int MSG_SYSTEM_GESTURE_EXCLUSION_CHANGED = 32;
+    private static final int MSG_LOCATION_IN_PARENT_DISPLAY_CHANGED = 33;
 
     final class ViewRootHandler extends Handler {
         @Override
@@ -4399,6 +4564,8 @@
                     return "MSG_INSETS_CONTROL_CHANGED";
                 case MSG_SYSTEM_GESTURE_EXCLUSION_CHANGED:
                     return "MSG_SYSTEM_GESTURE_EXCLUSION_CHANGED";
+                case MSG_LOCATION_IN_PARENT_DISPLAY_CHANGED:
+                    return "MSG_LOCATION_IN_PARENT_DISPLAY_CHANGED";
             }
             return super.getMessageName(message);
         }
@@ -4634,6 +4801,9 @@
                 case MSG_SYSTEM_GESTURE_EXCLUSION_CHANGED: {
                     systemGestureExclusionChanged();
                 } break;
+                case MSG_LOCATION_IN_PARENT_DISPLAY_CHANGED: {
+                    updateLocationInParentDisplay(msg.arg1, msg.arg2);
+                } break;
             }
         }
     }
@@ -7840,6 +8010,17 @@
         mHandler.sendMessage(msg);
     }
 
+    /**
+     * Dispatch the offset changed.
+     *
+     * @param offset the offset of this view in the parent window.
+     */
+    public void dispatchLocationInParentDisplayChanged(Point offset) {
+        Message msg =
+                mHandler.obtainMessage(MSG_LOCATION_IN_PARENT_DISPLAY_CHANGED, offset.x, offset.y);
+        mHandler.sendMessage(msg);
+    }
+
     public void windowFocusChanged(boolean hasFocus, boolean inTouchMode) {
         synchronized (this) {
             mWindowFocusChanged = true;
@@ -8367,6 +8548,14 @@
         }
 
         @Override
+        public void locationInParentDisplayChanged(Point offset) {
+            final ViewRootImpl viewAncestor = mViewAncestor.get();
+            if (viewAncestor != null) {
+                viewAncestor.dispatchLocationInParentDisplayChanged(offset);
+            }
+        }
+
+        @Override
         public void insetsChanged(InsetsState insetsState) {
             final ViewRootImpl viewAncestor = mViewAncestor.get();
             if (viewAncestor != null) {
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/view/WindowManager.java b/core/java/android/view/WindowManager.java
index a25f2ee..2e5a750 100644
--- a/core/java/android/view/WindowManager.java
+++ b/core/java/android/view/WindowManager.java
@@ -261,6 +261,13 @@
     int TRANSIT_TASK_CHANGE_WINDOWING_MODE = 27;
 
     /**
+     * A display which can only contain one task is being shown because the first activity is
+     * started or it's being turned on.
+     * @hide
+     */
+    int TRANSIT_SHOW_SINGLE_TASK_DISPLAY = 28;
+
+    /**
      * @hide
      */
     @IntDef(prefix = { "TRANSIT_" }, value = {
@@ -287,7 +294,8 @@
             TRANSIT_TRANSLUCENT_ACTIVITY_OPEN,
             TRANSIT_TRANSLUCENT_ACTIVITY_CLOSE,
             TRANSIT_CRASHING_ACTIVITY_CLOSE,
-            TRANSIT_TASK_CHANGE_WINDOWING_MODE
+            TRANSIT_TASK_CHANGE_WINDOWING_MODE,
+            TRANSIT_SHOW_SINGLE_TASK_DISPLAY
     })
     @Retention(RetentionPolicy.SOURCE)
     @interface TransitionType {}
@@ -311,6 +319,12 @@
     int TRANSIT_FLAG_KEYGUARD_GOING_AWAY_WITH_WALLPAPER = 0x4;
 
     /**
+     * Transition flag: Keyguard is going away with subtle animation.
+     * @hide
+     */
+    int TRANSIT_FLAG_KEYGUARD_GOING_AWAY_SUBTLE_ANIMATION = 0x8;
+
+    /**
      * @hide
      */
     @IntDef(flag = true, prefix = { "TRANSIT_FLAG_" }, value = {
diff --git a/core/java/android/view/WindowManagerPolicyConstants.java b/core/java/android/view/WindowManagerPolicyConstants.java
index 46a59f0..a22f5a5 100644
--- a/core/java/android/view/WindowManagerPolicyConstants.java
+++ b/core/java/android/view/WindowManagerPolicyConstants.java
@@ -38,10 +38,11 @@
     int FLAG_INTERACTIVE = 0x20000000;
     int FLAG_PASS_TO_USER = 0x40000000;
 
-    // Flags for IActivityManager.keyguardGoingAway()
+    // Flags for IActivityTaskManager.keyguardGoingAway()
     int KEYGUARD_GOING_AWAY_FLAG_TO_SHADE = 1 << 0;
     int KEYGUARD_GOING_AWAY_FLAG_NO_WINDOW_ANIMATIONS = 1 << 1;
     int KEYGUARD_GOING_AWAY_FLAG_WITH_WALLPAPER = 1 << 2;
+    int KEYGUARD_GOING_AWAY_FLAG_SUBTLE_WINDOW_ANIMATIONS = 1 << 3;
 
     // Flags used for indicating whether the internal and/or external input devices
     // of some type are available.
diff --git a/core/java/android/view/accessibility/TEST_MAPPING b/core/java/android/view/accessibility/TEST_MAPPING
index 535a31a..d2bd6ea 100644
--- a/core/java/android/view/accessibility/TEST_MAPPING
+++ b/core/java/android/view/accessibility/TEST_MAPPING
@@ -30,9 +30,6 @@
         },
         {
           "exclude-annotation": "androidx.test.filters.FlakyTest"
-        },
-        {
-          "exclude-filter": "android.view.textclassifier.TextClassifierTest#testSuggetsConversationActions_deduplicate"
         }
       ]
     }
diff --git a/core/java/android/view/contentcapture/MainContentCaptureSession.java b/core/java/android/view/contentcapture/MainContentCaptureSession.java
index c5a5f73..1e7440b 100644
--- a/core/java/android/view/contentcapture/MainContentCaptureSession.java
+++ b/core/java/android/view/contentcapture/MainContentCaptureSession.java
@@ -428,14 +428,16 @@
         }
 
         final int flushFrequencyMs;
-        if (reason == FLUSH_REASON_IDLE_TIMEOUT) {
-            flushFrequencyMs = mManager.mOptions.idleFlushingFrequencyMs;
-        } else if (reason == FLUSH_REASON_TEXT_CHANGE_TIMEOUT) {
+        if (reason == FLUSH_REASON_TEXT_CHANGE_TIMEOUT) {
             flushFrequencyMs = mManager.mOptions.textChangeFlushingFrequencyMs;
         } else {
-            Log.e(TAG, "handleScheduleFlush(" + getDebugState(reason) + "): not called with a "
-                    + "timeout reason.");
-            return;
+            if (reason != FLUSH_REASON_IDLE_TIMEOUT) {
+                if (sDebug) {
+                    Log.d(TAG, "handleScheduleFlush(" + getDebugState(reason) + "): not a timeout "
+                            + "reason because mDirectServiceInterface is not ready yet");
+                }
+            }
+            flushFrequencyMs = mManager.mOptions.idleFlushingFrequencyMs;
         }
 
         mNextFlush = System.currentTimeMillis() + flushFrequencyMs;
@@ -478,6 +480,8 @@
             return;
         }
 
+        mNextFlushForTextChanged = false;
+
         final int numberEvents = mEvents.size();
         final String reasonString = getFlushReasonAsString(reason);
         if (sDebug) {
@@ -493,10 +497,6 @@
         try {
             mHandler.removeMessages(MSG_FLUSH);
 
-            if (reason == FLUSH_REASON_TEXT_CHANGE_TIMEOUT) {
-                mNextFlushForTextChanged = false;
-            }
-
             final ParceledListSlice<ContentCaptureEvent> events = clearEvents();
             mDirectServiceInterface.sendEvents(events, reason, mManager.mOptions);
         } catch (RemoteException e) {
diff --git a/core/java/android/view/textclassifier/TEST_MAPPING b/core/java/android/view/textclassifier/TEST_MAPPING
index 31e240b..01a6ede 100644
--- a/core/java/android/view/textclassifier/TEST_MAPPING
+++ b/core/java/android/view/textclassifier/TEST_MAPPING
@@ -8,9 +8,6 @@
         },
         {
           "exclude-annotation": "androidx.test.filters.FlakyTest"
-        },
-        {
-          "exclude-filter": "android.view.textclassifier.TextClassifierTest#testSuggetsConversationActions_deduplicate"
         }
       ]
     }
diff --git a/core/java/android/webkit/PermissionRequest.java b/core/java/android/webkit/PermissionRequest.java
index 18ec334..ac145b1 100644
--- a/core/java/android/webkit/PermissionRequest.java
+++ b/core/java/android/webkit/PermissionRequest.java
@@ -32,7 +32,7 @@
  * avoid unintentionally granting requests for new permissions, you should pass the
  * specific permissions you intend to grant to {@link #grant(String[]) grant()},
  * and avoid writing code like this example:
- * <pre>
+ * <pre class="prettyprint">
  * permissionRequest.grant(permissionRequest.getResources())  // This is wrong!!!
  * </pre>
  * See the WebView's release notes for information about new protected resources.
diff --git a/core/java/android/webkit/WebChromeClient.java b/core/java/android/webkit/WebChromeClient.java
index 95fe963..4db6308 100644
--- a/core/java/android/webkit/WebChromeClient.java
+++ b/core/java/android/webkit/WebChromeClient.java
@@ -519,15 +519,17 @@
          * may not be supported and applications wishing to support these sources
          * or more advanced file operations should build their own Intent.
          *
-         * <pre>
-         * How to use:
-         * 1. Build an intent using {@link #createIntent}
-         * 2. Fire the intent using {@link android.app.Activity#startActivityForResult}.
-         * 3. Check for ActivityNotFoundException and take a user friendly action if thrown.
-         * 4. Listen the result using {@link android.app.Activity#onActivityResult}
-         * 5. Parse the result using {@link #parseResult} only if media capture was not requested.
-         * 6. Send the result using filePathCallback of {@link WebChromeClient#onShowFileChooser}
-         * </pre>
+         * <p>How to use:
+         * <ol>
+         *   <li>Build an intent using {@link #createIntent}</li>
+         *   <li>Fire the intent using {@link android.app.Activity#startActivityForResult}.</li>
+         *   <li>Check for ActivityNotFoundException and take a user friendly action if thrown.</li>
+         *   <li>Listen the result using {@link android.app.Activity#onActivityResult}</li>
+         *   <li>Parse the result using {@link #parseResult} only if media capture was not
+         *   requested.</li>
+         *   <li>Send the result using filePathCallback of {@link
+         *   WebChromeClient#onShowFileChooser}</li>
+         * </ol>
          *
          * @return an Intent that supports basic file chooser sources.
          */
diff --git a/core/java/android/webkit/WebSettings.java b/core/java/android/webkit/WebSettings.java
index a46580d..18d4d69 100644
--- a/core/java/android/webkit/WebSettings.java
+++ b/core/java/android/webkit/WebSettings.java
@@ -464,7 +464,9 @@
      * Note that the feature will continue to be supported on older versions of
      * Android as before.
      *
-     * This function does not have any effect.
+     * @deprecated In Android O and afterwards, this function does not have
+     * any effect, the form data will be saved to platform's autofill service
+     * if applicable.
      */
     @Deprecated
     public abstract  void setSaveFormData(boolean save);
diff --git a/core/java/android/webkit/WebView.java b/core/java/android/webkit/WebView.java
index 14be73d..721ac2d 100644
--- a/core/java/android/webkit/WebView.java
+++ b/core/java/android/webkit/WebView.java
@@ -413,6 +413,9 @@
         if (getImportantForAutofill() == IMPORTANT_FOR_AUTOFILL_AUTO) {
             setImportantForAutofill(IMPORTANT_FOR_AUTOFILL_YES);
         }
+        if (getImportantForContentCapture() == IMPORTANT_FOR_CONTENT_CAPTURE_AUTO) {
+            setImportantForContentCapture(IMPORTANT_FOR_CONTENT_CAPTURE_YES);
+        }
 
         if (context == null) {
             throw new IllegalArgumentException("Invalid context argument");
@@ -759,7 +762,7 @@
      * encoded. If the data is base64 encoded, the value of the encoding
      * parameter must be {@code "base64"}. HTML can be encoded with {@link
      * android.util.Base64#encodeToString(byte[],int)} like so:
-     * <pre>
+     * <pre class="prettyprint">
      * String unencodedHtml =
      *     "&lt;html&gt;&lt;body&gt;'%28' is the code for '('&lt;/body&gt;&lt;/html&gt;";
      * String encodedHtml = Base64.encodeToString(unencodedHtml.getBytes(), Base64.NO_PADDING);
@@ -1840,8 +1843,8 @@
 
     /**
      * Injects the supplied Java object into this WebView. The object is
-     * injected into the JavaScript context of the main frame, using the
-     * supplied name. This allows the Java object's methods to be
+     * injected into all frames of the web page, including all the iframes,
+     * using the supplied name. This allows the Java object's methods to be
      * accessed from JavaScript. For applications targeted to API
      * level {@link android.os.Build.VERSION_CODES#JELLY_BEAN_MR1}
      * and above, only public methods that are annotated with
@@ -1851,7 +1854,7 @@
      * important security note below for implications.
      * <p> Note that injected objects will not appear in JavaScript until the page is next
      * (re)loaded. JavaScript should be enabled before injecting the object. For example:
-     * <pre>
+     * <pre class="prettyprint">
      * class JsObject {
      *    {@literal @}JavascriptInterface
      *    public String toString() { return "injectedObject"; }
@@ -1880,6 +1883,11 @@
      * thread of this WebView. Care is therefore required to maintain thread
      * safety.
      * </li>
+     * <li> Because the object is exposed to all the frames, any frame could
+     * obtain the object name and call methods on it. There is no way to tell the
+     * calling frame's origin from the app side, so the app must not assume that
+     * the caller is trustworthy unless the app can guarantee that no third party
+     * content is ever loaded into the WebView even inside an iframe.</li>
      * <li> The Java object's fields are not accessible.</li>
      * <li> For applications targeted to API level {@link android.os.Build.VERSION_CODES#LOLLIPOP}
      * and above, methods of injected Java objects are enumerable from
@@ -2803,6 +2811,12 @@
         mProvider.getViewDelegate().onProvideAutofillVirtualStructure(structure, flags);
     }
 
+    /** @hide */
+    @Override
+    public void onProvideContentCaptureStructure(ViewStructure structure, int flags) {
+        mProvider.getViewDelegate().onProvideContentCaptureStructure(structure, flags);
+    }
+
     @Override
     public void autofill(SparseArray<AutofillValue>values) {
         mProvider.getViewDelegate().autofill(values);
diff --git a/core/java/android/widget/AbsSeekBar.java b/core/java/android/widget/AbsSeekBar.java
index c3e08fc..bbcba2e 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
@@ -171,6 +172,8 @@
         applyTickMarkTint();
 
         mScaledTouchSlop = ViewConfiguration.get(context).getScaledTouchSlop();
+        mThumbExclusionMaxSize = getResources().getDimensionPixelSize(
+                com.android.internal.R.dimen.seekbar_thumb_exclusion_max_size);
     }
 
     /**
@@ -763,12 +766,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/android/widget/AdapterView.java b/core/java/android/widget/AdapterView.java
index c3bb9a0..c55f7d6 100644
--- a/core/java/android/widget/AdapterView.java
+++ b/core/java/android/widget/AdapterView.java
@@ -1318,7 +1318,8 @@
             @ViewStructureType int viewFor, int flags) {
         super.onProvideStructure(structure, viewFor, flags);
 
-        if (viewFor == VIEW_STRUCTURE_FOR_AUTOFILL) {
+        if (viewFor == VIEW_STRUCTURE_FOR_AUTOFILL
+                || viewFor == VIEW_STRUCTURE_FOR_CONTENT_CAPTURE) {
             final Adapter adapter = getAdapter();
             if (adapter == null) return;
 
diff --git a/core/java/android/widget/ArrayAdapter.java b/core/java/android/widget/ArrayAdapter.java
index c3c2c0d..2bf1ba5 100644
--- a/core/java/android/widget/ArrayAdapter.java
+++ b/core/java/android/widget/ArrayAdapter.java
@@ -50,7 +50,7 @@
  * override {@link #getView(int, View, ViewGroup)}
  * and inflate a view resource.
  * For a code example, see
- * the <a href="https://developer.android.com/samples/CustomChoiceList/index.html">
+ * the <a href="https://github.com/googlesamples/android-CustomChoiceList/#readme">
  * CustomChoiceList</a> sample.
  * </p>
  * <p>
diff --git a/core/java/android/widget/ImageView.java b/core/java/android/widget/ImageView.java
index be5d221..d62b979 100644
--- a/core/java/android/widget/ImageView.java
+++ b/core/java/android/widget/ImageView.java
@@ -62,8 +62,9 @@
 /**
  * Displays image resources, for example {@link android.graphics.Bitmap}
  * or {@link android.graphics.drawable.Drawable} resources.
- * ImageView is also commonly used to {@link #setImageTintMode(PorterDuff.Mode)
- * apply tints to an image} and handle {@link #setScaleType(ScaleType) image scaling}.
+ * ImageView is also commonly used to
+ * <a href="#setImageTintMode(android.graphics.PorterDuff.Mode)">apply tints to an image</a> and
+ * handle <a href="#setScaleType(android.widget.ImageView.ScaleType)">image scaling</a>.
  *
  * <p>
  * The following XML snippet is a common example of using an ImageView to display an image resource:
@@ -76,7 +77,8 @@
  *     &lt;ImageView
  *         android:layout_width="wrap_content"
  *         android:layout_height="wrap_content"
- *         android:src="@mipmap/ic_launcher"
+ *         android:src="@drawable/my_image"
+ *         android:contentDescription="@string/my_image_description"
  *         /&gt;
  * &lt;/LinearLayout&gt;
  * </pre>
diff --git a/core/java/android/widget/RelativeLayout.java b/core/java/android/widget/RelativeLayout.java
index d985528..6b324a5 100644
--- a/core/java/android/widget/RelativeLayout.java
+++ b/core/java/android/widget/RelativeLayout.java
@@ -1202,13 +1202,13 @@
      * determine where to position the view on the screen.  If the view is not contained
      * within a relative layout, these attributes are ignored.
      *
-     * See the <a href="/guide/topics/ui/layout/relative.html">
-     * Relative Layout</a> guide for example code demonstrating how to use relative layout’s
+     * See the <a href="{@docRoot}guide/topics/ui/layout/relative.html">Relative
+     * Layout</a> guide for example code demonstrating how to use relative layout's
      * layout parameters in a layout XML.
      *
      * To learn more about layout parameters and how they differ from typical view attributes,
-     * see the <a href="/guide/topics/ui/declaring-layout.html#attributes">
-     *     Layouts guide</a>.
+     * see the <a href="{@docRoot}guide/topics/ui/declaring-layout.html#attributes">Layouts
+     * guide</a>.
      *
      *
      * @attr ref android.R.styleable#RelativeLayout_Layout_layout_alignWithParentIfMissing
diff --git a/core/java/android/widget/TabWidget.java b/core/java/android/widget/TabWidget.java
index 49a0f39..4c67b08 100644
--- a/core/java/android/widget/TabWidget.java
+++ b/core/java/android/widget/TabWidget.java
@@ -433,7 +433,7 @@
      * to the next tabbed view, in this example).
      * <p>
      * To move both the focus AND the selected tab at once, please use
-     * {@link #setCurrentTab}. Normally, the view logic takes care of
+     * {@link #focusCurrentTab}. Normally, the view logic takes care of
      * adjusting the focus, so unless you're circumventing the UI,
      * you'll probably just focus your interest here.
      *
diff --git a/core/java/android/widget/TextView.java b/core/java/android/widget/TextView.java
index 62598fc..0918c5f 100644
--- a/core/java/android/widget/TextView.java
+++ b/core/java/android/widget/TextView.java
@@ -162,6 +162,8 @@
 import android.view.animation.AnimationUtils;
 import android.view.autofill.AutofillManager;
 import android.view.autofill.AutofillValue;
+import android.view.contentcapture.ContentCaptureManager;
+import android.view.contentcapture.ContentCaptureSession;
 import android.view.inputmethod.BaseInputConnection;
 import android.view.inputmethod.CompletionInfo;
 import android.view.inputmethod.CorrectionInfo;
@@ -977,6 +979,9 @@
         if (getImportantForAutofill() == IMPORTANT_FOR_AUTOFILL_AUTO) {
             setImportantForAutofill(IMPORTANT_FOR_AUTOFILL_YES);
         }
+        if (getImportantForContentCapture() == IMPORTANT_FOR_CONTENT_CAPTURE_AUTO) {
+            setImportantForContentCapture(IMPORTANT_FOR_CONTENT_CAPTURE_YES);
+        }
 
         setTextInternal("");
 
@@ -10558,7 +10563,8 @@
     }
 
     /**
-     * Notify managers (such as {@link AutofillManager}) that are interested in text changes.
+     * Notify managers (such as {@link AutofillManager} and {@link ContentCaptureManager}) that are
+     * interested on text changes.
      */
     private void notifyListeningManagersAfterTextChanged() {
 
@@ -10574,6 +10580,22 @@
                 afm.notifyValueChanged(TextView.this);
             }
         }
+
+        // TODO(b/121045053): should use a flag / boolean to keep status of SHOWN / HIDDEN instead
+        // of using isLaidout(), so it's not called in cases where it's laid out but a
+        // notifyAppeared was not sent.
+
+        // ContentCapture
+        if (isLaidOut() && isImportantForContentCapture() && getNotifiedContentCaptureAppeared()) {
+            final ContentCaptureManager cm = mContext.getSystemService(ContentCaptureManager.class);
+            if (cm != null && cm.isContentCaptureEnabled()) {
+                final ContentCaptureSession session = getContentCaptureSession();
+                if (session != null) {
+                    // TODO(b/111276913): pass flags when edited by user / add CTS test
+                    session.notifyViewTextChanged(getAutofillId(), getText());
+                }
+            }
+        }
     }
 
     private boolean isAutofillable() {
@@ -11417,7 +11439,8 @@
 
         final boolean isPassword = hasPasswordTransformationMethod()
                 || isPasswordInputType(getInputType());
-        if (viewFor == VIEW_STRUCTURE_FOR_AUTOFILL) {
+        if (viewFor == VIEW_STRUCTURE_FOR_AUTOFILL
+                || viewFor == VIEW_STRUCTURE_FOR_CONTENT_CAPTURE) {
             if (viewFor == VIEW_STRUCTURE_FOR_AUTOFILL) {
                 structure.setDataIsSensitive(!mTextSetFromXmlOrResourceId);
             }
@@ -11433,8 +11456,12 @@
             }
         }
 
-        if (!isPassword || viewFor == VIEW_STRUCTURE_FOR_AUTOFILL) {
+        if (!isPassword || viewFor == VIEW_STRUCTURE_FOR_AUTOFILL
+                || viewFor == VIEW_STRUCTURE_FOR_CONTENT_CAPTURE) {
             if (mLayout == null) {
+                if (viewFor == VIEW_STRUCTURE_FOR_CONTENT_CAPTURE) {
+                    Log.w(LOG_TAG, "onProvideContentCaptureStructure(): calling assumeLayout()");
+                }
                 assumeLayout();
             }
             Layout layout = mLayout;
@@ -11522,7 +11549,8 @@
                 }
             }
 
-            if (viewFor == VIEW_STRUCTURE_FOR_ASSIST) {
+            if (viewFor == VIEW_STRUCTURE_FOR_ASSIST
+                    || viewFor == VIEW_STRUCTURE_FOR_CONTENT_CAPTURE) {
                 // Extract style information that applies to the TextView as a whole.
                 int style = 0;
                 int typefaceStyle = getTypefaceStyle();
@@ -11550,7 +11578,8 @@
                 structure.setTextStyle(getTextSize(), getCurrentTextColor(),
                         AssistStructure.ViewNode.TEXT_COLOR_UNDEFINED /* bgColor */, style);
             }
-            if (viewFor == VIEW_STRUCTURE_FOR_AUTOFILL) {
+            if (viewFor == VIEW_STRUCTURE_FOR_AUTOFILL
+                    || viewFor == VIEW_STRUCTURE_FOR_CONTENT_CAPTURE) {
                 structure.setMinTextEms(getMinEms());
                 structure.setMaxTextEms(getMaxEms());
                 int maxLength = -1;
diff --git a/core/java/com/android/internal/colorextraction/ColorExtractor.java b/core/java/com/android/internal/colorextraction/ColorExtractor.java
index b27c11b..3003ce8 100644
--- a/core/java/com/android/internal/colorextraction/ColorExtractor.java
+++ b/core/java/com/android/internal/colorextraction/ColorExtractor.java
@@ -73,13 +73,8 @@
         }
 
         mOnColorsChangedListeners = new ArrayList<>();
-
-        if (wallpaperManager == null) {
-            Log.w(TAG, "Can't listen to color changes!");
-        } else {
-            wallpaperManager.addOnColorsChangedListener(this, null /* handler */);
-            initExtractColors(wallpaperManager, immediately);
-        }
+        wallpaperManager.addOnColorsChangedListener(this, null /* handler */);
+        initExtractColors(wallpaperManager, immediately);
     }
 
     private void initExtractColors(WallpaperManager wallpaperManager, boolean immediately) {
diff --git a/core/java/com/android/internal/config/sysui/SystemUiDeviceConfigFlags.java b/core/java/com/android/internal/config/sysui/SystemUiDeviceConfigFlags.java
index 8dc47a4..33b5325 100644
--- a/core/java/com/android/internal/config/sysui/SystemUiDeviceConfigFlags.java
+++ b/core/java/com/android/internal/config/sysui/SystemUiDeviceConfigFlags.java
@@ -106,7 +106,7 @@
      */
     public static final String HASH_SALT_MAX_DAYS = "hash_salt_max_days";
 
-    // Flags related to Assistant Handles
+    // Flags related to Assistant
 
     /**
      * (String) Which behavior mode for the Assistant Handles to use.
@@ -177,11 +177,48 @@
             "assist_handles_suppress_on_apps";
 
     /**
+     * Allow touch passthrough above assist area during a session.
+     */
+    public static final String ASSIST_TAP_PASSTHROUGH = "assist_tap_passthrough";
+  
+    /**
      * (bool) Whether to show handles when taught.
      */
     public static final String ASSIST_HANDLES_SHOW_WHEN_TAUGHT = "assist_handles_show_when_taught";
 
     /**
+     * (long) Duration per pixel, in milliseconds, of scrolling text at fast speed.
+     */
+    public static final String ASSIST_TRANSCRIPTION_DURATION_PER_PX_FAST =
+            "assist_transcription_duration_per_px_fast";
+
+    /**
+     * (long) Duration per pixel, in milliseconds, of scrolling text at regular speed.
+     */
+    public static final String ASSIST_TRANSCRIPTION_DURATION_PER_PX_REGULAR =
+            "assist_transcription_duration_per_px_regular";
+
+    /**
+     * (long) Duration, in milliseconds, over which text fades in.
+     */
+    public static final String ASSIST_TRANSCRIPTION_FADE_IN_DURATION =
+            "assist_transcription_fade_in_duration";
+
+    /**
+     * (long) Maximum total duration, in milliseconds, for a given transcription.
+     */
+    public static final String ASSIST_TRANSCRIPTION_MAX_DURATION =
+            "assist_transcription_max_duration";
+
+    /**
+     * (long) Minimum total duration, in milliseconds, for a given transcription.
+     */
+    public static final String ASSIST_TRANSCRIPTION_MIN_DURATION =
+            "assist_transcription_min_duration";
+
+    // Flags related to brightline falsing
+
+    /**
      * (bool) Whether to use the new BrightLineFalsingManager.
      */
     public static final String BRIGHTLINE_FALSING_MANAGER_ENABLED =
@@ -270,5 +307,6 @@
             "brightline_falsing_zigzag_y_secondary_deviance";
 
 
-    private SystemUiDeviceConfigFlags() { }
+    private SystemUiDeviceConfigFlags() {
+    }
 }
diff --git a/core/java/com/android/internal/os/ZygoteConnection.java b/core/java/com/android/internal/os/ZygoteConnection.java
index c24ffb0..ad53eb9 100644
--- a/core/java/com/android/internal/os/ZygoteConnection.java
+++ b/core/java/com/android/internal/os/ZygoteConnection.java
@@ -479,10 +479,6 @@
 
         closeSocket();
 
-        if (parsedArgs.mNiceName != null) {
-            Process.setArgV0(parsedArgs.mNiceName);
-        }
-
         // End of the postFork event.
         Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
         if (parsedArgs.mInvokeWith != null) {
diff --git a/core/java/com/android/internal/policy/ScreenDecorationsUtils.java b/core/java/com/android/internal/policy/ScreenDecorationsUtils.java
index adf7692..52172cf 100644
--- a/core/java/com/android/internal/policy/ScreenDecorationsUtils.java
+++ b/core/java/com/android/internal/policy/ScreenDecorationsUtils.java
@@ -36,13 +36,16 @@
         }
 
         // Radius that should be used in case top or bottom aren't defined.
-        float defaultRadius = resources.getDimension(R.dimen.rounded_corner_radius);
+        float defaultRadius = resources.getDimension(R.dimen.rounded_corner_radius)
+                - resources.getDimension(R.dimen.rounded_corner_radius_adjustment);
 
-        float topRadius = resources.getDimension(R.dimen.rounded_corner_radius_top);
+        float topRadius = resources.getDimension(R.dimen.rounded_corner_radius_top)
+                - resources.getDimension(R.dimen.rounded_corner_radius_top_adjustment);
         if (topRadius == 0f) {
             topRadius = defaultRadius;
         }
-        float bottomRadius = resources.getDimension(R.dimen.rounded_corner_radius_bottom);
+        float bottomRadius = resources.getDimension(R.dimen.rounded_corner_radius_bottom)
+                - resources.getDimension(R.dimen.rounded_corner_radius_bottom_adjustment);
         if (bottomRadius == 0f) {
             bottomRadius = defaultRadius;
         }
diff --git a/core/java/com/android/internal/view/BaseIWindow.java b/core/java/com/android/internal/view/BaseIWindow.java
index fb9ff15..f9cdf3d 100644
--- a/core/java/com/android/internal/view/BaseIWindow.java
+++ b/core/java/com/android/internal/view/BaseIWindow.java
@@ -16,6 +16,7 @@
 
 package com.android.internal.view;
 
+import android.graphics.Point;
 import android.graphics.Rect;
 import android.hardware.input.InputManager;
 import android.os.Bundle;
@@ -55,6 +56,10 @@
     }
 
     @Override
+    public void locationInParentDisplayChanged(Point offset) {
+    }
+
+    @Override
     public void insetsChanged(InsetsState insetsState) {
     }
 
diff --git a/core/java/com/android/internal/widget/LockPatternView.java b/core/java/com/android/internal/widget/LockPatternView.java
index 2218267..3f6c4d4 100644
--- a/core/java/com/android/internal/widget/LockPatternView.java
+++ b/core/java/com/android/internal/widget/LockPatternView.java
@@ -627,6 +627,13 @@
     }
 
     /**
+     * If there are any cells being drawn.
+     */
+    public boolean isEmpty() {
+        return mPattern.isEmpty();
+    }
+
+    /**
      * Clear the pattern lookup table. Also reset the line fade start times for
      * the next attempt.
      */
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/jni/android_os_Debug.cpp b/core/jni/android_os_Debug.cpp
index 8a89ed9..13e1dfa 100644
--- a/core/jni/android_os_Debug.cpp
+++ b/core/jni/android_os_Debug.cpp
@@ -577,7 +577,7 @@
     if (outArray != NULL) {
         outLen = MEMINFO_COUNT;
         for (int i = 0; i < outLen; i++) {
-            if (i == MEMINFO_VMALLOC_USED) {
+            if (i == MEMINFO_VMALLOC_USED && mem[i] == 0) {
                 outArray[i] = smi.ReadVmallocInfo() / 1024;
                 continue;
             }
diff --git a/core/jni/android_view_DisplayEventReceiver.cpp b/core/jni/android_view_DisplayEventReceiver.cpp
index 8d702d1..ba538a8 100644
--- a/core/jni/android_view_DisplayEventReceiver.cpp
+++ b/core/jni/android_view_DisplayEventReceiver.cpp
@@ -48,7 +48,8 @@
 class NativeDisplayEventReceiver : public DisplayEventDispatcher {
 public:
     NativeDisplayEventReceiver(JNIEnv* env,
-            jobject receiverWeak, const sp<MessageQueue>& messageQueue, jint vsyncSource);
+            jobject receiverWeak, const sp<MessageQueue>& messageQueue, jint vsyncSource,
+            jint configChanged);
 
     void dispose();
 
@@ -68,9 +69,11 @@
 
 
 NativeDisplayEventReceiver::NativeDisplayEventReceiver(JNIEnv* env,
-        jobject receiverWeak, const sp<MessageQueue>& messageQueue, jint vsyncSource) :
+        jobject receiverWeak, const sp<MessageQueue>& messageQueue, jint vsyncSource,
+        jint configChanged) :
         DisplayEventDispatcher(messageQueue->getLooper(),
-                static_cast<ISurfaceComposer::VsyncSource>(vsyncSource)),
+                static_cast<ISurfaceComposer::VsyncSource>(vsyncSource),
+                static_cast<ISurfaceComposer::ConfigChanged>(configChanged)),
         mReceiverWeakGlobal(env->NewGlobalRef(receiverWeak)),
         mMessageQueue(messageQueue) {
     ALOGV("receiver %p ~ Initializing display event receiver.", this);
@@ -136,7 +139,7 @@
 
 
 static jlong nativeInit(JNIEnv* env, jclass clazz, jobject receiverWeak,
-        jobject messageQueueObj, jint vsyncSource) {
+        jobject messageQueueObj, jint vsyncSource, jint configChanged) {
     sp<MessageQueue> messageQueue = android_os_MessageQueue_getMessageQueue(env, messageQueueObj);
     if (messageQueue == NULL) {
         jniThrowRuntimeException(env, "MessageQueue is not initialized.");
@@ -144,7 +147,7 @@
     }
 
     sp<NativeDisplayEventReceiver> receiver = new NativeDisplayEventReceiver(env,
-            receiverWeak, messageQueue, vsyncSource);
+            receiverWeak, messageQueue, vsyncSource, configChanged);
     status_t status = receiver->initialize();
     if (status) {
         String8 message;
@@ -179,7 +182,7 @@
 static const JNINativeMethod gMethods[] = {
     /* name, signature, funcPtr */
     { "nativeInit",
-            "(Ljava/lang/ref/WeakReference;Landroid/os/MessageQueue;I)J",
+            "(Ljava/lang/ref/WeakReference;Landroid/os/MessageQueue;II)J",
             (void*)nativeInit },
     { "nativeDispose",
             "(J)V",
diff --git a/core/jni/android_view_Surface.cpp b/core/jni/android_view_Surface.cpp
index ccadc7d..ff14a2a 100644
--- a/core/jni/android_view_Surface.cpp
+++ b/core/jni/android_view_Surface.cpp
@@ -75,6 +75,24 @@
     jfieldID bottom;
 } gRectClassInfo;
 
+class JNamedColorSpace {
+public:
+    // ColorSpace.Named.SRGB.ordinal() = 0;
+    static constexpr jint SRGB = 0;
+
+    // ColorSpace.Named.DISPLAY_P3.ordinal() = 7;
+    static constexpr jint DISPLAY_P3 = 7;
+};
+
+constexpr ui::Dataspace fromNamedColorSpaceValueToDataspace(const jint colorSpace) {
+    switch (colorSpace) {
+        case JNamedColorSpace::DISPLAY_P3:
+            return ui::Dataspace::DISPLAY_P3;
+        default:
+            return ui::Dataspace::V0_SRGB;
+    }
+}
+
 // ----------------------------------------------------------------------------
 
 // this is just a pointer we use to pass to inc/decStrong
@@ -425,11 +443,12 @@
     return surface->disconnect(-1, IGraphicBufferProducer::DisconnectMode::AllLocal);
 }
 
-static jint nativeAttachAndQueueBuffer(JNIEnv *env, jclass clazz, jlong nativeObject,
-        jobject graphicBuffer) {
+static jint nativeAttachAndQueueBufferWithColorSpace(JNIEnv *env, jclass clazz, jlong nativeObject,
+        jobject graphicBuffer, jint colorSpaceId) {
     Surface* surface = reinterpret_cast<Surface*>(nativeObject);
     sp<GraphicBuffer> bp = graphicBufferForJavaObject(env, graphicBuffer);
-    int err = Surface::attachAndQueueBuffer(surface, bp);
+    int err = Surface::attachAndQueueBufferWithDataspace(surface, bp,
+            fromNamedColorSpaceValueToDataspace(colorSpaceId));
     return err;
 }
 
@@ -531,7 +550,8 @@
     {"nativeGetNextFrameNumber", "(J)J", (void*)nativeGetNextFrameNumber },
     {"nativeSetScalingMode", "(JI)I", (void*)nativeSetScalingMode },
     {"nativeForceScopedDisconnect", "(J)I", (void*)nativeForceScopedDisconnect},
-    {"nativeAttachAndQueueBuffer", "(JLandroid/graphics/GraphicBuffer;)I", (void*)nativeAttachAndQueueBuffer},
+    {"nativeAttachAndQueueBufferWithColorSpace", "(JLandroid/graphics/GraphicBuffer;I)I",
+            (void*)nativeAttachAndQueueBufferWithColorSpace},
     {"nativeSetSharedBufferModeEnabled", "(JZ)I", (void*)nativeSetSharedBufferModeEnabled},
     {"nativeSetAutoRefreshEnabled", "(JZ)I", (void*)nativeSetAutoRefreshEnabled},
 
diff --git a/core/proto/android/providers/settings/secure.proto b/core/proto/android/providers/settings/secure.proto
index fed2efa..61799ee 100644
--- a/core/proto/android/providers/settings/secure.proto
+++ b/core/proto/android/providers/settings/secure.proto
@@ -198,11 +198,19 @@
         optional SettingProto silence_alarms_count = 2 [ (android.privacy).dest = DEST_AUTOMATIC ];
         optional SettingProto silence_calls_count = 3 [ (android.privacy).dest = DEST_AUTOMATIC ];
         optional SettingProto silence_enabled = 4 [ (android.privacy).dest = DEST_AUTOMATIC ];
-        optional SettingProto silence_notification_count = 5 [ (android.privacy).dest = DEST_AUTOMATIC ];
+        // del: silence_notification_count = 5
         optional SettingProto silence_timer_count = 6 [ (android.privacy).dest = DEST_AUTOMATIC ];
 
         optional SettingProto skip_count = 7 [ (android.privacy).dest = DEST_AUTOMATIC ];
         optional SettingProto skip_enabled = 8 [ (android.privacy).dest = DEST_AUTOMATIC ];
+
+        optional SettingProto silence_alarms_touch_count = 9 [ (android.privacy).dest =
+            DEST_AUTOMATIC ];
+        optional SettingProto silence_calls_touch_count = 10 [ (android.privacy).dest =
+            DEST_AUTOMATIC ];
+        optional SettingProto silence_timer_touch_count = 11 [ (android.privacy).dest =
+            DEST_AUTOMATIC ];
+        optional SettingProto skip_touch_count = 12 [ (android.privacy).dest = DEST_AUTOMATIC ];
     }
     optional Gesture gesture = 74;
 
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index 02eed9a7..e7e20fc 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -724,6 +724,10 @@
 
     <!-- Allows an application to send SMS messages.
          <p>Protection level: dangerous
+
+         <p> This is a hard restricted permission which cannot be held by an app until
+         the installer on record whitelists the permission. For more details see
+         {@link android.content.pm.PackageInstaller.SessionParams#setWhitelistedRestrictedPermissions(Set)}.
     -->
     <permission android:name="android.permission.SEND_SMS"
         android:permissionGroup="android.permission-group.UNDEFINED"
@@ -734,6 +738,10 @@
 
     <!-- Allows an application to receive SMS messages.
          <p>Protection level: dangerous
+
+         <p> This is a hard restricted permission which cannot be held by an app until
+         the installer on record whitelists the permission. For more details see
+         {@link android.content.pm.PackageInstaller.SessionParams#setWhitelistedRestrictedPermissions(Set)}.
     -->
     <permission android:name="android.permission.RECEIVE_SMS"
         android:permissionGroup="android.permission-group.UNDEFINED"
@@ -744,6 +752,10 @@
 
     <!-- Allows an application to read SMS messages.
          <p>Protection level: dangerous
+
+         <p> This is a hard restricted permission which cannot be held by an app until
+         the installer on record whitelists the permission. For more details see
+         {@link android.content.pm.PackageInstaller.SessionParams#setWhitelistedRestrictedPermissions(Set)}.
     -->
     <permission android:name="android.permission.READ_SMS"
         android:permissionGroup="android.permission-group.UNDEFINED"
@@ -754,6 +766,10 @@
 
     <!-- Allows an application to receive WAP push messages.
          <p>Protection level: dangerous
+
+         <p> This is a hard restricted permission which cannot be held by an app until
+         the installer on record whitelists the permission. For more details see
+         {@link android.content.pm.PackageInstaller.SessionParams#setWhitelistedRestrictedPermissions(Set)}.
     -->
     <permission android:name="android.permission.RECEIVE_WAP_PUSH"
         android:permissionGroup="android.permission-group.UNDEFINED"
@@ -763,7 +779,11 @@
         android:protectionLevel="dangerous" />
 
     <!-- Allows an application to monitor incoming MMS messages.
-        <p>Protection level: dangerous
+         <p>Protection level: dangerous
+
+         <p> This is a hard restricted permission which cannot be held by an app until
+         the installer on record whitelists the permission. For more details see
+         {@link android.content.pm.PackageInstaller.SessionParams#setWhitelistedRestrictedPermissions(Set)}.
     -->
     <permission android:name="android.permission.RECEIVE_MMS"
         android:permissionGroup="android.permission-group.UNDEFINED"
@@ -783,6 +803,11 @@
          when the alert is first received, and to delay presenting the info
          to the user until after the initial alert dialog is dismissed.
          <p>Protection level: dangerous
+
+         <p> This is a hard restricted permission which cannot be held by an app until
+         the installer on record whitelists the permission. For more details see
+         {@link android.content.pm.PackageInstaller.SessionParams#setWhitelistedRestrictedPermissions(Set)}.
+
          @hide Pending API council approval -->
     <permission android:name="android.permission.READ_CELL_BROADCASTS"
         android:permissionGroup="android.permission-group.UNDEFINED"
@@ -805,31 +830,36 @@
         android:priority="900" />
 
     <!-- Allows an application to read from external storage.
-     <p>Any app that declares the {@link #WRITE_EXTERNAL_STORAGE} permission is implicitly
-     granted this permission.</p>
-     <p>This permission is enforced starting in API level 19.  Before API level 19, this
-     permission is not enforced and all apps still have access to read from external storage.
-     You can test your app with the permission enforced by enabling <em>Protect USB
-     storage</em> under Developer options in the Settings app on a device running Android 4.1 or
-     higher.</p>
-     <p>Also starting in API level 19, this permission is <em>not</em> required to
-     read/write files in your application-specific directories returned by
-     {@link android.content.Context#getExternalFilesDir} and
-     {@link android.content.Context#getExternalCacheDir}.
-     <p class="note"><strong>Note:</strong> If <em>both</em> your <a
-     href="{@docRoot}guide/topics/manifest/uses-sdk-element.html#min">{@code
-     minSdkVersion}</a> and <a
-     href="{@docRoot}guide/topics/manifest/uses-sdk-element.html#target">{@code
-     targetSdkVersion}</a> values are set to 3 or lower, the system implicitly
-     grants your app this permission. If you don't need this permission, be sure your <a
-     href="{@docRoot}guide/topics/manifest/uses-sdk-element.html#target">{@code
-     targetSdkVersion}</a> is 4 or higher.
-     <p>Is this permission is not whitelisted for an app that targets an API level before
-     {@link android.os.Build.VERSION_CODES#Q} this permission cannot be granted to apps.</p>
-     <p>Is this permission is not whitelisted for an app that targets an API level
-     {@link android.os.Build.VERSION_CODES#Q} or later the app will be forced into isolated storage.
-     </p>
-     -->
+      <p>Any app that declares the {@link #WRITE_EXTERNAL_STORAGE} permission is implicitly
+      granted this permission.</p>
+      <p>This permission is enforced starting in API level 19.  Before API level 19, this
+      permission is not enforced and all apps still have access to read from external storage.
+      You can test your app with the permission enforced by enabling <em>Protect USB
+      storage</em> under Developer options in the Settings app on a device running Android 4.1 or
+      higher.</p>
+      <p>Also starting in API level 19, this permission is <em>not</em> required to
+      read/write files in your application-specific directories returned by
+      {@link android.content.Context#getExternalFilesDir} and
+      {@link android.content.Context#getExternalCacheDir}.
+      <p class="note"><strong>Note:</strong> If <em>both</em> your <a
+      href="{@docRoot}guide/topics/manifest/uses-sdk-element.html#min">{@code
+      minSdkVersion}</a> and <a
+      href="{@docRoot}guide/topics/manifest/uses-sdk-element.html#target">{@code
+      targetSdkVersion}</a> values are set to 3 or lower, the system implicitly
+      grants your app this permission. If you don't need this permission, be sure your <a
+      href="{@docRoot}guide/topics/manifest/uses-sdk-element.html#target">{@code
+      targetSdkVersion}</a> is 4 or higher.
+
+      <p> This is a soft restricted permission which cannot be held by an app it its
+      full form until the installer on record whitelists the permission.
+      Specifically, if the permission is whitelisted the holder app can access
+      external storage and the visual and aural media collections while if the
+      permission is not whitelisted the holder app can only access to the visual
+      and aural medial collections. Also the permission is immutably restricted
+      meaning that the whitelist state can be specified only at install time and
+      cannot change until the app is installed. For more details see
+      {@link android.content.pm.PackageInstaller.SessionParams#setWhitelistedRestrictedPermissions(Set)}.
+     <p>Protection level: dangerous -->
     <permission android:name="android.permission.READ_EXTERNAL_STORAGE"
         android:permissionGroup="android.permission-group.UNDEFINED"
         android:label="@string/permlab_sdcardRead"
@@ -850,8 +880,9 @@
          read/write files in your application-specific directories returned by
          {@link android.content.Context#getExternalFilesDir} and
          {@link android.content.Context#getExternalCacheDir}.
-         <p>Is this permission is not whitelisted for an app that targets an API level before
+         <p>If this permission is not whitelisted for an app that targets an API level before
          {@link android.os.Build.VERSION_CODES#Q} this permission cannot be granted to apps.</p>
+         <p>Protection level: dangerous</p>
     -->
     <permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"
         android:permissionGroup="android.permission-group.UNDEFINED"
@@ -861,7 +892,8 @@
         android:protectionLevel="dangerous" />
 
     <!-- Allows an application to access any geographic locations persisted in the
-         user's shared collection. -->
+         user's shared collection.
+         <p>Protection level: dangerous -->
     <permission android:name="android.permission.ACCESS_MEDIA_LOCATION"
         android:permissionGroup="android.permission-group.UNDEFINED"
         android:label="@string/permlab_mediaLocation"
@@ -916,6 +948,10 @@
          {@link #ACCESS_FINE_LOCATION}. Requesting this permission by itself doesn't give you
          location access.
          <p>Protection level: dangerous
+
+         <p> This is a hard restricted permission which cannot be held by an app until
+         the installer on record whitelists the permission. For more details see
+         {@link android.content.pm.PackageInstaller.SessionParams#setWhitelistedRestrictedPermissions(Set)}.
     -->
     <permission android:name="android.permission.ACCESS_BACKGROUND_LOCATION"
         android:permissionGroup="android.permission-group.UNDEFINED"
@@ -958,6 +994,10 @@
          href="{@docRoot}guide/topics/manifest/uses-sdk-element.html#target">{@code
          targetSdkVersion}</a> is 16 or higher.</p>
          <p>Protection level: dangerous
+
+         <p> This is a hard restricted permission which cannot be held by an app until
+         the installer on record whitelists the permission. For more details see
+         {@link android.content.pm.PackageInstaller.SessionParams#setWhitelistedRestrictedPermissions(Set)}.
     -->
     <permission android:name="android.permission.READ_CALL_LOG"
         android:permissionGroup="android.permission-group.UNDEFINED"
@@ -978,6 +1018,10 @@
          href="{@docRoot}guide/topics/manifest/uses-sdk-element.html#target">{@code
          targetSdkVersion}</a> is 16 or higher.</p>
          <p>Protection level: dangerous
+
+         <p> This is a hard restricted permission which cannot be held by an app until
+         the installer on record whitelists the permission. For more details see
+         {@link android.content.pm.PackageInstaller.SessionParams#setWhitelistedRestrictedPermissions(Set)}.
     -->
     <permission android:name="android.permission.WRITE_CALL_LOG"
         android:permissionGroup="android.permission-group.UNDEFINED"
@@ -991,6 +1035,10 @@
          abort the call altogether.
          <p>Protection level: dangerous
 
+         <p> This is a hard restricted permission which cannot be held by an app until
+         the installer on record whitelists the permission. For more details see
+         {@link android.content.pm.PackageInstaller.SessionParams#setWhitelistedRestrictedPermissions(Set)}.
+
          @deprecated Applications should use {@link android.telecom.CallRedirectionService} instead
          of the {@link android.content.Intent#ACTION_NEW_OUTGOING_CALL} broadcast.
     -->
@@ -1665,7 +1713,7 @@
 
     <!-- Allows applications to pair bluetooth devices without user interaction, and to
          allow or disallow phonebook access or message access.
-         This is not available to third party applications. -->
+         <p>Not for use by third-party applications. -->
     <permission android:name="android.permission.BLUETOOTH_PRIVILEGED"
         android:protectionLevel="signature|privileged" />
 
@@ -2515,7 +2563,8 @@
         android:protectionLevel="signature" />
 
     <!-- Allows an application to modify the current configuration, such
-         as locale. -->
+         as locale.
+         <p>Protection level: signature|privileged|development -->
     <permission android:name="android.permission.CHANGE_CONFIGURATION"
         android:protectionLevel="signature|privileged|development" />
 
@@ -2814,7 +2863,8 @@
     <!-- ==================================== -->
     <eat-comment />
 
-    <!-- Allows access to the list of accounts in the Accounts Service. -->
+    <!-- Allows access to the list of accounts in the Accounts Service.
+         <p>Protection level: signature|privileged -->
     <permission android:name="android.permission.GET_ACCOUNTS_PRIVILEGED"
         android:protectionLevel="signature|privileged" />
 
@@ -3393,7 +3443,8 @@
         android:protectionLevel="signature" />
 
     <!-- Old permission for deleting an app's cache files, no longer used,
-         but signals for us to quietly ignore calls instead of throwing an exception. -->
+         but signals for us to quietly ignore calls instead of throwing an exception.
+         <p>Protection level: signature|privileged -->
     <permission android:name="android.permission.DELETE_CACHE_FILES"
         android:protectionLevel="signature|privileged" />
 
@@ -3751,7 +3802,8 @@
     <!-- Allows an application to collect component usage
          statistics
          <p>Declaring the permission implies intention to use the API and the user of the
-         device can grant permission through the Settings application. -->
+         device can grant permission through the Settings application.
+         <p>Protection level: signature|privileged|development|appop -->
     <permission android:name="android.permission.PACKAGE_USAGE_STATS"
         android:protectionLevel="signature|privileged|development|appop" />
     <uses-permission android:name="android.permission.PACKAGE_USAGE_STATS" />
@@ -3774,14 +3826,14 @@
 
     <!-- Permission an application must hold in order to use
          {@link android.provider.Settings#ACTION_REQUEST_IGNORE_BATTERY_OPTIMIZATIONS}.
-         This is a normal permission: an app requesting it will always be granted the
-         permission, without the user needing to approve or see it. -->
+         <p>Protection level: normal -->
     <permission android:name="android.permission.REQUEST_IGNORE_BATTERY_OPTIMIZATIONS"
         android:label="@string/permlab_requestIgnoreBatteryOptimizations"
         android:description="@string/permdesc_requestIgnoreBatteryOptimizations"
         android:protectionLevel="normal" />
 
-    <!-- Allows an application to collect battery statistics -->
+    <!-- Allows an application to collect battery statistics
+         <p>Protection level: signature|privileged|development -->
     <permission android:name="android.permission.BATTERY_STATS"
         android:protectionLevel="signature|privileged|development" />
 
@@ -3811,7 +3863,8 @@
         android:protectionLevel="signature" />
 
     <!-- Must be required by a {@link android.widget.RemoteViewsService},
-         to ensure that only the system can bind to it. -->
+         to ensure that only the system can bind to it.
+         <p>Protection level: signature|privileged -->
     <permission android:name="android.permission.BIND_REMOTEVIEWS"
         android:protectionLevel="signature|privileged" />
 
@@ -3853,7 +3906,8 @@
          to the path in the provider where global search queries are
          performed.  This permission can not be held by regular applications;
          it is used by applications to protect themselves from everyone else
-         besides global search. -->
+         besides global search.
+         <p>Protection level: signature|privileged -->
     <permission android:name="android.permission.GLOBAL_SEARCH"
         android:protectionLevel="signature|privileged" />
 
@@ -4392,7 +4446,8 @@
     <permission android:name="android.permission.MODIFY_THEME_OVERLAY"
                 android:protectionLevel="signature" />
 
-    <!-- Allows an instant app to create foreground services. -->
+    <!-- Allows an instant app to create foreground services.
+         <p>Protection level: signature|development|instant|appop -->
     <permission android:name="android.permission.INSTANT_APP_FOREGROUND_SERVICE"
         android:protectionLevel="signature|development|instant|appop" />
 
@@ -4462,7 +4517,8 @@
     <permission android:name="android.permission.MONITOR_DEFAULT_SMS_PACKAGE"
         android:protectionLevel="signature|privileged" />
 
-    <!-- A subclass of {@link android.service.carrier.CarrierMessagingClientService} must be protected with this permission. -->
+    <!-- A subclass of {@link android.service.carrier.CarrierMessagingClientService} must be protected with this permission.
+           <p>Protection level: signature -->
     <permission android:name="android.permission.BIND_CARRIER_MESSAGING_CLIENT_SERVICE"
         android:protectionLevel="signature" />
 
@@ -4494,13 +4550,15 @@
     <permission android:name="android.permission.GRANT_PROFILE_OWNER_DEVICE_IDS_ACCESS"
         android:protectionLevel="signature" />
 
-    <!-- Allows financial apps to read filtered sms messages. -->
+    <!-- Allows financial apps to read filtered sms messages.
+         Protection level: signature|appop  -->
     <permission android:name="android.permission.SMS_FINANCIAL_TRANSACTIONS"
         android:protectionLevel="signature|appop" />
 
     <!-- Required for apps targeting {@link android.os.Build.VERSION_CODES#Q} that want to use
          {@link android.app.Notification.Builder#setFullScreenIntent notification full screen
-         intents}.  -->
+         intents}.
+         <p>Protection level: normal -->
     <permission android:name="android.permission.USE_FULL_SCREEN_INTENT"
                 android:protectionLevel="normal" />
 
diff --git a/core/res/res/anim/lock_in.xml b/core/res/res/anim/lock_in.xml
deleted file mode 100644
index c7014e8..0000000
--- a/core/res/res/anim/lock_in.xml
+++ /dev/null
@@ -1,227 +0,0 @@
-<!-- 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.
--->
-<animated-vector xmlns:android="http://schemas.android.com/apk/res/android"
-                 xmlns:aapt="http://schemas.android.com/aapt">
-    <aapt:attr name="android:drawable">
-        <vector android:height="42dp" android:width="32dp" android:viewportHeight="42"
-                android:viewportWidth="32">
-            <group android:name="_R_G">
-                <group android:name="_R_G_L_2_G" android:translateX="1.6669999999999998"
-                       android:translateY="11.992999999999999" android:pivotX="14.333"
-                       android:pivotY="13" android:scaleX="0" android:scaleY="0">
-                    <path android:name="_R_G_L_2_G_D_0_P_0" android:strokeColor="#ffffff"
-                          android:strokeLineCap="round" android:strokeLineJoin="round"
-                          android:strokeWidth="2" android:strokeAlpha="1"
-                          android:pathData=" M22.33 21 C22.33,21 6.33,21 6.33,21 C5.6,21 5,20.4 5,19.67 C5,19.67 5,6.33 5,6.33 C5,5.6 5.6,5 6.33,5 C6.33,5 22.33,5 22.33,5 C23.07,5 23.67,5.6 23.67,6.33 C23.67,6.33 23.67,19.67 23.67,19.67 C23.67,20.4 23.07,21 22.33,21c "/>
-                </group>
-                <group android:name="_R_G_L_1_G_N_4_T_0" android:translateX="1.6669999999999998"
-                       android:translateY="11.992999999999999" android:pivotX="14.333"
-                       android:pivotY="13" android:scaleX="0" android:scaleY="0">
-                    <group android:name="_R_G_L_1_G" android:translateX="11.583"
-                           android:translateY="10.257">
-                        <path android:name="_R_G_L_1_G_D_0_P_0" android:fillColor="#ffffff"
-                              android:fillAlpha="1" android:fillType="nonZero"
-                              android:pathData=" M2.75 0.25 C4.13,0.25 5.25,1.37 5.25,2.75 C5.25,4.13 4.13,5.25 2.75,5.25 C1.37,5.25 0.25,4.13 0.25,2.75 C0.25,1.37 1.37,0.25 2.75,0.25c "/>
-                    </group>
-                </group>
-                <group android:name="_R_G_L_0_G_N_4_T_0" android:translateX="1.6669999999999998"
-                       android:translateY="11.992999999999999" android:pivotX="14.333"
-                       android:pivotY="13" android:scaleX="0" android:scaleY="0">
-                    <group android:name="_R_G_L_0_G_T_1" android:translateX="14.333"
-                           android:translateY="3.172">
-                        <group android:name="_R_G_L_0_G" android:translateX="-9.667"
-                               android:translateY="-9.667">
-                            <path android:name="_R_G_L_0_G_D_0_P_0" android:strokeColor="#ffffff"
-                                  android:strokeLineCap="round" android:strokeLineJoin="round"
-                                  android:strokeWidth="2" android:strokeAlpha="1"
-                                  android:trimPathStart="0.14" android:trimPathEnd="0.89"
-                                  android:trimPathOffset="0"
-                                  android:pathData=" M14.33 14.33 C14.33,14.33 14.33,9.67 14.33,9.67 C14.33,7.09 12.24,5 9.67,5 C7.09,5 5,7.09 5,9.67 C5,9.67 5,14.33 5,14.33 "/>
-                        </group>
-                    </group>
-                </group>
-            </group>
-            <group android:name="time_group"/>
-        </vector>
-    </aapt:attr>
-    <target android:name="_R_G_L_2_G">
-        <aapt:attr name="android:animation">
-            <set android:ordering="together">
-                <objectAnimator android:propertyName="scaleX" android:duration="233"
-                                android:startOffset="0" android:valueFrom="0" android:valueTo="1.02"
-                                android:valueType="floatType">
-                    <aapt:attr name="android:interpolator">
-                        <pathInterpolator android:pathData="M 0.0,0.0 c0.001,0 0.438,1 1.0,1.0"/>
-                    </aapt:attr>
-                </objectAnimator>
-                <objectAnimator android:propertyName="scaleY" android:duration="233"
-                                android:startOffset="0" android:valueFrom="0" android:valueTo="1.02"
-                                android:valueType="floatType">
-                    <aapt:attr name="android:interpolator">
-                        <pathInterpolator android:pathData="M 0.0,0.0 c0.001,0 0.438,1 1.0,1.0"/>
-                    </aapt:attr>
-                </objectAnimator>
-                <objectAnimator android:propertyName="scaleX" android:duration="117"
-                                android:startOffset="233" android:valueFrom="1.02"
-                                android:valueTo="1" android:valueType="floatType">
-                    <aapt:attr name="android:interpolator">
-                        <pathInterpolator android:pathData="M 0.0,0.0 c0.333,0 0.565,1 1.0,1.0"/>
-                    </aapt:attr>
-                </objectAnimator>
-                <objectAnimator android:propertyName="scaleY" android:duration="117"
-                                android:startOffset="233" android:valueFrom="1.02"
-                                android:valueTo="1" android:valueType="floatType">
-                    <aapt:attr name="android:interpolator">
-                        <pathInterpolator android:pathData="M 0.0,0.0 c0.333,0 0.565,1 1.0,1.0"/>
-                    </aapt:attr>
-                </objectAnimator>
-            </set>
-        </aapt:attr>
-    </target>
-    <target android:name="_R_G_L_1_G_N_4_T_0">
-        <aapt:attr name="android:animation">
-            <set android:ordering="together">
-                <objectAnimator android:propertyName="scaleX" android:duration="233"
-                                android:startOffset="0" android:valueFrom="0" android:valueTo="1.02"
-                                android:valueType="floatType">
-                    <aapt:attr name="android:interpolator">
-                        <pathInterpolator android:pathData="M 0.0,0.0 c0.001,0 0.438,1 1.0,1.0"/>
-                    </aapt:attr>
-                </objectAnimator>
-                <objectAnimator android:propertyName="scaleY" android:duration="233"
-                                android:startOffset="0" android:valueFrom="0" android:valueTo="1.02"
-                                android:valueType="floatType">
-                    <aapt:attr name="android:interpolator">
-                        <pathInterpolator android:pathData="M 0.0,0.0 c0.001,0 0.438,1 1.0,1.0"/>
-                    </aapt:attr>
-                </objectAnimator>
-                <objectAnimator android:propertyName="scaleX" android:duration="117"
-                                android:startOffset="233" android:valueFrom="1.02"
-                                android:valueTo="1" android:valueType="floatType">
-                    <aapt:attr name="android:interpolator">
-                        <pathInterpolator android:pathData="M 0.0,0.0 c0.333,0 0.565,1 1.0,1.0"/>
-                    </aapt:attr>
-                </objectAnimator>
-                <objectAnimator android:propertyName="scaleY" android:duration="117"
-                                android:startOffset="233" android:valueFrom="1.02"
-                                android:valueTo="1" android:valueType="floatType">
-                    <aapt:attr name="android:interpolator">
-                        <pathInterpolator android:pathData="M 0.0,0.0 c0.333,0 0.565,1 1.0,1.0"/>
-                    </aapt:attr>
-                </objectAnimator>
-            </set>
-        </aapt:attr>
-    </target>
-    <target android:name="_R_G_L_0_G_D_0_P_0">
-        <aapt:attr name="android:animation">
-            <set android:ordering="together">
-                <objectAnimator android:propertyName="trimPathStart" android:duration="50"
-                                android:startOffset="0" android:valueFrom="0.14"
-                                android:valueTo="0.14" android:valueType="floatType">
-                    <aapt:attr name="android:interpolator">
-                        <pathInterpolator
-                            android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0"/>
-                    </aapt:attr>
-                </objectAnimator>
-                <objectAnimator android:propertyName="trimPathStart" android:duration="67"
-                                android:startOffset="50" android:valueFrom="0.14"
-                                android:valueTo="0" android:valueType="floatType">
-                    <aapt:attr name="android:interpolator">
-                        <pathInterpolator
-                            android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0"/>
-                    </aapt:attr>
-                </objectAnimator>
-            </set>
-        </aapt:attr>
-    </target>
-    <target android:name="_R_G_L_0_G_D_0_P_0">
-        <aapt:attr name="android:animation">
-            <set android:ordering="together">
-                <objectAnimator android:propertyName="trimPathEnd" android:duration="50"
-                                android:startOffset="0" android:valueFrom="0.89"
-                                android:valueTo="0.89" android:valueType="floatType">
-                    <aapt:attr name="android:interpolator">
-                        <pathInterpolator
-                            android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0"/>
-                    </aapt:attr>
-                </objectAnimator>
-                <objectAnimator android:propertyName="trimPathEnd" android:duration="67"
-                                android:startOffset="50" android:valueFrom="0.89"
-                                android:valueTo="1" android:valueType="floatType">
-                    <aapt:attr name="android:interpolator">
-                        <pathInterpolator
-                            android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0"/>
-                    </aapt:attr>
-                </objectAnimator>
-            </set>
-        </aapt:attr>
-    </target>
-    <target android:name="_R_G_L_0_G_T_1">
-        <aapt:attr name="android:animation">
-            <set android:ordering="together">
-                <objectAnimator android:propertyName="translateY" android:duration="150"
-                                android:startOffset="0" android:valueFrom="3.172"
-                                android:valueTo="0.34" android:valueType="floatType">
-                    <aapt:attr name="android:interpolator">
-                        <pathInterpolator android:pathData="M 0.0,0.0 c0.23,-0.46 0.2,1 1.0,1.0"/>
-                    </aapt:attr>
-                </objectAnimator>
-            </set>
-        </aapt:attr>
-    </target>
-    <target android:name="_R_G_L_0_G_N_4_T_0">
-        <aapt:attr name="android:animation">
-            <set android:ordering="together">
-                <objectAnimator android:propertyName="scaleX" android:duration="233"
-                                android:startOffset="0" android:valueFrom="0" android:valueTo="1.02"
-                                android:valueType="floatType">
-                    <aapt:attr name="android:interpolator">
-                        <pathInterpolator android:pathData="M 0.0,0.0 c0.001,0 0.438,1 1.0,1.0"/>
-                    </aapt:attr>
-                </objectAnimator>
-                <objectAnimator android:propertyName="scaleY" android:duration="233"
-                                android:startOffset="0" android:valueFrom="0" android:valueTo="1.02"
-                                android:valueType="floatType">
-                    <aapt:attr name="android:interpolator">
-                        <pathInterpolator android:pathData="M 0.0,0.0 c0.001,0 0.438,1 1.0,1.0"/>
-                    </aapt:attr>
-                </objectAnimator>
-                <objectAnimator android:propertyName="scaleX" android:duration="117"
-                                android:startOffset="233" android:valueFrom="1.02"
-                                android:valueTo="1" android:valueType="floatType">
-                    <aapt:attr name="android:interpolator">
-                        <pathInterpolator android:pathData="M 0.0,0.0 c0.333,0 0.565,1 1.0,1.0"/>
-                    </aapt:attr>
-                </objectAnimator>
-                <objectAnimator android:propertyName="scaleY" android:duration="117"
-                                android:startOffset="233" android:valueFrom="1.02"
-                                android:valueTo="1" android:valueType="floatType">
-                    <aapt:attr name="android:interpolator">
-                        <pathInterpolator android:pathData="M 0.0,0.0 c0.333,0 0.565,1 1.0,1.0"/>
-                    </aapt:attr>
-                </objectAnimator>
-            </set>
-        </aapt:attr>
-    </target>
-    <target android:name="time_group">
-        <aapt:attr name="android:animation">
-            <set android:ordering="together">
-                <objectAnimator android:propertyName="translateX" android:duration="717"
-                                android:startOffset="0" android:valueFrom="0" android:valueTo="1"
-                                android:valueType="floatType"/>
-            </set>
-        </aapt:attr>
-    </target>
-</animated-vector>
\ No newline at end of file
diff --git a/core/res/res/anim/lock_screen_behind_enter_subtle.xml b/core/res/res/anim/lock_screen_behind_enter_subtle.xml
new file mode 100644
index 0000000..f9f69b1
--- /dev/null
+++ b/core/res/res/anim/lock_screen_behind_enter_subtle.xml
@@ -0,0 +1,33 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ 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
+  -->
+
+<set xmlns:android="http://schemas.android.com/apk/res/android"
+        android:detachWallpaper="true"
+        android:shareInterpolator="false">
+
+   <alpha
+        android:fromAlpha="0.0" android:toAlpha="1.0"
+        android:fillEnabled="true" android:fillBefore="true"
+        android:interpolator="@interpolator/linear"
+        android:startOffset="80"
+        android:duration="233"/>
+    <translate android:fromYDelta="5%p" android:toYDelta="0"
+            android:fillEnabled="true" android:fillBefore="true" android:fillAfter="true"
+            android:interpolator="@interpolator/fast_out_slow_in"
+            android:startOffset="80"
+            android:duration="233" />
+</set>
\ No newline at end of file
diff --git a/core/res/res/drawable/ic_audio_alarm.xml b/core/res/res/drawable/ic_audio_alarm.xml
index 96206ea..93f9f8f 100644
--- a/core/res/res/drawable/ic_audio_alarm.xml
+++ b/core/res/res/drawable/ic_audio_alarm.xml
@@ -14,8 +14,8 @@
     limitations under the License.
 -->
 <vector xmlns:android="http://schemas.android.com/apk/res/android"
-        android:width="32.0dp"
-        android:height="32.0dp"
+        android:width="24dp"
+        android:height="24dp"
         android:viewportWidth="48.0"
         android:viewportHeight="48.0"
         android:tint="?attr/colorControlNormal">
diff --git a/core/res/res/drawable/ic_audio_alarm_mute.xml b/core/res/res/drawable/ic_audio_alarm_mute.xml
index 7f248c3..510a7c6 100644
--- a/core/res/res/drawable/ic_audio_alarm_mute.xml
+++ b/core/res/res/drawable/ic_audio_alarm_mute.xml
@@ -14,8 +14,8 @@
     limitations under the License.
 -->
 <vector xmlns:android="http://schemas.android.com/apk/res/android"
-        android:width="32.0dp"
-        android:height="32.0dp"
+        android:width="24dp"
+        android:height="24dp"
         android:viewportWidth="48.0"
         android:viewportHeight="48.0"
         android:tint="?attr/colorControlNormal">
diff --git a/core/res/res/drawable/ic_battery_80_24dp.xml b/core/res/res/drawable/ic_battery_80_24dp.xml
new file mode 100644
index 0000000..2513d0d
--- /dev/null
+++ b/core/res/res/drawable/ic_battery_80_24dp.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+    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.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:width="24dp"
+    android:height="24dp"
+    android:viewportWidth="24"
+    android:viewportHeight="24">
+  <path
+      android:fillColor="@android:color/white"
+      android:pathData="M9.5,2v2H7.33C6.6,4 6,4.6 6,5.33V15v5.67C6,21.4 6.6,22 7.33,22h9.33C17.4,22 18,21.4 18,20.67V15V5.33C18,4.6 17.4,4 16.67,4H14.5V2H9.5zM8,20v-5V6h8v9v5H8L8,20z"/>
+  <path
+      android:fillColor="@android:color/white"
+      android:pathData="M16.67,22H7.33C6.6,22 6,21.4 6,20.67V8h12v12.67C18,21.4 17.4,22 16.67,22z"/>
+</vector>
\ No newline at end of file
diff --git a/core/res/res/drawable/ic_bluetooth_share_icon.xml b/core/res/res/drawable/ic_bluetooth_share_icon.xml
index 2152af5..6acfd57 100644
--- a/core/res/res/drawable/ic_bluetooth_share_icon.xml
+++ b/core/res/res/drawable/ic_bluetooth_share_icon.xml
@@ -19,7 +19,7 @@
     android:height="24dp"
     android:viewportWidth="24"
     android:viewportHeight="24"
-    android:tint="@android:color/accent_device_default_light">
+    android:tint="@*android:color/accent_device_default_light">
 
     <path
         android:fillColor="@android:color/white"
diff --git a/core/res/res/drawable/ic_corp_badge.xml b/core/res/res/drawable/ic_corp_badge.xml
index 6a7ac4a..16df452 100644
--- a/core/res/res/drawable/ic_corp_badge.xml
+++ b/core/res/res/drawable/ic_corp_badge.xml
@@ -15,8 +15,8 @@
     limitations under the License.
 -->
 <vector xmlns:android="http://schemas.android.com/apk/res/android"
-        android:width="48dp"
-        android:height="48dp"
+        android:width="24dp"
+        android:height="24dp"
         android:tint="@*android:color/accent_device_default_light"
         android:viewportWidth="24"
         android:viewportHeight="24">
diff --git a/core/res/res/drawable/ic_file_copy.xml b/core/res/res/drawable/ic_file_copy.xml
index b6d5e73..d05b55f 100644
--- a/core/res/res/drawable/ic_file_copy.xml
+++ b/core/res/res/drawable/ic_file_copy.xml
@@ -16,9 +16,10 @@
 <vector xmlns:android="http://schemas.android.com/apk/res/android"
     android:width="24dp"
     android:height="24dp"
+    android:tint="@*android:color/material_grey_600"
     android:viewportWidth="24"
     android:viewportHeight="24">
   <path
       android:pathData="M16,1L4,1c-1.1,0 -2,0.9 -2,2v14h2L4,3h12L16,1zM15,5l6,6v10c0,1.1 -0.9,2 -2,2L7.99,23C6.89,23 6,22.1 6,21l0.01,-14c0,-1.1 0.89,-2 1.99,-2h7zM14,12h5.5L14,6.5L14,12z"
-      android:fillColor="#FF737373"/>
+      android:fillColor="@android:color/white"/>
 </vector>
diff --git a/core/res/res/drawable/ic_qs_auto_rotate.xml b/core/res/res/drawable/ic_qs_auto_rotate.xml
index 47e1059..8858e2b 100644
--- a/core/res/res/drawable/ic_qs_auto_rotate.xml
+++ b/core/res/res/drawable/ic_qs_auto_rotate.xml
@@ -16,8 +16,8 @@
 -->
 <vector
     xmlns:android="http://schemas.android.com/apk/res/android"
-    android:height="48dp"
-    android:width="48dp"
+    android:height="24dp"
+    android:width="24dp"
     android:viewportWidth="24.0"
     android:viewportHeight="24.0">
     <path
diff --git a/core/res/res/drawable/ic_qs_battery_saver.xml b/core/res/res/drawable/ic_qs_battery_saver.xml
index 93975b6..6e1ced0 100644
--- a/core/res/res/drawable/ic_qs_battery_saver.xml
+++ b/core/res/res/drawable/ic_qs_battery_saver.xml
@@ -15,8 +15,8 @@
 -->
 <vector xmlns:android="http://schemas.android.com/apk/res/android"
         android:autoMirrored="true"
-        android:width="32.0dp"
-        android:height="32.0dp"
+        android:width="24dp"
+        android:height="24dp"
         android:viewportWidth="24.0"
         android:viewportHeight="24.0"
         android:tint="?android:attr/colorControlNormal">
diff --git a/core/res/res/drawable/ic_qs_flashlight.xml b/core/res/res/drawable/ic_qs_flashlight.xml
index e635953..59b0ccd 100644
--- a/core/res/res/drawable/ic_qs_flashlight.xml
+++ b/core/res/res/drawable/ic_qs_flashlight.xml
@@ -15,8 +15,8 @@
      limitations under the License.
 -->
 <vector xmlns:android="http://schemas.android.com/apk/res/android"
-    android:width="48dp"
-    android:height="48dp"
+    android:width="24dp"
+    android:height="24dp"
     android:viewportWidth="24.0"
     android:viewportHeight="24.0">
     <path
diff --git a/core/res/res/drawable/ic_qs_ui_mode_night.xml b/core/res/res/drawable/ic_qs_ui_mode_night.xml
index 7227827..34b535b 100644
--- a/core/res/res/drawable/ic_qs_ui_mode_night.xml
+++ b/core/res/res/drawable/ic_qs_ui_mode_night.xml
@@ -15,11 +15,11 @@
   ~ limitations under the License
   -->
 <vector xmlns:android="http://schemas.android.com/apk/res/android"
-        android:width="48dp"
-        android:height="48dp"
+        android:width="24dp"
+        android:height="24dp"
         android:viewportWidth="24.0"
         android:viewportHeight="24.0">
     <path
-        android:fillColor="#FF000000"
+        android:fillColor="@android:color/white"
         android:pathData="M12,22C17.52,22 22,17.52 22,12 22,6.48 17.52,2 12,2 6.48,2 2,6.48 2,12 2,17.52 6.48,22 12,22ZM12,3.915c3.889,0 8,4.005 8,8.085 0,4.08 -3.927,7.992 -7.928,7.992z"/>
-</vector>
\ No newline at end of file
+</vector>
diff --git a/core/res/res/drawable/perm_group_activity_recognition.xml b/core/res/res/drawable/perm_group_activity_recognition.xml
index 0ade6c6..ef025ac 100644
--- a/core/res/res/drawable/perm_group_activity_recognition.xml
+++ b/core/res/res/drawable/perm_group_activity_recognition.xml
@@ -17,6 +17,7 @@
 <vector xmlns:android="http://schemas.android.com/apk/res/android"
     android:width="24dp"
     android:height="24dp"
+    android:tint="?android:attr/colorControlNormal"
     android:viewportWidth="24"
     android:viewportHeight="24">
 
diff --git a/core/res/res/drawable/perm_group_aural.xml b/core/res/res/drawable/perm_group_aural.xml
index b2737f2..4b4c62c 100644
--- a/core/res/res/drawable/perm_group_aural.xml
+++ b/core/res/res/drawable/perm_group_aural.xml
@@ -16,6 +16,7 @@
 <vector xmlns:android="http://schemas.android.com/apk/res/android"
         android:width="24dp"
         android:height="24dp"
+        android:tint="?android:attr/colorControlNormal"
         android:viewportWidth="24.0"
         android:viewportHeight="24.0">
     <path
diff --git a/core/res/res/drawable/perm_group_calendar.xml b/core/res/res/drawable/perm_group_calendar.xml
index 4b46dd3..0dfb301 100644
--- a/core/res/res/drawable/perm_group_calendar.xml
+++ b/core/res/res/drawable/perm_group_calendar.xml
@@ -17,13 +17,12 @@
 <vector xmlns:android="http://schemas.android.com/apk/res/android"
     android:width="24dp"
     android:height="24dp"
+    android:tint="?android:attr/colorControlNormal"
     android:viewportWidth="24"
     android:viewportHeight="24">
 
     <path
         android:fillColor="#000000"
         android:pathData="M19 4h-1V2h-2v2H8V2H6v2H5c-1.11 0-1.99 0.9 -1.99 2L3 20c0 1.1 0.89 2 2 2h14c1.1 0 2-0.9 2-2V6c0-1.1-0.9-2-2-2zm0 16H5V10h14v10zm-4.5-7c-1.38 0-2.5 1.12-2.5 2.5s1.12 2.5 2.5 2.5 2.5-1.12 2.5-2.5-1.12-2.5-2.5-2.5z" />
-    <path
-        android:pathData="M0 0h24v24H0V0z" />
 
-</vector>
\ No newline at end of file
+</vector>
diff --git a/core/res/res/drawable/perm_group_call_log.xml b/core/res/res/drawable/perm_group_call_log.xml
index 0dfdbee..a37ed88 100644
--- a/core/res/res/drawable/perm_group_call_log.xml
+++ b/core/res/res/drawable/perm_group_call_log.xml
@@ -18,6 +18,7 @@
 <vector xmlns:android="http://schemas.android.com/apk/res/android"
         android:width="24dp"
         android:height="24dp"
+        android:tint="?android:attr/colorControlNormal"
         android:viewportWidth="24.0"
         android:viewportHeight="24.0">
     <path
diff --git a/core/res/res/drawable/perm_group_camera.xml b/core/res/res/drawable/perm_group_camera.xml
index db7833f..e65501c 100644
--- a/core/res/res/drawable/perm_group_camera.xml
+++ b/core/res/res/drawable/perm_group_camera.xml
@@ -17,6 +17,7 @@
 <vector xmlns:android="http://schemas.android.com/apk/res/android"
     android:width="24dp"
     android:height="24dp"
+    android:tint="?android:attr/colorControlNormal"
     android:viewportWidth="24"
     android:viewportHeight="24">
 
diff --git a/core/res/res/drawable/perm_group_contacts.xml b/core/res/res/drawable/perm_group_contacts.xml
index b834a27..dd6ae21 100644
--- a/core/res/res/drawable/perm_group_contacts.xml
+++ b/core/res/res/drawable/perm_group_contacts.xml
@@ -17,6 +17,7 @@
 <vector xmlns:android="http://schemas.android.com/apk/res/android"
     android:width="24dp"
     android:height="24dp"
+    android:tint="?android:attr/colorControlNormal"
     android:viewportWidth="24"
     android:viewportHeight="24">
 
diff --git a/core/res/res/drawable/perm_group_location.xml b/core/res/res/drawable/perm_group_location.xml
index a7fa524..a87fc0d 100644
--- a/core/res/res/drawable/perm_group_location.xml
+++ b/core/res/res/drawable/perm_group_location.xml
@@ -17,6 +17,7 @@
 <vector xmlns:android="http://schemas.android.com/apk/res/android"
     android:width="24dp"
     android:height="24dp"
+    android:tint="?android:attr/colorControlNormal"
     android:viewportWidth="24"
     android:viewportHeight="24">
 
diff --git a/core/res/res/drawable/perm_group_microphone.xml b/core/res/res/drawable/perm_group_microphone.xml
index 9b532c1..a1ed725 100644
--- a/core/res/res/drawable/perm_group_microphone.xml
+++ b/core/res/res/drawable/perm_group_microphone.xml
@@ -17,6 +17,7 @@
 <vector xmlns:android="http://schemas.android.com/apk/res/android"
     android:width="24dp"
     android:height="24dp"
+    android:tint="?android:attr/colorControlNormal"
     android:viewportWidth="24"
     android:viewportHeight="24">
 
diff --git a/core/res/res/drawable/perm_group_phone_calls.xml b/core/res/res/drawable/perm_group_phone_calls.xml
index 324d864..5632226 100644
--- a/core/res/res/drawable/perm_group_phone_calls.xml
+++ b/core/res/res/drawable/perm_group_phone_calls.xml
@@ -17,6 +17,7 @@
 <vector xmlns:android="http://schemas.android.com/apk/res/android"
     android:width="24dp"
     android:height="24dp"
+    android:tint="?android:attr/colorControlNormal"
     android:viewportWidth="24"
     android:viewportHeight="24">
     <path
@@ -25,4 +26,4 @@
 .37 2.33 .57 3.57 .57 .55 0 1 .45 1 1V20c0 .55-.45 1-1 1-9.39 0-17-7.61-17-17
 0-.55 .45 -1 1-1h3.5c.55 0 1 .45 1 1 0 1.25 .2 2.45 .57 3.57 .11 .35 .03 .74-.25
 1.02l-2.2 2.2z" />
-</vector>
\ No newline at end of file
+</vector>
diff --git a/core/res/res/drawable/perm_group_sensors.xml b/core/res/res/drawable/perm_group_sensors.xml
index e4663d7..f800965 100644
--- a/core/res/res/drawable/perm_group_sensors.xml
+++ b/core/res/res/drawable/perm_group_sensors.xml
@@ -17,6 +17,7 @@
 <vector xmlns:android="http://schemas.android.com/apk/res/android"
     android:width="24dp"
     android:height="24dp"
+    android:tint="?android:attr/colorControlNormal"
     android:viewportWidth="24"
     android:viewportHeight="24">
   <path
diff --git a/core/res/res/drawable/perm_group_sms.xml b/core/res/res/drawable/perm_group_sms.xml
index ebcf3d1..44ccdd6 100644
--- a/core/res/res/drawable/perm_group_sms.xml
+++ b/core/res/res/drawable/perm_group_sms.xml
@@ -17,6 +17,7 @@
 <vector xmlns:android="http://schemas.android.com/apk/res/android"
     android:width="24dp"
     android:height="24dp"
+    android:tint="?android:attr/colorControlNormal"
     android:viewportWidth="24"
     android:viewportHeight="24">
 
diff --git a/core/res/res/drawable/perm_group_storage.xml b/core/res/res/drawable/perm_group_storage.xml
index 4b8965b..fceda2b 100644
--- a/core/res/res/drawable/perm_group_storage.xml
+++ b/core/res/res/drawable/perm_group_storage.xml
@@ -17,6 +17,7 @@
 <vector xmlns:android="http://schemas.android.com/apk/res/android"
     android:width="24dp"
     android:height="24dp"
+    android:tint="?android:attr/colorControlNormal"
     android:viewportWidth="24"
     android:viewportHeight="24">
 
diff --git a/core/res/res/drawable/perm_group_visual.xml b/core/res/res/drawable/perm_group_visual.xml
index 9b21c27..bf3edea 100644
--- a/core/res/res/drawable/perm_group_visual.xml
+++ b/core/res/res/drawable/perm_group_visual.xml
@@ -16,11 +16,10 @@
 <vector xmlns:android="http://schemas.android.com/apk/res/android"
         android:width="24dp"
         android:height="24dp"
+        android:tint="?android:attr/colorControlNormal"
         android:viewportWidth="24.0"
         android:viewportHeight="24.0">
     <path
         android:fillColor="#000000"
         android:pathData="M20,4v12H8V4H20 M20,2H8C6.9,2,6,2.9,6,4v12c0,1.1,0.9,2,2,2h12c1.1,0,2-0.9,2-2V4C22,2.9,21.1,2,20,2L20,2z M2,6v14 c0,1.1,0.9,2,2,2h14v-2H4V6H2z M15.67,11l-2.5,2.98L11.5,11.8L9,15h10L15.67,11z" />
-    <path
-        android:pathData="M0,0h24v24H0V0z" />
 </vector>
diff --git a/core/res/res/layout/notification_template_material_media.xml b/core/res/res/layout/notification_template_material_media.xml
index 13fef67..575295b 100644
--- a/core/res/res/layout/notification_template_material_media.xml
+++ b/core/res/res/layout/notification_template_material_media.xml
@@ -15,7 +15,7 @@
   ~ limitations under the License
   -->
 
-<FrameLayout
+<com.android.internal.widget.MediaNotificationView
     android:id="@+id/status_bar_latest_event_content"
     xmlns:android="http://schemas.android.com/apk/res/android"
     android:layout_width="match_parent"
@@ -24,8 +24,8 @@
     android:tag="media"
     >
     <ImageView android:id="@+id/right_icon"
-        android:layout_width="wrap_content"
-        android:layout_height="match_parent"
+        android:layout_width="0dp"
+        android:layout_height="0dp"
         android:adjustViewBounds="true"
         android:layout_gravity="top|end"
         android:scaleType="centerCrop"
@@ -91,4 +91,4 @@
             android:layout_alignParentBottom="true"
         />
     </LinearLayout>
-</FrameLayout>
+</com.android.internal.widget.MediaNotificationView>
diff --git a/core/res/res/values-mcc313-mnc100/config.xml b/core/res/res/values-mcc313-mnc100/config.xml
new file mode 100644
index 0000000..ccd03f1
--- /dev/null
+++ b/core/res/res/values-mcc313-mnc100/config.xml
@@ -0,0 +1,45 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+** Copyright 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.
+*/
+-->
+
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string-array translatable="false" name="config_twoDigitNumberPattern">
+        <item>"0"</item>
+        <item>"00"</item>
+        <item>"*0"</item>
+        <item>"*1"</item>
+        <item>"*2"</item>
+        <item>"*3"</item>
+        <item>"*4"</item>
+        <item>"*5"</item>
+        <item>"*6"</item>
+        <item>"*7"</item>
+        <item>"*8"</item>
+        <item>"*9"</item>
+        <item>"#0"</item>
+        <item>"#1"</item>
+        <item>"#2"</item>
+        <item>"#3"</item>
+        <item>"#4"</item>
+        <item>"#5"</item>
+        <item>"#6"</item>
+        <item>"#7"</item>
+        <item>"#8"</item>
+        <item>"#9"</item>
+    </string-array>
+</resources>
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index 06503bd..efc943e 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -1115,6 +1115,22 @@
          regularly selected color mode will be used if this value is negative. -->
     <integer name="config_accessibilityColorMode">-1</integer>
 
+    <!-- The following two arrays specify which color space to use for display composition when a
+         certain color mode is active.
+         Composition color spaces are defined in android.view.Display.COLOR_MODE_xxx, and color
+         modes are defined in ColorDisplayManager.COLOR_MODE_xxx and
+         ColorDisplayManager.VENDOR_COLOR_MODE_xxx.
+         The color space COLOR_MODE_DEFAULT (0) lets the system select the most appropriate
+         composition color space for currently displayed content. Other values (e.g.,
+         COLOR_MODE_SRGB) override system selection; these other color spaces must be supported by
+         the device for for display composition.
+         If a color mode does not have a corresponding color space specified in this array, the
+         currently set composition color space will not be modified.-->
+    <integer-array name="config_displayCompositionColorModes">
+    </integer-array>
+    <integer-array name="config_displayCompositionColorSpaces">
+    </integer-array>
+
     <!-- Indicate whether to allow the device to suspend when the screen is off
          due to the proximity sensor.  This resource should only be set to true
          if the sensor HAL correctly handles the proximity sensor as a wake-up source.
@@ -2286,7 +2302,7 @@
          effectively and terminate the dream.  Use -1 to disable this safety feature.  -->
     <integer name="config_dreamsBatteryLevelDrainCutoff">5</integer>
     <!-- Limit of how long the device can remain unlocked due to attention checking.  -->
-    <integer name="config_attentionMaximumExtension">240000</integer> <!-- 4 minutes -->
+    <integer name="config_attentionMaximumExtension">330000</integer> <!-- 5 minutes and 30 sec.-->
     <!-- How long we should wait until we give up on receiving an attention API callback.  -->
     <integer name="config_attentionApiTimeout">2000</integer> <!-- 2 seconds -->
 
@@ -2319,7 +2335,7 @@
 
     <!-- If the sensor that wakes up the lock screen is available or not. -->
     <bool name="config_dozeWakeLockScreenSensorAvailable">false</bool>
-    <integer name="config_dozeWakeLockScreenDebounce">1500</integer>
+    <integer name="config_dozeWakeLockScreenDebounce">300</integer>
 
     <!-- Control whether the always on display mode is available. This should only be enabled on
          devices where the display has been tuned to be power efficient in DOZE and/or DOZE_SUSPEND
@@ -3808,9 +3824,11 @@
     <integer name="config_stableDeviceDisplayWidth">-1</integer>
     <integer name="config_stableDeviceDisplayHeight">-1</integer>
 
-    <!-- Decide whether to display 'No service' on status bar instead of 'Emergency calls only'
-         when SIM is unready. -->
-    <bool name="config_display_no_service_when_sim_unready">false</bool>
+    <!-- List of countries in which we display 'No service' on status bar
+         instead of 'Emergency calls only' when SIM is unready. -->
+    <string-array translatable="false" name="config_display_no_service_when_sim_unready">
+        <item>"DE"</item>
+    </string-array>
 
     <!-- Class names of device specific services inheriting com.android.server.SystemService. The
          classes are instantiated in the order of the array. -->
@@ -4050,16 +4068,62 @@
     </array>
 
     <!-- See DisplayWhiteBalanceController.
-         The ambient brightness threshold (in lux) beneath which we fall back to a fixed ambient
-         color temperature. -->
-    <item name="config_displayWhiteBalanceLowLightAmbientBrightnessThreshold" format="float" type="dimen">10.0</item>
+         A float array containing a list of ambient brightnesses, in Lux. This array,
+         together with config_displayWhiteBalanceLowLightAmbientBiases, is used to generate a
+         lookup table used in DisplayWhiteBalanceController. This lookup table is used to map
+         ambient brightness readings to a bias, where the bias is used to linearly interpolate
+         between ambient color temperature and
+         config_displayWhiteBalanceLowLightAmbientColorTemperature.
+         This table is optional. If used, this array must,
+         1) Contain at least two entries
+         2) Be the same length as config_displayWhiteBalanceLowLightAmbientBiases. -->
+    <array name ="config_displayWhiteBalanceLowLightAmbientBrightnesses">
+        <item>10.0</item>
+        <item>10.0</item>
+    </array>
 
     <!-- See DisplayWhiteBalanceController.
-         The ambient color temperature (in cct) to which we fall back when the ambient brightness
-         drops beneath a certain threshold. -->
+         An array containing a list of biases. See
+         config_displayWhiteBalanceLowLightAmbientBrightnesses for additional details.
+         This array must be in the range of [0.0, 1.0]. -->
+    <array name ="config_displayWhiteBalanceLowLightAmbientBiases">
+        <item>0.0</item>
+        <item>1.0</item>
+    </array>
+
+    <!-- See DisplayWhiteBalanceController.
+         The ambient color temperature (in cct) to which we interpolate towards using the
+         the look up table generated by config_displayWhiteBalanceLowLightAmbientBrightnesses
+         and config_displayWhiteBalanceLowLightAmbientBiases. -->
     <item name="config_displayWhiteBalanceLowLightAmbientColorTemperature" format="float" type="dimen">6500.0</item>
 
     <!-- See DisplayWhiteBalanceController.
+         A float array containing a list of ambient brightnesses, in Lux. This array,
+         together with config_displayWhiteBalanceHighLightAmbientBiases, is used to generate a
+         lookup table used in DisplayWhiteBalanceController. This lookup table is used to map
+         ambient brightness readings to a bias, where the bias is used to linearly interpolate
+         between ambient color temperature and
+         config_displayWhiteBalanceHighLightAmbientColorTemperature.
+         This table is optional. If used, this array must,
+         1) Contain at least two entries
+         2) Be the same length as config_displayWhiteBalanceHighLightAmbientBiases. -->
+    <array name ="config_displayWhiteBalanceHighLightAmbientBrightnesses">
+    </array>
+
+    <!-- See DisplayWhiteBalanceController.
+         An array containing a list of biases. See
+         config_displayWhiteBalanceHighLightAmbientBrightnesses for additional details.
+         This array must be in the range of [0.0, 1.0]. -->
+    <array name ="config_displayWhiteBalanceHighLightAmbientBiases">
+    </array>
+
+    <!-- See DisplayWhiteBalanceController.
+         The ambient color temperature (in cct) to which we interpolate towards using the
+         the look up table generated by config_displayWhiteBalanceHighLightAmbientBrightnesses
+         and config_displayWhiteBalanceHighLightAmbientBiases. -->
+    <item name="config_displayWhiteBalanceHighLightAmbientColorTemperature" format="float" type="dimen">8000.0</item>
+
+    <!-- See DisplayWhiteBalanceController.
          A float array containing a list of ambient color temperatures, in Kelvin. This array,
          together with config_displayWhiteBalanceDisplayColorTemperatures, is used to generate a
          lookup table used in DisplayWhiteBalanceController. This lookup table is used to map
@@ -4093,6 +4157,15 @@
         M9,10l-2,0l0,-2l-2,0l0,2l-2,0l0,2l2,0l0,2l2,0l0,-2l2,0z
     </string>
 
+    <!-- X path for SignalDrawable as defined on a 24x24 canvas. -->
+    <string name="config_signalXPath" translatable="false">
+        M22,16.41L20.59,15l-2.09,2.09L16.41,15L15,16.41l2.09,2.09L15,20.59L16.41,22l2.09-2.08L20.59,22L22,20.59l-2.08-2.09   L22,16.41z
+    </string>
+    <!-- config_signalCutout{Height,Width}Fraction define fraction of the 24x24 canvas that
+         should be cut out to display config_signalXPath.-->
+    <item name="config_signalCutoutWidthFraction" format="float" type="dimen">11</item>
+    <item name="config_signalCutoutHeightFraction" format="float" type="dimen">11</item>
+
     <!-- A dual tone battery meter draws the perimeter path twice - once to define the shape
      and a second time clipped to the fill level to indicate charge -->
     <bool name="config_batterymeterDualTone">false</bool>
@@ -4101,6 +4174,32 @@
          for higher refresh rates to be automatically used out of the box -->
     <integer name="config_defaultPeakRefreshRate">60</integer>
 
+    <!-- The display uses different gamma curves for different refresh rates. It's hard for panel
+         vendor to tune the curves to have exact same brightness for different refresh rate. So
+         flicker could be observed at switch time. The issue is worse at the gamma lower end.
+         In addition, human eyes are more sensitive to the flicker at darker environment.
+         To prevent flicker, we only support higher refresh rates if the display brightness is above
+         a threshold. And the darker environment could have higher threshold.
+         For example, no higher refresh rate if
+             display brightness <= disp0 && ambient brightness <= amb0
+             || display brightness <= disp1 && ambient brightness <= amb1 -->
+    <integer-array translatable="false" name="config_brightnessThresholdsOfPeakRefreshRate">
+         <!--
+           <item>disp0</item>
+           <item>disp1</item>
+        -->
+    </integer-array>
+    <integer-array translatable="false" name="config_ambientThresholdsOfPeakRefreshRate">
+         <!--
+           <item>amb0</item>
+           <item>amb1</item>
+        -->
+    </integer-array>
+
+    <!-- Default refresh rate in the zone defined by brightness and ambient thresholds.
+         If non-positive, then the refresh rate is unchanged even if thresholds are configured. -->
+    <integer name="config_defaultRefreshRateInZone">0</integer>
+
     <!-- The type of the light sensor to be used by the display framework for things like
          auto-brightness. If unset, then it just gets the default sensor of type TYPE_LIGHT. -->
     <string name="config_displayLightSensorType" translatable="false" />
@@ -4163,6 +4262,9 @@
     <integer-array name="config_face_acquire_vendor_biometricprompt_ignorelist" translatable="false" >
     </integer-array>
 
+    <!-- If face auth sends the user directly to home/last open app, or stays on keyguard -->
+    <bool name="config_faceAuthDismissesKeyguard">true</bool>
+
     <!-- The component name for the default profile supervisor, which can be set as a profile owner
     even after user setup is complete. The defined component should be used for supervision purposes
     only. The component must be part of a system app. -->
@@ -4178,4 +4280,8 @@
 
     <!-- Sharesheet: define a max number of targets per application for new shortcuts-based direct share introduced in Q -->
     <integer name="config_maxShortcutTargetsPerApp">3</integer>
+
+    <!-- The list of packages to automatically opt out of refresh rates higher than 60hz because
+         of known compatibility issues. -->
+    <string-array name="config_highRefreshRateBlacklist"></string-array>
 </resources>
diff --git a/core/res/res/values/dimens.xml b/core/res/res/values/dimens.xml
index 5363ef9..609659b 100644
--- a/core/res/res/values/dimens.xml
+++ b/core/res/res/values/dimens.xml
@@ -90,6 +90,24 @@
         orientation. If zero, the value of rounded_corner_radius is used. -->
     <dimen name="rounded_corner_radius_bottom">0dp</dimen>
 
+    <!-- Default adjustment for the software rounded corners since corners are not perfectly
+        round. This value is used when retrieving the "radius" of the rounded corner in cases
+        where the exact bezier curve cannot be retrieved.  This value will be subtracted from
+        rounded_corner_radius to more accurately provide a "radius" for the rounded corner. -->
+    <dimen name="rounded_corner_radius_adjustment">0px</dimen>
+    <!-- Top adjustment for the software rounded corners since corners are not perfectly
+        round.  This value is used when retrieving the "radius" of the top rounded corner in cases
+        where the exact bezier curve cannot be retrieved.  This value will be subtracted from
+        rounded_corner_radius_top to more accurately provide a "radius" for the top rounded corners.
+         -->
+    <dimen name="rounded_corner_radius_top_adjustment">0px</dimen>
+    <!-- Bottom adjustment for the software rounded corners since corners are not perfectly
+        round.  This value is used when retrieving the "radius" of the bottom rounded corner in
+        cases where the exact bezier curve cannot be retrieved.  This value will be subtracted from
+        rounded_corner_radius_bottom to more accurately provide a "radius" for the bottom rounded
+        corners. -->
+    <dimen name="rounded_corner_radius_bottom_adjustment">0px</dimen>
+
     <!-- Width of the window of the divider bar used to resize docked stacks. -->
     <dimen name="docked_stack_divider_thickness">48dp</dimen>
 
@@ -261,7 +279,7 @@
     <dimen name="notification_expand_button_padding_top">1dp</dimen>
 
     <!-- Height of a small notification in the status bar -->
-    <dimen name="notification_min_height">92dp</dimen>
+    <dimen name="notification_min_height">106dp</dimen>
 
     <!-- The width of the big icons in notifications. -->
     <dimen name="notification_large_icon_width">64dp</dimen>
@@ -730,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/strings.xml b/core/res/res/values/strings.xml
index 152b131..b4edc4d 100644
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -187,6 +187,9 @@
     <string name="notification_channel_wfc">Wi-Fi calling</string>
     <!-- Telephony notification channel name for a channel containing SIM notifications -->
     <string name="notification_channel_sim">SIM status</string>
+    <!-- Telephony notification channel name for a channel containing high priority SIM notifications -->
+    <string name="notification_channel_sim_high_prio">High priority SIM status</string>
+
 
     <!-- Displayed to tell the user that peer changed TTY mode -->
     <string name="peerTtyModeFull">Peer requested TTY Mode FULL</string>
@@ -1502,16 +1505,16 @@
     <string name="fingerprint_icon_content_description">Fingerprint icon</string>
 
     <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. [CHAR LIMIT=70] -->
-    <string name="permlab_manageFace">manage face authentication hardware</string>
+    <string name="permlab_manageFace">manage face unlock hardware</string>
     <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. [CHAR LIMIT=90] -->
     <string name="permdesc_manageFace">Allows the app to invoke methods to add and delete facial templates for use.</string>
     <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. [CHAR LIMIT=70] -->
-    <string name="permlab_useFaceAuthentication">use face authentication hardware</string>
+    <string name="permlab_useFaceAuthentication">use face unlock hardware</string>
     <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. [CHAR LIMIT=90] -->
-    <string name="permdesc_useFaceAuthentication">Allows the app to use face authentication hardware for authentication</string>
+    <string name="permdesc_useFaceAuthentication">Allows the app to use face unlock hardware for authentication</string>
 
     <!-- Notification name shown when the system requires the user to re-enroll their face. [CHAR LIMIT=NONE] -->
-    <string name="face_recalibrate_notification_name">Face Authentication</string>
+    <string name="face_recalibrate_notification_name">Face unlock</string>
     <!-- Notification title shown when the system requires the user to re-enroll their face. [CHAR LIMIT=NONE] -->
     <string name="face_recalibrate_notification_title">Re-enroll your face</string>
     <!-- Notification content shown when the system requires the user to re-enroll their face. [CHAR LIMIT=NONE] -->
@@ -1538,7 +1541,7 @@
     <!-- Message shown during face acquisition when the user is not front facing the sensor [CHAR LIMIT=50] -->
     <string name="face_acquired_poor_gaze">Please look more directly at your device.</string>
     <!-- Message shown during face acquisition when the user is not detected [CHAR LIMIT=50] -->
-    <string name="face_acquired_not_detected">Can\u2019t see your face. Look at the phone.</string>
+    <string name="face_acquired_not_detected">Position your face directly in front of the phone.</string>
     <!-- Message shown during face acquisition when the device is not steady [CHAR LIMIT=50] -->
     <string name="face_acquired_too_much_motion">Too much motion. Hold phone steady.</string>
     <!-- Message shown during face acquisition when the sensor needs to be recalibrated [CHAR LIMIT=50] -->
@@ -1555,8 +1558,8 @@
     <string name="face_acquired_roll_too_extreme">Turn your head a little less.</string>
     <!-- Message shown during acquisition when the user's face is obscured [CHAR LIMIT=50] -->
     <string name="face_acquired_obscured">Remove anything hiding your face.</string>
-    <!-- Message shown during acquisition when the sensor is dirty [CHAR LIMIT=50] -->
-    <string name="face_acquired_sensor_dirty">Clean the sensor at the top edge of the screen.</string>
+    <!-- Message shown during acquisition when the sensor is dirty [CHAR LIMIT=100] -->
+    <string name="face_acquired_sensor_dirty">Clean the top of your screen, including the black bar</string>
     <!-- Array containing custom messages shown during face acquisition from vendor.  Vendor is expected to add and translate these strings -->
     <string-array name="face_acquired_vendor">
     </string-array>
@@ -1564,23 +1567,23 @@
     <!-- Error message shown when the face hardware can't be accessed. [CHAR LIMIT=69] -->
     <string name="face_error_hw_not_available">Can\u2019t verify face. Hardware not available.</string>
     <!-- Error message shown when the face hardware timer has expired and the user needs to restart the operation. [CHAR LIMIT=50] -->
-    <string name="face_error_timeout">Try face authentication again.</string>
+    <string name="face_error_timeout">Try face unlock again.</string>
     <!-- Error message shown when the face hardware has run out of room for storing faces. [CHAR LIMIT=69] -->
     <string name="face_error_no_space">Can\u2019t store new face data. Delete an old one first.</string>
     <!-- Generic error message shown when the face operation (e.g. enrollment or authentication) is canceled. Generally not shown to the user. [CHAR LIMIT=50] -->
-    <string name="face_error_canceled">Face operation canceled</string>
-    <!-- Generic error message shown when the face authentication operation is canceled due to user input. Generally not shown to the user [CHAR LIMIT=54] -->
-    <string name="face_error_user_canceled">Face authentication canceled by user</string>
+    <string name="face_error_canceled">Face operation canceled.</string>
+    <!-- Generic error message shown when the face unlock operation is canceled due to user input. Generally not shown to the user [CHAR LIMIT=54] -->
+    <string name="face_error_user_canceled">Face unlock canceled by user.</string>
     <!-- Generic error message shown when the face operation fails because too many attempts have been made. [CHAR LIMIT=50] -->
     <string name="face_error_lockout">Too many attempts. Try again later.</string>
     <!-- Generic error message shown when the face operation fails because strong authentication is required. [CHAR LIMIT=71] -->
-    <string name="face_error_lockout_permanent">Too many attempts. Face authentication disabled.</string>
+    <string name="face_error_lockout_permanent">Too many attempts. Face unlock disabled.</string>
     <!-- Generic error message shown when the face hardware can't recognize the face. [CHAR LIMIT=50] -->
     <string name="face_error_unable_to_process">Can\u2019t verify face. Try again.</string>
     <!-- Generic error message shown when the user has no enrolled face. [CHAR LIMIT=52] -->
-    <string name="face_error_not_enrolled">You haven\u2019t set up face authentication</string>
-    <!-- Generic error message shown when the app requests face authentication on a device without a sensor. [CHAR LIMIT=61] -->
-    <string name="face_error_hw_not_present">Face authentication is not supported on this device</string>
+    <string name="face_error_not_enrolled">You haven\u2019t set up face unlock.</string>
+    <!-- Generic error message shown when the app requests face unlock on a device without a sensor. [CHAR LIMIT=61] -->
+    <string name="face_error_hw_not_present">Face unlock is not supported on this device.</string>
 
     <!-- Template to be used to name enrolled faces by default. [CHAR LIMIT=10] -->
     <string name="face_name_template">Face <xliff:g id="faceId" example="1">%d</xliff:g></string>
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index 61077af..e5805fd 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -654,6 +654,7 @@
   <java-symbol type="string" name="notification_channel_voice_mail" />
   <java-symbol type="string" name="notification_channel_wfc" />
   <java-symbol type="string" name="notification_channel_sim" />
+  <java-symbol type="string" name="notification_channel_sim_high_prio" />
   <java-symbol type="string" name="SetupCallDefault" />
   <java-symbol type="string" name="accept" />
   <java-symbol type="string" name="activity_chooser_view_see_all" />
@@ -2274,14 +2275,10 @@
   <java-symbol type="anim" name="lock_screen_behind_enter" />
   <java-symbol type="anim" name="lock_screen_behind_enter_wallpaper" />
   <java-symbol type="anim" name="lock_screen_behind_enter_fade_in" />
+  <java-symbol type="anim" name="lock_screen_behind_enter_subtle" />
   <java-symbol type="anim" name="lock_screen_wallpaper_exit" />
   <java-symbol type="anim" name="launch_task_behind_source" />
   <java-symbol type="anim" name="wallpaper_open_exit" />
-  <java-symbol type="anim" name="lock_to_error" />
-  <java-symbol type="anim" name="lock_lock" />
-  <java-symbol type="anim" name="lock_unlock" />
-  <java-symbol type="anim" name="lock_in" />
-  <java-symbol type="anim" name="lock_scanning" />
 
   <java-symbol type="bool" name="config_alwaysUseCdmaRssi" />
   <java-symbol type="dimen" name="status_bar_icon_size" />
@@ -2592,6 +2589,7 @@
   <java-symbol type="array" name="config_face_acquire_vendor_keyguard_ignorelist" />
   <java-symbol type="array" name="config_face_acquire_biometricprompt_ignorelist" />
   <java-symbol type="array" name="config_face_acquire_vendor_biometricprompt_ignorelist" />
+  <java-symbol type="bool" name="config_faceAuthDismissesKeyguard" />
 
   <!-- Face config -->
   <java-symbol type="integer" name="config_faceMaxTemplatesPerUser" />
@@ -3202,6 +3200,8 @@
   <java-symbol type="array" name="config_nightDisplayColorTemperatureCoefficientsNative" />
   <java-symbol type="array" name="config_availableColorModes" />
   <java-symbol type="integer" name="config_accessibilityColorMode" />
+  <java-symbol type="array" name="config_displayCompositionColorModes" />
+  <java-symbol type="array" name="config_displayCompositionColorSpaces" />
   <java-symbol type="bool" name="config_displayWhiteBalanceAvailable" />
   <java-symbol type="bool" name="config_displayWhiteBalanceEnabledDefault" />
   <java-symbol type="integer" name="config_displayWhiteBalanceColorTemperatureMin" />
@@ -3275,6 +3275,9 @@
   <java-symbol type="string" name="config_batterymeterBoltPath" />
   <java-symbol type="string" name="config_batterymeterPowersavePath" />
   <java-symbol type="bool" name="config_batterymeterDualTone" />
+  <java-symbol type="string" name="config_signalXPath" />
+  <java-symbol type="dimen" name="config_signalCutoutWidthFraction" />
+  <java-symbol type="dimen" name="config_signalCutoutHeightFraction" />
 
   <java-symbol type="bool" name="config_debugEnableAutomaticSystemServerHeapDumps" />
   <java-symbol type="integer" name="config_debugSystemServerPssThresholdBytes" />
@@ -3559,7 +3562,7 @@
 
   <java-symbol type="integer" name="config_stableDeviceDisplayWidth" />
   <java-symbol type="integer" name="config_stableDeviceDisplayHeight" />
-  <java-symbol type="bool" name="config_display_no_service_when_sim_unready" />
+  <java-symbol type="array" name="config_display_no_service_when_sim_unready" />
 
   <java-symbol type="layout" name="slice_grid" />
   <java-symbol type="layout" name="slice_message_local" />
@@ -3710,6 +3713,9 @@
   <java-symbol type="dimen" name="rounded_corner_radius" />
   <java-symbol type="dimen" name="rounded_corner_radius_top" />
   <java-symbol type="dimen" name="rounded_corner_radius_bottom" />
+  <java-symbol type="dimen" name="rounded_corner_radius_adjustment" />
+  <java-symbol type="dimen" name="rounded_corner_radius_top_adjustment" />
+  <java-symbol type="dimen" name="rounded_corner_radius_bottom_adjustment" />
   <java-symbol type="bool" name="config_supportsRoundedCornersOnWindows" />
 
   <java-symbol type="string" name="config_defaultModuleMetadataProvider" />
@@ -3759,8 +3765,12 @@
   <java-symbol type="array" name="config_displayWhiteBalanceBaseThresholds" />
   <java-symbol type="array" name="config_displayWhiteBalanceIncreaseThresholds" />
   <java-symbol type="array" name="config_displayWhiteBalanceDecreaseThresholds" />
-  <java-symbol type="dimen" name="config_displayWhiteBalanceLowLightAmbientBrightnessThreshold" />
+  <java-symbol type="array" name="config_displayWhiteBalanceLowLightAmbientBrightnesses" />
+  <java-symbol type="array" name="config_displayWhiteBalanceLowLightAmbientBiases" />
   <java-symbol type="dimen" name="config_displayWhiteBalanceLowLightAmbientColorTemperature" />
+  <java-symbol type="array" name="config_displayWhiteBalanceHighLightAmbientBrightnesses" />
+  <java-symbol type="array" name="config_displayWhiteBalanceHighLightAmbientBiases" />
+  <java-symbol type="dimen" name="config_displayWhiteBalanceHighLightAmbientColorTemperature" />
   <java-symbol type="array" name="config_displayWhiteBalanceAmbientColorTemperatures" />
   <java-symbol type="array" name="config_displayWhiteBalanceDisplayColorTemperatures" />
   <java-symbol type="drawable" name="ic_action_open" />
@@ -3788,11 +3798,15 @@
 
   <!-- For high refresh rate displays -->
   <java-symbol type="integer" name="config_defaultPeakRefreshRate" />
+  <java-symbol type="integer" name="config_defaultRefreshRateInZone" />
+  <java-symbol type="array" name="config_brightnessThresholdsOfPeakRefreshRate" />
+  <java-symbol type="array" name="config_ambientThresholdsOfPeakRefreshRate" />
 
   <!-- For Auto-Brightness -->
   <java-symbol type="string" name="config_displayLightSensorType" />
 
   <java-symbol type="drawable" name="iconfactory_adaptive_icon_drawable_wrapper"/>
+  <java-symbol type="dimen" name="notification_min_height" />
   <java-symbol type="dimen" name="resolver_icon_size"/>
   <java-symbol type="dimen" name="resolver_badge_size"/>
   <java-symbol type="dimen" name="resolver_button_bar_spacing"/>
@@ -3811,6 +3825,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" />
@@ -3822,6 +3837,8 @@
   <java-symbol type="bool" name="config_inflateSignalStrength" />
   <java-symbol type="array" name="config_restrictedPreinstalledCarrierApps" />
 
+  <java-symbol type="array" name="config_highRefreshRateBlacklist" />
+
   <java-symbol type="drawable" name="android_logotype" />
   <java-symbol type="layout" name="platlogo_layout" />
 
diff --git a/core/tests/coretests/res/values/overlayable_icons_test.xml b/core/tests/coretests/res/values/overlayable_icons_test.xml
index 68de2c0..6503f3e 100644
--- a/core/tests/coretests/res/values/overlayable_icons_test.xml
+++ b/core/tests/coretests/res/values/overlayable_icons_test.xml
@@ -20,15 +20,18 @@
   <array name="overlayable_icons">
     <item>@*android:drawable/ic_audio_alarm</item>
     <item>@*android:drawable/ic_audio_alarm_mute</item>
+    <item>@*android:drawable/ic_battery_80_24dp</item>
     <item>@*android:drawable/ic_bluetooth_share_icon</item>
     <item>@*android:drawable/ic_bt_headphones_a2dp</item>
     <item>@*android:drawable/ic_bt_headset_hfp</item>
     <item>@*android:drawable/ic_bt_hearing_aid</item>
     <item>@*android:drawable/ic_bt_laptop</item>
+    <item>@*android:drawable/ic_bt_misc_hid</item>
     <item>@*android:drawable/ic_bt_network_pan</item>
     <item>@*android:drawable/ic_bt_pointing_hid</item>
     <item>@*android:drawable/ic_corp_badge</item>
     <item>@*android:drawable/ic_expand_more</item>
+    <item>@*android:drawable/ic_faster_emergency</item>
     <item>@*android:drawable/ic_file_copy</item>
     <item>@*android:drawable/ic_lock</item>
     <item>@*android:drawable/ic_lock_bugreport</item>
@@ -36,6 +39,7 @@
     <item>@*android:drawable/ic_lock_power_off</item>
     <item>@*android:drawable/ic_lockscreen_ime</item>
     <item>@*android:drawable/ic_mode_edit</item>
+    <item>@*android:drawable/ic_notifications_alerted</item>
     <item>@*android:drawable/ic_phone</item>
     <item>@*android:drawable/ic_qs_airplane</item>
     <item>@*android:drawable/ic_qs_auto_rotate</item>
@@ -44,6 +48,7 @@
     <item>@*android:drawable/ic_qs_dnd</item>
     <item>@*android:drawable/ic_qs_flashlight</item>
     <item>@*android:drawable/ic_qs_night_display_on</item>
+    <item>@*android:drawable/ic_qs_ui_mode_night</item>
     <item>@*android:drawable/ic_restart</item>
     <item>@*android:drawable/ic_screenshot</item>
     <item>@*android:drawable/ic_settings_bluetooth</item>
@@ -65,6 +70,7 @@
     <item>@*android:drawable/ic_wifi_signal_3</item>
     <item>@*android:drawable/ic_wifi_signal_4</item>
     <item>@*android:drawable/perm_group_activity_recognition</item>
+    <item>@*android:drawable/perm_group_aural</item>
     <item>@*android:drawable/perm_group_calendar</item>
     <item>@*android:drawable/perm_group_call_log</item>
     <item>@*android:drawable/perm_group_camera</item>
diff --git a/core/tests/coretests/src/android/provider/SettingsBackupTest.java b/core/tests/coretests/src/android/provider/SettingsBackupTest.java
index cd36ba7..79c93ce 100644
--- a/core/tests/coretests/src/android/provider/SettingsBackupTest.java
+++ b/core/tests/coretests/src/android/provider/SettingsBackupTest.java
@@ -93,6 +93,7 @@
                     Settings.System.VOLUME_VOICE, // deprecated since API 2?
                     Settings.System.WHEN_TO_MAKE_WIFI_CALLS, // bug?
                     Settings.System.WINDOW_ORIENTATION_LISTENER_LOG, // used for debugging only
+                    Settings.System.MIN_REFRESH_RATE, // depends on hardware capabilities
                     Settings.System.PEAK_REFRESH_RATE // depends on hardware capabilities
                     );
 
@@ -264,6 +265,7 @@
                     Settings.Global.EUICC_PROVISIONED,
                     Settings.Global.EUICC_SUPPORTED_COUNTRIES,
                     Settings.Global.EUICC_FACTORY_RESET_TIMEOUT_MILLIS,
+                    Settings.Global.EUICC_REMOVING_INVISIBLE_PROFILES_TIMEOUT_MILLIS,
                     Settings.Global.FANCY_IME_ANIMATIONS,
                     Settings.Global.FORCE_ALLOW_ON_EXTERNAL,
                     Settings.Global.FORCED_APP_STANDBY_ENABLED,
@@ -714,13 +716,13 @@
                  Settings.Secure.PACKAGES_TO_CLEAR_DATA_BEFORE_FULL_RESTORE,
                  Settings.Secure.FLASHLIGHT_AVAILABLE,
                  Settings.Secure.FLASHLIGHT_ENABLED,
+                 Settings.Secure.MANAGED_PROVISIONING_DPC_DOWNLOADED,
                  Settings.Secure.CROSS_PROFILE_CALENDAR_ENABLED,
                  Settings.Secure.LOCATION_ACCESS_CHECK_INTERVAL_MILLIS,
                  Settings.Secure.LOCATION_ACCESS_CHECK_DELAY_MILLIS,
                  Settings.Secure.BIOMETRIC_DEBUG_ENABLED,
                  Settings.Secure.FACE_UNLOCK_ATTENTION_REQUIRED,
-                 Settings.Secure.FACE_UNLOCK_DIVERSITY_REQUIRED,
-                 Settings.Secure.FACE_UNLOCK_EDUCATION_INFO_DISPLAYED);
+                 Settings.Secure.FACE_UNLOCK_DIVERSITY_REQUIRED);
 
     @Test
     public void systemSettingsBackedUpOrBlacklisted() {
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/graphics/java/android/graphics/RectF.java b/graphics/java/android/graphics/RectF.java
index 3361fa2..1d294d5 100644
--- a/graphics/java/android/graphics/RectF.java
+++ b/graphics/java/android/graphics/RectF.java
@@ -27,7 +27,7 @@
 
 /**
  * RectF holds four float coordinates for a rectangle. The rectangle is
- * represented by the coordinates of its 4 edges (left, top, right bottom).
+ * represented by the coordinates of its 4 edges (left, top, right, bottom).
  * These fields can be accessed directly. Use width() and height() to retrieve
  * the rectangle's width and height. Note: most methods do not check to see that
  * the coordinates are sorted correctly (i.e. left <= right and top <= bottom).
diff --git a/libs/androidfw/DisplayEventDispatcher.cpp b/libs/androidfw/DisplayEventDispatcher.cpp
index 6606148..d8a3f426 100644
--- a/libs/androidfw/DisplayEventDispatcher.cpp
+++ b/libs/androidfw/DisplayEventDispatcher.cpp
@@ -34,8 +34,9 @@
 static const size_t EVENT_BUFFER_SIZE = 100;
 
 DisplayEventDispatcher::DisplayEventDispatcher(const sp<Looper>& looper,
-        ISurfaceComposer::VsyncSource vsyncSource) :
-        mLooper(looper), mReceiver(vsyncSource), mWaitingForVsync(false) {
+        ISurfaceComposer::VsyncSource vsyncSource,
+        ISurfaceComposer::ConfigChanged configChanged) :
+        mLooper(looper), mReceiver(vsyncSource, configChanged), mWaitingForVsync(false) {
     ALOGV("dispatcher %p ~ Initializing display event dispatcher.", this);
 }
 
diff --git a/libs/androidfw/include/androidfw/DisplayEventDispatcher.h b/libs/androidfw/include/androidfw/DisplayEventDispatcher.h
index 5381c01..8bc2520 100644
--- a/libs/androidfw/include/androidfw/DisplayEventDispatcher.h
+++ b/libs/androidfw/include/androidfw/DisplayEventDispatcher.h
@@ -23,7 +23,8 @@
 class DisplayEventDispatcher : public LooperCallback {
 public:
     explicit DisplayEventDispatcher(const sp<Looper>& looper,
-            ISurfaceComposer::VsyncSource vsyncSource = ISurfaceComposer::eVsyncSourceApp);
+            ISurfaceComposer::VsyncSource vsyncSource = ISurfaceComposer::eVsyncSourceApp,
+            ISurfaceComposer::ConfigChanged configChanged = ISurfaceComposer::eConfigChangedSuppress);
 
     status_t initialize();
     void dispose();
diff --git a/libs/hwui/renderthread/CanvasContext.cpp b/libs/hwui/renderthread/CanvasContext.cpp
index f326ce8..9898a1c 100644
--- a/libs/hwui/renderthread/CanvasContext.cpp
+++ b/libs/hwui/renderthread/CanvasContext.cpp
@@ -148,7 +148,8 @@
 
     if (surface) {
         mNativeSurface = new ReliableSurface{std::move(surface)};
-        mNativeSurface->setDequeueTimeout(500_ms);
+        // TODO: Fix error handling & re-shorten timeout
+        mNativeSurface->setDequeueTimeout(4000_ms);
     } else {
         mNativeSurface = nullptr;
     }
diff --git a/libs/hwui/renderthread/RenderThread.cpp b/libs/hwui/renderthread/RenderThread.cpp
index 41cb8fd..71c5b53 100644
--- a/libs/hwui/renderthread/RenderThread.cpp
+++ b/libs/hwui/renderthread/RenderThread.cpp
@@ -156,7 +156,9 @@
     LOG_ALWAYS_FATAL_IF(mVsyncSource, "Initializing a second DisplayEventReceiver?");
 
     if (!Properties::isolatedProcess) {
-        auto receiver = std::make_unique<DisplayEventReceiver>();
+        auto receiver = std::make_unique<DisplayEventReceiver>(
+            ISurfaceComposer::eVsyncSourceApp,
+            ISurfaceComposer::eConfigChangedDispatch);
         status_t status = receiver->initCheck();
         LOG_ALWAYS_FATAL_IF(status != NO_ERROR,
                             "Initialization of DisplayEventReceiver "
diff --git a/packages/CarSystemUI/src/com/android/systemui/qs/car/CarQSFragment.java b/packages/CarSystemUI/src/com/android/systemui/qs/car/CarQSFragment.java
index 769fc52..f9cfafa 100644
--- a/packages/CarSystemUI/src/com/android/systemui/qs/car/CarQSFragment.java
+++ b/packages/CarSystemUI/src/com/android/systemui/qs/car/CarQSFragment.java
@@ -171,11 +171,6 @@
     }
 
     @Override
-    public void setKeyguardShowing(boolean keyguardShowing) {
-        // No keyguard to show.
-    }
-
-    @Override
     public void animateHeaderSlidingIn(long delay) {
         // No header to animate.
     }
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/HidProfile.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/HidProfile.java
index 7f906f6..6d874ab 100644
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/HidProfile.java
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/HidProfile.java
@@ -117,7 +117,7 @@
 
     public boolean isPreferred(BluetoothDevice device) {
         if (mService == null) return false;
-        return mService.getPriority(device) > BluetoothProfile.PRIORITY_OFF;
+        return mService.getPriority(device) != BluetoothProfile.PRIORITY_OFF;
     }
 
     public int getPreferred(BluetoothDevice device) {
diff --git a/packages/SettingsLib/src/com/android/settingslib/core/instrumentation/SharedPreferencesLogger.java b/packages/SettingsLib/src/com/android/settingslib/core/instrumentation/SharedPreferencesLogger.java
index 320380f..869de0de 100644
--- a/packages/SettingsLib/src/com/android/settingslib/core/instrumentation/SharedPreferencesLogger.java
+++ b/packages/SettingsLib/src/com/android/settingslib/core/instrumentation/SharedPreferencesLogger.java
@@ -102,7 +102,8 @@
             OnSharedPreferenceChangeListener listener) {
     }
 
-    private void logValue(String key, Object value) {
+    @VisibleForTesting
+    protected void logValue(String key, Object value) {
         logValue(key, value, false /* forceLog */);
     }
 
@@ -138,11 +139,18 @@
             } else {
                 intVal = (int) floatValue;
             }
+        } else if (value instanceof String) {
+            try {
+                intVal = Integer.parseInt((String) value);
+            } catch (NumberFormatException e) {
+                Log.w(LOG_TAG, "Tried to log unloggable object=" + value);
+                return;
+            }
         } else {
-            Log.w(LOG_TAG, "Tried to log unloggable object" + value);
+            Log.w(LOG_TAG, "Tried to log unloggable object=" + value);
             return;
         }
-        // Pref key exists in set, log it's change in metrics.
+        // Pref key exists in set, log its change in metrics.
         mMetricsFeature.action(SettingsEnums.PAGE_UNKNOWN,
                 SettingsEnums.ACTION_SETTINGS_PREFERENCE_CHANGE,
                 SettingsEnums.PAGE_UNKNOWN,
diff --git a/packages/SettingsLib/src/com/android/settingslib/graph/SignalDrawable.java b/packages/SettingsLib/src/com/android/settingslib/graph/SignalDrawable.java
index c7380c58..5ac788e 100644
--- a/packages/SettingsLib/src/com/android/settingslib/graph/SignalDrawable.java
+++ b/packages/SettingsLib/src/com/android/settingslib/graph/SignalDrawable.java
@@ -22,6 +22,7 @@
 import android.content.res.ColorStateList;
 import android.graphics.Canvas;
 import android.graphics.ColorFilter;
+import android.graphics.Matrix;
 import android.graphics.Paint;
 import android.graphics.Path;
 import android.graphics.Path.Direction;
@@ -33,6 +34,7 @@
 import android.os.Handler;
 import android.telephony.SignalStrength;
 import android.util.LayoutDirection;
+import android.util.PathParser;
 
 import com.android.settingslib.R;
 import com.android.settingslib.Utils;
@@ -48,7 +50,6 @@
 
     private static final float VIEWPORT = 24f;
     private static final float PAD = 2f / VIEWPORT;
-    private static final float CUT_OUT = 7.9f / VIEWPORT;
 
     private static final float DOT_SIZE = 3f / VIEWPORT;
     private static final float DOT_PADDING = 1.5f / VIEWPORT;
@@ -65,21 +66,6 @@
 
     private static final long DOT_DELAY = 1000;
 
-    private static float[][] X_PATH = new float[][]{
-            {21.9f / VIEWPORT, 17.0f / VIEWPORT},
-            {-1.1f / VIEWPORT, -1.1f / VIEWPORT},
-            {-1.9f / VIEWPORT, 1.9f / VIEWPORT},
-            {-1.9f / VIEWPORT, -1.9f / VIEWPORT},
-            {-1.1f / VIEWPORT, 1.1f / VIEWPORT},
-            {1.9f / VIEWPORT, 1.9f / VIEWPORT},
-            {-1.9f / VIEWPORT, 1.9f / VIEWPORT},
-            {1.1f / VIEWPORT, 1.1f / VIEWPORT},
-            {1.9f / VIEWPORT, -1.9f / VIEWPORT},
-            {1.9f / VIEWPORT, 1.9f / VIEWPORT},
-            {1.1f / VIEWPORT, -1.1f / VIEWPORT},
-            {-1.9f / VIEWPORT, -1.9f / VIEWPORT},
-    };
-
     private final Paint mForegroundPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
     private final Paint mTransparentPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
     private final int mDarkModeFillColor;
@@ -87,7 +73,11 @@
     private final Path mCutoutPath = new Path();
     private final Path mForegroundPath = new Path();
     private final Path mXPath = new Path();
+    private final Matrix mXScaleMatrix = new Matrix();
+    private final Path mScaledXPath = new Path();
     private final Handler mHandler;
+    private final float mCutoutWidthFraction;
+    private final float mCutoutHeightFraction;
     private float mDarkIntensity = -1;
     private final int mIntrinsicSize;
     private boolean mAnimating;
@@ -95,6 +85,14 @@
 
     public SignalDrawable(Context context) {
         super(context.getDrawable(com.android.internal.R.drawable.ic_signal_cellular));
+        final String xPathString = context.getString(
+                com.android.internal.R.string.config_signalXPath);
+        mXPath.set(PathParser.createPathFromPathData(xPathString));
+        updateScaledXPath();
+        mCutoutWidthFraction = context.getResources().getFloat(
+                com.android.internal.R.dimen.config_signalCutoutWidthFraction);
+        mCutoutHeightFraction = context.getResources().getFloat(
+                com.android.internal.R.dimen.config_signalCutoutHeightFraction);
         mDarkModeFillColor = Utils.getColorStateListDefaultColor(context,
                 R.color.dark_mode_icon_color_single_tone);
         mLightModeFillColor = Utils.getColorStateListDefaultColor(context,
@@ -106,6 +104,15 @@
         setDarkIntensity(0);
     }
 
+    private void updateScaledXPath() {
+        if (getBounds().isEmpty()) {
+            mXScaleMatrix.setScale(1f, 1f);
+        } else {
+            mXScaleMatrix.setScale(getBounds().width() / VIEWPORT, getBounds().height() / VIEWPORT);
+        }
+        mXPath.transform(mXScaleMatrix, mScaledXPath);
+    }
+
     @Override
     public int getIntrinsicWidth() {
         return mIntrinsicSize;
@@ -170,6 +177,7 @@
     @Override
     protected void onBoundsChange(Rect bounds) {
         super.onBoundsChange(bounds);
+        updateScaledXPath();
         invalidateSelf();
     }
 
@@ -205,19 +213,15 @@
             canvas.drawPath(mCutoutPath, mTransparentPaint);
             canvas.drawPath(mForegroundPath, mForegroundPaint);
         } else if (isInState(STATE_CUT)) {
-            float cut = (CUT_OUT * width);
-            mCutoutPath.moveTo(width - padding, height - padding);
-            mCutoutPath.rLineTo(-cut, 0);
-            mCutoutPath.rLineTo(0, -cut);
-            mCutoutPath.rLineTo(cut, 0);
-            mCutoutPath.rLineTo(0, cut);
+            float cutX = (mCutoutWidthFraction * width / VIEWPORT);
+            float cutY = (mCutoutHeightFraction * height / VIEWPORT);
+            mCutoutPath.moveTo(width, height);
+            mCutoutPath.rLineTo(-cutX, 0);
+            mCutoutPath.rLineTo(0, -cutY);
+            mCutoutPath.rLineTo(cutX, 0);
+            mCutoutPath.rLineTo(0, cutY);
             canvas.drawPath(mCutoutPath, mTransparentPaint);
-            mXPath.reset();
-            mXPath.moveTo(X_PATH[0][0] * width, X_PATH[0][1] * height);
-            for (int i = 1; i < X_PATH.length; i++) {
-                mXPath.rLineTo(X_PATH[i][0] * width, X_PATH[i][1] * height);
-            }
-            canvas.drawPath(mXPath, mForegroundPaint);
+            canvas.drawPath(mScaledXPath, mForegroundPaint);
         }
         if (isRtl) {
             canvas.restore();
diff --git a/packages/SettingsLib/src/com/android/settingslib/location/RecentLocationApps.java b/packages/SettingsLib/src/com/android/settingslib/location/RecentLocationApps.java
index 6fd8749..60c9984 100644
--- a/packages/SettingsLib/src/com/android/settingslib/location/RecentLocationApps.java
+++ b/packages/SettingsLib/src/com/android/settingslib/location/RecentLocationApps.java
@@ -90,12 +90,16 @@
 
         for (int i = 0; i < appOpsCount; ++i) {
             AppOpsManager.PackageOps ops = appOps.get(i);
+            // Don't show the Android System in the list - it's not actionable for the user.
+            // Also don't show apps belonging to background users except managed users.
             String packageName = ops.getPackageName();
             int uid = ops.getUid();
             final UserHandle user = UserHandle.getUserHandleForUid(uid);
 
-            // Don't show apps belonging to background users except managed users.
-            if (!profiles.contains(user)) {
+            boolean isAndroidOs =
+                    (uid == android.os.Process.SYSTEM_UID) && ANDROID_SYSTEM_PACKAGE_NAME.equals(
+                            packageName);
+            if (isAndroidOs || !profiles.contains(user)) {
                 continue;
             }
 
diff --git a/packages/SettingsLib/src/com/android/settingslib/net/DataUsageUtils.java b/packages/SettingsLib/src/com/android/settingslib/net/DataUsageUtils.java
index de38e8a..23e29493 100644
--- a/packages/SettingsLib/src/com/android/settingslib/net/DataUsageUtils.java
+++ b/packages/SettingsLib/src/com/android/settingslib/net/DataUsageUtils.java
@@ -18,15 +18,11 @@
 
 import android.content.Context;
 import android.net.NetworkTemplate;
-import android.os.ParcelUuid;
-import android.telephony.SubscriptionInfo;
 import android.telephony.SubscriptionManager;
 import android.telephony.TelephonyManager;
 import android.util.Log;
 
-import java.util.ArrayList;
-import java.util.List;
-
+import com.android.internal.util.ArrayUtils;
 /**
  * Utils class for data usage
  */
@@ -41,31 +37,22 @@
                 TelephonyManager.class);
         final SubscriptionManager subscriptionManager = context.getSystemService(
                 SubscriptionManager.class);
-        final SubscriptionInfo info = subscriptionManager.getActiveSubscriptionInfo(subId);
         final NetworkTemplate mobileAll = NetworkTemplate.buildTemplateMobileAll(
                 telephonyManager.getSubscriberId(subId));
 
-        if (info == null) {
+        if (!subscriptionManager.isActiveSubId(subId)) {
             Log.i(TAG, "Subscription is not active: " + subId);
             return mobileAll;
         }
-        final ParcelUuid groupUuid = info.getGroupUuid();
-        if (groupUuid == null) {
-            Log.i(TAG, "Subscription doesn't have valid group uuid: " + subId);
+
+        final String[] mergedSubscriberIds = telephonyManager.createForSubscriptionId(subId)
+                .getMergedSubscriberIdsFromGroup();
+
+        if (ArrayUtils.isEmpty(mergedSubscriberIds)) {
+            Log.i(TAG, "mergedSubscriberIds is null.");
             return mobileAll;
         }
 
-        // Otherwise merge other subscriberId to create new NetworkTemplate
-        final List<SubscriptionInfo> groupInfos = subscriptionManager.getSubscriptionsInGroup(
-                groupUuid);
-        final List<String> mergedSubscriberIds = new ArrayList<>();
-        for (SubscriptionInfo subInfo : groupInfos) {
-            final String subscriberId = telephonyManager.getSubscriberId(
-                    subInfo.getSubscriptionId());
-            if (subscriberId != null) {
-                mergedSubscriberIds.add(subscriberId);
-            }
-        }
-        return NetworkTemplate.normalize(mobileAll, mergedSubscriberIds.toArray(new String[0]));
+        return NetworkTemplate.normalize(mobileAll, mergedSubscriberIds);
     }
 }
diff --git a/packages/SettingsLib/src/com/android/settingslib/wifi/AccessPoint.java b/packages/SettingsLib/src/com/android/settingslib/wifi/AccessPoint.java
index f16fb1c..6b1ceae 100644
--- a/packages/SettingsLib/src/com/android/settingslib/wifi/AccessPoint.java
+++ b/packages/SettingsLib/src/com/android/settingslib/wifi/AccessPoint.java
@@ -1435,7 +1435,7 @@
 
     void update(@Nullable WifiConfiguration config) {
         mConfig = config;
-        if (mConfig != null) {
+        if (mConfig != null && !isPasspoint()) {
             ssid = removeDoubleQuotes(mConfig.SSID);
         }
         networkId = config != null ? config.networkId : WifiConfiguration.INVALID_NETWORK_ID;
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/core/instrumentation/SharedPreferenceLoggerTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/core/instrumentation/SharedPreferenceLoggerTest.java
index 8f51dec..89de81f 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/core/instrumentation/SharedPreferenceLoggerTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/core/instrumentation/SharedPreferenceLoggerTest.java
@@ -162,4 +162,33 @@
                 "tag/key:com.android.settings",
                 0);
     }
+
+    @Test
+    public void putString_shouldNotLogInitialPut() {
+        mSharedPrefLogger.logValue(TEST_KEY, "1");
+        mSharedPrefLogger.logValue(TEST_KEY, "2");
+        mSharedPrefLogger.logValue(TEST_KEY, "62");
+        mSharedPrefLogger.logValue(TEST_KEY, "0");
+
+        verify(mMetricsFeature, times(3)).action(eq(SettingsEnums.PAGE_UNKNOWN),
+                eq(SettingsEnums.ACTION_SETTINGS_PREFERENCE_CHANGE),
+                eq(SettingsEnums.PAGE_UNKNOWN),
+                eq(TEST_TAGGED_KEY),
+                anyInt());
+    }
+
+    @Test
+    public void putString_shouldNotLogAnyNonIntegers() {
+        mSharedPrefLogger.logValue(TEST_KEY, "string");
+        mSharedPrefLogger.logValue(TEST_KEY, "not an int");
+        mSharedPrefLogger.logValue(TEST_KEY, "1.234f");
+        mSharedPrefLogger.logValue(TEST_KEY, "4.2");
+        mSharedPrefLogger.logValue(TEST_KEY, "3.0");
+
+        verify(mMetricsFeature, times(0)).action(eq(SettingsEnums.PAGE_UNKNOWN),
+                eq(SettingsEnums.ACTION_SETTINGS_PREFERENCE_CHANGE),
+                eq(SettingsEnums.PAGE_UNKNOWN),
+                eq(TEST_TAGGED_KEY),
+                anyInt());
+    }
 }
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/net/DataUsageUtilsTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/net/DataUsageUtilsTest.java
index dc33cfe..5cae611 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/net/DataUsageUtilsTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/net/DataUsageUtilsTest.java
@@ -18,6 +18,7 @@
 
 import static com.google.common.truth.Truth.assertThat;
 
+import static org.mockito.Matchers.anyInt;
 import static org.mockito.Mockito.spy;
 import static org.mockito.Mockito.when;
 
@@ -37,7 +38,6 @@
 import org.robolectric.RobolectricTestRunner;
 import org.robolectric.RuntimeEnvironment;
 
-import java.util.ArrayList;
 import java.util.List;
 
 @RunWith(RobolectricTestRunner.class)
@@ -70,18 +70,13 @@
         when(mContext.getSystemService(SubscriptionManager.class)).thenReturn(mSubscriptionManager);
         when(mTelephonyManager.getSubscriberId(SUB_ID)).thenReturn(SUBSCRIBER_ID);
         when(mTelephonyManager.getSubscriberId(SUB_ID_2)).thenReturn(SUBSCRIBER_ID_2);
-        when(mInfo1.getSubscriptionId()).thenReturn(SUB_ID);
-        when(mInfo2.getSubscriptionId()).thenReturn(SUB_ID_2);
-
-        mInfos = new ArrayList<>();
-        mInfos.add(mInfo1);
-        mInfos.add(mInfo2);
-        when(mSubscriptionManager.getSubscriptionsInGroup(mParcelUuid)).thenReturn(mInfos);
+        when(mTelephonyManager.createForSubscriptionId(anyInt())).thenReturn(mTelephonyManager);
+        when(mSubscriptionManager.isActiveSubId(anyInt())).thenReturn(true);
     }
 
     @Test
     public void getMobileTemplate_infoNull_returnMobileAll() {
-        when(mSubscriptionManager.getActiveSubscriptionInfo(SUB_ID)).thenReturn(null);
+        when(mSubscriptionManager.isActiveSubId(SUB_ID)).thenReturn(false);
 
         final NetworkTemplate networkTemplate = DataUsageUtils.getMobileTemplate(mContext, SUB_ID);
         assertThat(networkTemplate.matchesSubscriberId(SUBSCRIBER_ID)).isTrue();
@@ -92,6 +87,8 @@
     public void getMobileTemplate_groupUuidNull_returnMobileAll() {
         when(mSubscriptionManager.getActiveSubscriptionInfo(SUB_ID)).thenReturn(mInfo1);
         when(mInfo1.getGroupUuid()).thenReturn(null);
+        when(mTelephonyManager.getMergedSubscriberIdsFromGroup())
+                .thenReturn(new String[] {SUBSCRIBER_ID});
 
         final NetworkTemplate networkTemplate = DataUsageUtils.getMobileTemplate(mContext, SUB_ID);
         assertThat(networkTemplate.matchesSubscriberId(SUBSCRIBER_ID)).isTrue();
@@ -102,6 +99,8 @@
     public void getMobileTemplate_groupUuidExist_returnMobileMerged() {
         when(mSubscriptionManager.getActiveSubscriptionInfo(SUB_ID)).thenReturn(mInfo1);
         when(mInfo1.getGroupUuid()).thenReturn(mParcelUuid);
+        when(mTelephonyManager.getMergedSubscriberIdsFromGroup())
+                .thenReturn(new String[] {SUBSCRIBER_ID, SUBSCRIBER_ID_2});
 
         final NetworkTemplate networkTemplate = DataUsageUtils.getMobileTemplate(mContext, SUB_ID);
         assertThat(networkTemplate.matchesSubscriberId(SUBSCRIBER_ID)).isTrue();
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsBackupAgent.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsBackupAgent.java
index 9d398b5..d884fab 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsBackupAgent.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsBackupAgent.java
@@ -56,6 +56,7 @@
 import java.util.Arrays;
 import java.util.HashSet;
 import java.util.Map;
+import java.util.Set;
 import java.util.zip.CRC32;
 
 /**
@@ -241,6 +242,8 @@
         HashSet<String> movedToGlobal = new HashSet<String>();
         Settings.System.getMovedToGlobalSettings(movedToGlobal);
         Settings.Secure.getMovedToGlobalSettings(movedToGlobal);
+        Set<String> movedToSecure = getMovedToSecureSettings();
+
         byte[] restoredWifiSupplicantData = null;
         byte[] restoredWifiIpConfigData = null;
 
@@ -259,16 +262,17 @@
 
             switch (key) {
                 case KEY_SYSTEM :
-                    restoreSettings(data, Settings.System.CONTENT_URI, movedToGlobal);
+                    restoreSettings(data, Settings.System.CONTENT_URI, movedToGlobal,
+                            movedToSecure);
                     mSettingsHelper.applyAudioSettings();
                     break;
 
                 case KEY_SECURE :
-                    restoreSettings(data, Settings.Secure.CONTENT_URI, movedToGlobal);
+                    restoreSettings(data, Settings.Secure.CONTENT_URI, movedToGlobal, null);
                     break;
 
                 case KEY_GLOBAL :
-                    restoreSettings(data, Settings.Global.CONTENT_URI, null);
+                    restoreSettings(data, Settings.Global.CONTENT_URI, null, movedToSecure);
                     break;
 
                 case KEY_WIFI_SUPPLICANT :
@@ -347,20 +351,22 @@
             HashSet<String> movedToGlobal = new HashSet<String>();
             Settings.System.getMovedToGlobalSettings(movedToGlobal);
             Settings.Secure.getMovedToGlobalSettings(movedToGlobal);
+            Set<String> movedToSecure = getMovedToSecureSettings();
 
             // system settings data first
             int nBytes = in.readInt();
             if (DEBUG_BACKUP) Log.d(TAG, nBytes + " bytes of settings data");
             byte[] buffer = new byte[nBytes];
             in.readFully(buffer, 0, nBytes);
-            restoreSettings(buffer, nBytes, Settings.System.CONTENT_URI, movedToGlobal);
+            restoreSettings(buffer, nBytes, Settings.System.CONTENT_URI, movedToGlobal,
+                    movedToSecure);
 
             // secure settings
             nBytes = in.readInt();
             if (DEBUG_BACKUP) Log.d(TAG, nBytes + " bytes of secure settings data");
             if (nBytes > buffer.length) buffer = new byte[nBytes];
             in.readFully(buffer, 0, nBytes);
-            restoreSettings(buffer, nBytes, Settings.Secure.CONTENT_URI, movedToGlobal);
+            restoreSettings(buffer, nBytes, Settings.Secure.CONTENT_URI, movedToGlobal, null);
 
             // Global only if sufficiently new
             if (version >= FULL_BACKUP_ADDED_GLOBAL) {
@@ -369,7 +375,8 @@
                 if (nBytes > buffer.length) buffer = new byte[nBytes];
                 in.readFully(buffer, 0, nBytes);
                 movedToGlobal.clear();  // no redirection; this *is* the global namespace
-                restoreSettings(buffer, nBytes, Settings.Global.CONTENT_URI, movedToGlobal);
+                restoreSettings(buffer, nBytes, Settings.Global.CONTENT_URI, movedToGlobal,
+                        movedToSecure);
             }
 
             // locale
@@ -440,6 +447,13 @@
         }
     }
 
+    private Set<String> getMovedToSecureSettings() {
+        Set<String> movedToSecureSettings = new HashSet<>();
+        Settings.Global.getMovedToSecureSettings(movedToSecureSettings);
+        Settings.System.getMovedToSecureSettings(movedToSecureSettings);
+        return movedToSecureSettings;
+    }
+
     private long[] readOldChecksums(ParcelFileDescriptor oldState) throws IOException {
         long[] stateChecksums = new long[STATE_SIZE];
 
@@ -564,7 +578,7 @@
     }
 
     private void restoreSettings(BackupDataInput data, Uri contentUri,
-            HashSet<String> movedToGlobal) {
+            HashSet<String> movedToGlobal, Set<String> movedToSecure) {
         byte[] settings = new byte[data.getDataSize()];
         try {
             data.readEntityData(settings, 0, settings.length);
@@ -572,11 +586,11 @@
             Log.e(TAG, "Couldn't read entity data");
             return;
         }
-        restoreSettings(settings, settings.length, contentUri, movedToGlobal);
+        restoreSettings(settings, settings.length, contentUri, movedToGlobal, movedToSecure);
     }
 
     private void restoreSettings(byte[] settings, int bytes, Uri contentUri,
-            HashSet<String> movedToGlobal) {
+            HashSet<String> movedToGlobal, Set<String> movedToSecure) {
         if (DEBUG) {
             Log.i(TAG, "restoreSettings: " + contentUri);
         }
@@ -651,9 +665,14 @@
                 continue;
             }
 
-            final Uri destination = (movedToGlobal != null && movedToGlobal.contains(key))
-                    ? Settings.Global.CONTENT_URI
-                    : contentUri;
+            final Uri destination;
+            if (movedToGlobal != null && movedToGlobal.contains(key)) {
+                destination = Settings.Global.CONTENT_URI;
+            } else if (movedToSecure != null && movedToSecure.contains(key)) {
+                destination = Settings.Secure.CONTENT_URI;
+            } else {
+                destination = contentUri;
+            }
             settingsHelper.restoreValue(this, cr, contentValues, destination, key, value,
                     mRestoredFromSdkInt);
 
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java
index 3cd82df..b2c10ec 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java
@@ -1944,9 +1944,6 @@
                 Settings.Secure.SILENCE_GESTURE,
                 SecureSettingsProto.Gesture.SILENCE_ENABLED);
         dumpSetting(s, p,
-                Settings.Secure.SILENCE_NOTIFICATION_GESTURE_COUNT,
-                SecureSettingsProto.Gesture.SILENCE_NOTIFICATION_COUNT);
-        dumpSetting(s, p,
                 Settings.Secure.SILENCE_TIMER_GESTURE_COUNT,
                 SecureSettingsProto.Gesture.SILENCE_TIMER_COUNT);
 
@@ -1956,6 +1953,19 @@
         dumpSetting(s, p,
                 Settings.Secure.SKIP_GESTURE,
                 SecureSettingsProto.Gesture.SKIP_ENABLED);
+
+        dumpSetting(s, p,
+                Settings.Secure.SILENCE_ALARMS_TOUCH_COUNT,
+                SecureSettingsProto.Gesture.SILENCE_ALARMS_TOUCH_COUNT);
+        dumpSetting(s, p,
+                Settings.Secure.SILENCE_CALL_TOUCH_COUNT,
+                SecureSettingsProto.Gesture.SILENCE_CALLS_TOUCH_COUNT);
+        dumpSetting(s, p,
+                Settings.Secure.SILENCE_TIMER_TOUCH_COUNT,
+                SecureSettingsProto.Gesture.SILENCE_TIMER_TOUCH_COUNT);
+        dumpSetting(s, p,
+                Settings.Secure.SKIP_TOUCH_COUNT,
+                SecureSettingsProto.Gesture.SKIP_TOUCH_COUNT);
         p.end(gestureToken);
 
         dumpSetting(s, p,
diff --git a/packages/SystemUI/Android.bp b/packages/SystemUI/Android.bp
index 91a8ab5..4c52b132 100644
--- a/packages/SystemUI/Android.bp
+++ b/packages/SystemUI/Android.bp
@@ -75,6 +75,7 @@
         "--extra-packages",
         "com.android.keyguard",
     ],
+    kotlincflags: ["-Xjvm-default=enable"],
 
     plugins: ["dagger2-compiler-2.19"],
 }
@@ -128,6 +129,7 @@
         "telephony-common",
         "android.test.base",
     ],
+    kotlincflags: ["-Xjvm-default=enable"],
     aaptflags: [
         "--extra-packages",
         "com.android.keyguard:com.android.systemui",
@@ -155,6 +157,8 @@
         "telephony-common",
     ],
 
+    kotlincflags: ["-Xjvm-default=enable"],
+
     dxflags: ["--multi-dex"],
     aaptflags: [
         "--extra-packages",
@@ -191,6 +195,8 @@
         "telephony-common",
     ],
 
+    kotlincflags: ["-Xjvm-default=enable"],
+
     srcs: [
         "legacy/recents/src/**/*.java",
         "legacy/recents/src/**/I*.aidl",
diff --git a/packages/SystemUI/plugin/src/com/android/systemui/plugins/OverlayPlugin.java b/packages/SystemUI/plugin/src/com/android/systemui/plugins/OverlayPlugin.java
index 90fc86b..075df75 100644
--- a/packages/SystemUI/plugin/src/com/android/systemui/plugins/OverlayPlugin.java
+++ b/packages/SystemUI/plugin/src/com/android/systemui/plugins/OverlayPlugin.java
@@ -16,12 +16,13 @@
 import android.view.View;
 
 import com.android.systemui.plugins.annotations.ProvidesInterface;
+import com.android.systemui.plugins.statusbar.DozeParameters;
 
 @ProvidesInterface(action = OverlayPlugin.ACTION, version = OverlayPlugin.VERSION)
 public interface OverlayPlugin extends Plugin {
 
     String ACTION = "com.android.systemui.action.PLUGIN_OVERLAY";
-    int VERSION = 3;
+    int VERSION = 4;
 
     /**
      * Setup overlay plugin
@@ -29,9 +30,10 @@
     void setup(View statusBar, View navBar);
 
     /**
-     * Setup overlay plugin with callback
+     * Setup overlay plugin with callback and DozeParameters
      */
-    default void setup(View statusBar, View navBar, Callback callback) {
+    default void setup(View statusBar, View navBar, Callback callback,
+            DozeParameters dozeParameters) {
         setup(statusBar, navBar);
     }
 
diff --git a/packages/SystemUI/plugin/src/com/android/systemui/plugins/SensorManagerPlugin.java b/packages/SystemUI/plugin/src/com/android/systemui/plugins/SensorManagerPlugin.java
index 2cbd788..60435d0 100644
--- a/packages/SystemUI/plugin/src/com/android/systemui/plugins/SensorManagerPlugin.java
+++ b/packages/SystemUI/plugin/src/com/android/systemui/plugins/SensorManagerPlugin.java
@@ -58,7 +58,7 @@
         public static final int TYPE_WAKE_LOCK_SCREEN = 1;
         public static final int TYPE_WAKE_DISPLAY = 2;
         public static final int TYPE_SWIPE = 3;
-        public static final int TYPE_STATUS = 4;
+        public static final int TYPE_SKIP_STATUS = 4;
 
         private int mType;
 
diff --git a/packages/SystemUI/plugin/src/com/android/systemui/plugins/qs/QS.java b/packages/SystemUI/plugin/src/com/android/systemui/plugins/qs/QS.java
index 30d1352..85a9fec 100644
--- a/packages/SystemUI/plugin/src/com/android/systemui/plugins/qs/QS.java
+++ b/packages/SystemUI/plugin/src/com/android/systemui/plugins/qs/QS.java
@@ -34,7 +34,7 @@
 
     String ACTION = "com.android.systemui.action.PLUGIN_QS";
 
-    int VERSION = 6;
+    int VERSION = 7;
 
     String TAG = "QS";
 
@@ -51,7 +51,7 @@
     void setListening(boolean listening);
     boolean isShowingDetail();
     void closeDetail();
-    void setKeyguardShowing(boolean keyguardShowing);
+    default void setShowCollapsedOnKeyguard(boolean showCollapsedOnKeyguard) {}
     void animateHeaderSlidingIn(long delay);
     void animateHeaderSlidingOut();
     void setQsExpansion(float qsExpansionFraction, float headerTranslation);
diff --git a/packages/SystemUI/plugin/src/com/android/systemui/plugins/statusbar/DozeParameters.java b/packages/SystemUI/plugin/src/com/android/systemui/plugins/statusbar/DozeParameters.java
new file mode 100644
index 0000000..678eb31
--- /dev/null
+++ b/packages/SystemUI/plugin/src/com/android/systemui/plugins/statusbar/DozeParameters.java
@@ -0,0 +1,32 @@
+/*
+ * 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.systemui.plugins.statusbar;
+
+import com.android.systemui.plugins.annotations.ProvidesInterface;
+
+/**
+ * Retrieve doze information
+ */
+@ProvidesInterface(version = DozeParameters.VERSION)
+public interface DozeParameters {
+    int VERSION = 1;
+
+    /**
+     * Whether to doze when the screen turns off
+     */
+    boolean shouldControlScreenOff();
+}
diff --git a/packages/SystemUI/plugin/src/com/android/systemui/plugins/statusbar/StatusBarStateController.java b/packages/SystemUI/plugin/src/com/android/systemui/plugins/statusbar/StatusBarStateController.java
index 3ee69b4..fe547a0a 100644
--- a/packages/SystemUI/plugin/src/com/android/systemui/plugins/statusbar/StatusBarStateController.java
+++ b/packages/SystemUI/plugin/src/com/android/systemui/plugins/statusbar/StatusBarStateController.java
@@ -18,7 +18,6 @@
 
 import com.android.systemui.plugins.annotations.DependsOn;
 import com.android.systemui.plugins.annotations.ProvidesInterface;
-import com.android.systemui.plugins.statusbar.StatusBarStateController.StateListener;
 
 
 /**
@@ -94,5 +93,15 @@
          * performance regressions.
          */
         default void onDozeAmountChanged(float linear, float eased) {}
+
+        /**
+         * Callback to be notified when the sysui visibility changes
+         */
+        default void onSystemUiVisibilityChanged(int visibility) {}
+
+        /**
+         * Callback to be notified when the pulsing state changes
+         */
+        default void onPulsingChanged(boolean pulsing) {}
     }
 }
diff --git a/packages/SystemUI/res-keyguard/drawable/bubble_hour_hand.xml b/packages/SystemUI/res-keyguard/drawable/bubble_hour_hand.xml
index 65f7a0e..8c611f6 100644
--- a/packages/SystemUI/res-keyguard/drawable/bubble_hour_hand.xml
+++ b/packages/SystemUI/res-keyguard/drawable/bubble_hour_hand.xml
@@ -6,5 +6,5 @@
     <path
         android:pathData="M170,40m-39,0a39,39 0,1 1,78 0a39,39 0,1 1,-78 0"
         android:strokeColor="#000000"
-        android:strokeWidth="2"/>
+        android:strokeWidth="3"/>
 </vector>
diff --git a/packages/SystemUI/res-keyguard/drawable/bubble_minute_hand.xml b/packages/SystemUI/res-keyguard/drawable/bubble_minute_hand.xml
index 95b4b1a..27bc436 100644
--- a/packages/SystemUI/res-keyguard/drawable/bubble_minute_hand.xml
+++ b/packages/SystemUI/res-keyguard/drawable/bubble_minute_hand.xml
@@ -6,5 +6,5 @@
     <path
         android:pathData="M170,1L170,1A39,39 0,0 1,209 40L209,130A39,39 0,0 1,170 169L170,169A39,39 0,0 1,131 130L131,40A39,39 0,0 1,170 1z"
         android:strokeColor="#000000"
-        android:strokeWidth="2"/>
+        android:strokeWidth="3"/>
 </vector>
diff --git a/packages/SystemUI/res-keyguard/layout/keyguard_presentation.xml b/packages/SystemUI/res-keyguard/layout/keyguard_presentation.xml
index a9ba19d..f4d34f4 100644
--- a/packages/SystemUI/res-keyguard/layout/keyguard_presentation.xml
+++ b/packages/SystemUI/res-keyguard/layout/keyguard_presentation.xml
@@ -41,7 +41,7 @@
             <ImageView
                 android:layout_width="wrap_content"
                 android:layout_height="wrap_content"
-                android:layout_marginTop="@dimen/widget_vertical_padding"
+                android:layout_marginTop="24dp"
                 android:layout_gravity="center_horizontal"
                 android:src="@drawable/kg_security_lock_normal" />
         </LinearLayout>
diff --git a/packages/SystemUI/res-keyguard/layout/keyguard_status_view.xml b/packages/SystemUI/res-keyguard/layout/keyguard_status_view.xml
index 04d6afc..847fba4 100644
--- a/packages/SystemUI/res-keyguard/layout/keyguard_status_view.xml
+++ b/packages/SystemUI/res-keyguard/layout/keyguard_status_view.xml
@@ -25,14 +25,13 @@
     android:orientation="vertical"
     android:layout_width="match_parent"
     android:layout_height="wrap_content"
-    androidprv:layout_maxWidth="@dimen/keyguard_security_width"
-    androidprv:layout_maxHeight="@dimen/keyguard_security_height"
     android:gravity="center_horizontal|top">
     <LinearLayout
         android:id="@+id/status_view_container"
         android:layout_width="match_parent"
         android:layout_height="wrap_content"
-        android:layout_marginBottom="@dimen/widget_vertical_padding"
+        android:clipChildren="false"
+        android:clipToPadding="false"
         android:orientation="vertical">
         <TextView
             android:id="@+id/logout"
@@ -71,5 +70,11 @@
             android:letterSpacing="0.05"
             android:ellipsize="marquee"
             android:singleLine="true" />
+        <com.android.systemui.statusbar.phone.NotificationIconContainer
+            android:id="@+id/clock_notification_icon_container"
+            android:layout_width="match_parent"
+            android:layout_height="@dimen/notification_shelf_height"
+            android:layout_marginTop="@dimen/widget_vertical_padding"
+        />
     </LinearLayout>
 </com.android.keyguard.KeyguardStatusView>
diff --git a/packages/SystemUI/res-keyguard/values/dimens.xml b/packages/SystemUI/res-keyguard/values/dimens.xml
index 8e00efe..f9389ce 100644
--- a/packages/SystemUI/res-keyguard/values/dimens.xml
+++ b/packages/SystemUI/res-keyguard/values/dimens.xml
@@ -53,8 +53,8 @@
     <dimen name="title_clock_padding">4dp</dimen>
     <!-- Clock with header -->
     <dimen name="widget_small_font_size">@dimen/widget_title_font_size</dimen>
-    <dimen name="widget_vertical_padding">24dp</dimen>
-    <dimen name="widget_vertical_padding_with_header">32dp</dimen>
+    <dimen name="widget_vertical_padding">17dp</dimen>
+    <dimen name="widget_vertical_padding_with_header">25dp</dimen>
     <dimen name="widget_vertical_padding_clock">12dp</dimen>
     <!-- Subtitle paddings -->
     <dimen name="widget_horizontal_padding">8dp</dimen>
diff --git a/packages/SystemUI/res-keyguard/values/strings.xml b/packages/SystemUI/res-keyguard/values/strings.xml
index 9b47e14..0fe7084 100644
--- a/packages/SystemUI/res-keyguard/values/strings.xml
+++ b/packages/SystemUI/res-keyguard/values/strings.xml
@@ -407,14 +407,11 @@
 number">%d</xliff:g> remaining attempts before SIM becomes permanently unusable. Contact carrier for details.</item>
     </plurals>
 
-    <!-- Title for default clock face that will appear in the picker app next to a preview image of
-         the clock face. [CHAR LIMIT=8] -->
-    <string name="clock_title_default" translatable="false">Default</string>
-    <!-- Title for Bubble clock face that will appear in the picker app next to a preview image of
-         the clock face. [CHAR LIMIT=8] -->
-    <string name="clock_title_bubble" translatable="false">Bubble</string>
-    <!-- Title for Stretch clock face that will appear in the picker app next to a preview image of
-         the clock face. [CHAR LIMIT=8] -->
-    <string name="clock_title_analog" translatable="false">Analog</string>
+    <!-- Name of the "Default" clock face, which is the clock face that will be shown by default. [CHAR LIMIT=15]-->
+    <string name="clock_title_default">Default</string>
+    <!-- Name of the "Bubble" clock face, which is an analog clock with hands shaped like large bubbles [CHAR LIMIT=15]-->
+    <string name="clock_title_bubble">Bubble</string>
+    <!-- Name of the "Analog" clock face [CHAR LIMIT=15]-->
+    <string name="clock_title_analog">Analog</string>
 
 </resources>
diff --git a/core/res/res/anim/lock_lock.xml b/packages/SystemUI/res/anim/lock_lock.xml
similarity index 95%
rename from core/res/res/anim/lock_lock.xml
rename to packages/SystemUI/res/anim/lock_lock.xml
index 3b8c485..3167e7c 100644
--- a/core/res/res/anim/lock_lock.xml
+++ b/packages/SystemUI/res/anim/lock_lock.xml
@@ -1,17 +1,18 @@
-<!-- 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.
--->
+<!--
+  ~ 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
+  -->
 <animated-vector xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:aapt="http://schemas.android.com/aapt">
     <aapt:attr name="android:drawable">
diff --git a/packages/SystemUI/res/anim/lock_lock_circular.xml b/packages/SystemUI/res/anim/lock_lock_circular.xml
new file mode 100644
index 0000000..8169440
--- /dev/null
+++ b/packages/SystemUI/res/anim/lock_lock_circular.xml
@@ -0,0 +1,320 @@
+<?xml version="1.0" encoding="utf-8"?>
+<animated-vector xmlns:aapt="http://schemas.android.com/aapt"
+    xmlns:android="http://schemas.android.com/apk/res/android" >
+
+    <aapt:attr name="android:drawable" >
+        <vector
+            android:height="42dp"
+            android:viewportHeight="42"
+            android:viewportWidth="32"
+            android:width="32dp" >
+            <group android:name="_R_G" >
+                <group
+                    android:name="_R_G_L_2_G_T_1"
+                    android:translateX="15.999"
+                    android:translateY="24.333" >
+                    <group
+                        android:name="_R_G_L_2_G"
+                        android:translateX="-9.583"
+                        android:translateY="-8.916" >
+                        <path
+                            android:name="_R_G_L_2_G_D_0_P_0"
+                            android:fillAlpha="1"
+                            android:fillColor="#ffffff"
+                            android:fillType="nonZero"
+                            android:pathData=" M17.42 1.75 C17.42,1.75 17.42,14.58 17.42,14.58 C17.42,15.41 16.74,16.08 15.92,16.08 C15.92,16.08 3.25,16.08 3.25,16.08 C2.42,16.08 1.75,15.41 1.75,14.58 C1.75,14.58 1.75,1.75 1.75,1.75 C1.75,1.75 17.42,1.75 17.42,1.75c  M18.92 0.25 C18.92,0.25 0.25,0.25 0.25,0.25 C0.25,0.25 0.25,14.58 0.25,14.58 C0.25,16.24 1.59,17.58 3.25,17.58 C3.25,17.58 15.92,17.58 15.92,17.58 C17.57,17.58 18.92,16.24 18.92,14.58 C18.92,14.58 18.92,0.25 18.92,0.25c " />
+                    </group>
+                </group>
+                <group
+                    android:name="_R_G_L_1_G_N_4_T_1"
+                    android:translateX="15.999"
+                    android:translateY="24.333" >
+                    <group
+                        android:name="_R_G_L_1_G_N_4_T_0"
+                        android:translateX="-9.583"
+                        android:translateY="-8.916" >
+                        <group
+                            android:name="_R_G_L_1_G"
+                            android:pivotX="2.25"
+                            android:pivotY="3.334"
+                            android:scaleX="1"
+                            android:scaleY="1"
+                            android:translateX="7.334"
+                            android:translateY="5.333" >
+                            <path
+                                android:name="_R_G_L_1_G_D_0_P_0"
+                                android:fillAlpha="1"
+                                android:fillColor="#ffffff"
+                                android:fillType="nonZero"
+                                android:pathData=" M4.25 2.25 C4.25,3.35 3.35,4.25 2.25,4.25 C1.15,4.25 0.25,3.35 0.25,2.25 C0.25,1.15 1.15,0.25 2.25,0.25 C3.35,0.25 4.25,1.15 4.25,2.25c " />
+                            <path
+                                android:name="_R_G_L_1_G_D_1_P_0"
+                                android:pathData=" M2.25 2.25 C2.25,2.25 2.25,5.92 2.25,5.92 "
+                                android:strokeAlpha="1"
+                                android:strokeColor="#ffffff"
+                                android:strokeLineCap="round"
+                                android:strokeLineJoin="round"
+                                android:strokeWidth="1.5" />
+                        </group>
+                    </group>
+                </group>
+                <group
+                    android:name="_R_G_L_0_G_N_4_T_1"
+                    android:translateX="15.999"
+                    android:translateY="24.333" >
+                    <group
+                        android:name="_R_G_L_0_G_N_4_T_0"
+                        android:translateX="-9.583"
+                        android:translateY="-8.916" >
+                        <group
+                            android:name="_R_G_L_0_G"
+                            android:translateX="1.5"
+                            android:translateY="-11.835" >
+                            <path
+                                android:name="_R_G_L_0_G_D_0_P_0"
+                                android:pathData=" M12.42 12.6 C12.42,12.6 12.41,8.16 12.41,8.16 C12.41,5.81 14.36,3.75 16.75,3.77 C19.15,3.78 21.07,5.71 21.07,8.05 C21.07,8.05 21.08,8.22 21.08,8.22 "
+                                android:strokeAlpha="1"
+                                android:strokeColor="#ffffff"
+                                android:strokeLineCap="round"
+                                android:strokeLineJoin="round"
+                                android:strokeWidth="1.5" />
+                        </group>
+                    </group>
+                </group>
+            </group>
+            <group android:name="time_group" />
+        </vector>
+    </aapt:attr>
+
+    <target android:name="_R_G_L_2_G_T_1" >
+        <aapt:attr name="android:animation" >
+            <set android:ordering="together" >
+                <objectAnimator
+                    android:duration="400"
+                    android:propertyName="translateY"
+                    android:startOffset="0"
+                    android:valueFrom="24.333"
+                    android:valueTo="24.333"
+                    android:valueType="floatType" >
+                    <aapt:attr name="android:interpolator" >
+                        <pathInterpolator android:pathData="M 0.0,0.0 c0.333,0 0.667,1 1.0,1.0" />
+                    </aapt:attr>
+                </objectAnimator>
+                <objectAnimator
+                    android:duration="117"
+                    android:propertyName="translateY"
+                    android:startOffset="400"
+                    android:valueFrom="24.333"
+                    android:valueTo="25.833"
+                    android:valueType="floatType" >
+                    <aapt:attr name="android:interpolator" >
+                        <pathInterpolator android:pathData="M 0.0,0.0 c0.333,0 0.667,1 1.0,1.0" />
+                    </aapt:attr>
+                </objectAnimator>
+                <objectAnimator
+                    android:duration="117"
+                    android:propertyName="translateY"
+                    android:startOffset="517"
+                    android:valueFrom="25.833"
+                    android:valueTo="24.333"
+                    android:valueType="floatType" >
+                    <aapt:attr name="android:interpolator" >
+                        <pathInterpolator android:pathData="M 0.0,0.0 c0.333,0 0.667,1 1.0,1.0" />
+                    </aapt:attr>
+                </objectAnimator>
+            </set>
+        </aapt:attr>
+    </target>
+    <target android:name="_R_G_L_1_G" >
+        <aapt:attr name="android:animation" >
+            <set android:ordering="together" >
+                <objectAnimator
+                    android:duration="450"
+                    android:propertyName="scaleX"
+                    android:startOffset="0"
+                    android:valueFrom="1"
+                    android:valueTo="1"
+                    android:valueType="floatType" >
+                    <aapt:attr name="android:interpolator" >
+                        <pathInterpolator android:pathData="M 0.0,0.0 c0.333,0 0.667,1 1.0,1.0" />
+                    </aapt:attr>
+                </objectAnimator>
+                <objectAnimator
+                    android:duration="450"
+                    android:propertyName="scaleY"
+                    android:startOffset="0"
+                    android:valueFrom="1"
+                    android:valueTo="1"
+                    android:valueType="floatType" >
+                    <aapt:attr name="android:interpolator" >
+                        <pathInterpolator android:pathData="M 0.0,0.0 c0.333,0 0.667,1 1.0,1.0" />
+                    </aapt:attr>
+                </objectAnimator>
+                <objectAnimator
+                    android:duration="83"
+                    android:propertyName="scaleX"
+                    android:startOffset="450"
+                    android:valueFrom="1"
+                    android:valueTo="1.05"
+                    android:valueType="floatType" >
+                    <aapt:attr name="android:interpolator" >
+                        <pathInterpolator android:pathData="M 0.0,0.0 c0.333,0 0.667,1 1.0,1.0" />
+                    </aapt:attr>
+                </objectAnimator>
+                <objectAnimator
+                    android:duration="83"
+                    android:propertyName="scaleY"
+                    android:startOffset="450"
+                    android:valueFrom="1"
+                    android:valueTo="1.05"
+                    android:valueType="floatType" >
+                    <aapt:attr name="android:interpolator" >
+                        <pathInterpolator android:pathData="M 0.0,0.0 c0.333,0 0.667,1 1.0,1.0" />
+                    </aapt:attr>
+                </objectAnimator>
+                <objectAnimator
+                    android:duration="100"
+                    android:propertyName="scaleX"
+                    android:startOffset="533"
+                    android:valueFrom="1.05"
+                    android:valueTo="1"
+                    android:valueType="floatType" >
+                    <aapt:attr name="android:interpolator" >
+                        <pathInterpolator android:pathData="M 0.0,0.0 c0.333,0 0.667,1 1.0,1.0" />
+                    </aapt:attr>
+                </objectAnimator>
+                <objectAnimator
+                    android:duration="100"
+                    android:propertyName="scaleY"
+                    android:startOffset="533"
+                    android:valueFrom="1.05"
+                    android:valueTo="1"
+                    android:valueType="floatType" >
+                    <aapt:attr name="android:interpolator" >
+                        <pathInterpolator android:pathData="M 0.0,0.0 c0.333,0 0.667,1 1.0,1.0" />
+                    </aapt:attr>
+                </objectAnimator>
+            </set>
+        </aapt:attr>
+    </target>
+    <target android:name="_R_G_L_1_G_N_4_T_1" >
+        <aapt:attr name="android:animation" >
+            <set android:ordering="together" >
+                <objectAnimator
+                    android:duration="400"
+                    android:propertyName="translateY"
+                    android:startOffset="0"
+                    android:valueFrom="24.333"
+                    android:valueTo="24.333"
+                    android:valueType="floatType" >
+                    <aapt:attr name="android:interpolator" >
+                        <pathInterpolator android:pathData="M 0.0,0.0 c0.333,0 0.667,1 1.0,1.0" />
+                    </aapt:attr>
+                </objectAnimator>
+                <objectAnimator
+                    android:duration="117"
+                    android:propertyName="translateY"
+                    android:startOffset="400"
+                    android:valueFrom="24.333"
+                    android:valueTo="25.833"
+                    android:valueType="floatType" >
+                    <aapt:attr name="android:interpolator" >
+                        <pathInterpolator android:pathData="M 0.0,0.0 c0.333,0 0.667,1 1.0,1.0" />
+                    </aapt:attr>
+                </objectAnimator>
+                <objectAnimator
+                    android:duration="117"
+                    android:propertyName="translateY"
+                    android:startOffset="517"
+                    android:valueFrom="25.833"
+                    android:valueTo="24.333"
+                    android:valueType="floatType" >
+                    <aapt:attr name="android:interpolator" >
+                        <pathInterpolator android:pathData="M 0.0,0.0 c0.333,0 0.667,1 1.0,1.0" />
+                    </aapt:attr>
+                </objectAnimator>
+            </set>
+        </aapt:attr>
+    </target>
+    <target android:name="_R_G_L_0_G_D_0_P_0" >
+        <aapt:attr name="android:animation" >
+            <set android:ordering="together" >
+                <objectAnimator
+                    android:duration="333"
+                    android:propertyName="pathData"
+                    android:startOffset="0"
+                    android:valueFrom="M12.42 12.6 C12.42,12.6 12.41,8.16 12.41,8.16 C12.41,5.81 14.36,3.75 16.75,3.77 C19.15,3.78 21.07,5.71 21.07,8.05 C21.07,8.05 21.08,8.22 21.08,8.22 "
+                    android:valueTo="M12.42 12.6 C12.42,12.6 12.4,5.86 12.4,5.86 C12.4,3.52 10.46,1.44 8.06,1.44 C5.67,1.44 3.73,3.52 3.73,5.86 C3.73,5.86 3.75,7.41 3.75,7.41 "
+                    android:valueType="pathType" >
+                    <aapt:attr name="android:interpolator" >
+                        <pathInterpolator android:pathData="M 0.0,0.0 c0.635,0 0.43,1 1.0,1.0" />
+                    </aapt:attr>
+                </objectAnimator>
+                <objectAnimator
+                    android:duration="67"
+                    android:propertyName="pathData"
+                    android:startOffset="333"
+                    android:valueFrom="M12.42 12.6 C12.42,12.6 12.4,5.86 12.4,5.86 C12.4,3.52 10.46,1.44 8.06,1.44 C5.67,1.44 3.73,3.52 3.73,5.86 C3.73,5.86 3.75,7.41 3.75,7.41 "
+                    android:valueTo="M12.42 12.6 C12.42,12.6 12.42,8.17 12.42,8.17 C12.42,5.83 10.48,3.75 8.08,3.75 C5.69,3.75 3.75,5.83 3.75,8.17 C3.75,8.17 3.75,12.6 3.75,12.6 "
+                    android:valueType="pathType" >
+                    <aapt:attr name="android:interpolator" >
+                        <pathInterpolator android:pathData="M 0.0,0.0 c0.512,0 0.41,1 1.0,1.0" />
+                    </aapt:attr>
+                </objectAnimator>
+            </set>
+        </aapt:attr>
+    </target>
+    <target android:name="_R_G_L_0_G_N_4_T_1" >
+        <aapt:attr name="android:animation" >
+            <set android:ordering="together" >
+                <objectAnimator
+                    android:duration="400"
+                    android:propertyName="translateY"
+                    android:startOffset="0"
+                    android:valueFrom="24.333"
+                    android:valueTo="24.333"
+                    android:valueType="floatType" >
+                    <aapt:attr name="android:interpolator" >
+                        <pathInterpolator android:pathData="M 0.0,0.0 c0.333,0 0.667,1 1.0,1.0" />
+                    </aapt:attr>
+                </objectAnimator>
+                <objectAnimator
+                    android:duration="117"
+                    android:propertyName="translateY"
+                    android:startOffset="400"
+                    android:valueFrom="24.333"
+                    android:valueTo="25.833"
+                    android:valueType="floatType" >
+                    <aapt:attr name="android:interpolator" >
+                        <pathInterpolator android:pathData="M 0.0,0.0 c0.333,0 0.667,1 1.0,1.0" />
+                    </aapt:attr>
+                </objectAnimator>
+                <objectAnimator
+                    android:duration="117"
+                    android:propertyName="translateY"
+                    android:startOffset="517"
+                    android:valueFrom="25.833"
+                    android:valueTo="24.333"
+                    android:valueType="floatType" >
+                    <aapt:attr name="android:interpolator" >
+                        <pathInterpolator android:pathData="M 0.0,0.0 c0.333,0 0.667,1 1.0,1.0" />
+                    </aapt:attr>
+                </objectAnimator>
+            </set>
+        </aapt:attr>
+    </target>
+    <target android:name="time_group" >
+        <aapt:attr name="android:animation" >
+            <set android:ordering="together" >
+                <objectAnimator
+                    android:duration="717"
+                    android:propertyName="translateX"
+                    android:startOffset="0"
+                    android:valueFrom="0"
+                    android:valueTo="1"
+                    android:valueType="floatType" />
+            </set>
+        </aapt:attr>
+    </target>
+
+</animated-vector>
\ No newline at end of file
diff --git a/packages/SystemUI/res/anim/lock_lock_filled.xml b/packages/SystemUI/res/anim/lock_lock_filled.xml
new file mode 100644
index 0000000..017c329
--- /dev/null
+++ b/packages/SystemUI/res/anim/lock_lock_filled.xml
@@ -0,0 +1,215 @@
+<?xml version="1.0" encoding="utf-8"?>
+<animated-vector xmlns:aapt="http://schemas.android.com/aapt"
+    xmlns:android="http://schemas.android.com/apk/res/android" >
+
+    <aapt:attr name="android:drawable" >
+        <vector
+            android:height="42dp"
+            android:viewportHeight="42"
+            android:viewportWidth="32"
+            android:width="32dp" >
+            <group android:name="_R_G" >
+                <group
+                    android:name="_R_G_L_1_G_T_1"
+                    android:translateX="16"
+                    android:translateY="25" >
+                    <group
+                        android:name="_R_G_L_1_G"
+                        android:translateX="-10.917"
+                        android:translateY="-9.583" >
+                        <path
+                            android:name="_R_G_L_1_G_D_0_P_0"
+                            android:fillAlpha="1"
+                            android:fillColor="#ffffff"
+                            android:fillType="nonZero"
+                            android:pathData=" M18.92 0.25 C18.92,0.25 2.92,0.25 2.92,0.25 C1.45,0.25 0.25,1.45 0.25,2.92 C0.25,2.92 0.25,16.25 0.25,16.25 C0.25,17.72 1.45,18.92 2.92,18.92 C2.92,18.92 18.92,18.92 18.92,18.92 C20.38,18.92 21.58,17.72 21.58,16.25 C21.58,16.25 21.58,2.92 21.58,2.92 C21.58,1.45 20.38,0.25 18.92,0.25c  M10.92 12.25 C9.45,12.25 8.25,11.05 8.25,9.58 C8.25,8.12 9.45,6.92 10.92,6.92 C12.38,6.92 13.58,8.12 13.58,9.58 C13.58,11.05 12.38,12.25 10.92,12.25c " />
+                    </group>
+                </group>
+                <group
+                    android:name="_R_G_L_0_G_N_3_T_1"
+                    android:translateX="16"
+                    android:translateY="25" >
+                    <group
+                        android:name="_R_G_L_0_G_N_3_T_0"
+                        android:translateX="-10.917"
+                        android:translateY="-9.583" >
+                        <group
+                            android:name="_R_G_L_0_G"
+                            android:translateX="9.917000000000002"
+                            android:translateY="-12.75" >
+                            <path
+                                android:name="_R_G_L_0_G_D_0_P_0"
+                                android:pathData=" M13 9 C13,7.9 12.55,6.9 11.83,6.17 C11.1,5.45 10.11,5 9,5 C6.79,5 5,6.79 5,9 C5,9 5,13 5,13 "
+                                android:strokeAlpha="1"
+                                android:strokeColor="#ffffff"
+                                android:strokeLineCap="round"
+                                android:strokeLineJoin="round"
+                                android:strokeWidth="2" />
+                        </group>
+                    </group>
+                </group>
+            </group>
+            <group android:name="time_group" />
+        </vector>
+    </aapt:attr>
+
+    <target android:name="_R_G_L_1_G_D_0_P_0" >
+        <aapt:attr name="android:animation" >
+            <set android:ordering="together" >
+                <objectAnimator
+                    android:duration="450"
+                    android:propertyName="pathData"
+                    android:startOffset="0"
+                    android:valueFrom=" M18.92 0.25 C18.92,0.25 2.92,0.25 2.92,0.25 C1.45,0.25 0.25,1.45 0.25,2.92 C0.25,2.92 0.25,16.25 0.25,16.25 C0.25,17.72 1.45,18.92 2.92,18.92 C2.92,18.92 18.92,18.92 18.92,18.92 C20.38,18.92 21.58,17.72 21.58,16.25 C21.58,16.25 21.58,2.92 21.58,2.92 C21.58,1.45 20.38,0.25 18.92,0.25c M10.92 12.25 C9.45,12.25 8.25,11.05 8.25,9.58 C8.25,8.12 9.45,6.92 10.92,6.92 C12.38,6.92 13.58,8.12 13.58,9.58 C13.58,11.05 12.38,12.25 10.92,12.25c "
+                    android:valueTo=" M18.92 0.25 C18.92,0.25 2.92,0.25 2.92,0.25 C1.45,0.25 0.25,1.45 0.25,2.92 C0.25,2.92 0.25,16.25 0.25,16.25 C0.25,17.72 1.45,18.92 2.92,18.92 C2.92,18.92 18.92,18.92 18.92,18.92 C20.38,18.92 21.58,17.72 21.58,16.25 C21.58,16.25 21.58,2.92 21.58,2.92 C21.58,1.45 20.38,0.25 18.92,0.25c M10.92 12.25 C9.45,12.25 8.25,11.05 8.25,9.58 C8.25,8.12 9.45,6.92 10.92,6.92 C12.38,6.92 13.58,8.12 13.58,9.58 C13.58,11.05 12.38,12.25 10.92,12.25c "
+                    android:valueType="pathType" >
+                    <aapt:attr name="android:interpolator" >
+                        <pathInterpolator android:pathData="M 0.0,0.0 c0.333,0 0.667,1 1.0,1.0" />
+                    </aapt:attr>
+                </objectAnimator>
+                <objectAnimator
+                    android:duration="83"
+                    android:propertyName="pathData"
+                    android:startOffset="450"
+                    android:valueFrom=" M18.92 0.25 C18.92,0.25 2.92,0.25 2.92,0.25 C1.45,0.25 0.25,1.45 0.25,2.92 C0.25,2.92 0.25,16.25 0.25,16.25 C0.25,17.72 1.45,18.92 2.92,18.92 C2.92,18.92 18.92,18.92 18.92,18.92 C20.38,18.92 21.58,17.72 21.58,16.25 C21.58,16.25 21.58,2.92 21.58,2.92 C21.58,1.45 20.38,0.25 18.92,0.25c M10.92 12.25 C9.45,12.25 8.25,11.05 8.25,9.58 C8.25,8.12 9.45,6.92 10.92,6.92 C12.38,6.92 13.58,8.12 13.58,9.58 C13.58,11.05 12.38,12.25 10.92,12.25c "
+                    android:valueTo=" M18.92 0.25 C18.92,0.25 2.92,0.25 2.92,0.25 C1.45,0.25 0.25,1.45 0.25,2.92 C0.25,2.92 0.25,16.25 0.25,16.25 C0.25,17.72 1.45,18.92 2.92,18.92 C2.92,18.92 18.92,18.92 18.92,18.92 C20.38,18.92 21.58,17.72 21.58,16.25 C21.58,16.25 21.58,2.92 21.58,2.92 C21.58,1.45 20.38,0.25 18.92,0.25c M10.92 12.58 C9.27,12.58 7.92,11.23 7.92,9.58 C7.92,7.93 9.27,6.58 10.92,6.58 C12.57,6.58 13.92,7.93 13.92,9.58 C13.92,11.23 12.57,12.58 10.92,12.58c "
+                    android:valueType="pathType" >
+                    <aapt:attr name="android:interpolator" >
+                        <pathInterpolator android:pathData="M 0.0,0.0 c0.333,0 0.667,1 1.0,1.0" />
+                    </aapt:attr>
+                </objectAnimator>
+                <objectAnimator
+                    android:duration="100"
+                    android:propertyName="pathData"
+                    android:startOffset="533"
+                    android:valueFrom=" M18.92 0.25 C18.92,0.25 2.92,0.25 2.92,0.25 C1.45,0.25 0.25,1.45 0.25,2.92 C0.25,2.92 0.25,16.25 0.25,16.25 C0.25,17.72 1.45,18.92 2.92,18.92 C2.92,18.92 18.92,18.92 18.92,18.92 C20.38,18.92 21.58,17.72 21.58,16.25 C21.58,16.25 21.58,2.92 21.58,2.92 C21.58,1.45 20.38,0.25 18.92,0.25c M10.92 12.58 C9.27,12.58 7.92,11.23 7.92,9.58 C7.92,7.93 9.27,6.58 10.92,6.58 C12.57,6.58 13.92,7.93 13.92,9.58 C13.92,11.23 12.57,12.58 10.92,12.58c "
+                    android:valueTo=" M18.92 0.25 C18.92,0.25 2.92,0.25 2.92,0.25 C1.45,0.25 0.25,1.45 0.25,2.92 C0.25,2.92 0.25,16.25 0.25,16.25 C0.25,17.72 1.45,18.92 2.92,18.92 C2.92,18.92 18.92,18.92 18.92,18.92 C20.38,18.92 21.58,17.72 21.58,16.25 C21.58,16.25 21.58,2.92 21.58,2.92 C21.58,1.45 20.38,0.25 18.92,0.25c M10.92 12.25 C9.45,12.25 8.25,11.05 8.25,9.58 C8.25,8.12 9.45,6.92 10.92,6.92 C12.38,6.92 13.58,8.12 13.58,9.58 C13.58,11.05 12.38,12.25 10.92,12.25c "
+                    android:valueType="pathType" >
+                    <aapt:attr name="android:interpolator" >
+                        <pathInterpolator android:pathData="M 0.0,0.0 c0.333,0 0.667,1 1.0,1.0" />
+                    </aapt:attr>
+                </objectAnimator>
+            </set>
+        </aapt:attr>
+    </target>
+    <target android:name="_R_G_L_1_G_T_1" >
+        <aapt:attr name="android:animation" >
+            <set android:ordering="together" >
+                <objectAnimator
+                    android:duration="400"
+                    android:pathData="M 16,25C 16,25.27083334326744 16,25 16,25"
+                    android:propertyName="translateXY"
+                    android:propertyXName="translateX"
+                    android:propertyYName="translateY"
+                    android:startOffset="0" >
+                    <aapt:attr name="android:interpolator" >
+                        <pathInterpolator android:pathData="M 0.0,0.0 c0.333,0 0.667,1 1.0,1.0" />
+                    </aapt:attr>
+                </objectAnimator>
+                <objectAnimator
+                    android:duration="117"
+                    android:pathData="M 16,25C 16,25.27083334326744 16,26.625 16,26.625"
+                    android:propertyName="translateXY"
+                    android:propertyXName="translateX"
+                    android:propertyYName="translateY"
+                    android:startOffset="400" >
+                    <aapt:attr name="android:interpolator" >
+                        <pathInterpolator android:pathData="M 0.0,0.0 c0.333,0 0.667,1 1.0,1.0" />
+                    </aapt:attr>
+                </objectAnimator>
+                <objectAnimator
+                    android:duration="117"
+                    android:pathData="M 16,26.625C 16,26.625 16,25.27083334326744 16,25"
+                    android:propertyName="translateXY"
+                    android:propertyXName="translateX"
+                    android:propertyYName="translateY"
+                    android:startOffset="517" >
+                    <aapt:attr name="android:interpolator" >
+                        <pathInterpolator android:pathData="M 0.0,0.0 c0.333,0 0.667,1 1.0,1.0" />
+                    </aapt:attr>
+                </objectAnimator>
+            </set>
+        </aapt:attr>
+    </target>
+    <target android:name="_R_G_L_0_G_D_0_P_0" >
+        <aapt:attr name="android:animation" >
+            <set android:ordering="together" >
+                <objectAnimator
+                    android:duration="317"
+                    android:propertyName="pathData"
+                    android:startOffset="0"
+                    android:valueFrom="M13 9 C13,7.9 12.55,6.9 11.83,6.17 C11.1,5.45 10.11,5 9,5 C6.79,5 5,6.79 5,9 C5,9 5,13 5,13 "
+                    android:valueTo="M-3 6.73 C-3,5.62 -2.56,4.67 -1.84,4 C-1.11,3.32 -0.09,2.93 1.06,2.94 C3.27,2.96 5,4.54 5,6.75 C5,6.75 5,13 5,13 "
+                    android:valueType="pathType" >
+                    <aapt:attr name="android:interpolator" >
+                        <pathInterpolator android:pathData="M 0.0,0.0 c0.637,0 0.437,1 1.0,1.0" />
+                    </aapt:attr>
+                </objectAnimator>
+                <objectAnimator
+                    android:duration="133"
+                    android:propertyName="pathData"
+                    android:startOffset="317"
+                    android:valueFrom="M-3 6.73 C-3,5.62 -2.56,4.67 -1.84,4 C-1.11,3.32 -0.09,2.93 1.06,2.94 C3.27,2.96 5,4.54 5,6.75 C5,6.75 5,13 5,13 "
+                    android:valueTo="M-3 13.04 C-3,13.04 -3,9.04 -3,9.04 C-3,6.83 -1.25,5.05 0.69,5.01 C2.9,4.97 5,6.79 5,9 C5,9 5,13 5,13 "
+                    android:valueType="pathType" >
+                    <aapt:attr name="android:interpolator" >
+                        <pathInterpolator android:pathData="M 0.0,0.0 c0.497,0 0.408,1 1.0,1.0" />
+                    </aapt:attr>
+                </objectAnimator>
+            </set>
+        </aapt:attr>
+    </target>
+    <target android:name="_R_G_L_0_G_N_3_T_1" >
+        <aapt:attr name="android:animation" >
+            <set android:ordering="together" >
+                <objectAnimator
+                    android:duration="400"
+                    android:pathData="M 16,25C 16,25.27083334326744 16,25 16,25"
+                    android:propertyName="translateXY"
+                    android:propertyXName="translateX"
+                    android:propertyYName="translateY"
+                    android:startOffset="0" >
+                    <aapt:attr name="android:interpolator" >
+                        <pathInterpolator android:pathData="M 0.0,0.0 c0.333,0 0.667,1 1.0,1.0" />
+                    </aapt:attr>
+                </objectAnimator>
+                <objectAnimator
+                    android:duration="117"
+                    android:pathData="M 16,25C 16,25.27083334326744 16,26.625 16,26.625"
+                    android:propertyName="translateXY"
+                    android:propertyXName="translateX"
+                    android:propertyYName="translateY"
+                    android:startOffset="400" >
+                    <aapt:attr name="android:interpolator" >
+                        <pathInterpolator android:pathData="M 0.0,0.0 c0.333,0 0.667,1 1.0,1.0" />
+                    </aapt:attr>
+                </objectAnimator>
+                <objectAnimator
+                    android:duration="117"
+                    android:pathData="M 16,26.625C 16,26.625 16,25.27083334326744 16,25"
+                    android:propertyName="translateXY"
+                    android:propertyXName="translateX"
+                    android:propertyYName="translateY"
+                    android:startOffset="517" >
+                    <aapt:attr name="android:interpolator" >
+                        <pathInterpolator android:pathData="M 0.0,0.0 c0.333,0 0.667,1 1.0,1.0" />
+                    </aapt:attr>
+                </objectAnimator>
+            </set>
+        </aapt:attr>
+    </target>
+    <target android:name="time_group" >
+        <aapt:attr name="android:animation" >
+            <set android:ordering="together" >
+                <objectAnimator
+                    android:duration="717"
+                    android:propertyName="translateX"
+                    android:startOffset="0"
+                    android:valueFrom="0"
+                    android:valueTo="1"
+                    android:valueType="floatType" />
+            </set>
+        </aapt:attr>
+    </target>
+
+</animated-vector>
\ No newline at end of file
diff --git a/packages/SystemUI/res/anim/lock_lock_rounded.xml b/packages/SystemUI/res/anim/lock_lock_rounded.xml
new file mode 100644
index 0000000..fc4545c
--- /dev/null
+++ b/packages/SystemUI/res/anim/lock_lock_rounded.xml
@@ -0,0 +1,314 @@
+<?xml version="1.0" encoding="utf-8"?>
+<animated-vector xmlns:aapt="http://schemas.android.com/aapt"
+    xmlns:android="http://schemas.android.com/apk/res/android" >
+
+    <aapt:attr name="android:drawable" >
+        <vector
+            android:height="42dp"
+            android:viewportHeight="42"
+            android:viewportWidth="32"
+            android:width="32dp" >
+            <group android:name="_R_G" >
+                <group
+                    android:name="_R_G_L_2_G_T_1"
+                    android:translateX="16"
+                    android:translateY="25" >
+                    <group
+                        android:name="_R_G_L_2_G"
+                        android:translateX="-14.667"
+                        android:translateY="-12.667" >
+                        <path
+                            android:name="_R_G_L_2_G_D_0_P_0"
+                            android:pathData=" M22.09 5 C22.09,5 6,5 6,5 C5.45,5 5,5.45 5,6 C5,6 5,19.33 5,19.33 C5,19.89 5.45,20.33 6,20.33 C6,20.33 23.33,20.33 23.33,20.33 C23.89,20.33 24.33,19.89 24.33,19.33 C24.33,19.33 24.33,6 24.33,6 C24.33,5.45 23.89,5 23.33,5 C23.33,5 22.09,5 22.09,5c "
+                            android:strokeAlpha="1"
+                            android:strokeColor="#ffffff"
+                            android:strokeLineCap="round"
+                            android:strokeLineJoin="round"
+                            android:strokeWidth="1.5" />
+                    </group>
+                </group>
+                <group
+                    android:name="_R_G_L_1_G_N_5_T_1"
+                    android:translateX="16"
+                    android:translateY="25" >
+                    <group
+                        android:name="_R_G_L_1_G_N_5_T_0"
+                        android:translateX="-14.667"
+                        android:translateY="-12.667" >
+                        <group
+                            android:name="_R_G_L_1_G"
+                            android:pivotX="2.25"
+                            android:pivotY="2.25"
+                            android:scaleX="1"
+                            android:scaleY="1"
+                            android:translateX="12.416"
+                            android:translateY="10.417" >
+                            <path
+                                android:name="_R_G_L_1_G_D_0_P_0"
+                                android:fillAlpha="1"
+                                android:fillColor="#ffffff"
+                                android:fillType="nonZero"
+                                android:pathData=" M2.25 0.25 C3.35,0.25 4.25,1.15 4.25,2.25 C4.25,3.35 3.35,4.25 2.25,4.25 C1.15,4.25 0.25,3.35 0.25,2.25 C0.25,1.15 1.15,0.25 2.25,0.25c " />
+                        </group>
+                    </group>
+                </group>
+                <group
+                    android:name="_R_G_L_0_G_N_5_T_1"
+                    android:translateX="16"
+                    android:translateY="25" >
+                    <group
+                        android:name="_R_G_L_0_G_N_5_T_0"
+                        android:translateX="-14.667"
+                        android:translateY="-12.667" >
+                        <group
+                            android:name="_R_G_L_0_G"
+                            android:translateX="5.333"
+                            android:translateY="-9.425999999999998" >
+                            <path
+                                android:name="_R_G_L_0_G_D_0_P_0"
+                                android:pathData=" M13.67 13.8 C13.67,13.8 13.67,8.94 13.67,8.94 C13.68,6.62 15.69,5.03 18.01,5.04 C20.46,5.04 22.32,6.89 22.34,8.85 C22.34,8.85 22.33,8.89 22.33,8.89 "
+                                android:strokeAlpha="1"
+                                android:strokeColor="#ffffff"
+                                android:strokeLineCap="round"
+                                android:strokeLineJoin="round"
+                                android:strokeWidth="1.5" />
+                        </group>
+                    </group>
+                </group>
+            </group>
+            <group android:name="time_group" />
+        </vector>
+    </aapt:attr>
+
+    <target android:name="_R_G_L_2_G_T_1" >
+        <aapt:attr name="android:animation" >
+            <set android:ordering="together" >
+                <objectAnimator
+                    android:duration="400"
+                    android:pathData="M 16,25C 16,25.35416665673256 16,25 16,25"
+                    android:propertyName="translateXY"
+                    android:propertyXName="translateX"
+                    android:propertyYName="translateY"
+                    android:startOffset="0" >
+                    <aapt:attr name="android:interpolator" >
+                        <pathInterpolator android:pathData="M 0.0,0.0 c0.333,0 0.667,1 1.0,1.0" />
+                    </aapt:attr>
+                </objectAnimator>
+                <objectAnimator
+                    android:duration="117"
+                    android:pathData="M 16,25C 16,25.35416665673256 16,27.125 16,27.125"
+                    android:propertyName="translateXY"
+                    android:propertyXName="translateX"
+                    android:propertyYName="translateY"
+                    android:startOffset="400" >
+                    <aapt:attr name="android:interpolator" >
+                        <pathInterpolator android:pathData="M 0.0,0.0 c0.333,0 0.667,1 1.0,1.0" />
+                    </aapt:attr>
+                </objectAnimator>
+                <objectAnimator
+                    android:duration="117"
+                    android:pathData="M 16,27.125C 16,27.125 16,25.35416665673256 16,25"
+                    android:propertyName="translateXY"
+                    android:propertyXName="translateX"
+                    android:propertyYName="translateY"
+                    android:startOffset="517" >
+                    <aapt:attr name="android:interpolator" >
+                        <pathInterpolator android:pathData="M 0.0,0.0 c0.333,0 0.667,1 1.0,1.0" />
+                    </aapt:attr>
+                </objectAnimator>
+            </set>
+        </aapt:attr>
+    </target>
+    <target android:name="_R_G_L_1_G" >
+        <aapt:attr name="android:animation" >
+            <set android:ordering="together" >
+                <objectAnimator
+                    android:duration="450"
+                    android:propertyName="scaleX"
+                    android:startOffset="0"
+                    android:valueFrom="1"
+                    android:valueTo="1"
+                    android:valueType="floatType" >
+                    <aapt:attr name="android:interpolator" >
+                        <pathInterpolator android:pathData="M 0.0,0.0 c0.333,0 0.667,1 1.0,1.0" />
+                    </aapt:attr>
+                </objectAnimator>
+                <objectAnimator
+                    android:duration="450"
+                    android:propertyName="scaleY"
+                    android:startOffset="0"
+                    android:valueFrom="1"
+                    android:valueTo="1"
+                    android:valueType="floatType" >
+                    <aapt:attr name="android:interpolator" >
+                        <pathInterpolator android:pathData="M 0.0,0.0 c0.333,0 0.667,1 1.0,1.0" />
+                    </aapt:attr>
+                </objectAnimator>
+                <objectAnimator
+                    android:duration="83"
+                    android:propertyName="scaleX"
+                    android:startOffset="450"
+                    android:valueFrom="1"
+                    android:valueTo="1.12"
+                    android:valueType="floatType" >
+                    <aapt:attr name="android:interpolator" >
+                        <pathInterpolator android:pathData="M 0.0,0.0 c0.333,0 0.667,1 1.0,1.0" />
+                    </aapt:attr>
+                </objectAnimator>
+                <objectAnimator
+                    android:duration="83"
+                    android:propertyName="scaleY"
+                    android:startOffset="450"
+                    android:valueFrom="1"
+                    android:valueTo="1.12"
+                    android:valueType="floatType" >
+                    <aapt:attr name="android:interpolator" >
+                        <pathInterpolator android:pathData="M 0.0,0.0 c0.333,0 0.667,1 1.0,1.0" />
+                    </aapt:attr>
+                </objectAnimator>
+                <objectAnimator
+                    android:duration="100"
+                    android:propertyName="scaleX"
+                    android:startOffset="533"
+                    android:valueFrom="1.12"
+                    android:valueTo="1"
+                    android:valueType="floatType" >
+                    <aapt:attr name="android:interpolator" >
+                        <pathInterpolator android:pathData="M 0.0,0.0 c0.333,0 0.667,1 1.0,1.0" />
+                    </aapt:attr>
+                </objectAnimator>
+                <objectAnimator
+                    android:duration="100"
+                    android:propertyName="scaleY"
+                    android:startOffset="533"
+                    android:valueFrom="1.12"
+                    android:valueTo="1"
+                    android:valueType="floatType" >
+                    <aapt:attr name="android:interpolator" >
+                        <pathInterpolator android:pathData="M 0.0,0.0 c0.333,0 0.667,1 1.0,1.0" />
+                    </aapt:attr>
+                </objectAnimator>
+            </set>
+        </aapt:attr>
+    </target>
+    <target android:name="_R_G_L_1_G_N_5_T_1" >
+        <aapt:attr name="android:animation" >
+            <set android:ordering="together" >
+                <objectAnimator
+                    android:duration="400"
+                    android:pathData="M 16,25C 16,25.35416665673256 16,25 16,25"
+                    android:propertyName="translateXY"
+                    android:propertyXName="translateX"
+                    android:propertyYName="translateY"
+                    android:startOffset="0" >
+                    <aapt:attr name="android:interpolator" >
+                        <pathInterpolator android:pathData="M 0.0,0.0 c0.333,0 0.667,1 1.0,1.0" />
+                    </aapt:attr>
+                </objectAnimator>
+                <objectAnimator
+                    android:duration="117"
+                    android:pathData="M 16,25C 16,25.35416665673256 16,27.125 16,27.125"
+                    android:propertyName="translateXY"
+                    android:propertyXName="translateX"
+                    android:propertyYName="translateY"
+                    android:startOffset="400" >
+                    <aapt:attr name="android:interpolator" >
+                        <pathInterpolator android:pathData="M 0.0,0.0 c0.333,0 0.667,1 1.0,1.0" />
+                    </aapt:attr>
+                </objectAnimator>
+                <objectAnimator
+                    android:duration="117"
+                    android:pathData="M 16,27.125C 16,27.125 16,25.35416665673256 16,25"
+                    android:propertyName="translateXY"
+                    android:propertyXName="translateX"
+                    android:propertyYName="translateY"
+                    android:startOffset="517" >
+                    <aapt:attr name="android:interpolator" >
+                        <pathInterpolator android:pathData="M 0.0,0.0 c0.333,0 0.667,1 1.0,1.0" />
+                    </aapt:attr>
+                </objectAnimator>
+            </set>
+        </aapt:attr>
+    </target>
+    <target android:name="_R_G_L_0_G_D_0_P_0" >
+        <aapt:attr name="android:animation" >
+            <set android:ordering="together" >
+                <objectAnimator
+                    android:duration="317"
+                    android:propertyName="pathData"
+                    android:startOffset="0"
+                    android:valueFrom="M13.67 13.8 C13.67,13.8 13.67,8.94 13.67,8.94 C13.68,6.62 15.69,5.03 18.01,5.04 C20.46,5.04 22.32,6.89 22.34,8.85 C22.34,8.85 22.33,8.89 22.33,8.89 "
+                    android:valueTo="M13.67 13.8 C13.67,13.8 13.69,5.06 13.69,5.06 C13.65,2.87 11.71,1.13 9.35,1.16 C7,1.13 5.06,2.87 5.02,5.06 C5.02,5.06 5,7.93 5,7.93 "
+                    android:valueType="pathType" >
+                    <aapt:attr name="android:interpolator" >
+                        <pathInterpolator android:pathData="M 0.0,0.0 c0.825,0 0.321,1 1.0,1.0" />
+                    </aapt:attr>
+                </objectAnimator>
+                <objectAnimator
+                    android:duration="133"
+                    android:propertyName="pathData"
+                    android:startOffset="317"
+                    android:valueFrom="M13.67 13.8 C13.67,13.8 13.69,5.06 13.69,5.06 C13.65,2.87 11.71,1.13 9.35,1.16 C7,1.13 5.06,2.87 5.02,5.06 C5.02,5.06 5,7.93 5,7.93 "
+                    android:valueTo="M13.67 13.8 C13.67,13.8 13.67,8.94 13.67,8.94 C13.63,6.75 11.69,5 9.33,5.04 C6.98,5 5.04,6.75 5,8.94 C5,8.94 5,13.8 5,13.8 "
+                    android:valueType="pathType" >
+                    <aapt:attr name="android:interpolator" >
+                        <pathInterpolator android:pathData="M 0.0,0.0 c0.683,0 0.342,1 1.0,1.0" />
+                    </aapt:attr>
+                </objectAnimator>
+            </set>
+        </aapt:attr>
+    </target>
+    <target android:name="_R_G_L_0_G_N_5_T_1" >
+        <aapt:attr name="android:animation" >
+            <set android:ordering="together" >
+                <objectAnimator
+                    android:duration="400"
+                    android:pathData="M 16,25C 16,25.35416665673256 16,25 16,25"
+                    android:propertyName="translateXY"
+                    android:propertyXName="translateX"
+                    android:propertyYName="translateY"
+                    android:startOffset="0" >
+                    <aapt:attr name="android:interpolator" >
+                        <pathInterpolator android:pathData="M 0.0,0.0 c0.333,0 0.667,1 1.0,1.0" />
+                    </aapt:attr>
+                </objectAnimator>
+                <objectAnimator
+                    android:duration="117"
+                    android:pathData="M 16,25C 16,25.35416665673256 16,27.125 16,27.125"
+                    android:propertyName="translateXY"
+                    android:propertyXName="translateX"
+                    android:propertyYName="translateY"
+                    android:startOffset="400" >
+                    <aapt:attr name="android:interpolator" >
+                        <pathInterpolator android:pathData="M 0.0,0.0 c0.333,0 0.667,1 1.0,1.0" />
+                    </aapt:attr>
+                </objectAnimator>
+                <objectAnimator
+                    android:duration="117"
+                    android:pathData="M 16,27.125C 16,27.125 16,25.35416665673256 16,25"
+                    android:propertyName="translateXY"
+                    android:propertyXName="translateX"
+                    android:propertyYName="translateY"
+                    android:startOffset="517" >
+                    <aapt:attr name="android:interpolator" >
+                        <pathInterpolator android:pathData="M 0.0,0.0 c0.333,0 0.667,1 1.0,1.0" />
+                    </aapt:attr>
+                </objectAnimator>
+            </set>
+        </aapt:attr>
+    </target>
+    <target android:name="time_group" >
+        <aapt:attr name="android:animation" >
+            <set android:ordering="together" >
+                <objectAnimator
+                    android:duration="717"
+                    android:propertyName="translateX"
+                    android:startOffset="0"
+                    android:valueFrom="0"
+                    android:valueTo="1"
+                    android:valueType="floatType" />
+            </set>
+        </aapt:attr>
+    </target>
+
+</animated-vector>
\ No newline at end of file
diff --git a/core/res/res/anim/lock_scanning.xml b/packages/SystemUI/res/anim/lock_scanning.xml
similarity index 100%
rename from core/res/res/anim/lock_scanning.xml
rename to packages/SystemUI/res/anim/lock_scanning.xml
diff --git a/packages/SystemUI/res/anim/lock_scanning_circular.xml b/packages/SystemUI/res/anim/lock_scanning_circular.xml
new file mode 100644
index 0000000..9468213
--- /dev/null
+++ b/packages/SystemUI/res/anim/lock_scanning_circular.xml
@@ -0,0 +1,537 @@
+<?xml version="1.0" encoding="utf-8"?>
+<animated-vector xmlns:aapt="http://schemas.android.com/aapt"
+    xmlns:android="http://schemas.android.com/apk/res/android" >
+
+    <aapt:attr name="android:drawable" >
+        <vector
+            android:height="42dp"
+            android:viewportHeight="42"
+            android:viewportWidth="32"
+            android:width="32dp" >
+            <group android:name="_R_G" >
+                <group
+                    android:name="_R_G_L_2_G"
+                    android:pivotX="9.583"
+                    android:pivotY="8.916"
+                    android:scaleX="1"
+                    android:scaleY="1"
+                    android:translateX="6.416"
+                    android:translateY="15.416999999999998" >
+                    <path
+                        android:name="_R_G_L_2_G_D_0_P_0"
+                        android:fillAlpha="1"
+                        android:fillColor="#ffffff"
+                        android:fillType="nonZero"
+                        android:pathData=" M17.42 1.75 C17.42,1.75 17.42,14.58 17.42,14.58 C17.42,15.41 16.74,16.08 15.92,16.08 C15.92,16.08 3.25,16.08 3.25,16.08 C2.42,16.08 1.75,15.41 1.75,14.58 C1.75,14.58 1.75,1.75 1.75,1.75 C1.75,1.75 17.42,1.75 17.42,1.75c  M18.92 0.25 C18.92,0.25 0.25,0.25 0.25,0.25 C0.25,0.25 0.25,14.58 0.25,14.58 C0.25,16.24 1.59,17.58 3.25,17.58 C3.25,17.58 15.92,17.58 15.92,17.58 C17.57,17.58 18.92,16.24 18.92,14.58 C18.92,14.58 18.92,0.25 18.92,0.25c " />
+                </group>
+                <group
+                    android:name="_R_G_L_1_G_N_3_T_0"
+                    android:pivotX="9.583"
+                    android:pivotY="8.916"
+                    android:scaleX="1"
+                    android:scaleY="1"
+                    android:translateX="6.416"
+                    android:translateY="15.416999999999998" >
+                    <group
+                        android:name="_R_G_L_1_G"
+                        android:pivotX="2.25"
+                        android:pivotY="3.334"
+                        android:scaleX="1"
+                        android:scaleY="1"
+                        android:translateX="7.334"
+                        android:translateY="5.333" >
+                        <path
+                            android:name="_R_G_L_1_G_D_0_P_0"
+                            android:fillAlpha="1"
+                            android:fillColor="#ffffff"
+                            android:fillType="nonZero"
+                            android:pathData=" M4.25 2.25 C4.25,3.35 3.35,4.25 2.25,4.25 C1.15,4.25 0.25,3.35 0.25,2.25 C0.25,1.15 1.15,0.25 2.25,0.25 C3.35,0.25 4.25,1.15 4.25,2.25c " />
+                        <path
+                            android:name="_R_G_L_1_G_D_1_P_0"
+                            android:pathData=" M2.25 2.25 C2.25,2.25 2.25,5.92 2.25,5.92 "
+                            android:strokeAlpha="1"
+                            android:strokeColor="#ffffff"
+                            android:strokeLineCap="round"
+                            android:strokeLineJoin="round"
+                            android:strokeWidth="1.5" />
+                    </group>
+                </group>
+                <group
+                    android:name="_R_G_L_0_G_N_3_T_0"
+                    android:pivotX="9.583"
+                    android:pivotY="8.916"
+                    android:scaleX="1"
+                    android:scaleY="1"
+                    android:translateX="6.416"
+                    android:translateY="15.416999999999998" >
+                    <group
+                        android:name="_R_G_L_0_G_T_1"
+                        android:translateX="9.583"
+                        android:translateY="-3.662" >
+                        <group
+                            android:name="_R_G_L_0_G"
+                            android:translateX="-8.083"
+                            android:translateY="-8.173" >
+                            <path
+                                android:name="_R_G_L_0_G_D_0_P_0"
+                                android:pathData=" M12.42 12.6 C12.42,12.6 12.42,8.17 12.42,8.17 C12.42,5.83 10.48,3.75 8.08,3.75 C5.69,3.75 3.75,5.83 3.75,8.17 C3.75,8.17 3.75,12.6 3.75,12.6 "
+                                android:strokeAlpha="1"
+                                android:strokeColor="#ffffff"
+                                android:strokeLineCap="round"
+                                android:strokeLineJoin="round"
+                                android:strokeWidth="1.5" />
+                        </group>
+                    </group>
+                </group>
+            </group>
+            <group android:name="time_group" />
+        </vector>
+    </aapt:attr>
+
+    <target android:name="_R_G_L_2_G" >
+        <aapt:attr name="android:animation" >
+            <set android:ordering="together" >
+                <objectAnimator
+                    android:duration="83"
+                    android:propertyName="scaleX"
+                    android:startOffset="0"
+                    android:valueFrom="1"
+                    android:valueTo="1"
+                    android:valueType="floatType" >
+                    <aapt:attr name="android:interpolator" >
+                        <pathInterpolator android:pathData="M 0.0,0.0 c0.333,0 0.36,1 1.0,1.0" />
+                    </aapt:attr>
+                </objectAnimator>
+                <objectAnimator
+                    android:duration="83"
+                    android:propertyName="scaleY"
+                    android:startOffset="0"
+                    android:valueFrom="1"
+                    android:valueTo="1"
+                    android:valueType="floatType" >
+                    <aapt:attr name="android:interpolator" >
+                        <pathInterpolator android:pathData="M 0.0,0.0 c0.333,0 0.36,1 1.0,1.0" />
+                    </aapt:attr>
+                </objectAnimator>
+                <objectAnimator
+                    android:duration="83"
+                    android:propertyName="scaleX"
+                    android:startOffset="83"
+                    android:valueFrom="1"
+                    android:valueTo="0.9500000000000001"
+                    android:valueType="floatType" >
+                    <aapt:attr name="android:interpolator" >
+                        <pathInterpolator android:pathData="M 0.0,0.0 c0.333,0 0.36,1 1.0,1.0" />
+                    </aapt:attr>
+                </objectAnimator>
+                <objectAnimator
+                    android:duration="83"
+                    android:propertyName="scaleY"
+                    android:startOffset="83"
+                    android:valueFrom="1"
+                    android:valueTo="0.9500000000000001"
+                    android:valueType="floatType" >
+                    <aapt:attr name="android:interpolator" >
+                        <pathInterpolator android:pathData="M 0.0,0.0 c0.333,0 0.36,1 1.0,1.0" />
+                    </aapt:attr>
+                </objectAnimator>
+                <objectAnimator
+                    android:duration="183"
+                    android:propertyName="scaleX"
+                    android:startOffset="167"
+                    android:valueFrom="0.9500000000000001"
+                    android:valueTo="1.2"
+                    android:valueType="floatType" >
+                    <aapt:attr name="android:interpolator" >
+                        <pathInterpolator android:pathData="M 0.0,0.0 c0.461,0 0.526,1 1.0,1.0" />
+                    </aapt:attr>
+                </objectAnimator>
+                <objectAnimator
+                    android:duration="183"
+                    android:propertyName="scaleY"
+                    android:startOffset="167"
+                    android:valueFrom="0.9500000000000001"
+                    android:valueTo="1.2"
+                    android:valueType="floatType" >
+                    <aapt:attr name="android:interpolator" >
+                        <pathInterpolator android:pathData="M 0.0,0.0 c0.461,0 0.526,1 1.0,1.0" />
+                    </aapt:attr>
+                </objectAnimator>
+                <objectAnimator
+                    android:duration="233"
+                    android:propertyName="scaleX"
+                    android:startOffset="350"
+                    android:valueFrom="1.2"
+                    android:valueTo="1"
+                    android:valueType="floatType" >
+                    <aapt:attr name="android:interpolator" >
+                        <pathInterpolator android:pathData="M 0.0,0.0 c0.428,0 0.532,1 1.0,1.0" />
+                    </aapt:attr>
+                </objectAnimator>
+                <objectAnimator
+                    android:duration="233"
+                    android:propertyName="scaleY"
+                    android:startOffset="350"
+                    android:valueFrom="1.2"
+                    android:valueTo="1"
+                    android:valueType="floatType" >
+                    <aapt:attr name="android:interpolator" >
+                        <pathInterpolator android:pathData="M 0.0,0.0 c0.428,0 0.532,1 1.0,1.0" />
+                    </aapt:attr>
+                </objectAnimator>
+            </set>
+        </aapt:attr>
+    </target>
+    <target android:name="_R_G_L_1_G" >
+        <aapt:attr name="android:animation" >
+            <set android:ordering="together" >
+                <objectAnimator
+                    android:duration="150"
+                    android:propertyName="scaleX"
+                    android:startOffset="0"
+                    android:valueFrom="1"
+                    android:valueTo="1"
+                    android:valueType="floatType" >
+                    <aapt:attr name="android:interpolator" >
+                        <pathInterpolator android:pathData="M 0.0,0.0 c0.613,0 0.396,1 1.0,1.0" />
+                    </aapt:attr>
+                </objectAnimator>
+                <objectAnimator
+                    android:duration="150"
+                    android:propertyName="scaleY"
+                    android:startOffset="0"
+                    android:valueFrom="1"
+                    android:valueTo="1"
+                    android:valueType="floatType" >
+                    <aapt:attr name="android:interpolator" >
+                        <pathInterpolator android:pathData="M 0.0,0.0 c0.613,0 0.396,1 1.0,1.0" />
+                    </aapt:attr>
+                </objectAnimator>
+                <objectAnimator
+                    android:duration="117"
+                    android:propertyName="scaleX"
+                    android:startOffset="150"
+                    android:valueFrom="1"
+                    android:valueTo="0.6"
+                    android:valueType="floatType" >
+                    <aapt:attr name="android:interpolator" >
+                        <pathInterpolator android:pathData="M 0.0,0.0 c0.613,0 0.396,1 1.0,1.0" />
+                    </aapt:attr>
+                </objectAnimator>
+                <objectAnimator
+                    android:duration="117"
+                    android:propertyName="scaleY"
+                    android:startOffset="150"
+                    android:valueFrom="1"
+                    android:valueTo="0.6"
+                    android:valueType="floatType" >
+                    <aapt:attr name="android:interpolator" >
+                        <pathInterpolator android:pathData="M 0.0,0.0 c0.613,0 0.396,1 1.0,1.0" />
+                    </aapt:attr>
+                </objectAnimator>
+                <objectAnimator
+                    android:duration="317"
+                    android:propertyName="scaleX"
+                    android:startOffset="267"
+                    android:valueFrom="0.6"
+                    android:valueTo="1"
+                    android:valueType="floatType" >
+                    <aapt:attr name="android:interpolator" >
+                        <pathInterpolator android:pathData="M 0.0,0.0 c0.429,0 0.613,1 1.0,1.0" />
+                    </aapt:attr>
+                </objectAnimator>
+                <objectAnimator
+                    android:duration="317"
+                    android:propertyName="scaleY"
+                    android:startOffset="267"
+                    android:valueFrom="0.6"
+                    android:valueTo="1"
+                    android:valueType="floatType" >
+                    <aapt:attr name="android:interpolator" >
+                        <pathInterpolator android:pathData="M 0.0,0.0 c0.429,0 0.613,1 1.0,1.0" />
+                    </aapt:attr>
+                </objectAnimator>
+            </set>
+        </aapt:attr>
+    </target>
+    <target android:name="_R_G_L_1_G_N_3_T_0" >
+        <aapt:attr name="android:animation" >
+            <set android:ordering="together" >
+                <objectAnimator
+                    android:duration="83"
+                    android:propertyName="scaleX"
+                    android:startOffset="0"
+                    android:valueFrom="1"
+                    android:valueTo="1"
+                    android:valueType="floatType" >
+                    <aapt:attr name="android:interpolator" >
+                        <pathInterpolator android:pathData="M 0.0,0.0 c0.333,0 0.36,1 1.0,1.0" />
+                    </aapt:attr>
+                </objectAnimator>
+                <objectAnimator
+                    android:duration="83"
+                    android:propertyName="scaleY"
+                    android:startOffset="0"
+                    android:valueFrom="1"
+                    android:valueTo="1"
+                    android:valueType="floatType" >
+                    <aapt:attr name="android:interpolator" >
+                        <pathInterpolator android:pathData="M 0.0,0.0 c0.333,0 0.36,1 1.0,1.0" />
+                    </aapt:attr>
+                </objectAnimator>
+                <objectAnimator
+                    android:duration="83"
+                    android:propertyName="scaleX"
+                    android:startOffset="83"
+                    android:valueFrom="1"
+                    android:valueTo="0.9500000000000001"
+                    android:valueType="floatType" >
+                    <aapt:attr name="android:interpolator" >
+                        <pathInterpolator android:pathData="M 0.0,0.0 c0.333,0 0.36,1 1.0,1.0" />
+                    </aapt:attr>
+                </objectAnimator>
+                <objectAnimator
+                    android:duration="83"
+                    android:propertyName="scaleY"
+                    android:startOffset="83"
+                    android:valueFrom="1"
+                    android:valueTo="0.9500000000000001"
+                    android:valueType="floatType" >
+                    <aapt:attr name="android:interpolator" >
+                        <pathInterpolator android:pathData="M 0.0,0.0 c0.333,0 0.36,1 1.0,1.0" />
+                    </aapt:attr>
+                </objectAnimator>
+                <objectAnimator
+                    android:duration="183"
+                    android:propertyName="scaleX"
+                    android:startOffset="167"
+                    android:valueFrom="0.9500000000000001"
+                    android:valueTo="1.2"
+                    android:valueType="floatType" >
+                    <aapt:attr name="android:interpolator" >
+                        <pathInterpolator android:pathData="M 0.0,0.0 c0.461,0 0.526,1 1.0,1.0" />
+                    </aapt:attr>
+                </objectAnimator>
+                <objectAnimator
+                    android:duration="183"
+                    android:propertyName="scaleY"
+                    android:startOffset="167"
+                    android:valueFrom="0.9500000000000001"
+                    android:valueTo="1.2"
+                    android:valueType="floatType" >
+                    <aapt:attr name="android:interpolator" >
+                        <pathInterpolator android:pathData="M 0.0,0.0 c0.461,0 0.526,1 1.0,1.0" />
+                    </aapt:attr>
+                </objectAnimator>
+                <objectAnimator
+                    android:duration="233"
+                    android:propertyName="scaleX"
+                    android:startOffset="350"
+                    android:valueFrom="1.2"
+                    android:valueTo="1"
+                    android:valueType="floatType" >
+                    <aapt:attr name="android:interpolator" >
+                        <pathInterpolator android:pathData="M 0.0,0.0 c0.428,0 0.532,1 1.0,1.0" />
+                    </aapt:attr>
+                </objectAnimator>
+                <objectAnimator
+                    android:duration="233"
+                    android:propertyName="scaleY"
+                    android:startOffset="350"
+                    android:valueFrom="1.2"
+                    android:valueTo="1"
+                    android:valueType="floatType" >
+                    <aapt:attr name="android:interpolator" >
+                        <pathInterpolator android:pathData="M 0.0,0.0 c0.428,0 0.532,1 1.0,1.0" />
+                    </aapt:attr>
+                </objectAnimator>
+            </set>
+        </aapt:attr>
+    </target>
+    <target android:name="_R_G_L_0_G_D_0_P_0" >
+        <aapt:attr name="android:animation" >
+            <set android:ordering="together" >
+                <objectAnimator
+                    android:duration="83"
+                    android:propertyName="pathData"
+                    android:startOffset="0"
+                    android:valueFrom="M12.42 12.6 C12.42,12.6 12.42,8.17 12.42,8.17 C12.42,5.83 10.48,3.75 8.08,3.75 C5.69,3.75 3.75,5.83 3.75,8.17 C3.75,8.17 3.75,12.6 3.75,12.6 "
+                    android:valueTo="M12.42 12.6 C12.42,12.6 12.42,8.17 12.42,8.17 C12.42,5.83 10.48,3.75 8.08,3.75 C5.69,3.75 3.75,5.83 3.75,8.17 C3.75,8.17 3.75,12.6 3.75,12.6 "
+                    android:valueType="pathType" >
+                    <aapt:attr name="android:interpolator" >
+                        <pathInterpolator android:pathData="M 0.0,0.0 c0.333,0 0.667,1 1.0,1.0" />
+                    </aapt:attr>
+                </objectAnimator>
+                <objectAnimator
+                    android:duration="167"
+                    android:propertyName="pathData"
+                    android:startOffset="83"
+                    android:valueFrom="M12.42 12.6 C12.42,12.6 12.42,8.17 12.42,8.17 C12.42,5.83 10.48,3.75 8.08,3.75 C5.69,3.75 3.75,5.83 3.75,8.17 C3.75,8.17 3.75,12.6 3.75,12.6 "
+                    android:valueTo="M12.39 9.16 C12.39,9.16 12.42,8.17 12.42,8.17 C12.42,5.83 10.48,3.75 8.08,3.75 C5.69,3.75 3.75,5.83 3.75,8.17 C3.75,8.17 3.73,9.16 3.73,9.16 "
+                    android:valueType="pathType" >
+                    <aapt:attr name="android:interpolator" >
+                        <pathInterpolator android:pathData="M 0.0,0.0 c0.333,0 0.667,1 1.0,1.0" />
+                    </aapt:attr>
+                </objectAnimator>
+                <objectAnimator
+                    android:duration="100"
+                    android:propertyName="pathData"
+                    android:startOffset="250"
+                    android:valueFrom="M12.39 9.16 C12.39,9.16 12.42,8.17 12.42,8.17 C12.42,5.83 10.48,3.75 8.08,3.75 C5.69,3.75 3.75,5.83 3.75,8.17 C3.75,8.17 3.73,9.16 3.73,9.16 "
+                    android:valueTo="M12.42 12.6 C12.42,12.6 12.42,8.17 12.42,8.17 C12.42,5.83 10.48,3.75 8.08,3.75 C5.69,3.75 3.75,5.83 3.75,8.17 C3.75,8.17 3.75,12.6 3.75,12.6 "
+                    android:valueType="pathType" >
+                    <aapt:attr name="android:interpolator" >
+                        <pathInterpolator android:pathData="M 0.0,0.0 c0.333,0 0.667,1 1.0,1.0" />
+                    </aapt:attr>
+                </objectAnimator>
+            </set>
+        </aapt:attr>
+    </target>
+    <target android:name="_R_G_L_0_G_T_1" >
+        <aapt:attr name="android:animation" >
+            <set android:ordering="together" >
+                <objectAnimator
+                    android:duration="83"
+                    android:pathData="M 9.583,-3.662C 9.583,-3.03073584985733 9.583,-3.662 9.583,-3.662"
+                    android:propertyName="translateXY"
+                    android:propertyXName="translateX"
+                    android:propertyYName="translateY"
+                    android:startOffset="0" >
+                    <aapt:attr name="android:interpolator" >
+                        <pathInterpolator android:pathData="M 0.0,0.0 c0.333,0 0.667,1 1.0,1.0" />
+                    </aapt:attr>
+                </objectAnimator>
+                <objectAnimator
+                    android:duration="167"
+                    android:pathData="M 9.583,-3.662C 9.583,-3.03073584985733 9.583,0.126 9.583,0.126"
+                    android:propertyName="translateXY"
+                    android:propertyXName="translateX"
+                    android:propertyYName="translateY"
+                    android:startOffset="83" >
+                    <aapt:attr name="android:interpolator" >
+                        <pathInterpolator android:pathData="M 0.0,0.0 c0.333,0 0.667,1 1.0,1.0" />
+                    </aapt:attr>
+                </objectAnimator>
+                <objectAnimator
+                    android:duration="100"
+                    android:pathData="M 9.583,0.126C 9.583,0.126 9.583,-3.03073584985733 9.583,-3.662"
+                    android:propertyName="translateXY"
+                    android:propertyXName="translateX"
+                    android:propertyYName="translateY"
+                    android:startOffset="250" >
+                    <aapt:attr name="android:interpolator" >
+                        <pathInterpolator android:pathData="M 0.0,0.0 c0.333,0 0.667,1 1.0,1.0" />
+                    </aapt:attr>
+                </objectAnimator>
+            </set>
+        </aapt:attr>
+    </target>
+    <target android:name="_R_G_L_0_G_N_3_T_0" >
+        <aapt:attr name="android:animation" >
+            <set android:ordering="together" >
+                <objectAnimator
+                    android:duration="83"
+                    android:propertyName="scaleX"
+                    android:startOffset="0"
+                    android:valueFrom="1"
+                    android:valueTo="1"
+                    android:valueType="floatType" >
+                    <aapt:attr name="android:interpolator" >
+                        <pathInterpolator android:pathData="M 0.0,0.0 c0.333,0 0.36,1 1.0,1.0" />
+                    </aapt:attr>
+                </objectAnimator>
+                <objectAnimator
+                    android:duration="83"
+                    android:propertyName="scaleY"
+                    android:startOffset="0"
+                    android:valueFrom="1"
+                    android:valueTo="1"
+                    android:valueType="floatType" >
+                    <aapt:attr name="android:interpolator" >
+                        <pathInterpolator android:pathData="M 0.0,0.0 c0.333,0 0.36,1 1.0,1.0" />
+                    </aapt:attr>
+                </objectAnimator>
+                <objectAnimator
+                    android:duration="83"
+                    android:propertyName="scaleX"
+                    android:startOffset="83"
+                    android:valueFrom="1"
+                    android:valueTo="0.9500000000000001"
+                    android:valueType="floatType" >
+                    <aapt:attr name="android:interpolator" >
+                        <pathInterpolator android:pathData="M 0.0,0.0 c0.333,0 0.36,1 1.0,1.0" />
+                    </aapt:attr>
+                </objectAnimator>
+                <objectAnimator
+                    android:duration="83"
+                    android:propertyName="scaleY"
+                    android:startOffset="83"
+                    android:valueFrom="1"
+                    android:valueTo="0.9500000000000001"
+                    android:valueType="floatType" >
+                    <aapt:attr name="android:interpolator" >
+                        <pathInterpolator android:pathData="M 0.0,0.0 c0.333,0 0.36,1 1.0,1.0" />
+                    </aapt:attr>
+                </objectAnimator>
+                <objectAnimator
+                    android:duration="183"
+                    android:propertyName="scaleX"
+                    android:startOffset="167"
+                    android:valueFrom="0.9500000000000001"
+                    android:valueTo="1.2"
+                    android:valueType="floatType" >
+                    <aapt:attr name="android:interpolator" >
+                        <pathInterpolator android:pathData="M 0.0,0.0 c0.461,0 0.526,1 1.0,1.0" />
+                    </aapt:attr>
+                </objectAnimator>
+                <objectAnimator
+                    android:duration="183"
+                    android:propertyName="scaleY"
+                    android:startOffset="167"
+                    android:valueFrom="0.9500000000000001"
+                    android:valueTo="1.2"
+                    android:valueType="floatType" >
+                    <aapt:attr name="android:interpolator" >
+                        <pathInterpolator android:pathData="M 0.0,0.0 c0.461,0 0.526,1 1.0,1.0" />
+                    </aapt:attr>
+                </objectAnimator>
+                <objectAnimator
+                    android:duration="233"
+                    android:propertyName="scaleX"
+                    android:startOffset="350"
+                    android:valueFrom="1.2"
+                    android:valueTo="1"
+                    android:valueType="floatType" >
+                    <aapt:attr name="android:interpolator" >
+                        <pathInterpolator android:pathData="M 0.0,0.0 c0.428,0 0.532,1 1.0,1.0" />
+                    </aapt:attr>
+                </objectAnimator>
+                <objectAnimator
+                    android:duration="233"
+                    android:propertyName="scaleY"
+                    android:startOffset="350"
+                    android:valueFrom="1.2"
+                    android:valueTo="1"
+                    android:valueType="floatType" >
+                    <aapt:attr name="android:interpolator" >
+                        <pathInterpolator android:pathData="M 0.0,0.0 c0.428,0 0.532,1 1.0,1.0" />
+                    </aapt:attr>
+                </objectAnimator>
+            </set>
+        </aapt:attr>
+    </target>
+    <target android:name="time_group" >
+        <aapt:attr name="android:animation" >
+            <set android:ordering="together" >
+                <objectAnimator
+                    android:duration="717"
+                    android:propertyName="translateX"
+                    android:startOffset="0"
+                    android:valueFrom="0"
+                    android:valueTo="1"
+                    android:valueType="floatType" />
+            </set>
+        </aapt:attr>
+    </target>
+
+</animated-vector>
\ No newline at end of file
diff --git a/packages/SystemUI/res/anim/lock_scanning_filled.xml b/packages/SystemUI/res/anim/lock_scanning_filled.xml
new file mode 100644
index 0000000..83ac8ad
--- /dev/null
+++ b/packages/SystemUI/res/anim/lock_scanning_filled.xml
@@ -0,0 +1,339 @@
+<?xml version="1.0" encoding="utf-8"?>
+<animated-vector xmlns:aapt="http://schemas.android.com/aapt"
+    xmlns:android="http://schemas.android.com/apk/res/android" >
+
+    <aapt:attr name="android:drawable" >
+        <vector
+            android:height="42dp"
+            android:viewportHeight="42"
+            android:viewportWidth="32"
+            android:width="32dp" >
+            <group android:name="_R_G" >
+                <group
+                    android:name="_R_G_L_1_G"
+                    android:pivotX="10.917"
+                    android:pivotY="9.583"
+                    android:scaleX="1"
+                    android:scaleY="1"
+                    android:translateX="5.083"
+                    android:translateY="15.417" >
+                    <path
+                        android:name="_R_G_L_1_G_D_0_P_0"
+                        android:fillAlpha="1"
+                        android:fillColor="#ffffff"
+                        android:fillType="nonZero"
+                        android:pathData=" M18.92 0.25 C18.92,0.25 2.92,0.25 2.92,0.25 C1.45,0.25 0.25,1.45 0.25,2.92 C0.25,2.92 0.25,16.25 0.25,16.25 C0.25,17.72 1.45,18.92 2.92,18.92 C2.92,18.92 18.92,18.92 18.92,18.92 C20.38,18.92 21.58,17.72 21.58,16.25 C21.58,16.25 21.58,2.92 21.58,2.92 C21.58,1.45 20.38,0.25 18.92,0.25c  M10.92 12.25 C9.45,12.25 8.25,11.05 8.25,9.58 C8.25,8.12 9.45,6.92 10.92,6.92 C12.38,6.92 13.58,8.12 13.58,9.58 C13.58,11.05 12.38,12.25 10.92,12.25c " />
+                </group>
+                <group
+                    android:name="_R_G_L_0_G_N_2_T_0"
+                    android:pivotX="10.917"
+                    android:pivotY="9.583"
+                    android:scaleX="1"
+                    android:scaleY="1"
+                    android:translateX="5.083"
+                    android:translateY="15.417" >
+                    <group
+                        android:name="_R_G_L_0_G_T_1"
+                        android:translateX="10.917"
+                        android:translateY="-3.75" >
+                        <group
+                            android:name="_R_G_L_0_G"
+                            android:translateX="-9"
+                            android:translateY="-9" >
+                            <path
+                                android:name="_R_G_L_0_G_D_0_P_0"
+                                android:pathData=" M13 13 C13,13 13,9 13,9 C13,6.79 11.21,5 9,5 C6.79,5 5,6.79 5,9 C5,9 5,13 5,13 "
+                                android:strokeAlpha="1"
+                                android:strokeColor="#ffffff"
+                                android:strokeLineCap="round"
+                                android:strokeLineJoin="round"
+                                android:strokeWidth="2" />
+                        </group>
+                    </group>
+                </group>
+            </group>
+            <group android:name="time_group" />
+        </vector>
+    </aapt:attr>
+
+    <target android:name="_R_G_L_1_G_D_0_P_0" >
+        <aapt:attr name="android:animation" >
+            <set android:ordering="together" >
+                <objectAnimator
+                    android:duration="150"
+                    android:propertyName="pathData"
+                    android:startOffset="0"
+                    android:valueFrom=" M18.92 0.25 C18.92,0.25 2.92,0.25 2.92,0.25 C1.45,0.25 0.25,1.45 0.25,2.92 C0.25,2.92 0.25,16.25 0.25,16.25 C0.25,17.72 1.45,18.92 2.92,18.92 C2.92,18.92 18.92,18.92 18.92,18.92 C20.38,18.92 21.58,17.72 21.58,16.25 C21.58,16.25 21.58,2.92 21.58,2.92 C21.58,1.45 20.38,0.25 18.92,0.25c M10.92 12.25 C9.45,12.25 8.25,11.05 8.25,9.58 C8.25,8.12 9.45,6.92 10.92,6.92 C12.38,6.92 13.58,8.12 13.58,9.58 C13.58,11.05 12.38,12.25 10.92,12.25c "
+                    android:valueTo=" M18.92 0.25 C18.92,0.25 2.92,0.25 2.92,0.25 C1.45,0.25 0.25,1.45 0.25,2.92 C0.25,2.92 0.25,16.25 0.25,16.25 C0.25,17.72 1.45,18.92 2.92,18.92 C2.92,18.92 18.92,18.92 18.92,18.92 C20.38,18.92 21.58,17.72 21.58,16.25 C21.58,16.25 21.58,2.92 21.58,2.92 C21.58,1.45 20.38,0.25 18.92,0.25c M10.92 12.25 C9.45,12.25 8.25,11.05 8.25,9.58 C8.25,8.12 9.45,6.92 10.92,6.92 C12.38,6.92 13.58,8.12 13.58,9.58 C13.58,11.05 12.38,12.25 10.92,12.25c "
+                    android:valueType="pathType" >
+                    <aapt:attr name="android:interpolator" >
+                        <pathInterpolator android:pathData="M 0.0,0.0 c0.333,0 0.667,1 1.0,1.0" />
+                    </aapt:attr>
+                </objectAnimator>
+                <objectAnimator
+                    android:duration="117"
+                    android:propertyName="pathData"
+                    android:startOffset="150"
+                    android:valueFrom=" M18.92 0.25 C18.92,0.25 2.92,0.25 2.92,0.25 C1.45,0.25 0.25,1.45 0.25,2.92 C0.25,2.92 0.25,16.25 0.25,16.25 C0.25,17.72 1.45,18.92 2.92,18.92 C2.92,18.92 18.92,18.92 18.92,18.92 C20.38,18.92 21.58,17.72 21.58,16.25 C21.58,16.25 21.58,2.92 21.58,2.92 C21.58,1.45 20.38,0.25 18.92,0.25c M10.92 12.25 C9.45,12.25 8.25,11.05 8.25,9.58 C8.25,8.12 9.45,6.92 10.92,6.92 C12.38,6.92 13.58,8.12 13.58,9.58 C13.58,11.05 12.38,12.25 10.92,12.25c "
+                    android:valueTo=" M18.92 0.25 C18.92,0.25 2.92,0.25 2.92,0.25 C1.45,0.25 0.25,1.45 0.25,2.92 C0.25,2.92 0.25,16.25 0.25,16.25 C0.25,17.72 1.45,18.92 2.92,18.92 C2.92,18.92 18.92,18.92 18.92,18.92 C20.38,18.92 21.58,17.72 21.58,16.25 C21.58,16.25 21.58,2.92 21.58,2.92 C21.58,1.45 20.38,0.25 18.92,0.25c M10.92 11.4 C9.91,11.4 9.1,10.59 9.1,9.58 C9.1,8.58 9.91,7.76 10.92,7.76 C11.92,7.76 12.74,8.58 12.74,9.58 C12.74,10.59 11.92,11.4 10.92,11.4c "
+                    android:valueType="pathType" >
+                    <aapt:attr name="android:interpolator" >
+                        <pathInterpolator android:pathData="M 0.0,0.0 c0.333,0 0.667,1 1.0,1.0" />
+                    </aapt:attr>
+                </objectAnimator>
+                <objectAnimator
+                    android:duration="317"
+                    android:propertyName="pathData"
+                    android:startOffset="267"
+                    android:valueFrom=" M18.92 0.25 C18.92,0.25 2.92,0.25 2.92,0.25 C1.45,0.25 0.25,1.45 0.25,2.92 C0.25,2.92 0.25,16.25 0.25,16.25 C0.25,17.72 1.45,18.92 2.92,18.92 C2.92,18.92 18.92,18.92 18.92,18.92 C20.38,18.92 21.58,17.72 21.58,16.25 C21.58,16.25 21.58,2.92 21.58,2.92 C21.58,1.45 20.38,0.25 18.92,0.25c M10.92 11.4 C9.91,11.4 9.1,10.59 9.1,9.58 C9.1,8.58 9.91,7.76 10.92,7.76 C11.92,7.76 12.74,8.58 12.74,9.58 C12.74,10.59 11.92,11.4 10.92,11.4c "
+                    android:valueTo=" M18.92 0.25 C18.92,0.25 2.92,0.25 2.92,0.25 C1.45,0.25 0.25,1.45 0.25,2.92 C0.25,2.92 0.25,16.25 0.25,16.25 C0.25,17.72 1.45,18.92 2.92,18.92 C2.92,18.92 18.92,18.92 18.92,18.92 C20.38,18.92 21.58,17.72 21.58,16.25 C21.58,16.25 21.58,2.92 21.58,2.92 C21.58,1.45 20.38,0.25 18.92,0.25c M10.92 12.25 C9.45,12.25 8.25,11.05 8.25,9.58 C8.25,8.12 9.45,6.92 10.92,6.92 C12.38,6.92 13.58,8.12 13.58,9.58 C13.58,11.05 12.38,12.25 10.92,12.25c "
+                    android:valueType="pathType" >
+                    <aapt:attr name="android:interpolator" >
+                        <pathInterpolator android:pathData="M 0.0,0.0 c0.333,0 0.667,1 1.0,1.0" />
+                    </aapt:attr>
+                </objectAnimator>
+            </set>
+        </aapt:attr>
+    </target>
+    <target android:name="_R_G_L_1_G" >
+        <aapt:attr name="android:animation" >
+            <set android:ordering="together" >
+                <objectAnimator
+                    android:duration="83"
+                    android:propertyName="scaleX"
+                    android:startOffset="0"
+                    android:valueFrom="1"
+                    android:valueTo="1"
+                    android:valueType="floatType" >
+                    <aapt:attr name="android:interpolator" >
+                        <pathInterpolator android:pathData="M 0.0,0.0 c0.333,0 0.36,1 1.0,1.0" />
+                    </aapt:attr>
+                </objectAnimator>
+                <objectAnimator
+                    android:duration="83"
+                    android:propertyName="scaleY"
+                    android:startOffset="0"
+                    android:valueFrom="1"
+                    android:valueTo="1"
+                    android:valueType="floatType" >
+                    <aapt:attr name="android:interpolator" >
+                        <pathInterpolator android:pathData="M 0.0,0.0 c0.333,0 0.36,1 1.0,1.0" />
+                    </aapt:attr>
+                </objectAnimator>
+                <objectAnimator
+                    android:duration="83"
+                    android:propertyName="scaleX"
+                    android:startOffset="83"
+                    android:valueFrom="1"
+                    android:valueTo="0.9500000000000001"
+                    android:valueType="floatType" >
+                    <aapt:attr name="android:interpolator" >
+                        <pathInterpolator android:pathData="M 0.0,0.0 c0.333,0 0.36,1 1.0,1.0" />
+                    </aapt:attr>
+                </objectAnimator>
+                <objectAnimator
+                    android:duration="83"
+                    android:propertyName="scaleY"
+                    android:startOffset="83"
+                    android:valueFrom="1"
+                    android:valueTo="0.9500000000000001"
+                    android:valueType="floatType" >
+                    <aapt:attr name="android:interpolator" >
+                        <pathInterpolator android:pathData="M 0.0,0.0 c0.333,0 0.36,1 1.0,1.0" />
+                    </aapt:attr>
+                </objectAnimator>
+                <objectAnimator
+                    android:duration="183"
+                    android:propertyName="scaleX"
+                    android:startOffset="167"
+                    android:valueFrom="0.9500000000000001"
+                    android:valueTo="1.2"
+                    android:valueType="floatType" >
+                    <aapt:attr name="android:interpolator" >
+                        <pathInterpolator android:pathData="M 0.0,0.0 c0.461,0 0.526,1 1.0,1.0" />
+                    </aapt:attr>
+                </objectAnimator>
+                <objectAnimator
+                    android:duration="183"
+                    android:propertyName="scaleY"
+                    android:startOffset="167"
+                    android:valueFrom="0.9500000000000001"
+                    android:valueTo="1.2"
+                    android:valueType="floatType" >
+                    <aapt:attr name="android:interpolator" >
+                        <pathInterpolator android:pathData="M 0.0,0.0 c0.461,0 0.526,1 1.0,1.0" />
+                    </aapt:attr>
+                </objectAnimator>
+                <objectAnimator
+                    android:duration="233"
+                    android:propertyName="scaleX"
+                    android:startOffset="350"
+                    android:valueFrom="1.2"
+                    android:valueTo="1"
+                    android:valueType="floatType" >
+                    <aapt:attr name="android:interpolator" >
+                        <pathInterpolator android:pathData="M 0.0,0.0 c0.428,0 0.532,1 1.0,1.0" />
+                    </aapt:attr>
+                </objectAnimator>
+                <objectAnimator
+                    android:duration="233"
+                    android:propertyName="scaleY"
+                    android:startOffset="350"
+                    android:valueFrom="1.2"
+                    android:valueTo="1"
+                    android:valueType="floatType" >
+                    <aapt:attr name="android:interpolator" >
+                        <pathInterpolator android:pathData="M 0.0,0.0 c0.428,0 0.532,1 1.0,1.0" />
+                    </aapt:attr>
+                </objectAnimator>
+            </set>
+        </aapt:attr>
+    </target>
+    <target android:name="_R_G_L_0_G_T_1" >
+        <aapt:attr name="android:animation" >
+            <set android:ordering="together" >
+                <objectAnimator
+                    android:duration="83"
+                    android:pathData="M 10.917,-3.75C 10.917,-3.13846284151077 10.917,-3.75 10.917,-3.75"
+                    android:propertyName="translateXY"
+                    android:propertyXName="translateX"
+                    android:propertyYName="translateY"
+                    android:startOffset="0" >
+                    <aapt:attr name="android:interpolator" >
+                        <pathInterpolator android:pathData="M 0.0,0.0 c0.333,0 0.667,1 1.0,1.0" />
+                    </aapt:attr>
+                </objectAnimator>
+                <objectAnimator
+                    android:duration="167"
+                    android:pathData="M 10.917,-3.75C 10.917,-3.13846284151077 10.917,-0.081 10.917,-0.081"
+                    android:propertyName="translateXY"
+                    android:propertyXName="translateX"
+                    android:propertyYName="translateY"
+                    android:startOffset="83" >
+                    <aapt:attr name="android:interpolator" >
+                        <pathInterpolator android:pathData="M 0.0,0.0 c0.333,0 0.667,1 1.0,1.0" />
+                    </aapt:attr>
+                </objectAnimator>
+                <objectAnimator
+                    android:duration="100"
+                    android:pathData="M 10.917,-0.081C 10.917,-0.081 10.917,-3.13846284151077 10.917,-3.75"
+                    android:propertyName="translateXY"
+                    android:propertyXName="translateX"
+                    android:propertyYName="translateY"
+                    android:startOffset="250" >
+                    <aapt:attr name="android:interpolator" >
+                        <pathInterpolator android:pathData="M 0.0,0.0 c0.333,0 0.667,1 1.0,1.0" />
+                    </aapt:attr>
+                </objectAnimator>
+            </set>
+        </aapt:attr>
+    </target>
+    <target android:name="_R_G_L_0_G_N_2_T_0" >
+        <aapt:attr name="android:animation" >
+            <set android:ordering="together" >
+                <objectAnimator
+                    android:duration="83"
+                    android:propertyName="scaleX"
+                    android:startOffset="0"
+                    android:valueFrom="1"
+                    android:valueTo="1"
+                    android:valueType="floatType" >
+                    <aapt:attr name="android:interpolator" >
+                        <pathInterpolator android:pathData="M 0.0,0.0 c0.333,0 0.36,1 1.0,1.0" />
+                    </aapt:attr>
+                </objectAnimator>
+                <objectAnimator
+                    android:duration="83"
+                    android:propertyName="scaleY"
+                    android:startOffset="0"
+                    android:valueFrom="1"
+                    android:valueTo="1"
+                    android:valueType="floatType" >
+                    <aapt:attr name="android:interpolator" >
+                        <pathInterpolator android:pathData="M 0.0,0.0 c0.333,0 0.36,1 1.0,1.0" />
+                    </aapt:attr>
+                </objectAnimator>
+                <objectAnimator
+                    android:duration="83"
+                    android:propertyName="scaleX"
+                    android:startOffset="83"
+                    android:valueFrom="1"
+                    android:valueTo="0.9500000000000001"
+                    android:valueType="floatType" >
+                    <aapt:attr name="android:interpolator" >
+                        <pathInterpolator android:pathData="M 0.0,0.0 c0.333,0 0.36,1 1.0,1.0" />
+                    </aapt:attr>
+                </objectAnimator>
+                <objectAnimator
+                    android:duration="83"
+                    android:propertyName="scaleY"
+                    android:startOffset="83"
+                    android:valueFrom="1"
+                    android:valueTo="0.9500000000000001"
+                    android:valueType="floatType" >
+                    <aapt:attr name="android:interpolator" >
+                        <pathInterpolator android:pathData="M 0.0,0.0 c0.333,0 0.36,1 1.0,1.0" />
+                    </aapt:attr>
+                </objectAnimator>
+                <objectAnimator
+                    android:duration="183"
+                    android:propertyName="scaleX"
+                    android:startOffset="167"
+                    android:valueFrom="0.9500000000000001"
+                    android:valueTo="1.2"
+                    android:valueType="floatType" >
+                    <aapt:attr name="android:interpolator" >
+                        <pathInterpolator android:pathData="M 0.0,0.0 c0.461,0 0.526,1 1.0,1.0" />
+                    </aapt:attr>
+                </objectAnimator>
+                <objectAnimator
+                    android:duration="183"
+                    android:propertyName="scaleY"
+                    android:startOffset="167"
+                    android:valueFrom="0.9500000000000001"
+                    android:valueTo="1.2"
+                    android:valueType="floatType" >
+                    <aapt:attr name="android:interpolator" >
+                        <pathInterpolator android:pathData="M 0.0,0.0 c0.461,0 0.526,1 1.0,1.0" />
+                    </aapt:attr>
+                </objectAnimator>
+                <objectAnimator
+                    android:duration="233"
+                    android:propertyName="scaleX"
+                    android:startOffset="350"
+                    android:valueFrom="1.2"
+                    android:valueTo="1"
+                    android:valueType="floatType" >
+                    <aapt:attr name="android:interpolator" >
+                        <pathInterpolator android:pathData="M 0.0,0.0 c0.428,0 0.532,1 1.0,1.0" />
+                    </aapt:attr>
+                </objectAnimator>
+                <objectAnimator
+                    android:duration="233"
+                    android:propertyName="scaleY"
+                    android:startOffset="350"
+                    android:valueFrom="1.2"
+                    android:valueTo="1"
+                    android:valueType="floatType" >
+                    <aapt:attr name="android:interpolator" >
+                        <pathInterpolator android:pathData="M 0.0,0.0 c0.428,0 0.532,1 1.0,1.0" />
+                    </aapt:attr>
+                </objectAnimator>
+            </set>
+        </aapt:attr>
+    </target>
+    <target android:name="time_group" >
+        <aapt:attr name="android:animation" >
+            <set android:ordering="together" >
+                <objectAnimator
+                    android:duration="717"
+                    android:propertyName="translateX"
+                    android:startOffset="0"
+                    android:valueFrom="0"
+                    android:valueTo="1"
+                    android:valueType="floatType" />
+            </set>
+        </aapt:attr>
+    </target>
+
+</animated-vector>
\ No newline at end of file
diff --git a/packages/SystemUI/res/anim/lock_scanning_rounded.xml b/packages/SystemUI/res/anim/lock_scanning_rounded.xml
new file mode 100644
index 0000000..9835492
--- /dev/null
+++ b/packages/SystemUI/res/anim/lock_scanning_rounded.xml
@@ -0,0 +1,531 @@
+<?xml version="1.0" encoding="utf-8"?>
+<animated-vector xmlns:aapt="http://schemas.android.com/aapt"
+    xmlns:android="http://schemas.android.com/apk/res/android" >
+
+    <aapt:attr name="android:drawable" >
+        <vector
+            android:height="38dp"
+            android:viewportHeight="38"
+            android:viewportWidth="32"
+            android:width="32dp" >
+            <group android:name="_R_G" >
+                <group
+                    android:name="_R_G_L_2_G"
+                    android:pivotX="14.667"
+                    android:pivotY="12.667"
+                    android:scaleX="1"
+                    android:scaleY="1"
+                    android:translateX="1.3330000000000002"
+                    android:translateY="10.333" >
+                    <path
+                        android:name="_R_G_L_2_G_D_0_P_0"
+                        android:pathData=" M22.09 5 C22.09,5 6,5 6,5 C5.45,5 5,5.45 5,6 C5,6 5,19.33 5,19.33 C5,19.89 5.45,20.33 6,20.33 C6,20.33 23.33,20.33 23.33,20.33 C23.89,20.33 24.33,19.89 24.33,19.33 C24.33,19.33 24.33,6 24.33,6 C24.33,5.45 23.89,5 23.33,5 C23.33,5 22.09,5 22.09,5c "
+                        android:strokeAlpha="1"
+                        android:strokeColor="#ffffff"
+                        android:strokeLineCap="round"
+                        android:strokeLineJoin="round"
+                        android:strokeWidth="1.5" />
+                </group>
+                <group
+                    android:name="_R_G_L_1_G_N_4_T_0"
+                    android:pivotX="14.667"
+                    android:pivotY="12.667"
+                    android:scaleX="1"
+                    android:scaleY="1"
+                    android:translateX="1.3330000000000002"
+                    android:translateY="10.333" >
+                    <group
+                        android:name="_R_G_L_1_G"
+                        android:pivotX="2.25"
+                        android:pivotY="2.25"
+                        android:scaleX="1"
+                        android:scaleY="1"
+                        android:translateX="12.416"
+                        android:translateY="10.417" >
+                        <path
+                            android:name="_R_G_L_1_G_D_0_P_0"
+                            android:fillAlpha="1"
+                            android:fillColor="#ffffff"
+                            android:fillType="nonZero"
+                            android:pathData=" M2.25 0.25 C3.35,0.25 4.25,1.15 4.25,2.25 C4.25,3.35 3.35,4.25 2.25,4.25 C1.15,4.25 0.25,3.35 0.25,2.25 C0.25,1.15 1.15,0.25 2.25,0.25c " />
+                    </group>
+                </group>
+                <group
+                    android:name="_R_G_L_0_G_N_4_T_0"
+                    android:pivotX="14.667"
+                    android:pivotY="12.667"
+                    android:scaleX="1"
+                    android:scaleY="1"
+                    android:translateX="1.3330000000000002"
+                    android:translateY="10.333" >
+                    <group
+                        android:name="_R_G_L_0_G_T_1"
+                        android:translateX="14.666"
+                        android:translateY="0.287" >
+                        <group
+                            android:name="_R_G_L_0_G"
+                            android:translateX="-9.333"
+                            android:translateY="-9.713" >
+                            <path
+                                android:name="_R_G_L_0_G_D_0_P_0"
+                                android:pathData=" M13.67 13.8 C13.67,13.8 13.67,8.94 13.67,8.94 C13.63,6.75 11.69,5 9.33,5.04 C6.98,5 5.04,6.75 5,8.94 C5,8.94 5,13.8 5,13.8 "
+                                android:strokeAlpha="1"
+                                android:strokeColor="#ffffff"
+                                android:strokeLineCap="round"
+                                android:strokeLineJoin="round"
+                                android:strokeWidth="1.5" />
+                        </group>
+                    </group>
+                </group>
+            </group>
+            <group android:name="time_group" />
+        </vector>
+    </aapt:attr>
+
+    <target android:name="_R_G_L_2_G" >
+        <aapt:attr name="android:animation" >
+            <set android:ordering="together" >
+                <objectAnimator
+                    android:duration="83"
+                    android:propertyName="scaleX"
+                    android:startOffset="0"
+                    android:valueFrom="1"
+                    android:valueTo="1"
+                    android:valueType="floatType" >
+                    <aapt:attr name="android:interpolator" >
+                        <pathInterpolator android:pathData="M 0.0,0.0 c0.333,0 0.36,1 1.0,1.0" />
+                    </aapt:attr>
+                </objectAnimator>
+                <objectAnimator
+                    android:duration="83"
+                    android:propertyName="scaleY"
+                    android:startOffset="0"
+                    android:valueFrom="1"
+                    android:valueTo="1"
+                    android:valueType="floatType" >
+                    <aapt:attr name="android:interpolator" >
+                        <pathInterpolator android:pathData="M 0.0,0.0 c0.333,0 0.36,1 1.0,1.0" />
+                    </aapt:attr>
+                </objectAnimator>
+                <objectAnimator
+                    android:duration="83"
+                    android:propertyName="scaleX"
+                    android:startOffset="83"
+                    android:valueFrom="1"
+                    android:valueTo="0.9500000000000001"
+                    android:valueType="floatType" >
+                    <aapt:attr name="android:interpolator" >
+                        <pathInterpolator android:pathData="M 0.0,0.0 c0.333,0 0.36,1 1.0,1.0" />
+                    </aapt:attr>
+                </objectAnimator>
+                <objectAnimator
+                    android:duration="83"
+                    android:propertyName="scaleY"
+                    android:startOffset="83"
+                    android:valueFrom="1"
+                    android:valueTo="0.9500000000000001"
+                    android:valueType="floatType" >
+                    <aapt:attr name="android:interpolator" >
+                        <pathInterpolator android:pathData="M 0.0,0.0 c0.333,0 0.36,1 1.0,1.0" />
+                    </aapt:attr>
+                </objectAnimator>
+                <objectAnimator
+                    android:duration="183"
+                    android:propertyName="scaleX"
+                    android:startOffset="167"
+                    android:valueFrom="0.9500000000000001"
+                    android:valueTo="1.2"
+                    android:valueType="floatType" >
+                    <aapt:attr name="android:interpolator" >
+                        <pathInterpolator android:pathData="M 0.0,0.0 c0.461,0 0.526,1 1.0,1.0" />
+                    </aapt:attr>
+                </objectAnimator>
+                <objectAnimator
+                    android:duration="183"
+                    android:propertyName="scaleY"
+                    android:startOffset="167"
+                    android:valueFrom="0.9500000000000001"
+                    android:valueTo="1.2"
+                    android:valueType="floatType" >
+                    <aapt:attr name="android:interpolator" >
+                        <pathInterpolator android:pathData="M 0.0,0.0 c0.461,0 0.526,1 1.0,1.0" />
+                    </aapt:attr>
+                </objectAnimator>
+                <objectAnimator
+                    android:duration="233"
+                    android:propertyName="scaleX"
+                    android:startOffset="350"
+                    android:valueFrom="1.2"
+                    android:valueTo="1"
+                    android:valueType="floatType" >
+                    <aapt:attr name="android:interpolator" >
+                        <pathInterpolator android:pathData="M 0.0,0.0 c0.428,0 0.397,1 1.0,1.0" />
+                    </aapt:attr>
+                </objectAnimator>
+                <objectAnimator
+                    android:duration="233"
+                    android:propertyName="scaleY"
+                    android:startOffset="350"
+                    android:valueFrom="1.2"
+                    android:valueTo="1"
+                    android:valueType="floatType" >
+                    <aapt:attr name="android:interpolator" >
+                        <pathInterpolator android:pathData="M 0.0,0.0 c0.428,0 0.397,1 1.0,1.0" />
+                    </aapt:attr>
+                </objectAnimator>
+            </set>
+        </aapt:attr>
+    </target>
+    <target android:name="_R_G_L_1_G" >
+        <aapt:attr name="android:animation" >
+            <set android:ordering="together" >
+                <objectAnimator
+                    android:duration="150"
+                    android:propertyName="scaleX"
+                    android:startOffset="0"
+                    android:valueFrom="1"
+                    android:valueTo="1"
+                    android:valueType="floatType" >
+                    <aapt:attr name="android:interpolator" >
+                        <pathInterpolator android:pathData="M 0.0,0.0 c0.333,0 0.667,1 1.0,1.0" />
+                    </aapt:attr>
+                </objectAnimator>
+                <objectAnimator
+                    android:duration="150"
+                    android:propertyName="scaleY"
+                    android:startOffset="0"
+                    android:valueFrom="1"
+                    android:valueTo="1"
+                    android:valueType="floatType" >
+                    <aapt:attr name="android:interpolator" >
+                        <pathInterpolator android:pathData="M 0.0,0.0 c0.333,0 0.667,1 1.0,1.0" />
+                    </aapt:attr>
+                </objectAnimator>
+                <objectAnimator
+                    android:duration="117"
+                    android:propertyName="scaleX"
+                    android:startOffset="150"
+                    android:valueFrom="1"
+                    android:valueTo="0.8"
+                    android:valueType="floatType" >
+                    <aapt:attr name="android:interpolator" >
+                        <pathInterpolator android:pathData="M 0.0,0.0 c0.333,0 0.667,1 1.0,1.0" />
+                    </aapt:attr>
+                </objectAnimator>
+                <objectAnimator
+                    android:duration="117"
+                    android:propertyName="scaleY"
+                    android:startOffset="150"
+                    android:valueFrom="1"
+                    android:valueTo="0.8"
+                    android:valueType="floatType" >
+                    <aapt:attr name="android:interpolator" >
+                        <pathInterpolator android:pathData="M 0.0,0.0 c0.333,0 0.667,1 1.0,1.0" />
+                    </aapt:attr>
+                </objectAnimator>
+                <objectAnimator
+                    android:duration="317"
+                    android:propertyName="scaleX"
+                    android:startOffset="267"
+                    android:valueFrom="0.8"
+                    android:valueTo="1"
+                    android:valueType="floatType" >
+                    <aapt:attr name="android:interpolator" >
+                        <pathInterpolator android:pathData="M 0.0,0.0 c0.333,0 0.667,1 1.0,1.0" />
+                    </aapt:attr>
+                </objectAnimator>
+                <objectAnimator
+                    android:duration="317"
+                    android:propertyName="scaleY"
+                    android:startOffset="267"
+                    android:valueFrom="0.8"
+                    android:valueTo="1"
+                    android:valueType="floatType" >
+                    <aapt:attr name="android:interpolator" >
+                        <pathInterpolator android:pathData="M 0.0,0.0 c0.333,0 0.667,1 1.0,1.0" />
+                    </aapt:attr>
+                </objectAnimator>
+            </set>
+        </aapt:attr>
+    </target>
+    <target android:name="_R_G_L_1_G_N_4_T_0" >
+        <aapt:attr name="android:animation" >
+            <set android:ordering="together" >
+                <objectAnimator
+                    android:duration="83"
+                    android:propertyName="scaleX"
+                    android:startOffset="0"
+                    android:valueFrom="1"
+                    android:valueTo="1"
+                    android:valueType="floatType" >
+                    <aapt:attr name="android:interpolator" >
+                        <pathInterpolator android:pathData="M 0.0,0.0 c0.333,0 0.36,1 1.0,1.0" />
+                    </aapt:attr>
+                </objectAnimator>
+                <objectAnimator
+                    android:duration="83"
+                    android:propertyName="scaleY"
+                    android:startOffset="0"
+                    android:valueFrom="1"
+                    android:valueTo="1"
+                    android:valueType="floatType" >
+                    <aapt:attr name="android:interpolator" >
+                        <pathInterpolator android:pathData="M 0.0,0.0 c0.333,0 0.36,1 1.0,1.0" />
+                    </aapt:attr>
+                </objectAnimator>
+                <objectAnimator
+                    android:duration="83"
+                    android:propertyName="scaleX"
+                    android:startOffset="83"
+                    android:valueFrom="1"
+                    android:valueTo="0.9500000000000001"
+                    android:valueType="floatType" >
+                    <aapt:attr name="android:interpolator" >
+                        <pathInterpolator android:pathData="M 0.0,0.0 c0.333,0 0.36,1 1.0,1.0" />
+                    </aapt:attr>
+                </objectAnimator>
+                <objectAnimator
+                    android:duration="83"
+                    android:propertyName="scaleY"
+                    android:startOffset="83"
+                    android:valueFrom="1"
+                    android:valueTo="0.9500000000000001"
+                    android:valueType="floatType" >
+                    <aapt:attr name="android:interpolator" >
+                        <pathInterpolator android:pathData="M 0.0,0.0 c0.333,0 0.36,1 1.0,1.0" />
+                    </aapt:attr>
+                </objectAnimator>
+                <objectAnimator
+                    android:duration="183"
+                    android:propertyName="scaleX"
+                    android:startOffset="167"
+                    android:valueFrom="0.9500000000000001"
+                    android:valueTo="1.2"
+                    android:valueType="floatType" >
+                    <aapt:attr name="android:interpolator" >
+                        <pathInterpolator android:pathData="M 0.0,0.0 c0.461,0 0.526,1 1.0,1.0" />
+                    </aapt:attr>
+                </objectAnimator>
+                <objectAnimator
+                    android:duration="183"
+                    android:propertyName="scaleY"
+                    android:startOffset="167"
+                    android:valueFrom="0.9500000000000001"
+                    android:valueTo="1.2"
+                    android:valueType="floatType" >
+                    <aapt:attr name="android:interpolator" >
+                        <pathInterpolator android:pathData="M 0.0,0.0 c0.461,0 0.526,1 1.0,1.0" />
+                    </aapt:attr>
+                </objectAnimator>
+                <objectAnimator
+                    android:duration="233"
+                    android:propertyName="scaleX"
+                    android:startOffset="350"
+                    android:valueFrom="1.2"
+                    android:valueTo="1"
+                    android:valueType="floatType" >
+                    <aapt:attr name="android:interpolator" >
+                        <pathInterpolator android:pathData="M 0.0,0.0 c0.428,0 0.397,1 1.0,1.0" />
+                    </aapt:attr>
+                </objectAnimator>
+                <objectAnimator
+                    android:duration="233"
+                    android:propertyName="scaleY"
+                    android:startOffset="350"
+                    android:valueFrom="1.2"
+                    android:valueTo="1"
+                    android:valueType="floatType" >
+                    <aapt:attr name="android:interpolator" >
+                        <pathInterpolator android:pathData="M 0.0,0.0 c0.428,0 0.397,1 1.0,1.0" />
+                    </aapt:attr>
+                </objectAnimator>
+            </set>
+        </aapt:attr>
+    </target>
+    <target android:name="_R_G_L_0_G_D_0_P_0" >
+        <aapt:attr name="android:animation" >
+            <set android:ordering="together" >
+                <objectAnimator
+                    android:duration="83"
+                    android:propertyName="pathData"
+                    android:startOffset="0"
+                    android:valueFrom="M13.67 13.8 C13.67,13.8 13.67,8.94 13.67,8.94 C13.63,6.75 11.69,5 9.33,5.04 C6.98,5 5.04,6.75 5,8.94 C5,8.94 5,13.8 5,13.8 "
+                    android:valueTo="M13.67 13.8 C13.67,13.8 13.67,8.94 13.67,8.94 C13.63,6.75 11.69,5 9.33,5.04 C6.98,5 5.04,6.75 5,8.94 C5,8.94 5,13.8 5,13.8 "
+                    android:valueType="pathType" >
+                    <aapt:attr name="android:interpolator" >
+                        <pathInterpolator android:pathData="M 0.0,0.0 c0.333,0 0.667,1 1.0,1.0" />
+                    </aapt:attr>
+                </objectAnimator>
+                <objectAnimator
+                    android:duration="167"
+                    android:propertyName="pathData"
+                    android:startOffset="83"
+                    android:valueFrom="M13.67 13.8 C13.67,13.8 13.67,8.94 13.67,8.94 C13.63,6.75 11.69,5 9.33,5.04 C6.98,5 5.04,6.75 5,8.94 C5,8.94 5,13.8 5,13.8 "
+                    android:valueTo="M13.7 10.21 C13.7,10.21 13.67,8.94 13.67,8.94 C13.63,6.75 11.69,5 9.33,5.04 C6.98,5 5.04,6.75 5,8.94 C5,8.94 5.03,10.21 5.03,10.21 "
+                    android:valueType="pathType" >
+                    <aapt:attr name="android:interpolator" >
+                        <pathInterpolator android:pathData="M 0.0,0.0 c0.333,0 0.667,1 1.0,1.0" />
+                    </aapt:attr>
+                </objectAnimator>
+                <objectAnimator
+                    android:duration="100"
+                    android:propertyName="pathData"
+                    android:startOffset="250"
+                    android:valueFrom="M13.7 10.21 C13.7,10.21 13.67,8.94 13.67,8.94 C13.63,6.75 11.69,5 9.33,5.04 C6.98,5 5.04,6.75 5,8.94 C5,8.94 5.03,10.21 5.03,10.21 "
+                    android:valueTo="M13.67 13.8 C13.67,13.8 13.67,8.94 13.67,8.94 C13.63,6.75 11.69,5 9.33,5.04 C6.98,5 5.04,6.75 5,8.94 C5,8.94 5,13.8 5,13.8 "
+                    android:valueType="pathType" >
+                    <aapt:attr name="android:interpolator" >
+                        <pathInterpolator android:pathData="M 0.0,0.0 c0.333,0 0.667,1 1.0,1.0" />
+                    </aapt:attr>
+                </objectAnimator>
+            </set>
+        </aapt:attr>
+    </target>
+    <target android:name="_R_G_L_0_G_T_1" >
+        <aapt:attr name="android:animation" >
+            <set android:ordering="together" >
+                <objectAnimator
+                    android:duration="83"
+                    android:pathData="M 14.666,0.287C 14.666,0.8689466710090599 14.666,0.287 14.666,0.287"
+                    android:propertyName="translateXY"
+                    android:propertyXName="translateX"
+                    android:propertyYName="translateY"
+                    android:startOffset="0" >
+                    <aapt:attr name="android:interpolator" >
+                        <pathInterpolator android:pathData="M 0.0,0.0 c0.333,0 0.667,1 1.0,1.0" />
+                    </aapt:attr>
+                </objectAnimator>
+                <objectAnimator
+                    android:duration="167"
+                    android:pathData="M 14.666,0.287C 14.666,0.8689466710090599 14.666,3.779 14.666,3.779"
+                    android:propertyName="translateXY"
+                    android:propertyXName="translateX"
+                    android:propertyYName="translateY"
+                    android:startOffset="83" >
+                    <aapt:attr name="android:interpolator" >
+                        <pathInterpolator android:pathData="M 0.0,0.0 c0.333,0 0.667,1 1.0,1.0" />
+                    </aapt:attr>
+                </objectAnimator>
+                <objectAnimator
+                    android:duration="100"
+                    android:pathData="M 14.666,3.779C 14.666,3.779 14.666,0.8689466710090599 14.666,0.287"
+                    android:propertyName="translateXY"
+                    android:propertyXName="translateX"
+                    android:propertyYName="translateY"
+                    android:startOffset="250" >
+                    <aapt:attr name="android:interpolator" >
+                        <pathInterpolator android:pathData="M 0.0,0.0 c0.333,0 0.667,1 1.0,1.0" />
+                    </aapt:attr>
+                </objectAnimator>
+            </set>
+        </aapt:attr>
+    </target>
+    <target android:name="_R_G_L_0_G_N_4_T_0" >
+        <aapt:attr name="android:animation" >
+            <set android:ordering="together" >
+                <objectAnimator
+                    android:duration="83"
+                    android:propertyName="scaleX"
+                    android:startOffset="0"
+                    android:valueFrom="1"
+                    android:valueTo="1"
+                    android:valueType="floatType" >
+                    <aapt:attr name="android:interpolator" >
+                        <pathInterpolator android:pathData="M 0.0,0.0 c0.333,0 0.36,1 1.0,1.0" />
+                    </aapt:attr>
+                </objectAnimator>
+                <objectAnimator
+                    android:duration="83"
+                    android:propertyName="scaleY"
+                    android:startOffset="0"
+                    android:valueFrom="1"
+                    android:valueTo="1"
+                    android:valueType="floatType" >
+                    <aapt:attr name="android:interpolator" >
+                        <pathInterpolator android:pathData="M 0.0,0.0 c0.333,0 0.36,1 1.0,1.0" />
+                    </aapt:attr>
+                </objectAnimator>
+                <objectAnimator
+                    android:duration="83"
+                    android:propertyName="scaleX"
+                    android:startOffset="83"
+                    android:valueFrom="1"
+                    android:valueTo="0.9500000000000001"
+                    android:valueType="floatType" >
+                    <aapt:attr name="android:interpolator" >
+                        <pathInterpolator android:pathData="M 0.0,0.0 c0.333,0 0.36,1 1.0,1.0" />
+                    </aapt:attr>
+                </objectAnimator>
+                <objectAnimator
+                    android:duration="83"
+                    android:propertyName="scaleY"
+                    android:startOffset="83"
+                    android:valueFrom="1"
+                    android:valueTo="0.9500000000000001"
+                    android:valueType="floatType" >
+                    <aapt:attr name="android:interpolator" >
+                        <pathInterpolator android:pathData="M 0.0,0.0 c0.333,0 0.36,1 1.0,1.0" />
+                    </aapt:attr>
+                </objectAnimator>
+                <objectAnimator
+                    android:duration="183"
+                    android:propertyName="scaleX"
+                    android:startOffset="167"
+                    android:valueFrom="0.9500000000000001"
+                    android:valueTo="1.2"
+                    android:valueType="floatType" >
+                    <aapt:attr name="android:interpolator" >
+                        <pathInterpolator android:pathData="M 0.0,0.0 c0.461,0 0.526,1 1.0,1.0" />
+                    </aapt:attr>
+                </objectAnimator>
+                <objectAnimator
+                    android:duration="183"
+                    android:propertyName="scaleY"
+                    android:startOffset="167"
+                    android:valueFrom="0.9500000000000001"
+                    android:valueTo="1.2"
+                    android:valueType="floatType" >
+                    <aapt:attr name="android:interpolator" >
+                        <pathInterpolator android:pathData="M 0.0,0.0 c0.461,0 0.526,1 1.0,1.0" />
+                    </aapt:attr>
+                </objectAnimator>
+                <objectAnimator
+                    android:duration="233"
+                    android:propertyName="scaleX"
+                    android:startOffset="350"
+                    android:valueFrom="1.2"
+                    android:valueTo="1"
+                    android:valueType="floatType" >
+                    <aapt:attr name="android:interpolator" >
+                        <pathInterpolator android:pathData="M 0.0,0.0 c0.428,0 0.397,1 1.0,1.0" />
+                    </aapt:attr>
+                </objectAnimator>
+                <objectAnimator
+                    android:duration="233"
+                    android:propertyName="scaleY"
+                    android:startOffset="350"
+                    android:valueFrom="1.2"
+                    android:valueTo="1"
+                    android:valueType="floatType" >
+                    <aapt:attr name="android:interpolator" >
+                        <pathInterpolator android:pathData="M 0.0,0.0 c0.428,0 0.397,1 1.0,1.0" />
+                    </aapt:attr>
+                </objectAnimator>
+            </set>
+        </aapt:attr>
+    </target>
+    <target android:name="time_group" >
+        <aapt:attr name="android:animation" >
+            <set android:ordering="together" >
+                <objectAnimator
+                    android:duration="717"
+                    android:propertyName="translateX"
+                    android:startOffset="0"
+                    android:valueFrom="0"
+                    android:valueTo="1"
+                    android:valueType="floatType" />
+            </set>
+        </aapt:attr>
+    </target>
+
+</animated-vector>
\ No newline at end of file
diff --git a/core/res/res/anim/lock_to_error.xml b/packages/SystemUI/res/anim/lock_to_error.xml
similarity index 100%
rename from core/res/res/anim/lock_to_error.xml
rename to packages/SystemUI/res/anim/lock_to_error.xml
diff --git a/packages/SystemUI/res/anim/lock_to_error_circular.xml b/packages/SystemUI/res/anim/lock_to_error_circular.xml
new file mode 100644
index 0000000..9a84723
--- /dev/null
+++ b/packages/SystemUI/res/anim/lock_to_error_circular.xml
@@ -0,0 +1,276 @@
+<?xml version="1.0" encoding="utf-8"?>
+<animated-vector xmlns:aapt="http://schemas.android.com/aapt"
+    xmlns:android="http://schemas.android.com/apk/res/android" >
+
+    <aapt:attr name="android:drawable" >
+        <vector
+            android:height="32dp"
+            android:viewportHeight="32"
+            android:viewportWidth="32"
+            android:width="32dp" >
+            <group android:name="_R_G" >
+                <group
+                    android:name="_R_G_L_2_G"
+                    android:pivotX="9.583"
+                    android:pivotY="8.916"
+                    android:rotation="0"
+                    android:translateX="6.416"
+                    android:translateY="10.416999999999998" >
+                    <path
+                        android:name="_R_G_L_2_G_D_0_P_0"
+                        android:fillAlpha="1"
+                        android:fillColor="#ffffff"
+                        android:fillType="nonZero"
+                        android:pathData=" M17.42 1.75 C17.42,1.75 17.42,14.58 17.42,14.58 C17.42,15.41 16.74,16.08 15.92,16.08 C15.92,16.08 3.25,16.08 3.25,16.08 C2.42,16.08 1.75,15.41 1.75,14.58 C1.75,14.58 1.75,1.75 1.75,1.75 C1.75,1.75 17.42,1.75 17.42,1.75c  M18.92 0.25 C18.92,0.25 0.25,0.25 0.25,0.25 C0.25,0.25 0.25,14.58 0.25,14.58 C0.25,16.24 1.59,17.58 3.25,17.58 C3.25,17.58 15.92,17.58 15.92,17.58 C17.57,17.58 18.92,16.24 18.92,14.58 C18.92,14.58 18.92,0.25 18.92,0.25c " />
+                </group>
+                <group
+                    android:name="_R_G_L_1_G_N_3_T_0"
+                    android:pivotX="9.583"
+                    android:pivotY="8.916"
+                    android:rotation="0"
+                    android:translateX="6.416"
+                    android:translateY="10.416999999999998" >
+                    <group
+                        android:name="_R_G_L_1_G"
+                        android:translateX="7.334"
+                        android:translateY="5.333" >
+                        <path
+                            android:name="_R_G_L_1_G_D_0_P_0"
+                            android:fillAlpha="1"
+                            android:fillColor="#ffffff"
+                            android:fillType="nonZero"
+                            android:pathData=" M4.25 2.25 C4.25,3.35 3.35,4.25 2.25,4.25 C1.15,4.25 0.25,3.35 0.25,2.25 C0.25,1.15 1.15,0.25 2.25,0.25 C3.35,0.25 4.25,1.15 4.25,2.25c " />
+                        <path
+                            android:name="_R_G_L_1_G_D_1_P_0"
+                            android:pathData=" M2.25 2.25 C2.25,2.25 2.25,5.92 2.25,5.92 "
+                            android:strokeAlpha="1"
+                            android:strokeColor="#ffffff"
+                            android:strokeLineCap="round"
+                            android:strokeLineJoin="round"
+                            android:strokeWidth="1.5" />
+                    </group>
+                </group>
+                <group
+                    android:name="_R_G_L_0_G_N_3_T_0"
+                    android:pivotX="9.583"
+                    android:pivotY="8.916"
+                    android:rotation="0"
+                    android:translateX="6.416"
+                    android:translateY="10.416999999999998" >
+                    <group
+                        android:name="_R_G_L_0_G"
+                        android:translateX="1.5"
+                        android:translateY="-11.835" >
+                        <path
+                            android:name="_R_G_L_0_G_D_0_P_0"
+                            android:pathData=" M12.42 12.6 C12.42,12.6 12.42,8.17 12.42,8.17 C12.42,5.83 10.48,3.75 8.08,3.75 C5.69,3.75 3.75,5.83 3.75,8.17 C3.75,8.17 3.75,12.6 3.75,12.6 "
+                            android:strokeAlpha="1"
+                            android:strokeColor="#ffffff"
+                            android:strokeLineCap="round"
+                            android:strokeLineJoin="round"
+                            android:strokeWidth="1.5" />
+                    </group>
+                </group>
+            </group>
+            <group android:name="time_group" />
+        </vector>
+    </aapt:attr>
+
+    <target android:name="_R_G_L_2_G" >
+        <aapt:attr name="android:animation" >
+            <set android:ordering="together" >
+                <objectAnimator
+                    android:duration="133"
+                    android:propertyName="rotation"
+                    android:startOffset="0"
+                    android:valueFrom="0"
+                    android:valueTo="0"
+                    android:valueType="floatType" >
+                    <aapt:attr name="android:interpolator" >
+                        <pathInterpolator android:pathData="M 0.0,0.0 c0.44,0 0.601,1 1.0,1.0" />
+                    </aapt:attr>
+                </objectAnimator>
+                <objectAnimator
+                    android:duration="120"
+                    android:propertyName="rotation"
+                    android:startOffset="133"
+                    android:valueFrom="0"
+                    android:valueTo="-10"
+                    android:valueType="floatType" >
+                    <aapt:attr name="android:interpolator" >
+                        <pathInterpolator android:pathData="M 0.0,0.0 c0.44,0 0.601,1 1.0,1.0" />
+                    </aapt:attr>
+                </objectAnimator>
+                <objectAnimator
+                    android:duration="97"
+                    android:propertyName="rotation"
+                    android:startOffset="253"
+                    android:valueFrom="-10"
+                    android:valueTo="10"
+                    android:valueType="floatType" >
+                    <aapt:attr name="android:interpolator" >
+                        <pathInterpolator android:pathData="M 0.0,0.0 c0.531,0 0.389,1 1.0,1.0" />
+                    </aapt:attr>
+                </objectAnimator>
+                <objectAnimator
+                    android:duration="100"
+                    android:propertyName="rotation"
+                    android:startOffset="350"
+                    android:valueFrom="10"
+                    android:valueTo="-5"
+                    android:valueType="floatType" >
+                    <aapt:attr name="android:interpolator" >
+                        <pathInterpolator android:pathData="M 0.0,0.0 c0.499,0 0.489,1 1.0,1.0" />
+                    </aapt:attr>
+                </objectAnimator>
+                <objectAnimator
+                    android:duration="167"
+                    android:propertyName="rotation"
+                    android:startOffset="450"
+                    android:valueFrom="-5"
+                    android:valueTo="0"
+                    android:valueType="floatType" >
+                    <aapt:attr name="android:interpolator" >
+                        <pathInterpolator android:pathData="M 0.0,0.0 c0.293,0 0.689,1 1.0,1.0" />
+                    </aapt:attr>
+                </objectAnimator>
+            </set>
+        </aapt:attr>
+    </target>
+    <target android:name="_R_G_L_1_G_N_3_T_0" >
+        <aapt:attr name="android:animation" >
+            <set android:ordering="together" >
+                <objectAnimator
+                    android:duration="133"
+                    android:propertyName="rotation"
+                    android:startOffset="0"
+                    android:valueFrom="0"
+                    android:valueTo="0"
+                    android:valueType="floatType" >
+                    <aapt:attr name="android:interpolator" >
+                        <pathInterpolator android:pathData="M 0.0,0.0 c0.44,0 0.601,1 1.0,1.0" />
+                    </aapt:attr>
+                </objectAnimator>
+                <objectAnimator
+                    android:duration="120"
+                    android:propertyName="rotation"
+                    android:startOffset="133"
+                    android:valueFrom="0"
+                    android:valueTo="-10"
+                    android:valueType="floatType" >
+                    <aapt:attr name="android:interpolator" >
+                        <pathInterpolator android:pathData="M 0.0,0.0 c0.44,0 0.601,1 1.0,1.0" />
+                    </aapt:attr>
+                </objectAnimator>
+                <objectAnimator
+                    android:duration="97"
+                    android:propertyName="rotation"
+                    android:startOffset="253"
+                    android:valueFrom="-10"
+                    android:valueTo="10"
+                    android:valueType="floatType" >
+                    <aapt:attr name="android:interpolator" >
+                        <pathInterpolator android:pathData="M 0.0,0.0 c0.531,0 0.389,1 1.0,1.0" />
+                    </aapt:attr>
+                </objectAnimator>
+                <objectAnimator
+                    android:duration="100"
+                    android:propertyName="rotation"
+                    android:startOffset="350"
+                    android:valueFrom="10"
+                    android:valueTo="-5"
+                    android:valueType="floatType" >
+                    <aapt:attr name="android:interpolator" >
+                        <pathInterpolator android:pathData="M 0.0,0.0 c0.499,0 0.489,1 1.0,1.0" />
+                    </aapt:attr>
+                </objectAnimator>
+                <objectAnimator
+                    android:duration="167"
+                    android:propertyName="rotation"
+                    android:startOffset="450"
+                    android:valueFrom="-5"
+                    android:valueTo="0"
+                    android:valueType="floatType" >
+                    <aapt:attr name="android:interpolator" >
+                        <pathInterpolator android:pathData="M 0.0,0.0 c0.293,0 0.689,1 1.0,1.0" />
+                    </aapt:attr>
+                </objectAnimator>
+            </set>
+        </aapt:attr>
+    </target>
+    <target android:name="_R_G_L_0_G_N_3_T_0" >
+        <aapt:attr name="android:animation" >
+            <set android:ordering="together" >
+                <objectAnimator
+                    android:duration="133"
+                    android:propertyName="rotation"
+                    android:startOffset="0"
+                    android:valueFrom="0"
+                    android:valueTo="0"
+                    android:valueType="floatType" >
+                    <aapt:attr name="android:interpolator" >
+                        <pathInterpolator android:pathData="M 0.0,0.0 c0.44,0 0.601,1 1.0,1.0" />
+                    </aapt:attr>
+                </objectAnimator>
+                <objectAnimator
+                    android:duration="120"
+                    android:propertyName="rotation"
+                    android:startOffset="133"
+                    android:valueFrom="0"
+                    android:valueTo="-10"
+                    android:valueType="floatType" >
+                    <aapt:attr name="android:interpolator" >
+                        <pathInterpolator android:pathData="M 0.0,0.0 c0.44,0 0.601,1 1.0,1.0" />
+                    </aapt:attr>
+                </objectAnimator>
+                <objectAnimator
+                    android:duration="97"
+                    android:propertyName="rotation"
+                    android:startOffset="253"
+                    android:valueFrom="-10"
+                    android:valueTo="10"
+                    android:valueType="floatType" >
+                    <aapt:attr name="android:interpolator" >
+                        <pathInterpolator android:pathData="M 0.0,0.0 c0.531,0 0.389,1 1.0,1.0" />
+                    </aapt:attr>
+                </objectAnimator>
+                <objectAnimator
+                    android:duration="100"
+                    android:propertyName="rotation"
+                    android:startOffset="350"
+                    android:valueFrom="10"
+                    android:valueTo="-5"
+                    android:valueType="floatType" >
+                    <aapt:attr name="android:interpolator" >
+                        <pathInterpolator android:pathData="M 0.0,0.0 c0.499,0 0.489,1 1.0,1.0" />
+                    </aapt:attr>
+                </objectAnimator>
+                <objectAnimator
+                    android:duration="167"
+                    android:propertyName="rotation"
+                    android:startOffset="450"
+                    android:valueFrom="-5"
+                    android:valueTo="0"
+                    android:valueType="floatType" >
+                    <aapt:attr name="android:interpolator" >
+                        <pathInterpolator android:pathData="M 0.0,0.0 c0.293,0 0.689,1 1.0,1.0" />
+                    </aapt:attr>
+                </objectAnimator>
+            </set>
+        </aapt:attr>
+    </target>
+    <target android:name="time_group" >
+        <aapt:attr name="android:animation" >
+            <set android:ordering="together" >
+                <objectAnimator
+                    android:duration="717"
+                    android:propertyName="translateX"
+                    android:startOffset="0"
+                    android:valueFrom="0"
+                    android:valueTo="1"
+                    android:valueType="floatType" />
+            </set>
+        </aapt:attr>
+    </target>
+
+</animated-vector>
\ No newline at end of file
diff --git a/packages/SystemUI/res/anim/lock_to_error_filled.xml b/packages/SystemUI/res/anim/lock_to_error_filled.xml
new file mode 100644
index 0000000..6eb7425
--- /dev/null
+++ b/packages/SystemUI/res/anim/lock_to_error_filled.xml
@@ -0,0 +1,188 @@
+<?xml version="1.0" encoding="utf-8"?>
+<animated-vector xmlns:aapt="http://schemas.android.com/aapt"
+    xmlns:android="http://schemas.android.com/apk/res/android" >
+
+    <aapt:attr name="android:drawable" >
+        <vector
+            android:height="32dp"
+            android:viewportHeight="32"
+            android:viewportWidth="32"
+            android:width="32dp" >
+            <group android:name="_R_G" >
+                <group
+                    android:name="_R_G_L_1_G"
+                    android:pivotX="10.917"
+                    android:pivotY="9.583"
+                    android:rotation="0"
+                    android:translateX="5.083"
+                    android:translateY="10.417" >
+                    <path
+                        android:name="_R_G_L_1_G_D_0_P_0"
+                        android:fillAlpha="1"
+                        android:fillColor="#ffffff"
+                        android:fillType="nonZero"
+                        android:pathData=" M18.92 0.25 C18.92,0.25 2.92,0.25 2.92,0.25 C1.45,0.25 0.25,1.45 0.25,2.92 C0.25,2.92 0.25,16.25 0.25,16.25 C0.25,17.72 1.45,18.92 2.92,18.92 C2.92,18.92 18.92,18.92 18.92,18.92 C20.38,18.92 21.58,17.72 21.58,16.25 C21.58,16.25 21.58,2.92 21.58,2.92 C21.58,1.45 20.38,0.25 18.92,0.25c  M10.92 12.25 C9.45,12.25 8.25,11.05 8.25,9.58 C8.25,8.12 9.45,6.92 10.92,6.92 C12.38,6.92 13.58,8.12 13.58,9.58 C13.58,11.05 12.38,12.25 10.92,12.25c " />
+                </group>
+                <group
+                    android:name="_R_G_L_0_G_N_2_T_0"
+                    android:pivotX="10.917"
+                    android:pivotY="9.583"
+                    android:rotation="0"
+                    android:translateX="5.083"
+                    android:translateY="10.417" >
+                    <group
+                        android:name="_R_G_L_0_G"
+                        android:translateX="1.9169999999999998"
+                        android:translateY="-12.75" >
+                        <path
+                            android:name="_R_G_L_0_G_D_0_P_0"
+                            android:pathData=" M13 13 C13,13 13,9 13,9 C13,6.79 11.21,5 9,5 C6.79,5 5,6.79 5,9 C5,9 5,13 5,13 "
+                            android:strokeAlpha="1"
+                            android:strokeColor="#ffffff"
+                            android:strokeLineCap="round"
+                            android:strokeLineJoin="round"
+                            android:strokeWidth="2" />
+                    </group>
+                </group>
+            </group>
+            <group android:name="time_group" />
+        </vector>
+    </aapt:attr>
+
+    <target android:name="_R_G_L_1_G" >
+        <aapt:attr name="android:animation" >
+            <set android:ordering="together" >
+                <objectAnimator
+                    android:duration="133"
+                    android:propertyName="rotation"
+                    android:startOffset="0"
+                    android:valueFrom="0"
+                    android:valueTo="0"
+                    android:valueType="floatType" >
+                    <aapt:attr name="android:interpolator" >
+                        <pathInterpolator android:pathData="M 0.0,0.0 c0.44,0 0.601,1 1.0,1.0" />
+                    </aapt:attr>
+                </objectAnimator>
+                <objectAnimator
+                    android:duration="120"
+                    android:propertyName="rotation"
+                    android:startOffset="133"
+                    android:valueFrom="0"
+                    android:valueTo="-10"
+                    android:valueType="floatType" >
+                    <aapt:attr name="android:interpolator" >
+                        <pathInterpolator android:pathData="M 0.0,0.0 c0.44,0 0.601,1 1.0,1.0" />
+                    </aapt:attr>
+                </objectAnimator>
+                <objectAnimator
+                    android:duration="97"
+                    android:propertyName="rotation"
+                    android:startOffset="253"
+                    android:valueFrom="-10"
+                    android:valueTo="10"
+                    android:valueType="floatType" >
+                    <aapt:attr name="android:interpolator" >
+                        <pathInterpolator android:pathData="M 0.0,0.0 c0.531,0 0.389,1 1.0,1.0" />
+                    </aapt:attr>
+                </objectAnimator>
+                <objectAnimator
+                    android:duration="100"
+                    android:propertyName="rotation"
+                    android:startOffset="350"
+                    android:valueFrom="10"
+                    android:valueTo="-5"
+                    android:valueType="floatType" >
+                    <aapt:attr name="android:interpolator" >
+                        <pathInterpolator android:pathData="M 0.0,0.0 c0.499,0 0.489,1 1.0,1.0" />
+                    </aapt:attr>
+                </objectAnimator>
+                <objectAnimator
+                    android:duration="167"
+                    android:propertyName="rotation"
+                    android:startOffset="450"
+                    android:valueFrom="-5"
+                    android:valueTo="0"
+                    android:valueType="floatType" >
+                    <aapt:attr name="android:interpolator" >
+                        <pathInterpolator android:pathData="M 0.0,0.0 c0.293,0 0.689,1 1.0,1.0" />
+                    </aapt:attr>
+                </objectAnimator>
+            </set>
+        </aapt:attr>
+    </target>
+    <target android:name="_R_G_L_0_G_N_2_T_0" >
+        <aapt:attr name="android:animation" >
+            <set android:ordering="together" >
+                <objectAnimator
+                    android:duration="133"
+                    android:propertyName="rotation"
+                    android:startOffset="0"
+                    android:valueFrom="0"
+                    android:valueTo="0"
+                    android:valueType="floatType" >
+                    <aapt:attr name="android:interpolator" >
+                        <pathInterpolator android:pathData="M 0.0,0.0 c0.44,0 0.601,1 1.0,1.0" />
+                    </aapt:attr>
+                </objectAnimator>
+                <objectAnimator
+                    android:duration="120"
+                    android:propertyName="rotation"
+                    android:startOffset="133"
+                    android:valueFrom="0"
+                    android:valueTo="-10"
+                    android:valueType="floatType" >
+                    <aapt:attr name="android:interpolator" >
+                        <pathInterpolator android:pathData="M 0.0,0.0 c0.44,0 0.601,1 1.0,1.0" />
+                    </aapt:attr>
+                </objectAnimator>
+                <objectAnimator
+                    android:duration="97"
+                    android:propertyName="rotation"
+                    android:startOffset="253"
+                    android:valueFrom="-10"
+                    android:valueTo="10"
+                    android:valueType="floatType" >
+                    <aapt:attr name="android:interpolator" >
+                        <pathInterpolator android:pathData="M 0.0,0.0 c0.531,0 0.389,1 1.0,1.0" />
+                    </aapt:attr>
+                </objectAnimator>
+                <objectAnimator
+                    android:duration="100"
+                    android:propertyName="rotation"
+                    android:startOffset="350"
+                    android:valueFrom="10"
+                    android:valueTo="-5"
+                    android:valueType="floatType" >
+                    <aapt:attr name="android:interpolator" >
+                        <pathInterpolator android:pathData="M 0.0,0.0 c0.499,0 0.489,1 1.0,1.0" />
+                    </aapt:attr>
+                </objectAnimator>
+                <objectAnimator
+                    android:duration="167"
+                    android:propertyName="rotation"
+                    android:startOffset="450"
+                    android:valueFrom="-5"
+                    android:valueTo="0"
+                    android:valueType="floatType" >
+                    <aapt:attr name="android:interpolator" >
+                        <pathInterpolator android:pathData="M 0.0,0.0 c0.293,0 0.689,1 1.0,1.0" />
+                    </aapt:attr>
+                </objectAnimator>
+            </set>
+        </aapt:attr>
+    </target>
+    <target android:name="time_group" >
+        <aapt:attr name="android:animation" >
+            <set android:ordering="together" >
+                <objectAnimator
+                    android:duration="717"
+                    android:propertyName="translateX"
+                    android:startOffset="0"
+                    android:valueFrom="0"
+                    android:valueTo="1"
+                    android:valueType="floatType" />
+            </set>
+        </aapt:attr>
+    </target>
+
+</animated-vector>
\ No newline at end of file
diff --git a/packages/SystemUI/res/anim/lock_to_error_rounded.xml b/packages/SystemUI/res/anim/lock_to_error_rounded.xml
new file mode 100644
index 0000000..46043ca
--- /dev/null
+++ b/packages/SystemUI/res/anim/lock_to_error_rounded.xml
@@ -0,0 +1,270 @@
+<?xml version="1.0" encoding="utf-8"?>
+<animated-vector xmlns:aapt="http://schemas.android.com/aapt"
+    xmlns:android="http://schemas.android.com/apk/res/android" >
+
+    <aapt:attr name="android:drawable" >
+        <vector
+            android:height="32dp"
+            android:viewportHeight="32"
+            android:viewportWidth="32"
+            android:width="32dp" >
+            <group android:name="_R_G" >
+                <group
+                    android:name="_R_G_L_2_G"
+                    android:pivotX="14.667"
+                    android:pivotY="12.667"
+                    android:rotation="0"
+                    android:translateX="1.3330000000000002"
+                    android:translateY="7.333" >
+                    <path
+                        android:name="_R_G_L_2_G_D_0_P_0"
+                        android:pathData=" M22.09 5 C22.09,5 6,5 6,5 C5.45,5 5,5.45 5,6 C5,6 5,19.33 5,19.33 C5,19.89 5.45,20.33 6,20.33 C6,20.33 23.33,20.33 23.33,20.33 C23.89,20.33 24.33,19.89 24.33,19.33 C24.33,19.33 24.33,6 24.33,6 C24.33,5.45 23.89,5 23.33,5 C23.33,5 22.09,5 22.09,5c "
+                        android:strokeAlpha="1"
+                        android:strokeColor="#ffffff"
+                        android:strokeLineCap="round"
+                        android:strokeLineJoin="round"
+                        android:strokeWidth="1.5" />
+                </group>
+                <group
+                    android:name="_R_G_L_1_G_N_4_T_0"
+                    android:pivotX="14.667"
+                    android:pivotY="12.667"
+                    android:rotation="0"
+                    android:translateX="1.3330000000000002"
+                    android:translateY="7.333" >
+                    <group
+                        android:name="_R_G_L_1_G"
+                        android:translateX="12.416"
+                        android:translateY="10.417" >
+                        <path
+                            android:name="_R_G_L_1_G_D_0_P_0"
+                            android:fillAlpha="1"
+                            android:fillColor="#ffffff"
+                            android:fillType="nonZero"
+                            android:pathData=" M2.25 0.25 C3.35,0.25 4.25,1.15 4.25,2.25 C4.25,3.35 3.35,4.25 2.25,4.25 C1.15,4.25 0.25,3.35 0.25,2.25 C0.25,1.15 1.15,0.25 2.25,0.25c " />
+                    </group>
+                </group>
+                <group
+                    android:name="_R_G_L_0_G_N_4_T_0"
+                    android:pivotX="14.667"
+                    android:pivotY="12.667"
+                    android:rotation="0"
+                    android:translateX="1.3330000000000002"
+                    android:translateY="7.333" >
+                    <group
+                        android:name="_R_G_L_0_G"
+                        android:translateX="5.333"
+                        android:translateY="-9.425999999999998" >
+                        <path
+                            android:name="_R_G_L_0_G_D_0_P_0"
+                            android:pathData=" M13.67 13.8 C13.67,13.8 13.67,8.94 13.67,8.94 C13.63,6.75 11.69,5 9.33,5.04 C6.98,5 5.04,6.75 5,8.94 C5,8.94 5,13.8 5,13.8 "
+                            android:strokeAlpha="1"
+                            android:strokeColor="#ffffff"
+                            android:strokeLineCap="round"
+                            android:strokeLineJoin="round"
+                            android:strokeWidth="1.5" />
+                    </group>
+                </group>
+            </group>
+            <group android:name="time_group" />
+        </vector>
+    </aapt:attr>
+
+    <target android:name="_R_G_L_2_G" >
+        <aapt:attr name="android:animation" >
+            <set android:ordering="together" >
+                <objectAnimator
+                    android:duration="133"
+                    android:propertyName="rotation"
+                    android:startOffset="0"
+                    android:valueFrom="0"
+                    android:valueTo="0"
+                    android:valueType="floatType" >
+                    <aapt:attr name="android:interpolator" >
+                        <pathInterpolator android:pathData="M 0.0,0.0 c0.44,0 0.601,1 1.0,1.0" />
+                    </aapt:attr>
+                </objectAnimator>
+                <objectAnimator
+                    android:duration="120"
+                    android:propertyName="rotation"
+                    android:startOffset="133"
+                    android:valueFrom="0"
+                    android:valueTo="-10"
+                    android:valueType="floatType" >
+                    <aapt:attr name="android:interpolator" >
+                        <pathInterpolator android:pathData="M 0.0,0.0 c0.44,0 0.601,1 1.0,1.0" />
+                    </aapt:attr>
+                </objectAnimator>
+                <objectAnimator
+                    android:duration="97"
+                    android:propertyName="rotation"
+                    android:startOffset="253"
+                    android:valueFrom="-10"
+                    android:valueTo="10"
+                    android:valueType="floatType" >
+                    <aapt:attr name="android:interpolator" >
+                        <pathInterpolator android:pathData="M 0.0,0.0 c0.531,0 0.389,1 1.0,1.0" />
+                    </aapt:attr>
+                </objectAnimator>
+                <objectAnimator
+                    android:duration="100"
+                    android:propertyName="rotation"
+                    android:startOffset="350"
+                    android:valueFrom="10"
+                    android:valueTo="-5"
+                    android:valueType="floatType" >
+                    <aapt:attr name="android:interpolator" >
+                        <pathInterpolator android:pathData="M 0.0,0.0 c0.499,0 0.489,1 1.0,1.0" />
+                    </aapt:attr>
+                </objectAnimator>
+                <objectAnimator
+                    android:duration="167"
+                    android:propertyName="rotation"
+                    android:startOffset="450"
+                    android:valueFrom="-5"
+                    android:valueTo="0"
+                    android:valueType="floatType" >
+                    <aapt:attr name="android:interpolator" >
+                        <pathInterpolator android:pathData="M 0.0,0.0 c0.293,0 0.689,1 1.0,1.0" />
+                    </aapt:attr>
+                </objectAnimator>
+            </set>
+        </aapt:attr>
+    </target>
+    <target android:name="_R_G_L_1_G_N_4_T_0" >
+        <aapt:attr name="android:animation" >
+            <set android:ordering="together" >
+                <objectAnimator
+                    android:duration="133"
+                    android:propertyName="rotation"
+                    android:startOffset="0"
+                    android:valueFrom="0"
+                    android:valueTo="0"
+                    android:valueType="floatType" >
+                    <aapt:attr name="android:interpolator" >
+                        <pathInterpolator android:pathData="M 0.0,0.0 c0.44,0 0.601,1 1.0,1.0" />
+                    </aapt:attr>
+                </objectAnimator>
+                <objectAnimator
+                    android:duration="120"
+                    android:propertyName="rotation"
+                    android:startOffset="133"
+                    android:valueFrom="0"
+                    android:valueTo="-10"
+                    android:valueType="floatType" >
+                    <aapt:attr name="android:interpolator" >
+                        <pathInterpolator android:pathData="M 0.0,0.0 c0.44,0 0.601,1 1.0,1.0" />
+                    </aapt:attr>
+                </objectAnimator>
+                <objectAnimator
+                    android:duration="97"
+                    android:propertyName="rotation"
+                    android:startOffset="253"
+                    android:valueFrom="-10"
+                    android:valueTo="10"
+                    android:valueType="floatType" >
+                    <aapt:attr name="android:interpolator" >
+                        <pathInterpolator android:pathData="M 0.0,0.0 c0.531,0 0.389,1 1.0,1.0" />
+                    </aapt:attr>
+                </objectAnimator>
+                <objectAnimator
+                    android:duration="100"
+                    android:propertyName="rotation"
+                    android:startOffset="350"
+                    android:valueFrom="10"
+                    android:valueTo="-5"
+                    android:valueType="floatType" >
+                    <aapt:attr name="android:interpolator" >
+                        <pathInterpolator android:pathData="M 0.0,0.0 c0.499,0 0.489,1 1.0,1.0" />
+                    </aapt:attr>
+                </objectAnimator>
+                <objectAnimator
+                    android:duration="167"
+                    android:propertyName="rotation"
+                    android:startOffset="450"
+                    android:valueFrom="-5"
+                    android:valueTo="0"
+                    android:valueType="floatType" >
+                    <aapt:attr name="android:interpolator" >
+                        <pathInterpolator android:pathData="M 0.0,0.0 c0.293,0 0.689,1 1.0,1.0" />
+                    </aapt:attr>
+                </objectAnimator>
+            </set>
+        </aapt:attr>
+    </target>
+    <target android:name="_R_G_L_0_G_N_4_T_0" >
+        <aapt:attr name="android:animation" >
+            <set android:ordering="together" >
+                <objectAnimator
+                    android:duration="133"
+                    android:propertyName="rotation"
+                    android:startOffset="0"
+                    android:valueFrom="0"
+                    android:valueTo="0"
+                    android:valueType="floatType" >
+                    <aapt:attr name="android:interpolator" >
+                        <pathInterpolator android:pathData="M 0.0,0.0 c0.44,0 0.601,1 1.0,1.0" />
+                    </aapt:attr>
+                </objectAnimator>
+                <objectAnimator
+                    android:duration="120"
+                    android:propertyName="rotation"
+                    android:startOffset="133"
+                    android:valueFrom="0"
+                    android:valueTo="-10"
+                    android:valueType="floatType" >
+                    <aapt:attr name="android:interpolator" >
+                        <pathInterpolator android:pathData="M 0.0,0.0 c0.44,0 0.601,1 1.0,1.0" />
+                    </aapt:attr>
+                </objectAnimator>
+                <objectAnimator
+                    android:duration="97"
+                    android:propertyName="rotation"
+                    android:startOffset="253"
+                    android:valueFrom="-10"
+                    android:valueTo="10"
+                    android:valueType="floatType" >
+                    <aapt:attr name="android:interpolator" >
+                        <pathInterpolator android:pathData="M 0.0,0.0 c0.531,0 0.389,1 1.0,1.0" />
+                    </aapt:attr>
+                </objectAnimator>
+                <objectAnimator
+                    android:duration="100"
+                    android:propertyName="rotation"
+                    android:startOffset="350"
+                    android:valueFrom="10"
+                    android:valueTo="-5"
+                    android:valueType="floatType" >
+                    <aapt:attr name="android:interpolator" >
+                        <pathInterpolator android:pathData="M 0.0,0.0 c0.499,0 0.489,1 1.0,1.0" />
+                    </aapt:attr>
+                </objectAnimator>
+                <objectAnimator
+                    android:duration="167"
+                    android:propertyName="rotation"
+                    android:startOffset="450"
+                    android:valueFrom="-5"
+                    android:valueTo="0"
+                    android:valueType="floatType" >
+                    <aapt:attr name="android:interpolator" >
+                        <pathInterpolator android:pathData="M 0.0,0.0 c0.293,0 0.689,1 1.0,1.0" />
+                    </aapt:attr>
+                </objectAnimator>
+            </set>
+        </aapt:attr>
+    </target>
+    <target android:name="time_group" >
+        <aapt:attr name="android:animation" >
+            <set android:ordering="together" >
+                <objectAnimator
+                    android:duration="717"
+                    android:propertyName="translateX"
+                    android:startOffset="0"
+                    android:valueFrom="0"
+                    android:valueTo="1"
+                    android:valueType="floatType" />
+            </set>
+        </aapt:attr>
+    </target>
+
+</animated-vector>
\ No newline at end of file
diff --git a/core/res/res/anim/lock_unlock.xml b/packages/SystemUI/res/anim/lock_unlock.xml
similarity index 98%
rename from core/res/res/anim/lock_unlock.xml
rename to packages/SystemUI/res/anim/lock_unlock.xml
index 91d4432..64456ce 100644
--- a/core/res/res/anim/lock_unlock.xml
+++ b/packages/SystemUI/res/anim/lock_unlock.xml
@@ -34,7 +34,7 @@
                             android:pathData=" M22.33 21 C22.33,21 6.33,21 6.33,21 C5.6,21 5,20.4 5,19.67 C5,19.67 5,6.33 5,6.33 C5,5.6 5.6,5 6.33,5 C6.33,5 22.33,5 22.33,5 C23.07,5 23.67,5.6 23.67,6.33 C23.67,6.33 23.67,19.67 23.67,19.67 C23.67,20.4 23.07,21 22.33,21c "
                             android:strokeWidth="2"
                             android:strokeAlpha="1"
-                            android:strokeColor="#ffffff" />
+                            android:strokeColor="#ffffff"/>
                     </group>
                 </group>
                 <group
@@ -79,7 +79,7 @@
                                 android:pathData=" M14.33 14.33 C14.33,14.33 14.33,9.67 14.33,9.67 C14.33,7.09 12.24,5 9.67,5 C7.09,5 5,7.09 5,9.67 C5,9.67 5,14.33 5,14.33 "
                                 android:strokeWidth="2"
                                 android:strokeAlpha="1"
-                                android:strokeColor="#ffffff" />
+                                android:strokeColor="#ffffff"/>
                         </group>
                     </group>
                 </group>
@@ -230,7 +230,7 @@
                     </aapt:attr>
                 </objectAnimator>
                 <objectAnimator
-                    android:duration="333"
+                    android:duration="183"
                     android:propertyName="pathData"
                     android:startOffset="67"
                     android:valueFrom="M14.33 14.33 C14.33,14.33 14.29,6.17 14.29,6.17 C14.29,3.59 12.2,1.5 9.63,1.5 C7.05,1.5 4.96,3.59 4.96,6.17 C4.96,6.17 4.96,7.33 4.96,7.33 "
@@ -286,7 +286,7 @@
         <aapt:attr name="android:animation">
             <set android:ordering="together">
                 <objectAnimator
-                    android:duration="717"
+                    android:duration="983"
                     android:propertyName="translateX"
                     android:startOffset="0"
                     android:valueFrom="0"
diff --git a/packages/SystemUI/res/anim/lock_unlock_circular.xml b/packages/SystemUI/res/anim/lock_unlock_circular.xml
new file mode 100644
index 0000000..c3968ac
--- /dev/null
+++ b/packages/SystemUI/res/anim/lock_unlock_circular.xml
@@ -0,0 +1,212 @@
+<!-- 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.
+-->
+<animated-vector xmlns:android="http://schemas.android.com/apk/res/android"
+                 xmlns:aapt="http://schemas.android.com/aapt">
+    <aapt:attr name="android:drawable">
+        <vector android:height="42dp" android:width="32dp" android:viewportHeight="42"
+                android:viewportWidth="32">
+            <group android:name="_R_G">
+                <group android:name="_R_G_L_2_G_T_1" android:translateX="15.999"
+                       android:translateY="24.333">
+                    <group android:name="_R_G_L_2_G" android:translateX="-9.583"
+                           android:translateY="-8.916">
+                        <path android:name="_R_G_L_2_G_D_0_P_0" android:fillColor="#ffffff"
+                              android:fillAlpha="1" android:fillType="nonZero"
+                              android:pathData=" M17.42 1.75 C17.42,1.75 17.42,14.58 17.42,14.58 C17.42,15.41 16.74,16.08 15.92,16.08 C15.92,16.08 3.25,16.08 3.25,16.08 C2.42,16.08 1.75,15.41 1.75,14.58 C1.75,14.58 1.75,1.75 1.75,1.75 C1.75,1.75 17.42,1.75 17.42,1.75c  M18.92 0.25 C18.92,0.25 0.25,0.25 0.25,0.25 C0.25,0.25 0.25,14.58 0.25,14.58 C0.25,16.24 1.59,17.58 3.25,17.58 C3.25,17.58 15.92,17.58 15.92,17.58 C17.57,17.58 18.92,16.24 18.92,14.58 C18.92,14.58 18.92,0.25 18.92,0.25c "/>
+                    </group>
+                </group>
+                <group android:name="_R_G_L_1_G_N_3_T_1" android:translateX="15.999"
+                       android:translateY="24.333">
+                    <group android:name="_R_G_L_1_G_N_3_T_0" android:translateX="-9.583"
+                           android:translateY="-8.916">
+                        <group android:name="_R_G_L_1_G" android:translateX="7.334"
+                               android:translateY="5.333" android:pivotX="2.25"
+                               android:pivotY="3.334" android:scaleX="1" android:scaleY="1">
+                            <path android:name="_R_G_L_1_G_D_0_P_0" android:fillColor="#ffffff"
+                                  android:fillAlpha="1" android:fillType="nonZero"
+                                  android:pathData=" M4.25 2.25 C4.25,3.35 3.35,4.25 2.25,4.25 C1.15,4.25 0.25,3.35 0.25,2.25 C0.25,1.15 1.15,0.25 2.25,0.25 C3.35,0.25 4.25,1.15 4.25,2.25c "/>
+                            <path android:name="_R_G_L_1_G_D_1_P_0" android:strokeColor="#ffffff"
+                                  android:strokeLineCap="round" android:strokeLineJoin="round"
+                                  android:strokeWidth="1.5" android:strokeAlpha="1"
+                                  android:pathData=" M2.25 2.25 C2.25,2.25 2.25,5.92 2.25,5.92 "/>
+                        </group>
+                    </group>
+                </group>
+                <group android:name="_R_G_L_0_G_N_3_T_1" android:translateX="15.999"
+                       android:translateY="24.333">
+                    <group android:name="_R_G_L_0_G_N_3_T_0" android:translateX="-9.583"
+                           android:translateY="-8.916">
+                        <group android:name="_R_G_L_0_G" android:translateX="1.5"
+                               android:translateY="-11.835">
+                            <path android:name="_R_G_L_0_G_D_0_P_0" android:strokeColor="#ffffff"
+                                  android:strokeLineCap="round" android:strokeLineJoin="round"
+                                  android:strokeWidth="1.5" android:strokeAlpha="1"
+                                  android:pathData=" M12.42 12.6 C12.42,12.6 12.42,8.17 12.42,8.17 C12.42,5.83 10.48,3.75 8.08,3.75 C5.69,3.75 3.75,5.83 3.75,8.17 C3.75,8.17 3.75,12.6 3.75,12.6 "/>
+                        </group>
+                    </group>
+                </group>
+            </group>
+            <group android:name="time_group"/>
+        </vector>
+    </aapt:attr>
+    <target android:name="_R_G_L_2_G_T_1">
+        <aapt:attr name="android:animation">
+            <set android:ordering="together">
+                <objectAnimator android:propertyName="translateY" android:duration="133"
+                                android:startOffset="0" android:valueFrom="24.333"
+                                android:valueTo="22.458" android:valueType="floatType">
+                    <aapt:attr name="android:interpolator">
+                        <pathInterpolator android:pathData="M 0.0,0.0 c0.333,0 0.705,1 1.0,1.0"/>
+                    </aapt:attr>
+                </objectAnimator>
+                <objectAnimator android:propertyName="translateY" android:duration="133"
+                                android:startOffset="133" android:valueFrom="22.458"
+                                android:valueTo="25.333" android:valueType="floatType">
+                    <aapt:attr name="android:interpolator">
+                        <pathInterpolator android:pathData="M 0.0,0.0 c0.289,0 0.724,1 1.0,1.0"/>
+                    </aapt:attr>
+                </objectAnimator>
+                <objectAnimator android:propertyName="translateY" android:duration="100"
+                                android:startOffset="267" android:valueFrom="25.333"
+                                android:valueTo="24.333" android:valueType="floatType">
+                    <aapt:attr name="android:interpolator">
+                        <pathInterpolator android:pathData="M 0.0,0.0 c0.333,0 0.624,1 1.0,1.0"/>
+                    </aapt:attr>
+                </objectAnimator>
+            </set>
+        </aapt:attr>
+    </target>
+    <target android:name="_R_G_L_1_G">
+        <aapt:attr name="android:animation">
+            <set android:ordering="together">
+                <objectAnimator android:propertyName="scaleX" android:duration="100"
+                                android:startOffset="0" android:valueFrom="1" android:valueTo="0.9"
+                                android:valueType="floatType">
+                    <aapt:attr name="android:interpolator">
+                        <pathInterpolator android:pathData="M 0.0,0.0 c0.333,0 0.667,1 1.0,1.0"/>
+                    </aapt:attr>
+                </objectAnimator>
+                <objectAnimator android:propertyName="scaleY" android:duration="100"
+                                android:startOffset="0" android:valueFrom="1" android:valueTo="0.9"
+                                android:valueType="floatType">
+                    <aapt:attr name="android:interpolator">
+                        <pathInterpolator android:pathData="M 0.0,0.0 c0.333,0 0.667,1 1.0,1.0"/>
+                    </aapt:attr>
+                </objectAnimator>
+                <objectAnimator android:propertyName="scaleX" android:duration="283"
+                                android:startOffset="100" android:valueFrom="0.9"
+                                android:valueTo="1" android:valueType="floatType">
+                    <aapt:attr name="android:interpolator">
+                        <pathInterpolator android:pathData="M 0.0,0.0 c0.333,0 0.667,1 1.0,1.0"/>
+                    </aapt:attr>
+                </objectAnimator>
+                <objectAnimator android:propertyName="scaleY" android:duration="283"
+                                android:startOffset="100" android:valueFrom="0.9"
+                                android:valueTo="1" android:valueType="floatType">
+                    <aapt:attr name="android:interpolator">
+                        <pathInterpolator android:pathData="M 0.0,0.0 c0.333,0 0.667,1 1.0,1.0"/>
+                    </aapt:attr>
+                </objectAnimator>
+            </set>
+        </aapt:attr>
+    </target>
+    <target android:name="_R_G_L_1_G_N_3_T_1">
+        <aapt:attr name="android:animation">
+            <set android:ordering="together">
+                <objectAnimator android:propertyName="translateY" android:duration="133"
+                                android:startOffset="0" android:valueFrom="24.333"
+                                android:valueTo="22.458" android:valueType="floatType">
+                    <aapt:attr name="android:interpolator">
+                        <pathInterpolator android:pathData="M 0.0,0.0 c0.333,0 0.705,1 1.0,1.0"/>
+                    </aapt:attr>
+                </objectAnimator>
+                <objectAnimator android:propertyName="translateY" android:duration="133"
+                                android:startOffset="133" android:valueFrom="22.458"
+                                android:valueTo="25.333" android:valueType="floatType">
+                    <aapt:attr name="android:interpolator">
+                        <pathInterpolator android:pathData="M 0.0,0.0 c0.289,0 0.724,1 1.0,1.0"/>
+                    </aapt:attr>
+                </objectAnimator>
+                <objectAnimator android:propertyName="translateY" android:duration="100"
+                                android:startOffset="267" android:valueFrom="25.333"
+                                android:valueTo="24.333" android:valueType="floatType">
+                    <aapt:attr name="android:interpolator">
+                        <pathInterpolator android:pathData="M 0.0,0.0 c0.333,0 0.624,1 1.0,1.0"/>
+                    </aapt:attr>
+                </objectAnimator>
+            </set>
+        </aapt:attr>
+    </target>
+    <target android:name="_R_G_L_0_G_D_0_P_0">
+        <aapt:attr name="android:animation">
+            <set android:ordering="together">
+                <objectAnimator android:propertyName="pathData" android:duration="67"
+                                android:startOffset="0"
+                                android:valueFrom="M12.42 12.6 C12.42,12.6 12.42,8.17 12.42,8.17 C12.42,5.83 10.48,3.75 8.08,3.75 C5.69,3.75 3.75,5.83 3.75,8.17 C3.75,8.17 3.75,12.6 3.75,12.6 "
+                                android:valueTo="M12.42 12.6 C12.42,12.6 12.4,5.86 12.4,5.86 C12.4,3.52 10.46,1.44 8.06,1.44 C5.67,1.44 3.73,3.52 3.73,5.86 C3.73,5.86 3.75,7.41 3.75,7.41 "
+                                android:valueType="pathType">
+                    <aapt:attr name="android:interpolator">
+                        <pathInterpolator android:pathData="M 0.0,0.0 c0.59,0 0.488,1 1.0,1.0"/>
+                    </aapt:attr>
+                </objectAnimator>
+                <objectAnimator android:propertyName="pathData" android:duration="183"
+                                android:startOffset="67"
+                                android:valueFrom="M12.42 12.6 C12.42,12.6 12.4,5.86 12.4,5.86 C12.4,3.52 10.46,1.44 8.06,1.44 C5.67,1.44 3.73,3.52 3.73,5.86 C3.73,5.86 3.75,7.41 3.75,7.41 "
+                                android:valueTo="M12.42 12.6 C12.42,12.6 12.41,8.16 12.41,8.16 C12.41,5.81 14.36,3.75 16.75,3.77 C19.15,3.78 21.07,5.71 21.07,8.05 C21.07,8.05 21.08,8.22 21.08,8.22 "
+                                android:valueType="pathType">
+                    <aapt:attr name="android:interpolator">
+                        <pathInterpolator android:pathData="M 0.0,0.0 c0.57,0 0.365,1 1.0,1.0"/>
+                    </aapt:attr>
+                </objectAnimator>
+            </set>
+        </aapt:attr>
+    </target>
+    <target android:name="_R_G_L_0_G_N_3_T_1">
+        <aapt:attr name="android:animation">
+            <set android:ordering="together">
+                <objectAnimator android:propertyName="translateY" android:duration="133"
+                                android:startOffset="0" android:valueFrom="24.333"
+                                android:valueTo="22.458" android:valueType="floatType">
+                    <aapt:attr name="android:interpolator">
+                        <pathInterpolator android:pathData="M 0.0,0.0 c0.333,0 0.705,1 1.0,1.0"/>
+                    </aapt:attr>
+                </objectAnimator>
+                <objectAnimator android:propertyName="translateY" android:duration="133"
+                                android:startOffset="133" android:valueFrom="22.458"
+                                android:valueTo="25.333" android:valueType="floatType">
+                    <aapt:attr name="android:interpolator">
+                        <pathInterpolator android:pathData="M 0.0,0.0 c0.289,0 0.724,1 1.0,1.0"/>
+                    </aapt:attr>
+                </objectAnimator>
+                <objectAnimator android:propertyName="translateY" android:duration="100"
+                                android:startOffset="267" android:valueFrom="25.333"
+                                android:valueTo="24.333" android:valueType="floatType">
+                    <aapt:attr name="android:interpolator">
+                        <pathInterpolator android:pathData="M 0.0,0.0 c0.333,0 0.624,1 1.0,1.0"/>
+                    </aapt:attr>
+                </objectAnimator>
+            </set>
+        </aapt:attr>
+    </target>
+    <target android:name="time_group">
+        <aapt:attr name="android:animation">
+            <set android:ordering="together">
+                <objectAnimator android:propertyName="translateX" android:duration="717"
+                                android:startOffset="0" android:valueFrom="0" android:valueTo="1"
+                                android:valueType="floatType"/>
+            </set>
+        </aapt:attr>
+    </target>
+</animated-vector>
\ No newline at end of file
diff --git a/packages/SystemUI/res/anim/lock_unlock_filled.xml b/packages/SystemUI/res/anim/lock_unlock_filled.xml
new file mode 100644
index 0000000..b2238ad
--- /dev/null
+++ b/packages/SystemUI/res/anim/lock_unlock_filled.xml
@@ -0,0 +1,158 @@
+<!-- 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.
+-->
+<animated-vector xmlns:android="http://schemas.android.com/apk/res/android"
+                 xmlns:aapt="http://schemas.android.com/aapt">
+    <aapt:attr name="android:drawable">
+        <vector android:height="42dp" android:width="32dp" android:viewportHeight="42"
+                android:viewportWidth="32">
+            <group android:name="_R_G">
+                <group android:name="_R_G_L_1_G_T_1" android:translateX="16"
+                       android:translateY="25">
+                    <group android:name="_R_G_L_1_G" android:translateX="-10.917"
+                           android:translateY="-9.583">
+                        <path android:name="_R_G_L_1_G_D_0_P_0" android:fillColor="#ffffff"
+                              android:fillAlpha="1" android:fillType="nonZero"
+                              android:pathData=" M18.92 0.25 C18.92,0.25 2.92,0.25 2.92,0.25 C1.45,0.25 0.25,1.45 0.25,2.92 C0.25,2.92 0.25,16.25 0.25,16.25 C0.25,17.72 1.45,18.92 2.92,18.92 C2.92,18.92 18.92,18.92 18.92,18.92 C20.38,18.92 21.58,17.72 21.58,16.25 C21.58,16.25 21.58,2.92 21.58,2.92 C21.58,1.45 20.38,0.25 18.92,0.25c  M10.92 12.25 C9.45,12.25 8.25,11.05 8.25,9.58 C8.25,8.12 9.45,6.92 10.92,6.92 C12.38,6.92 13.58,8.12 13.58,9.58 C13.58,11.05 12.38,12.25 10.92,12.25c "/>
+                    </group>
+                </group>
+                <group android:name="_R_G_L_0_G_N_3_T_1" android:translateX="16"
+                       android:translateY="25">
+                    <group android:name="_R_G_L_0_G_N_3_T_0" android:translateX="-10.917"
+                           android:translateY="-9.583">
+                        <group android:name="_R_G_L_0_G" android:translateX="9.917000000000002"
+                               android:translateY="-12.75">
+                            <path android:name="_R_G_L_0_G_D_0_P_0" android:strokeColor="#ffffff"
+                                  android:strokeLineCap="round" android:strokeLineJoin="round"
+                                  android:strokeWidth="2" android:strokeAlpha="1"
+                                  android:pathData=" M-3 13.04 C-3,13.04 -3,9.04 -3,9.04 C-3,6.83 -1.03,5.04 0.91,5 C3.12,4.96 5,6.79 5,9 C5,9 5,13 5,13 "/>
+                        </group>
+                    </group>
+                </group>
+            </group>
+            <group android:name="time_group"/>
+        </vector>
+    </aapt:attr>
+    <target android:name="_R_G_L_1_G_D_0_P_0">
+        <aapt:attr name="android:animation">
+            <set android:ordering="together">
+                <objectAnimator android:propertyName="pathData" android:duration="100"
+                                android:startOffset="0"
+                                android:valueFrom=" M18.92 0.25 C18.92,0.25 2.92,0.25 2.92,0.25 C1.45,0.25 0.25,1.45 0.25,2.92 C0.25,2.92 0.25,16.25 0.25,16.25 C0.25,17.72 1.45,18.92 2.92,18.92 C2.92,18.92 18.92,18.92 18.92,18.92 C20.38,18.92 21.58,17.72 21.58,16.25 C21.58,16.25 21.58,2.92 21.58,2.92 C21.58,1.45 20.38,0.25 18.92,0.25c M10.92 12.25 C9.45,12.25 8.25,11.05 8.25,9.58 C8.25,8.12 9.45,6.92 10.92,6.92 C12.38,6.92 13.58,8.12 13.58,9.58 C13.58,11.05 12.38,12.25 10.92,12.25c "
+                                android:valueTo=" M18.92 0.25 C18.92,0.25 2.92,0.25 2.92,0.25 C1.45,0.25 0.25,1.45 0.25,2.92 C0.25,2.92 0.25,16.25 0.25,16.25 C0.25,17.72 1.45,18.92 2.92,18.92 C2.92,18.92 18.92,18.92 18.92,18.92 C20.38,18.92 21.58,17.72 21.58,16.25 C21.58,16.25 21.58,2.92 21.58,2.92 C21.58,1.45 20.38,0.25 18.92,0.25c M10.92 11.78 C9.71,11.78 8.72,10.79 8.72,9.58 C8.72,8.37 9.71,7.38 10.92,7.38 C12.13,7.38 13.12,8.37 13.12,9.58 C13.12,10.79 12.13,11.78 10.92,11.78c "
+                                android:valueType="pathType">
+                    <aapt:attr name="android:interpolator">
+                        <pathInterpolator android:pathData="M 0.0,0.0 c0.333,0 0.667,1 1.0,1.0"/>
+                    </aapt:attr>
+                </objectAnimator>
+                <objectAnimator android:propertyName="pathData" android:duration="283"
+                                android:startOffset="100"
+                                android:valueFrom=" M18.92 0.25 C18.92,0.25 2.92,0.25 2.92,0.25 C1.45,0.25 0.25,1.45 0.25,2.92 C0.25,2.92 0.25,16.25 0.25,16.25 C0.25,17.72 1.45,18.92 2.92,18.92 C2.92,18.92 18.92,18.92 18.92,18.92 C20.38,18.92 21.58,17.72 21.58,16.25 C21.58,16.25 21.58,2.92 21.58,2.92 C21.58,1.45 20.38,0.25 18.92,0.25c M10.92 11.78 C9.71,11.78 8.72,10.79 8.72,9.58 C8.72,8.37 9.71,7.38 10.92,7.38 C12.13,7.38 13.12,8.37 13.12,9.58 C13.12,10.79 12.13,11.78 10.92,11.78c "
+                                android:valueTo=" M18.92 0.25 C18.92,0.25 2.92,0.25 2.92,0.25 C1.45,0.25 0.25,1.45 0.25,2.92 C0.25,2.92 0.25,16.25 0.25,16.25 C0.25,17.72 1.45,18.92 2.92,18.92 C2.92,18.92 18.92,18.92 18.92,18.92 C20.38,18.92 21.58,17.72 21.58,16.25 C21.58,16.25 21.58,2.92 21.58,2.92 C21.58,1.45 20.38,0.25 18.92,0.25c M10.92 12.25 C9.45,12.25 8.25,11.05 8.25,9.58 C8.25,8.12 9.45,6.92 10.92,6.92 C12.38,6.92 13.58,8.12 13.58,9.58 C13.58,11.05 12.38,12.25 10.92,12.25c "
+                                android:valueType="pathType">
+                    <aapt:attr name="android:interpolator">
+                        <pathInterpolator android:pathData="M 0.0,0.0 c0.333,0 0.667,1 1.0,1.0"/>
+                    </aapt:attr>
+                </objectAnimator>
+            </set>
+        </aapt:attr>
+    </target>
+    <target android:name="_R_G_L_1_G_T_1">
+        <aapt:attr name="android:animation">
+            <set android:ordering="together">
+                <objectAnimator android:propertyName="translateY" android:duration="133"
+                                android:startOffset="0" android:valueFrom="25" android:valueTo="23"
+                                android:valueType="floatType">
+                    <aapt:attr name="android:interpolator">
+                        <pathInterpolator android:pathData="M 0.0,0.0 c0.32,0 0.803,1 1.0,1.0"/>
+                    </aapt:attr>
+                </objectAnimator>
+                <objectAnimator android:propertyName="translateY" android:duration="133"
+                                android:startOffset="133" android:valueFrom="23"
+                                android:valueTo="26.5" android:valueType="floatType">
+                    <aapt:attr name="android:interpolator">
+                        <pathInterpolator android:pathData="M 0.0,0.0 c0.223,0 0.761,1 1.0,1.0"/>
+                    </aapt:attr>
+                </objectAnimator>
+                <objectAnimator android:propertyName="translateY" android:duration="100"
+                                android:startOffset="267" android:valueFrom="26.5"
+                                android:valueTo="25" android:valueType="floatType">
+                    <aapt:attr name="android:interpolator">
+                        <pathInterpolator android:pathData="M 0.0,0.0 c0.311,0 0.633,1 1.0,1.0"/>
+                    </aapt:attr>
+                </objectAnimator>
+            </set>
+        </aapt:attr>
+    </target>
+    <target android:name="_R_G_L_0_G_D_0_P_0">
+        <aapt:attr name="android:animation">
+            <set android:ordering="together">
+                <objectAnimator android:propertyName="pathData" android:duration="67"
+                                android:startOffset="0"
+                                android:valueFrom="M-3 13.04 C-3,13.04 -3,9.04 -3,9.04 C-3,6.83 -1.03,5.04 0.91,5 C3.12,4.96 5,6.79 5,9 C5,9 5,13 5,13 "
+                                android:valueTo="M-3 6.73 C-3,5.62 -2.56,4.67 -1.84,4 C-1.11,3.32 -0.09,2.93 1.06,2.94 C3.27,2.96 5,4.54 5,6.75 C5,6.75 5,13 5,13 "
+                                android:valueType="pathType">
+                    <aapt:attr name="android:interpolator">
+                        <pathInterpolator android:pathData="M 0.0,0.0 c0.592,0 0.503,1 1.0,1.0"/>
+                    </aapt:attr>
+                </objectAnimator>
+                <objectAnimator android:propertyName="pathData" android:duration="183"
+                                android:startOffset="67"
+                                android:valueFrom="M-3 6.73 C-3,5.62 -2.56,4.67 -1.84,4 C-1.11,3.32 -0.09,2.93 1.06,2.94 C3.27,2.96 5,4.54 5,6.75 C5,6.75 5,13 5,13 "
+                                android:valueTo="M13 9 C13,7.9 12.55,6.9 11.83,6.17 C11.1,5.45 10.11,5 9,5 C6.79,5 5,6.79 5,9 C5,9 5,13 5,13 "
+                                android:valueType="pathType">
+                    <aapt:attr name="android:interpolator">
+                        <pathInterpolator android:pathData="M 0.0,0.0 c0.563,0 0.363,1 1.0,1.0"/>
+                    </aapt:attr>
+                </objectAnimator>
+            </set>
+        </aapt:attr>
+    </target>
+    <target android:name="_R_G_L_0_G_N_3_T_1">
+        <aapt:attr name="android:animation">
+            <set android:ordering="together">
+                <objectAnimator android:propertyName="translateY" android:duration="133"
+                                android:startOffset="0" android:valueFrom="25" android:valueTo="23"
+                                android:valueType="floatType">
+                    <aapt:attr name="android:interpolator">
+                        <pathInterpolator android:pathData="M 0.0,0.0 c0.32,0 0.803,1 1.0,1.0"/>
+                    </aapt:attr>
+                </objectAnimator>
+                <objectAnimator android:propertyName="translateY" android:duration="133"
+                                android:startOffset="133" android:valueFrom="23"
+                                android:valueTo="26.5" android:valueType="floatType">
+                    <aapt:attr name="android:interpolator">
+                        <pathInterpolator android:pathData="M 0.0,0.0 c0.223,0 0.761,1 1.0,1.0"/>
+                    </aapt:attr>
+                </objectAnimator>
+                <objectAnimator android:propertyName="translateY" android:duration="100"
+                                android:startOffset="267" android:valueFrom="26.5"
+                                android:valueTo="25" android:valueType="floatType">
+                    <aapt:attr name="android:interpolator">
+                        <pathInterpolator android:pathData="M 0.0,0.0 c0.311,0 0.633,1 1.0,1.0"/>
+                    </aapt:attr>
+                </objectAnimator>
+            </set>
+        </aapt:attr>
+    </target>
+    <target android:name="time_group">
+        <aapt:attr name="android:animation">
+            <set android:ordering="together">
+                <objectAnimator android:propertyName="translateX" android:duration="717"
+                                android:startOffset="0" android:valueFrom="0" android:valueTo="1"
+                                android:valueType="floatType"/>
+            </set>
+        </aapt:attr>
+    </target>
+</animated-vector>
\ No newline at end of file
diff --git a/packages/SystemUI/res/anim/lock_unlock_rounded.xml b/packages/SystemUI/res/anim/lock_unlock_rounded.xml
new file mode 100644
index 0000000..14a88a4
--- /dev/null
+++ b/packages/SystemUI/res/anim/lock_unlock_rounded.xml
@@ -0,0 +1,209 @@
+<!-- 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.
+-->
+<animated-vector xmlns:android="http://schemas.android.com/apk/res/android"
+                 xmlns:aapt="http://schemas.android.com/aapt">
+    <aapt:attr name="android:drawable">
+        <vector android:height="42dp" android:width="32dp" android:viewportHeight="42"
+                android:viewportWidth="32">
+            <group android:name="_R_G">
+                <group android:name="_R_G_L_2_G_T_1" android:translateX="16"
+                       android:translateY="25">
+                    <group android:name="_R_G_L_2_G" android:translateX="-14.667"
+                           android:translateY="-12.667">
+                        <path android:name="_R_G_L_2_G_D_0_P_0" android:strokeColor="#ffffff"
+                              android:strokeLineCap="round" android:strokeLineJoin="round"
+                              android:strokeWidth="1.5" android:strokeAlpha="1"
+                              android:pathData=" M22.09 5 C22.09,5 6,5 6,5 C5.45,5 5,5.45 5,6 C5,6 5,19.33 5,19.33 C5,19.89 5.45,20.33 6,20.33 C6,20.33 23.33,20.33 23.33,20.33 C23.89,20.33 24.33,19.89 24.33,19.33 C24.33,19.33 24.33,6 24.33,6 C24.33,5.45 23.89,5 23.33,5 C23.33,5 22.09,5 22.09,5c "/>
+                    </group>
+                </group>
+                <group android:name="_R_G_L_1_G_N_4_T_1" android:translateX="16"
+                       android:translateY="25">
+                    <group android:name="_R_G_L_1_G_N_4_T_0" android:translateX="-14.667"
+                           android:translateY="-12.667">
+                        <group android:name="_R_G_L_1_G" android:translateX="12.416"
+                               android:translateY="10.417" android:pivotX="2.25"
+                               android:pivotY="2.25" android:scaleX="1" android:scaleY="1">
+                            <path android:name="_R_G_L_1_G_D_0_P_0" android:fillColor="#ffffff"
+                                  android:fillAlpha="1" android:fillType="nonZero"
+                                  android:pathData=" M2.25 0.25 C3.35,0.25 4.25,1.15 4.25,2.25 C4.25,3.35 3.35,4.25 2.25,4.25 C1.15,4.25 0.25,3.35 0.25,2.25 C0.25,1.15 1.15,0.25 2.25,0.25c "/>
+                        </group>
+                    </group>
+                </group>
+                <group android:name="_R_G_L_0_G_N_4_T_1" android:translateX="16"
+                       android:translateY="25">
+                    <group android:name="_R_G_L_0_G_N_4_T_0" android:translateX="-14.667"
+                           android:translateY="-12.667">
+                        <group android:name="_R_G_L_0_G" android:translateX="5.333"
+                               android:translateY="-9.425999999999998">
+                            <path android:name="_R_G_L_0_G_D_0_P_0" android:strokeColor="#ffffff"
+                                  android:strokeLineCap="round" android:strokeLineJoin="round"
+                                  android:strokeWidth="1.5" android:strokeAlpha="1"
+                                  android:pathData=" M13.67 13.8 C13.67,13.8 13.67,8.94 13.67,8.94 C13.63,6.75 11.69,5 9.33,5.04 C6.98,5 5.04,6.75 5,8.94 C5,8.94 5,13.8 5,13.8 "/>
+                        </group>
+                    </group>
+                </group>
+            </group>
+            <group android:name="time_group"/>
+        </vector>
+    </aapt:attr>
+    <target android:name="_R_G_L_2_G_T_1">
+        <aapt:attr name="android:animation">
+            <set android:ordering="together">
+                <objectAnimator android:propertyName="translateY" android:duration="133"
+                                android:startOffset="0" android:valueFrom="25"
+                                android:valueTo="23.5" android:valueType="floatType">
+                    <aapt:attr name="android:interpolator">
+                        <pathInterpolator android:pathData="M 0.0,0.0 c0.333,0 0.667,1 1.0,1.0"/>
+                    </aapt:attr>
+                </objectAnimator>
+                <objectAnimator android:propertyName="translateY" android:duration="133"
+                                android:startOffset="133" android:valueFrom="23.5"
+                                android:valueTo="26" android:valueType="floatType">
+                    <aapt:attr name="android:interpolator">
+                        <pathInterpolator android:pathData="M 0.0,0.0 c0.333,0 0.667,1 1.0,1.0"/>
+                    </aapt:attr>
+                </objectAnimator>
+                <objectAnimator android:propertyName="translateY" android:duration="100"
+                                android:startOffset="267" android:valueFrom="26"
+                                android:valueTo="25" android:valueType="floatType">
+                    <aapt:attr name="android:interpolator">
+                        <pathInterpolator android:pathData="M 0.0,0.0 c0.333,0 0.667,1 1.0,1.0"/>
+                    </aapt:attr>
+                </objectAnimator>
+            </set>
+        </aapt:attr>
+    </target>
+    <target android:name="_R_G_L_1_G">
+        <aapt:attr name="android:animation">
+            <set android:ordering="together">
+                <objectAnimator android:propertyName="scaleX" android:duration="100"
+                                android:startOffset="0" android:valueFrom="1" android:valueTo="0.85"
+                                android:valueType="floatType">
+                    <aapt:attr name="android:interpolator">
+                        <pathInterpolator android:pathData="M 0.0,0.0 c0.333,0 0.346,1 1.0,1.0"/>
+                    </aapt:attr>
+                </objectAnimator>
+                <objectAnimator android:propertyName="scaleY" android:duration="100"
+                                android:startOffset="0" android:valueFrom="1" android:valueTo="0.85"
+                                android:valueType="floatType">
+                    <aapt:attr name="android:interpolator">
+                        <pathInterpolator android:pathData="M 0.0,0.0 c0.333,0 0.346,1 1.0,1.0"/>
+                    </aapt:attr>
+                </objectAnimator>
+                <objectAnimator android:propertyName="scaleX" android:duration="283"
+                                android:startOffset="100" android:valueFrom="0.85"
+                                android:valueTo="1" android:valueType="floatType">
+                    <aapt:attr name="android:interpolator">
+                        <pathInterpolator android:pathData="M 0.0,0.0 c0.423,0 0.667,1 1.0,1.0"/>
+                    </aapt:attr>
+                </objectAnimator>
+                <objectAnimator android:propertyName="scaleY" android:duration="283"
+                                android:startOffset="100" android:valueFrom="0.85"
+                                android:valueTo="1" android:valueType="floatType">
+                    <aapt:attr name="android:interpolator">
+                        <pathInterpolator android:pathData="M 0.0,0.0 c0.423,0 0.667,1 1.0,1.0"/>
+                    </aapt:attr>
+                </objectAnimator>
+            </set>
+        </aapt:attr>
+    </target>
+    <target android:name="_R_G_L_1_G_N_4_T_1">
+        <aapt:attr name="android:animation">
+            <set android:ordering="together">
+                <objectAnimator android:propertyName="translateY" android:duration="133"
+                                android:startOffset="0" android:valueFrom="25"
+                                android:valueTo="23.5" android:valueType="floatType">
+                    <aapt:attr name="android:interpolator">
+                        <pathInterpolator android:pathData="M 0.0,0.0 c0.333,0 0.667,1 1.0,1.0"/>
+                    </aapt:attr>
+                </objectAnimator>
+                <objectAnimator android:propertyName="translateY" android:duration="133"
+                                android:startOffset="133" android:valueFrom="23.5"
+                                android:valueTo="26" android:valueType="floatType">
+                    <aapt:attr name="android:interpolator">
+                        <pathInterpolator android:pathData="M 0.0,0.0 c0.333,0 0.667,1 1.0,1.0"/>
+                    </aapt:attr>
+                </objectAnimator>
+                <objectAnimator android:propertyName="translateY" android:duration="100"
+                                android:startOffset="267" android:valueFrom="26"
+                                android:valueTo="25" android:valueType="floatType">
+                    <aapt:attr name="android:interpolator">
+                        <pathInterpolator android:pathData="M 0.0,0.0 c0.333,0 0.667,1 1.0,1.0"/>
+                    </aapt:attr>
+                </objectAnimator>
+            </set>
+        </aapt:attr>
+    </target>
+    <target android:name="_R_G_L_0_G_D_0_P_0">
+        <aapt:attr name="android:animation">
+            <set android:ordering="together">
+                <objectAnimator android:propertyName="pathData" android:duration="67"
+                                android:startOffset="0"
+                                android:valueFrom="M13.67 13.8 C13.67,13.8 13.67,8.94 13.67,8.94 C13.63,6.75 11.69,5 9.33,5.04 C6.98,5 5.04,6.75 5,8.94 C5,8.94 5,13.8 5,13.8 "
+                                android:valueTo="M13.67 13.8 C13.67,13.8 13.69,5.06 13.69,5.06 C13.65,2.87 11.71,1.13 9.35,1.16 C7,1.13 5.06,2.87 5.02,5.06 C5.02,5.06 5,7.93 5,7.93 "
+                                android:valueType="pathType">
+                    <aapt:attr name="android:interpolator">
+                        <pathInterpolator android:pathData="M 0.0,0.0 c0.658,0 0.317,1 1.0,1.0"/>
+                    </aapt:attr>
+                </objectAnimator>
+                <objectAnimator android:propertyName="pathData" android:duration="183"
+                                android:startOffset="67"
+                                android:valueFrom="M13.67 13.8 C13.67,13.8 13.69,5.06 13.69,5.06 C13.65,2.87 11.71,1.13 9.35,1.16 C7,1.13 5.06,2.87 5.02,5.06 C5.02,5.06 5,7.93 5,7.93 "
+                                android:valueTo="M13.67 13.8 C13.67,13.8 13.67,8.94 13.67,8.94 C13.68,6.62 15.69,5.03 18.01,5.04 C20.46,5.04 22.32,6.89 22.34,8.85 C22.34,8.85 22.33,8.89 22.33,8.89 "
+                                android:valueType="pathType">
+                    <aapt:attr name="android:interpolator">
+                        <pathInterpolator android:pathData="M 0.0,0.0 c0.679,0 0.175,1 1.0,1.0"/>
+                    </aapt:attr>
+                </objectAnimator>
+            </set>
+        </aapt:attr>
+    </target>
+    <target android:name="_R_G_L_0_G_N_4_T_1">
+        <aapt:attr name="android:animation">
+            <set android:ordering="together">
+                <objectAnimator android:propertyName="translateY" android:duration="133"
+                                android:startOffset="0" android:valueFrom="25"
+                                android:valueTo="23.5" android:valueType="floatType">
+                    <aapt:attr name="android:interpolator">
+                        <pathInterpolator android:pathData="M 0.0,0.0 c0.333,0 0.667,1 1.0,1.0"/>
+                    </aapt:attr>
+                </objectAnimator>
+                <objectAnimator android:propertyName="translateY" android:duration="133"
+                                android:startOffset="133" android:valueFrom="23.5"
+                                android:valueTo="26" android:valueType="floatType">
+                    <aapt:attr name="android:interpolator">
+                        <pathInterpolator android:pathData="M 0.0,0.0 c0.333,0 0.667,1 1.0,1.0"/>
+                    </aapt:attr>
+                </objectAnimator>
+                <objectAnimator android:propertyName="translateY" android:duration="100"
+                                android:startOffset="267" android:valueFrom="26"
+                                android:valueTo="25" android:valueType="floatType">
+                    <aapt:attr name="android:interpolator">
+                        <pathInterpolator android:pathData="M 0.0,0.0 c0.333,0 0.667,1 1.0,1.0"/>
+                    </aapt:attr>
+                </objectAnimator>
+            </set>
+        </aapt:attr>
+    </target>
+    <target android:name="time_group">
+        <aapt:attr name="android:animation">
+            <set android:ordering="together">
+                <objectAnimator android:propertyName="translateX" android:duration="717"
+                                android:startOffset="0" android:valueFrom="0" android:valueTo="1"
+                                android:valueType="floatType"/>
+            </set>
+        </aapt:attr>
+    </target>
+</animated-vector>
\ No newline at end of file
diff --git a/packages/SystemUI/res/drawable/ic_5g_e_mobiledata.xml b/packages/SystemUI/res/drawable/ic_5g_e_mobiledata.xml
index fe1bb26..7c7c8c1 100644
--- a/packages/SystemUI/res/drawable/ic_5g_e_mobiledata.xml
+++ b/packages/SystemUI/res/drawable/ic_5g_e_mobiledata.xml
@@ -16,16 +16,10 @@
 <vector xmlns:android="http://schemas.android.com/apk/res/android"
     android:viewportWidth="22"
     android:viewportHeight="17"
-    android:width="22dp"
-    android:height="17dp">
+    android:width="19.41dp"
+    android:height="15dp">
   <path
       android:fillColor="#FFFFFFFF"
-      android:pathData="M1.22,8.49l0.43-4.96h4.33v1.17H2.67L2.44,7.41c0.41-0.29,0.85-0.43,1.33-0.43c0.77,0,1.38,0.3,1.83,0.9 s0.66,1.41,0.66,2.43c0,1.03-0.24,1.84-0.72,2.43s-1.14,0.88-1.98,0.88c-0.75,0-1.36-0.24-1.83-0.73s-0.74-1.16-0.81-2.02h1.13 c0.07,0.57,0.23,1,0.49,1.29c0.26,0.29,0.59,0.43,1.01,0.43c0.47,0,0.84-0.2,1.1-0.61c0.26-0.41,0.4-0.96,0.4-1.65 c0-0.65-0.14-1.18-0.43-1.59S3.96,8.11,3.47,8.11c-0.4,0-0.72,0.1-0.96,0.31L2.19,8.75L1.22,8.49z" />
-  <path
-      android:fillColor="#FFFFFFFF"
-      android:pathData="M14.14,12.24l-0.22,0.27c-0.63,0.73-1.55,1.1-2.76,1.1c-1.08,0-1.92-0.36-2.53-1.07c-0.61-0.71-0.93-1.72-0.94-3.02V7.56 c0-1.39,0.28-2.44,0.84-3.13c0.56-0.7,1.39-1.04,2.51-1.04c0.95,0,1.69,0.26,2.23,0.79c0.54,0.53,0.83,1.28,0.89,2.26h-1.25 c-0.05-0.62-0.22-1.1-0.52-1.45c-0.29-0.35-0.74-0.52-1.34-0.52c-0.72,0-1.24,0.23-1.57,0.7C9.14,5.63,8.96,6.37,8.95,7.4v2.03 c0,1,0.19,1.77,0.57,2.31c0.38,0.54,0.93,0.8,1.65,0.8c0.67,0,1.19-0.16,1.54-0.49l0.18-0.17V9.59h-1.82V8.52h3.07V12.24z" />
-  <path
-      android:fillColor="#FFFFFFFF"
-      android:pathData="M20.96,8.88h-3.52v3.53h4.1v1.07h-5.35V3.52h5.28V4.6h-4.03V7.8h3.52V8.88z" />
-
+      android:pathData="M 6.72 3.52 L 6.54 4.69 L 3.34 4.69 L 2.63 7.41 C 3.011 7.143 3.465 7 3.93 7 C 4.5 6.986 5.041 7.251 5.38 7.71 C 5.756 8.249 5.952 8.893 5.94 9.55 C 5.98 10.276 5.864 11.002 5.6 11.68 C 5.385 12.267 5.007 12.78 4.51 13.16 C 4.043 13.499 3.476 13.671 2.9 13.65 C 2.271 13.653 1.675 13.369 1.28 12.88 C 0.854 12.302 0.636 11.597 0.66 10.88 L 1.76 10.88 C 1.81 12 2.21 12.57 3 12.58 C 3.592 12.589 4.132 12.243 4.37 11.7 C 4.708 11.044 4.85 10.305 4.78 9.57 C 4.767 9.209 4.645 8.86 4.43 8.57 C 4.239 8.309 3.934 8.156 3.61 8.16 C 3.404 8.138 3.196 8.162 3 8.23 C 2.748 8.358 2.518 8.527 2.32 8.73 L 1.31 8.46 L 2.51 3.52 L 6.72 3.52 Z M 11.7 3.39 C 12.459 3.353 13.195 3.662 13.7 4.23 C 14.185 4.864 14.42 5.654 14.36 6.45 L 13.1 6.45 C 13.131 5.938 12.998 5.43 12.72 5 C 12.455 4.679 12.056 4.498 11.64 4.51 C 11.025 4.456 10.42 4.688 10 5.14 C 9.491 5.811 9.179 6.611 9.1 7.45 L 8.75 9.54 L 8.75 10.57 C 8.82 11.86 9.36 12.52 10.36 12.57 C 10.701 12.593 11.043 12.538 11.36 12.41 C 11.661 12.281 11.943 12.113 12.2 11.91 L 12.62 9.62 L 10.77 9.62 L 11 8.52 L 14 8.52 L 13.36 12.23 C 13.176 12.483 12.953 12.706 12.7 12.89 C 11.995 13.398 11.138 13.652 10.27 13.61 C 9.507 13.634 8.773 13.315 8.27 12.74 C 7.748 12.085 7.475 11.267 7.5 10.43 C 7.47 10.097 7.47 9.763 7.5 9.43 L 7.8 7.43 C 7.927 6.332 8.36 5.293 9.05 4.43 C 9.725 3.692 10.703 3.308 11.7 3.39 Z M 20.81 7.21 L 20.62 8.29 L 18.32 8.29 L 18.06 9.8 L 20.06 9.8 L 19.83 10.84 L 17.88 10.84 L 17.59 12.54 L 19.9 12.54 L 19.71 13.61 L 16.14 13.61 L 17.25 7.21 L 20.81 7.21 Z" />
+  <path android:pathData="M 0 0 H 14 V 17 H 0 V 0 Z"/>
 </vector>
diff --git a/packages/SystemUI/res/drawable/ic_info_outline.xml b/packages/SystemUI/res/drawable/ic_info_outline.xml
index a4a3e9a..44e09f6 100644
--- a/packages/SystemUI/res/drawable/ic_info_outline.xml
+++ b/packages/SystemUI/res/drawable/ic_info_outline.xml
@@ -15,8 +15,8 @@
   -->
 
 <vector xmlns:android="http://schemas.android.com/apk/res/android"
-        android:width="32dp"
-        android:height="32dp"
+        android:width="24dp"
+        android:height="24dp"
         android:viewportWidth="24.0"
         android:viewportHeight="24.0">
     <path
diff --git a/packages/SystemUI/res/drawable/ic_invert_colors.xml b/packages/SystemUI/res/drawable/ic_invert_colors.xml
index 77d4918..37ea080 100644
--- a/packages/SystemUI/res/drawable/ic_invert_colors.xml
+++ b/packages/SystemUI/res/drawable/ic_invert_colors.xml
@@ -15,8 +15,8 @@
      limitations under the License.
 -->
 <vector xmlns:android="http://schemas.android.com/apk/res/android"
-    android:width="48dp"
-    android:height="48dp"
+    android:width="24dp"
+    android:height="24dp"
     android:viewportWidth="24.0"
     android:viewportHeight="24.0">
     <path
diff --git a/packages/SystemUI/res/drawable/ic_qs_bluetooth_connecting.xml b/packages/SystemUI/res/drawable/ic_qs_bluetooth_connecting.xml
index fbd92de..d2ee283 100644
--- a/packages/SystemUI/res/drawable/ic_qs_bluetooth_connecting.xml
+++ b/packages/SystemUI/res/drawable/ic_qs_bluetooth_connecting.xml
@@ -14,8 +14,8 @@
     limitations under the License.
 -->
 <vector xmlns:android="http://schemas.android.com/apk/res/android"
-    android:width="64dp"
-    android:height="64dp"
+    android:width="24dp"
+    android:height="24dp"
     android:viewportWidth="24.0"
     android:viewportHeight="24.0"
     android:tint="?android:attr/colorControlNormal" >
diff --git a/packages/SystemUI/res/drawable/ic_qs_no_sim.xml b/packages/SystemUI/res/drawable/ic_qs_no_sim.xml
index 22e12cc..6cabcaf 100644
--- a/packages/SystemUI/res/drawable/ic_qs_no_sim.xml
+++ b/packages/SystemUI/res/drawable/ic_qs_no_sim.xml
@@ -14,8 +14,8 @@
     limitations under the License.
 -->
 <vector xmlns:android="http://schemas.android.com/apk/res/android"
-        android:width="32dp"
-        android:height="32dp"
+        android:width="24dp"
+        android:height="24dp"
         android:viewportWidth="24.0"
         android:viewportHeight="24.0">
     <path
diff --git a/packages/SystemUI/res/drawable/ic_screenshot_delete.xml b/packages/SystemUI/res/drawable/ic_screenshot_delete.xml
index d60ee41..4cf578a 100644
--- a/packages/SystemUI/res/drawable/ic_screenshot_delete.xml
+++ b/packages/SystemUI/res/drawable/ic_screenshot_delete.xml
@@ -14,8 +14,8 @@
     limitations under the License.
 -->
 <vector xmlns:android="http://schemas.android.com/apk/res/android"
-        android:width="32dp"
-        android:height="32dp"
+        android:width="24dp"
+        android:height="24dp"
         android:viewportWidth="24.0"
         android:viewportHeight="24.0">
     <path
diff --git a/packages/SystemUI/res/layout/keyguard_bottom_area.xml b/packages/SystemUI/res/layout/keyguard_bottom_area.xml
index 7fc2066..21c2c6b 100644
--- a/packages/SystemUI/res/layout/keyguard_bottom_area.xml
+++ b/packages/SystemUI/res/layout/keyguard_bottom_area.xml
@@ -46,6 +46,8 @@
                 android:layout_width="match_parent"
                 android:layout_height="wrap_content"
                 android:gravity="center"
+                android:paddingStart="@dimen/keyguard_indication_text_padding"
+                android:paddingEnd="@dimen/keyguard_indication_text_padding"
                 android:textAppearance="@style/TextAppearance.Keyguard.BottomArea"
                 android:visibility="gone" />
 
@@ -54,6 +56,8 @@
                 android:layout_width="match_parent"
                 android:layout_height="wrap_content"
                 android:gravity="center"
+                android:paddingStart="@dimen/keyguard_indication_text_padding"
+                android:paddingEnd="@dimen/keyguard_indication_text_padding"
                 android:textAppearance="@style/TextAppearance.Keyguard.BottomArea"
                 android:accessibilityLiveRegion="polite" />
 
diff --git a/packages/SystemUI/res/values/attrs.xml b/packages/SystemUI/res/values/attrs.xml
index f124d89..6becd21 100644
--- a/packages/SystemUI/res/values/attrs.xml
+++ b/packages/SystemUI/res/values/attrs.xml
@@ -75,14 +75,15 @@
         <attr name="horizontalSpacing" format="dimension" />
     </declare-styleable>
 
-    <!-- Theme for icons in the status bar (light/dark). background/fillColor is used for dual tone
-         icons like wifi and signal, and singleToneColor is used for icons with only one tone.
+    <!-- Theme for icons in the status/nav bar (light/dark). background/fillColor is used for dual
+         tone icons like wifi and signal, and singleToneColor is used for icons with only one tone.
          Contract: Pixel with fillColor blended over backgroundColor blended over translucent should
          equal to singleToneColor blended over translucent. -->
     <declare-styleable name="TonedIcon">
         <attr name="backgroundColor" format="integer" />
         <attr name="fillColor" format="integer" />
         <attr name="singleToneColor" format="integer" />
+        <attr name="homeHandleColor" format="integer" />
     </declare-styleable>
 
     <declare-styleable name="StatusBarWindowView_Layout">
diff --git a/packages/SystemUI/res/values/colors.xml b/packages/SystemUI/res/values/colors.xml
index e7a1a66..61816f6 100644
--- a/packages/SystemUI/res/values/colors.xml
+++ b/packages/SystemUI/res/values/colors.xml
@@ -116,6 +116,9 @@
     <!-- The color of the navigation bar icons. Need to be in sync with ic_sysbar_* -->
     <color name="navigation_bar_icon_color">#E5FFFFFF</color>
 
+    <color name="navigation_bar_home_handle_light_color">#EBffffff</color>
+    <color name="navigation_bar_home_handle_dark_color">#99000000</color>
+
     <!-- The shadow color for light navigation bar icons. -->
     <color name="nav_key_button_shadow_color">#30000000</color>
 
diff --git a/packages/SystemUI/res/values/config.xml b/packages/SystemUI/res/values/config.xml
index 6e6c009..340cb3a 100644
--- a/packages/SystemUI/res/values/config.xml
+++ b/packages/SystemUI/res/values/config.xml
@@ -40,8 +40,8 @@
     <!-- Whether or not we show the number in the bar. -->
     <bool name="config_statusBarShowNumber">false</bool>
 
-    <!-- If the lock screen should be dismissed after biometric auth. -->
-    <bool name="config_faceAuthDismissesKeyguard">false</bool>
+    <!-- For how long the lock screen can be on before the display turns off. -->
+    <integer name="config_lockScreenDisplayTimeout">10000</integer>
 
     <!-- Vibrator pattern for camera gesture launch. -->
     <integer-array translatable="false" name="config_cameraLaunchGestureVibePattern">
@@ -141,6 +141,9 @@
     <!-- The number of milliseconds before the heads up notification auto-dismisses. -->
     <integer name="heads_up_notification_decay">5000</integer>
 
+    <!-- The number of milliseconds before the heads up notification sent automatically by the system auto-dismisses. -->
+    <integer name="auto_heads_up_notification_decay">3000</integer>
+
     <!-- The number of milliseconds after a heads up notification is pushed back
      before the app can interrupt again. -->
     <integer name="heads_up_default_snooze_length_ms">60000</integer>
@@ -151,15 +154,8 @@
     <!-- The number of milliseconds before the heads up notification accepts touches. -->
     <integer name="touch_acceptance_delay">700</integer>
 
-    <!-- The number of milliseconds before the ambient notification auto-dismisses. This will
-         override the default pulse length. -->
-    <integer name="ambient_notification_decay">10000</integer>
-
-    <!-- Minimum display time for a heads up notification, in milliseconds. -->
-    <integer name="ambient_notification_minimum_time">2000</integer>
-
     <!-- The number of milliseconds to extend ambient pulse by when prompted (e.g. on touch) -->
-    <integer name="ambient_notification_extension_time">6000</integer>
+    <integer name="ambient_notification_extension_time">10000</integer>
 
     <!-- In multi-window, determines whether the stack where recents lives should grow from
          the smallest position when being launched. -->
@@ -200,25 +196,9 @@
     <!-- Doze: duration to avoid false pickup gestures triggered by notification vibrations -->
     <integer name="doze_pickup_vibration_threshold">2000</integer>
 
-    <!-- Doze: can we assume the pickup sensor includes a proximity check?
-         This is ignored if doze_pickup_subtype_performs_proximity_check is not empty.
-         @deprecated: use doze_pickup_subtype_performs_proximity_check instead.-->
+    <!-- Doze: can we assume the pickup sensor includes a proximity check? -->
     <bool name="doze_pickup_performs_proximity_check">false</bool>
 
-    <!-- Doze: a list of pickup sensor subtypes that perform a proximity check before they trigger.
-               If not empty, either * or !* must appear to specify the default.
-               If empty, falls back to doze_pickup_performs_proximity_check.
-
-               Examples: 1,2,3,!* -> subtypes 1,2 and 3 perform the check, all others don't.
-                         !1,!2,*  -> subtypes 1 and 2 don't perform the check, all others do.
-                         !8,*     -> subtype 8 does not perform the check, all others do
-                         1,1,*    -> illegal, every item may only appear once
-                         1,!1,*   -> illegal, no contradictions allowed
-                         1,2      -> illegal, need either * or !*
-                         1,,4a3   -> illegal, no empty or non-numeric terms allowed
-    -->
-    <string name="doze_pickup_subtype_performs_proximity_check"></string>
-
     <!-- Type of a sensor that provides a low-power estimate of the desired display
          brightness, suitable to listen to while the device is asleep (e.g. during
          always-on display) -->
@@ -496,4 +476,13 @@
     <!-- ThemePicker package name for overlaying icons. -->
     <string name="themepicker_overlayable_package" translatable="false">com.android.wallpaper</string>
 
+    <!-- Default rounded corner curve (a Bezier). Must match (the curved path in) rounded.xml.
+         Note that while rounded.xml includes the entire path (including the horizontal and vertical
+         corner edges), this pulls out just the curve.
+     -->
+    <string name="config_rounded_mask" translatable="false">"M8,0C3.6,0,0,3.6,0,8"</string>
+
+    <!-- Preferred refresh rate at keyguard, if supported by the display -->
+    <integer name="config_keyguardRefreshRate">-1</integer>
+
 </resources>
diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml
index c5e4662..bef1fc2 100644
--- a/packages/SystemUI/res/values/dimens.xml
+++ b/packages/SystemUI/res/values/dimens.xml
@@ -112,7 +112,7 @@
     <dimen name="status_bar_connected_device_bt_indicator_size">17dp</dimen>
 
     <!-- Height of a small notification in the status bar-->
-    <dimen name="notification_min_height">106dp</dimen>
+    <dimen name="notification_min_height">@*android:dimen/notification_min_height</dimen>
 
     <!-- Increased height of a small notification in the status bar -->
     <dimen name="notification_min_height_increased">146dp</dimen>
@@ -183,6 +183,9 @@
     <!-- The padding on the bottom of the notifications on the keyguard -->
     <dimen name="keyguard_indication_bottom_padding">12sp</dimen>
 
+    <!-- The padding at start and end of indication text shown on AOD -->
+    <dimen name="keyguard_indication_text_padding">16dp</dimen>
+
     <!-- Shadows under the clock, date and other keyguard text fields -->
     <dimen name="keyguard_shadow_radius">5</dimen>
 
@@ -258,8 +261,8 @@
     <!-- size at which Notification icons will be drawn on Ambient Display -->
     <dimen name="status_bar_icon_drawing_size_dark">@*android:dimen/notification_header_icon_size_ambient</dimen>
 
-    <!-- size of notification icons on AOD -->
-    <dimen name="dark_shelf_icon_size">16dp</dimen>
+    <!-- size of notification icons when the notifications are hidden -->
+    <dimen name="hidden_shelf_icon_size">16dp</dimen>
 
     <!-- opacity at which Notification icons will be drawn in the status bar -->
     <item type="dimen" name="status_bar_icon_drawing_alpha">90%</item>
diff --git a/packages/SystemUI/res/values/ids.xml b/packages/SystemUI/res/values/ids.xml
index e97055f0..66f1949 100644
--- a/packages/SystemUI/res/values/ids.xml
+++ b/packages/SystemUI/res/values/ids.xml
@@ -94,6 +94,16 @@
     <item type="id" name="top_roundess_animator_start_tag"/>
     <item type="id" name="top_roundess_animator_end_tag"/>
 
+    <item type="id" name="keyguard_hun_animator_tag"/>
+    <item type="id" name="keyguard_hun_animator_start_tag"/>
+    <item type="id" name="keyguard_hun_animator_end_tag"/>
+
+    <item type="id" name="view_group_fade_helper_modified_views"/>
+    <item type="id" name="view_group_fade_helper_animator"/>
+    <item type="id" name="view_group_fade_helper_previous_value_tag"/>
+    <item type="id" name="view_group_fade_helper_restore_tag"/>
+    <item type="id" name="view_group_fade_helper_hardware_layer"/>
+
     <!-- Accessibility actions for the notification menu -->
     <item type="id" name="action_snooze_undo"/>
     <item type="id" name="action_snooze_shorter"/>
diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml
index 591af82..7feacb4 100644
--- a/packages/SystemUI/res/values/strings.xml
+++ b/packages/SystemUI/res/values/strings.xml
@@ -303,6 +303,8 @@
     <string name="biometric_dialog_face_icon_description_authenticated">Face authenticated</string>
     <!-- Content description for the face icon when the user has been authenticated and the confirm button has been pressed [CHAR LIMIT=NONE] -->
     <string name="biometric_dialog_face_icon_description_confirmed">Confirmed</string>
+    <!-- Message shown when a biometric is authenticated, waiting for the user to confirm authentication [CHAR LIMIT=40]-->
+    <string name="biometric_dialog_tap_confirm">Tap Confirm to complete</string>
 
     <!-- Message shown when the system-provided fingerprint dialog is shown, asking for authentication -->
     <string name="fingerprint_dialog_touch_sensor">Touch the fingerprint sensor</string>
@@ -953,8 +955,8 @@
     <!-- Shows to explain the double tap interaction with notifications: After tapping a notification on Keyguard, this will explain users to tap again to launch a notification. [CHAR LIMIT=60] -->
     <string name="notification_tap_again">Tap again to open</string>
 
-    <!-- Shows when people have pressed the unlock icon to explain how to unlock. [CHAR LIMIT=60] -->
-    <string name="keyguard_unlock">Swipe up to unlock</string>
+    <!-- Message shown when lock screen is tapped or face authentication fails. [CHAR LIMIT=60] -->
+    <string name="keyguard_unlock">Swipe up to open</string>
 
     <!-- Text on keyguard screen and in Quick Settings footer indicating that the device is enterprise-managed by a Device Owner [CHAR LIMIT=60] -->
     <string name="do_disclosure_generic">This device is managed by your organization</string>
diff --git a/packages/SystemUI/res/values/styles.xml b/packages/SystemUI/res/values/styles.xml
index 2f1770a..6374191 100644
--- a/packages/SystemUI/res/values/styles.xml
+++ b/packages/SystemUI/res/values/styles.xml
@@ -366,11 +366,13 @@
         <item name="backgroundColor">@color/light_mode_icon_color_dual_tone_background</item>
         <item name="fillColor">@color/light_mode_icon_color_dual_tone_fill</item>
         <item name="singleToneColor">@color/light_mode_icon_color_single_tone</item>
+        <item name="homeHandleColor">@color/navigation_bar_home_handle_light_color</item>
     </style>
     <style name="DualToneDarkTheme">
         <item name="backgroundColor">@color/dark_mode_icon_color_dual_tone_background</item>
         <item name="fillColor">@color/dark_mode_icon_color_dual_tone_fill</item>
         <item name="singleToneColor">@color/dark_mode_icon_color_single_tone</item>
+        <item name="homeHandleColor">@color/navigation_bar_home_handle_dark_color</item>
     </style>
     <style name="QSHeaderDarkTheme">
         <item name="backgroundColor">@color/dark_mode_qs_icon_color_dual_tone_background</item>
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/recents/model/Task.java b/packages/SystemUI/shared/src/com/android/systemui/shared/recents/model/Task.java
index 5b9ee1c..dcb134e 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/recents/model/Task.java
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/recents/model/Task.java
@@ -20,6 +20,7 @@
 
 import android.app.ActivityManager;
 import android.app.ActivityManager.TaskDescription;
+import android.app.TaskInfo;
 import android.content.ComponentName;
 import android.content.Intent;
 import android.content.pm.ActivityInfo;
@@ -75,7 +76,7 @@
 
         private int mHashCode;
 
-        public TaskKey(ActivityManager.RecentTaskInfo t) {
+        public TaskKey(TaskInfo t) {
             ComponentName sourceComponent = t.origActivity != null
                     // Activity alias if there is one
                     ? t.origActivity
@@ -226,6 +227,17 @@
         // Do nothing
     }
 
+    /**
+     * Creates a task object from the provided task info
+     */
+    public static Task from(TaskKey taskKey, TaskInfo taskInfo, boolean isLocked) {
+        ActivityManager.TaskDescription td = taskInfo.taskDescription;
+        return new Task(taskKey,
+                td != null ? td.getPrimaryColor() : 0,
+                td != null ? td.getBackgroundColor() : 0,
+                taskInfo.supportsSplitScreenMultiWindow, isLocked, td, taskInfo.topActivity);
+    }
+
     public Task(TaskKey key) {
         this.key = key;
         this.taskDescription = new TaskDescription();
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/recents/model/TaskKeyLruCache.java b/packages/SystemUI/shared/src/com/android/systemui/shared/recents/model/TaskKeyLruCache.java
index b2c79a4..e106c65 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/recents/model/TaskKeyLruCache.java
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/recents/model/TaskKeyLruCache.java
@@ -52,7 +52,11 @@
                 if (mEvictionCallback != null) {
                     mEvictionCallback.onEntryEvicted(mKeys.get(taskId));
                 }
-                mKeys.remove(taskId);
+
+                // Only remove from mKeys on cache remove, not a cache update.
+                if (newV == null) {
+                    mKeys.remove(taskId);
+                }
             }
         };
     }
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/system/ActivityManagerWrapper.java b/packages/SystemUI/shared/src/com/android/systemui/shared/system/ActivityManagerWrapper.java
index a2abb4b..328116d 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/system/ActivityManagerWrapper.java
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/system/ActivityManagerWrapper.java
@@ -30,10 +30,12 @@
 import android.annotation.NonNull;
 import android.app.ActivityManager;
 import android.app.ActivityManager.RecentTaskInfo;
+import android.app.ActivityManager.RunningTaskInfo;
 import android.app.ActivityOptions;
 import android.app.ActivityTaskManager;
 import android.app.AppGlobals;
 import android.app.IAssistDataReceiver;
+import android.app.WindowConfiguration;
 import android.app.WindowConfiguration.ActivityType;
 import android.content.ContentResolver;
 import android.content.Context;
@@ -307,28 +309,22 @@
         }
         final ActivityOptions finalOptions = options;
 
-        // Execute this from another thread such that we can do other things (like caching the
-        // bitmap for the thumbnail) while AM is busy starting our activity.
-        mBackgroundExecutor.submit(new Runnable() {
-            @Override
-            public void run() {
-                boolean result = false;
-                try {
-                    result = startActivityFromRecents(taskKey.id, finalOptions);
-                } catch (Exception e) {
-                    // Fall through
+
+        boolean result = false;
+        try {
+            result = startActivityFromRecents(taskKey.id, finalOptions);
+        } catch (Exception e) {
+            // Fall through
+        }
+        final boolean finalResult = result;
+        if (resultCallback != null) {
+            resultCallbackHandler.post(new Runnable() {
+                @Override
+                public void run() {
+                    resultCallback.accept(finalResult);
                 }
-                final boolean finalResult = result;
-                if (resultCallback != null) {
-                    resultCallbackHandler.post(new Runnable() {
-                        @Override
-                        public void run() {
-                            resultCallback.accept(finalResult);
-                        }
-                    });
-                }
-            }
-        });
+            });
+        }
     }
 
     /**
@@ -506,4 +502,12 @@
                 PackageManager.FEATURE_FREEFORM_WINDOW_MANAGEMENT)
                 || freeformDevOption);
     }
+
+    /**
+     * Returns true if the running task represents the home task
+     */
+    public static boolean isHomeTask(RunningTaskInfo info) {
+        return info.configuration.windowConfiguration.getActivityType()
+                == WindowConfiguration.ACTIVITY_TYPE_HOME;
+    }
 }
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/system/QuickStepContract.java b/packages/SystemUI/shared/src/com/android/systemui/shared/system/QuickStepContract.java
index 7fbe5db..08996c3 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/system/QuickStepContract.java
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/system/QuickStepContract.java
@@ -49,6 +49,15 @@
     public static final String NAV_BAR_MODE_GESTURAL_OVERLAY =
             WindowManagerPolicyConstants.NAV_BAR_MODE_GESTURAL_OVERLAY;
 
+    // Action sent by a system app to switch to gesture nav
+    public static final String ACTION_ENABLE_GESTURE_NAV =
+            "com.android.systemui.ENABLE_GESTURE_NAV";
+    // Action for the intent to receive the result
+    public static final String ACTION_ENABLE_GESTURE_NAV_RESULT =
+            "com.android.systemui.action.ENABLE_GESTURE_NAV_RESULT";
+    // Extra containing the pending intent to receive the result
+    public static final String EXTRA_RESULT_INTENT = "com.android.systemui.EXTRA_RESULT_INTENT";
+
     // Overview is disabled, either because the device is in lock task mode, or because the device
     // policy has disabled the feature
     public static final int SYSUI_STATE_SCREEN_PINNING = 1 << 0;
@@ -71,18 +80,25 @@
     public static final int SYSUI_STATE_HOME_DISABLED = 1 << 8;
     // The keyguard is showing, but occluded
     public static final int SYSUI_STATE_STATUS_BAR_KEYGUARD_SHOWING_OCCLUDED = 1 << 9;
+    // The search feature is disabled (either by SUW/SysUI/device policy)
+    public static final int SYSUI_STATE_SEARCH_DISABLED = 1 << 10;
+    // The notification panel is expanded and interactive (either locked or unlocked), and the
+    // quick settings is not expanded
+    public static final int SYSUI_STATE_QUICK_SETTINGS_EXPANDED = 1 << 11;
 
     @Retention(RetentionPolicy.SOURCE)
     @IntDef({SYSUI_STATE_SCREEN_PINNING,
             SYSUI_STATE_NAV_BAR_HIDDEN,
             SYSUI_STATE_NOTIFICATION_PANEL_EXPANDED,
+            SYSUI_STATE_QUICK_SETTINGS_EXPANDED,
             SYSUI_STATE_BOUNCER_SHOWING,
             SYSUI_STATE_A11Y_BUTTON_CLICKABLE,
             SYSUI_STATE_A11Y_BUTTON_LONG_CLICKABLE,
             SYSUI_STATE_STATUS_BAR_KEYGUARD_SHOWING,
             SYSUI_STATE_STATUS_BAR_KEYGUARD_SHOWING_OCCLUDED,
             SYSUI_STATE_OVERVIEW_DISABLED,
-            SYSUI_STATE_HOME_DISABLED
+            SYSUI_STATE_HOME_DISABLED,
+            SYSUI_STATE_SEARCH_DISABLED
     })
     public @interface SystemUiStateFlags {}
 
@@ -91,8 +107,10 @@
         str.add((flags & SYSUI_STATE_SCREEN_PINNING) != 0 ? "screen_pinned" : "");
         str.add((flags & SYSUI_STATE_OVERVIEW_DISABLED) != 0 ? "overview_disabled" : "");
         str.add((flags & SYSUI_STATE_HOME_DISABLED) != 0 ? "home_disabled" : "");
+        str.add((flags & SYSUI_STATE_SEARCH_DISABLED) != 0 ? "search_disabled" : "");
         str.add((flags & SYSUI_STATE_NAV_BAR_HIDDEN) != 0 ? "navbar_hidden" : "");
         str.add((flags & SYSUI_STATE_NOTIFICATION_PANEL_EXPANDED) != 0 ? "notif_visible" : "");
+        str.add((flags & SYSUI_STATE_QUICK_SETTINGS_EXPANDED) != 0 ? "qs_visible" : "");
         str.add((flags & SYSUI_STATE_STATUS_BAR_KEYGUARD_SHOWING) != 0 ? "keygrd_visible" : "");
         str.add((flags & SYSUI_STATE_STATUS_BAR_KEYGUARD_SHOWING_OCCLUDED) != 0
                 ? "keygrd_occluded" : "");
@@ -141,10 +159,13 @@
      * disabled.
      */
     public static boolean isAssistantGestureDisabled(int sysuiStateFlags) {
-        // Disable when in screen pinning, immersive, the bouncer is showing
+        // Disable when in quick settings, screen pinning, immersive, the bouncer is showing, 
+        // or search is disabled
         int disableFlags = SYSUI_STATE_SCREEN_PINNING
                 | SYSUI_STATE_NAV_BAR_HIDDEN
-                | SYSUI_STATE_BOUNCER_SHOWING;
+                | SYSUI_STATE_BOUNCER_SHOWING
+                | SYSUI_STATE_SEARCH_DISABLED
+                | SYSUI_STATE_QUICK_SETTINGS_EXPANDED;
         if ((sysuiStateFlags & disableFlags) != 0) {
             return true;
         }
@@ -167,9 +188,8 @@
         if ((sysuiStateFlags & SYSUI_STATE_BOUNCER_SHOWING) != 0) {
             return false;
         }
-        // Disable when in screen pinning, immersive, or the notifications are interactive
-        int disableFlags = SYSUI_STATE_SCREEN_PINNING
-                | SYSUI_STATE_NAV_BAR_HIDDEN
+        // Disable when in immersive, or the notifications are interactive
+        int disableFlags = SYSUI_STATE_NAV_BAR_HIDDEN
                 | SYSUI_STATE_NOTIFICATION_PANEL_EXPANDED
                 | SYSUI_STATE_STATUS_BAR_KEYGUARD_SHOWING;
         return (sysuiStateFlags & disableFlags) != 0;
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/system/RecentTaskInfoCompat.java b/packages/SystemUI/shared/src/com/android/systemui/shared/system/RecentTaskInfoCompat.java
deleted file mode 100644
index a529903..0000000
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/system/RecentTaskInfoCompat.java
+++ /dev/null
@@ -1,45 +0,0 @@
-/*
- * Copyright (C) 2018 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.systemui.shared.system;
-
-import android.app.ActivityManager;
-import android.content.ComponentName;
-
-public class RecentTaskInfoCompat {
-
-    private ActivityManager.RecentTaskInfo mInfo;
-
-    public RecentTaskInfoCompat(ActivityManager.RecentTaskInfo info) {
-        mInfo = info;
-    }
-
-    public int getUserId() {
-        return mInfo.userId;
-    }
-
-    public boolean supportsSplitScreenMultiWindow() {
-        return mInfo.supportsSplitScreenMultiWindow;
-    }
-
-    public ComponentName getTopActivity() {
-        return mInfo.topActivity;
-    }
-
-    public ActivityManager.TaskDescription getTaskDescription() {
-        return mInfo.taskDescription;
-    }
-}
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/system/RecentsAnimationControllerCompat.java b/packages/SystemUI/shared/src/com/android/systemui/shared/system/RecentsAnimationControllerCompat.java
index d2fe5cd..2ef0422 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/system/RecentsAnimationControllerCompat.java
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/system/RecentsAnimationControllerCompat.java
@@ -91,6 +91,7 @@
         }
     }
 
+    @Deprecated
     public void setCancelWithDeferredScreenshot(boolean screenshot) {
         try {
             mAnimationController.setCancelWithDeferredScreenshot(screenshot);
@@ -99,6 +100,14 @@
         }
     }
 
+    public void setDeferCancelUntilNextTransition(boolean defer, boolean screenshot) {
+        try {
+            mAnimationController.setDeferCancelUntilNextTransition(defer, screenshot);
+        } catch (RemoteException e) {
+            Log.e(TAG, "Failed to set deferred cancel with screenshot", e);
+        }
+    }
+
     public void cleanupScreenshot() {
         try {
             mAnimationController.cleanupScreenshot();
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/shared/src/com/android/systemui/shared/system/TaskInfoCompat.java b/packages/SystemUI/shared/src/com/android/systemui/shared/system/TaskInfoCompat.java
new file mode 100644
index 0000000..326c2aa
--- /dev/null
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/system/TaskInfoCompat.java
@@ -0,0 +1,48 @@
+/*
+ * Copyright (C) 2018 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.systemui.shared.system;
+
+import android.app.ActivityManager;
+import android.app.TaskInfo;
+import android.content.ComponentName;
+
+public class TaskInfoCompat {
+
+    public static int getUserId(TaskInfo info) {
+        return info.userId;
+    }
+
+    public static int getActivityType(TaskInfo info) {
+        return info.configuration.windowConfiguration.getActivityType();
+    }
+
+    public static int getWindowingMode(TaskInfo info) {
+        return info.configuration.windowConfiguration.getWindowingMode();
+    }
+
+    public static boolean supportsSplitScreenMultiWindow(TaskInfo info) {
+        return info.supportsSplitScreenMultiWindow;
+    }
+
+    public static ComponentName getTopActivity(TaskInfo info) {
+        return info.topActivity;
+    }
+
+    public static ActivityManager.TaskDescription getTaskDescription(TaskInfo info) {
+        return info.taskDescription;
+    }
+}
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/system/TaskStackChangeListener.java b/packages/SystemUI/shared/src/com/android/systemui/shared/system/TaskStackChangeListener.java
index 3d9abaf..c215d0f 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/system/TaskStackChangeListener.java
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/system/TaskStackChangeListener.java
@@ -64,6 +64,14 @@
         onActivityLaunchOnSecondaryDisplayRerouted();
     }
 
+    /**
+     * Called when contents are drawn for the first time on a display which can only contain one
+     * task.
+     *
+     * @param displayId the id of the display on which contents are drawn.
+     */
+    public void onSingleTaskDisplayDrawn(int displayId) { }
+
     public void onTaskProfileLocked(int taskId, int userId) { }
     public void onTaskCreated(int taskId, ComponentName componentName) { }
     public void onTaskRemoved(int taskId) { }
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/system/TaskStackChangeListeners.java b/packages/SystemUI/shared/src/com/android/systemui/shared/system/TaskStackChangeListeners.java
index beb4f05..d570a58 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/system/TaskStackChangeListeners.java
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/system/TaskStackChangeListeners.java
@@ -196,12 +196,19 @@
     }
 
     @Override
-    public void onSizeCompatModeActivityChanged(int displayId, IBinder activityToken) {
+    public void onSizeCompatModeActivityChanged(int displayId, IBinder activityToken)
+            throws RemoteException {
         mHandler.obtainMessage(H.ON_SIZE_COMPAT_MODE_ACTIVITY_CHANGED, displayId, 0 /* unused */,
                 activityToken).sendToTarget();
     }
 
     @Override
+    public void onSingleTaskDisplayDrawn(int displayId) throws RemoteException {
+        mHandler.obtainMessage(H.ON_SINGLE_TASK_DISPLAY_DRAWN, displayId,
+                0 /* unused */).sendToTarget();
+    }
+
+    @Override
     public void onTaskDisplayChanged(int taskId, int newDisplayId) throws RemoteException {
         mHandler.obtainMessage(H.ON_TASK_DISPLAY_CHANGED, taskId, newDisplayId).sendToTarget();
     }
@@ -225,7 +232,8 @@
         private static final int ON_ACTIVITY_LAUNCH_ON_SECONDARY_DISPLAY_REROUTED = 16;
         private static final int ON_SIZE_COMPAT_MODE_ACTIVITY_CHANGED = 17;
         private static final int ON_BACK_PRESSED_ON_TASK_ROOT = 18;
-        private static final int ON_TASK_DISPLAY_CHANGED = 19;
+        private static final int ON_SINGLE_TASK_DISPLAY_DRAWN = 19;
+        private static final int ON_TASK_DISPLAY_CHANGED = 20;
 
 
         public H(Looper looper) {
@@ -362,6 +370,12 @@
                         }
                         break;
                     }
+                    case ON_SINGLE_TASK_DISPLAY_DRAWN: {
+                        for (int i = mTaskStackListeners.size() - 1; i >= 0; i--) {
+                            mTaskStackListeners.get(i).onSingleTaskDisplayDrawn(msg.arg1);
+                        }
+                        break;
+                    }
                     case ON_TASK_DISPLAY_CHANGED: {
                         for (int i = mTaskStackListeners.size() - 1; i >= 0; i--) {
                             mTaskStackListeners.get(i).onTaskDisplayChanged(msg.arg1, msg.arg2);
diff --git a/packages/SystemUI/src/com/android/keyguard/CarrierTextController.java b/packages/SystemUI/src/com/android/keyguard/CarrierTextController.java
index 2090748..10d132a 100644
--- a/packages/SystemUI/src/com/android/keyguard/CarrierTextController.java
+++ b/packages/SystemUI/src/com/android/keyguard/CarrierTextController.java
@@ -303,6 +303,11 @@
             }
         } else {
             subs = mKeyguardUpdateMonitor.getSubscriptionInfo(false);
+            if (subs == null) {
+                subs = new ArrayList<>();
+            } else {
+                filterMobileSubscriptionInSameGroup(subs);
+            }
         }
         return subs;
     }
@@ -395,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.
@@ -405,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/KeyguardAbsKeyInputView.java b/packages/SystemUI/src/com/android/keyguard/KeyguardAbsKeyInputView.java
index 2ff7266..a4b6958 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardAbsKeyInputView.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardAbsKeyInputView.java
@@ -310,7 +310,9 @@
 
     @Override
     public void showMessage(CharSequence message, ColorStateList colorState) {
-        mSecurityMessageDisplay.setNextMessageColor(colorState);
+        if (colorState != null) {
+            mSecurityMessageDisplay.setNextMessageColor(colorState);
+        }
         mSecurityMessageDisplay.setMessage(message);
     }
 
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitch.java b/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitch.java
index fee2c9b..5097216 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitch.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitch.java
@@ -3,13 +3,13 @@
 import static com.android.systemui.util.InjectionInflationController.VIEW_CONTEXT;
 
 import android.animation.Animator;
-import android.animation.AnimatorListenerAdapter;
 import android.animation.ValueAnimator;
 import android.app.WallpaperManager;
 import android.content.Context;
 import android.graphics.Paint;
 import android.graphics.Paint.Style;
 import android.os.Build;
+import android.transition.Fade;
 import android.transition.Transition;
 import android.transition.TransitionListenerAdapter;
 import android.transition.TransitionManager;
@@ -34,6 +34,7 @@
 import com.android.systemui.plugins.ClockPlugin;
 import com.android.systemui.plugins.statusbar.StatusBarStateController;
 import com.android.systemui.statusbar.StatusBarState;
+import com.android.systemui.util.wakelock.KeepAwakeAnimationListener;
 
 import java.io.FileDescriptor;
 import java.io.PrintWriter;
@@ -117,6 +118,11 @@
     private float mDarkAmount;
 
     /**
+     * Boolean value indicating if notifications are visible on lock screen.
+     */
+    private boolean mHasVisibleNotifications;
+
+    /**
      * If the Keyguard Slice has a header (big center-aligned text.)
      */
     private boolean mShowingHeader;
@@ -227,8 +233,13 @@
             mClockPlugin = null;
         }
         if (plugin == null) {
-            mClockView.setVisibility(View.VISIBLE);
-            mClockViewBold.setVisibility(View.INVISIBLE);
+            if (mShowingHeader) {
+                mClockView.setVisibility(View.GONE);
+                mClockViewBold.setVisibility(View.VISIBLE);
+            } else {
+                mClockView.setVisibility(View.VISIBLE);
+                mClockViewBold.setVisibility(View.INVISIBLE);
+            }
             mKeyguardStatusArea.setVisibility(View.VISIBLE);
             return;
         }
@@ -325,6 +336,24 @@
         if (mClockPlugin != null) {
             mClockPlugin.setDarkAmount(darkAmount);
         }
+        updateBigClockAlpha();
+    }
+
+    /**
+     * Set whether or not the lock screen is showing notifications.
+     */
+    void setHasVisibleNotifications(boolean hasVisibleNotifications) {
+        if (hasVisibleNotifications == mHasVisibleNotifications) {
+            return;
+        }
+        mHasVisibleNotifications = hasVisibleNotifications;
+        if (mDarkAmount == 0f && mBigClockContainer != null) {
+            // Starting a fade transition since the visibility of the big clock will change.
+            TransitionManager.beginDelayedTransition(mBigClockContainer,
+                    new Fade().setDuration(KeyguardSliceView.DEFAULT_ANIM_DURATION / 2).addTarget(
+                            mBigClockContainer));
+        }
+        updateBigClockAlpha();
     }
 
     public Paint getPaint() {
@@ -401,15 +430,30 @@
         }
     }
 
+    private void updateBigClockAlpha() {
+        if (mBigClockContainer != null) {
+            final float alpha = mHasVisibleNotifications ? mDarkAmount : 1f;
+            mBigClockContainer.setAlpha(alpha);
+            if (alpha == 0f) {
+                mBigClockContainer.setVisibility(INVISIBLE);
+            } else if (mBigClockContainer.getVisibility() == INVISIBLE) {
+                mBigClockContainer.setVisibility(VISIBLE);
+            }
+        }
+    }
+
     /**
      * Sets if the keyguard slice is showing a center-aligned header. We need a smaller clock in
      * these cases.
      */
     void setKeyguardShowingHeader(boolean hasHeader) {
-        if (mShowingHeader == hasHeader || hasCustomClock()) {
+        if (mShowingHeader == hasHeader) {
             return;
         }
         mShowingHeader = hasHeader;
+        if (hasCustomClock()) {
+            return;
+        }
 
         float smallFontSize = mContext.getResources().getDimensionPixelSize(
                 R.dimen.widget_small_font_size);
@@ -580,11 +624,16 @@
                 view.setScaleX(scale);
                 view.setScaleY(scale);
             });
-            animator.addListener(new AnimatorListenerAdapter() {
+            animator.addListener(new KeepAwakeAnimationListener(getContext()) {
                 @Override
                 public void onAnimationStart(Animator animation) {
                     super.onAnimationStart(animation);
                     view.setVisibility(startVisibility);
+                }
+
+                @Override
+                public void onAnimationEnd(Animator animation) {
+                    super.onAnimationEnd(animation);
                     animation.removeListener(this);
                 }
             });
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardPatternView.java b/packages/SystemUI/src/com/android/keyguard/KeyguardPatternView.java
index d8086da..55ddfc3 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardPatternView.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardPatternView.java
@@ -248,7 +248,8 @@
 
     @Override
     public boolean disallowInterceptTouch(MotionEvent event) {
-        return mLockPatternScreenBounds.contains((int) event.getRawX(), (int) event.getRawY());
+        return !mLockPatternView.isEmpty()
+                || mLockPatternScreenBounds.contains((int) event.getRawX(), (int) event.getRawY());
     }
 
     /** TODO: hook this up */
@@ -442,7 +443,9 @@
 
     @Override
     public void showMessage(CharSequence message, ColorStateList colorState) {
-        mSecurityMessageDisplay.setNextMessageColor(colorState);
+        if (colorState != null) {
+            mSecurityMessageDisplay.setNextMessageColor(colorState);
+        }
         mSecurityMessageDisplay.setMessage(message);
     }
 
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainer.java b/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainer.java
index a6b7202..8059dcf 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainer.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainer.java
@@ -46,6 +46,7 @@
 import com.android.keyguard.KeyguardSecurityModel.SecurityMode;
 import com.android.systemui.Dependency;
 import com.android.systemui.SystemUIFactory;
+import com.android.systemui.statusbar.phone.UnlockMethodCache;
 import com.android.systemui.util.InjectionInflationController;
 
 public class KeyguardSecurityContainer extends FrameLayout implements KeyguardSecurityView {
@@ -90,6 +91,7 @@
     private final SpringAnimation mSpringAnimation;
     private final VelocityTracker mVelocityTracker = VelocityTracker.obtain();
     private final KeyguardUpdateMonitor mUpdateMonitor;
+    private final UnlockMethodCache mUnlockMethodCache;
 
     private final MetricsLogger mMetricsLogger = Dependency.get(MetricsLogger.class);
     private float mLastTouchY = -1;
@@ -129,6 +131,7 @@
         mSpringAnimation = new SpringAnimation(this, DynamicAnimation.Y);
         mInjectionInflationController =  new InjectionInflationController(
             SystemUIFactory.getInstance().getRootComponent());
+        mUnlockMethodCache = UnlockMethodCache.getInstance(context);
         mViewConfiguration = ViewConfiguration.get(context);
     }
 
@@ -231,8 +234,11 @@
         }
         if (action == MotionEvent.ACTION_UP) {
             if (-getTranslationY() > TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP,
-                    MIN_DRAG_SIZE, getResources().getDisplayMetrics())) {
+                    MIN_DRAG_SIZE, getResources().getDisplayMetrics())
+                    && !mUpdateMonitor.isFaceDetectionRunning()) {
                 mUpdateMonitor.requestFaceAuth();
+                mCallback.userActivity();
+                showMessage(null, null);
             }
         }
         return true;
@@ -263,8 +269,7 @@
      */
     private void updateBiometricRetry() {
         SecurityMode securityMode = getSecurityMode();
-        int userId = KeyguardUpdateMonitor.getCurrentUser();
-        mSwipeUpToRetry = mUpdateMonitor.isUnlockWithFacePossible(userId)
+        mSwipeUpToRetry = mUnlockMethodCache.isFaceAuthEnabled()
                 && securityMode != SecurityMode.SimPin
                 && securityMode != SecurityMode.SimPuk
                 && securityMode != SecurityMode.None;
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/keyguard/KeyguardStatusView.java b/packages/SystemUI/src/com/android/keyguard/KeyguardStatusView.java
index a7fe607..37e89c0 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardStatusView.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardStatusView.java
@@ -61,6 +61,7 @@
     private KeyguardClockSwitch mClockView;
     private TextView mOwnerInfo;
     private KeyguardSliceView mKeyguardSlice;
+    private View mNotificationIcons;
     private Runnable mPendingMarqueeStart;
     private Handler mHandler;
 
@@ -72,8 +73,8 @@
      * Bottom margin that defines the margin between bottom of smart space and top of notification
      * icons on AOD.
      */
-    private int mBottomMargin;
-    private int mBottomMarginWithHeader;
+    private int mIconTopMargin;
+    private int mIconTopMarginWithHeader;
     private boolean mShowingHeader;
 
     private KeyguardUpdateMonitorCallback mInfoCallback = new KeyguardUpdateMonitorCallback() {
@@ -144,6 +145,13 @@
         return mClockView.hasCustomClock();
     }
 
+    /**
+     * Set whether or not the lock screen is showing notifications.
+     */
+    public void setHasVisibleNotifications(boolean hasVisibleNotifications) {
+        mClockView.setHasVisibleNotifications(hasVisibleNotifications);
+    }
+
     private void setEnableMarquee(boolean enabled) {
         if (DEBUG) Log.v(TAG, "Schedule setEnableMarquee: " + (enabled ? "Enable" : "Disable"));
         if (enabled) {
@@ -173,6 +181,7 @@
         super.onFinishInflate();
         mStatusViewContainer = findViewById(R.id.status_view_container);
         mLogoutView = findViewById(R.id.logout);
+        mNotificationIcons = findViewById(R.id.clock_notification_icon_container);
         if (mLogoutView != null) {
             mLogoutView.setOnClickListener(this::onLogoutClicked);
         }
@@ -207,12 +216,14 @@
             return;
         }
         mShowingHeader = hasHeader;
-        // Update bottom margin since header has appeared/disappeared.
-        if (mStatusViewContainer != null) {
-            MarginLayoutParams params = (MarginLayoutParams) mStatusViewContainer.getLayoutParams();
-            params.setMargins(params.leftMargin, params.topMargin, params.rightMargin,
-                    hasHeader ? mBottomMarginWithHeader : mBottomMargin);
-            mStatusViewContainer.setLayoutParams(params);
+        if (mNotificationIcons != null) {
+            // Update top margin since header has appeared/disappeared.
+            MarginLayoutParams params = (MarginLayoutParams) mNotificationIcons.getLayoutParams();
+            params.setMargins(params.leftMargin,
+                    hasHeader ? mIconTopMarginWithHeader : mIconTopMargin,
+                    params.rightMargin,
+                    params.bottomMargin);
+            mNotificationIcons.setLayoutParams(params);
         }
     }
 
@@ -338,8 +349,8 @@
     }
 
     private void loadBottomMargin() {
-        mBottomMargin = getResources().getDimensionPixelSize(R.dimen.widget_vertical_padding);
-        mBottomMarginWithHeader = getResources().getDimensionPixelSize(
+        mIconTopMargin = getResources().getDimensionPixelSize(R.dimen.widget_vertical_padding);
+        mIconTopMarginWithHeader = getResources().getDimensionPixelSize(
                 R.dimen.widget_vertical_padding_with_header);
     }
 
@@ -412,6 +423,13 @@
             int expanded = mOwnerInfo.getBottom() + mOwnerInfo.getPaddingBottom();
             int toRemove = (int) ((expanded - collapsed) * ratio);
             setBottom(getMeasuredHeight() - toRemove);
+            if (mNotificationIcons != null) {
+                // We're using scrolling in order not to overload the translation which is used
+                // when appearing the icons
+                mNotificationIcons.setScrollY(toRemove);
+            }
+        } else if (mNotificationIcons != null){
+            mNotificationIcons.setScrollY(0);
         }
     }
 
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
index 6a4dbc8d..109f270 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
@@ -28,6 +28,13 @@
 import static android.os.BatteryManager.EXTRA_MAX_CHARGING_VOLTAGE;
 import static android.os.BatteryManager.EXTRA_PLUGGED;
 import static android.os.BatteryManager.EXTRA_STATUS;
+import static android.telephony.PhoneStateListener.LISTEN_ACTIVE_DATA_SUBSCRIPTION_ID_CHANGE;
+
+import static com.android.internal.widget.LockPatternUtils.StrongAuthTracker.STRONG_AUTH_REQUIRED_AFTER_BOOT;
+import static com.android.internal.widget.LockPatternUtils.StrongAuthTracker.STRONG_AUTH_REQUIRED_AFTER_DPM_LOCK_NOW;
+import static com.android.internal.widget.LockPatternUtils.StrongAuthTracker.STRONG_AUTH_REQUIRED_AFTER_LOCKOUT;
+import static com.android.internal.widget.LockPatternUtils.StrongAuthTracker.STRONG_AUTH_REQUIRED_AFTER_TIMEOUT;
+import static com.android.internal.widget.LockPatternUtils.StrongAuthTracker.STRONG_AUTH_REQUIRED_AFTER_USER_LOCKDOWN;
 
 import android.annotation.AnyThread;
 import android.annotation.MainThread;
@@ -70,6 +77,7 @@
 import android.provider.Settings;
 import android.service.dreams.DreamService;
 import android.service.dreams.IDreamManager;
+import android.telephony.PhoneStateListener;
 import android.telephony.ServiceState;
 import android.telephony.SubscriptionInfo;
 import android.telephony.SubscriptionManager;
@@ -88,6 +96,7 @@
 import com.android.settingslib.WirelessUtils;
 import com.android.systemui.shared.system.ActivityManagerWrapper;
 import com.android.systemui.shared.system.TaskStackChangeListener;
+import com.android.systemui.statusbar.phone.KeyguardBypassController;
 
 import com.google.android.collect.Lists;
 
@@ -111,6 +120,7 @@
     private static final String TAG = "KeyguardUpdateMonitor";
     private static final boolean DEBUG = KeyguardConstants.DEBUG;
     private static final boolean DEBUG_SIM_STATES = KeyguardConstants.DEBUG_SIM_STATES;
+    private static final boolean DEBUG_FACE = true;
     private static final int LOW_BATTERY_THRESHOLD = 20;
 
     private static final String ACTION_FACE_UNLOCK_STARTED
@@ -168,6 +178,9 @@
      */
     private static final int BIOMETRIC_STATE_CANCELLING_RESTARTING = 3;
 
+    private static final int BIOMETRIC_HELP_FINGERPRINT_NOT_RECOGNIZED = -1;
+    public static final int BIOMETRIC_HELP_FACE_NOT_RECOGNIZED = -2;
+
     private static final int DEFAULT_CHARGING_VOLTAGE_MICRO_VOLT = 5000000;
 
     private static final ComponentName FALLBACK_HOME_COMPONENT = new ComponentName(
@@ -179,6 +192,7 @@
      * Prudently disable lockscreen.
      */
     public static final boolean CORE_APPS_ONLY;
+
     static {
         try {
             CORE_APPS_ONLY = IPackageManager.Stub.asInterface(
@@ -207,6 +221,7 @@
     private boolean mHasLockscreenWallpaper;
     private boolean mAssistantVisible;
     private boolean mKeyguardOccluded;
+    private boolean mSecureCameraLaunched;
     @VisibleForTesting
     protected boolean mTelephonyCapable;
 
@@ -231,6 +246,7 @@
     private List<SubscriptionInfo> mSubscriptionInfo;
     private TrustManager mTrustManager;
     private UserManager mUserManager;
+    private KeyguardBypassController mKeyguardBypassController;
     private int mFingerprintRunningState = BIOMETRIC_STATE_STOPPED;
     private int mFaceRunningState = BIOMETRIC_STATE_STOPPED;
     private LockPatternUtils mLockPatternUtils;
@@ -248,11 +264,11 @@
      */
     private static final int BIOMETRIC_CONTINUE_DELAY_MS = 500;
 
-    // If FP daemon dies, keyguard should retry after a short delay
+    // If the HAL dies or is unable to authenticate, keyguard should retry after a short delay
     private int mHardwareFingerprintUnavailableRetryCount = 0;
     private int mHardwareFaceUnavailableRetryCount = 0;
-    private static final int HW_UNAVAILABLE_TIMEOUT = 3000; // ms
-    private static final int HW_UNAVAILABLE_RETRY_MAX = 3;
+    private static final int HAL_ERROR_RETRY_TIMEOUT = 500; // ms
+    private static final int HAL_ERROR_RETRY_MAX = 10;
 
     private final Handler mHandler = new Handler(Looper.getMainLooper()) {
         @Override
@@ -361,19 +377,27 @@
         }
     };
 
-    private boolean mFaceSettingEnabledForUser;
+    private SparseBooleanArray mFaceSettingEnabledForUser = new SparseBooleanArray();
     private BiometricManager mBiometricManager;
     private IBiometricEnabledOnKeyguardCallback mBiometricEnabledCallback =
             new IBiometricEnabledOnKeyguardCallback.Stub() {
         @Override
-        public void onChanged(BiometricSourceType type, boolean enabled) throws RemoteException {
+        public void onChanged(BiometricSourceType type, boolean enabled, int userId)
+                throws RemoteException {
             if (type == BiometricSourceType.FACE) {
-                mFaceSettingEnabledForUser = enabled;
+                mFaceSettingEnabledForUser.put(userId, enabled);
                 updateFaceListeningState();
             }
         }
     };
 
+    private PhoneStateListener mPhoneStateListener = new PhoneStateListener() {
+        @Override
+        public void onActiveDataSubscriptionIdChanged(int subId) {
+            mHandler.sendEmptyMessage(MSG_SIM_SUBSCRIPTION_INFO_CHANGED);
+        }
+    };
+
     private OnSubscriptionsChangedListener mSubscriptionListener =
             new OnSubscriptionsChangedListener() {
         @Override
@@ -423,7 +447,7 @@
     private void handleSimSubscriptionInfoChanged() {
         if (DEBUG_SIM_STATES) {
             Log.v(TAG, "onSubscriptionInfoChanged()");
-            List<SubscriptionInfo> sil = mSubscriptionManager.getActiveSubscriptionInfoList();
+            List<SubscriptionInfo> sil = mSubscriptionManager.getActiveSubscriptionInfoList(false);
             if (sil != null) {
                 for (SubscriptionInfo subInfo : sil) {
                     Log.v(TAG, "SubInfo:" + subInfo);
@@ -475,7 +499,7 @@
     public List<SubscriptionInfo> getSubscriptionInfo(boolean forceReload) {
         List<SubscriptionInfo> sil = mSubscriptionInfo;
         if (sil == null || forceReload) {
-            sil = mSubscriptionManager.getActiveSubscriptionInfoList();
+            sil = mSubscriptionManager.getActiveSubscriptionInfoList(false);
         }
         if (sil == null) {
             // getActiveSubscriptionInfoList was null callers expect an empty list.
@@ -518,6 +542,14 @@
     }
 
     /**
+     * Invoked when the secure camera is launched.
+     */
+    public void onCameraLaunched() {
+        mSecureCameraLaunched = true;
+        updateBiometricListeningState();
+    }
+
+    /**
      * @return a cached version of DreamManager.isDreaming()
      */
     public boolean isDreaming() {
@@ -570,7 +602,8 @@
                 cb.onBiometricAuthFailed(BiometricSourceType.FINGERPRINT);
             }
         }
-        handleFingerprintHelp(-1, mContext.getString(R.string.kg_fingerprint_not_recognized));
+        handleFingerprintHelp(BIOMETRIC_HELP_FINGERPRINT_NOT_RECOGNIZED,
+                mContext.getString(R.string.kg_fingerprint_not_recognized));
     }
 
     private void handleFingerprintAcquired(int acquireInfo) {
@@ -638,16 +671,15 @@
         }
 
         if (msgId == FingerprintManager.FINGERPRINT_ERROR_HW_UNAVAILABLE) {
-            if (mHardwareFingerprintUnavailableRetryCount < HW_UNAVAILABLE_RETRY_MAX) {
+            if (mHardwareFingerprintUnavailableRetryCount < HAL_ERROR_RETRY_MAX) {
                 mHardwareFingerprintUnavailableRetryCount++;
                 mHandler.removeCallbacks(mRetryFingerprintAuthentication);
-                mHandler.postDelayed(mRetryFingerprintAuthentication, HW_UNAVAILABLE_TIMEOUT);
+                mHandler.postDelayed(mRetryFingerprintAuthentication, HAL_ERROR_RETRY_TIMEOUT);
             }
         }
 
         if (msgId == FingerprintManager.FINGERPRINT_ERROR_LOCKOUT_PERMANENT) {
-            mLockPatternUtils.requireStrongAuth(
-                    LockPatternUtils.StrongAuthTracker.STRONG_AUTH_REQUIRED_AFTER_LOCKOUT,
+            mLockPatternUtils.requireStrongAuth(STRONG_AUTH_REQUIRED_AFTER_LOCKOUT,
                     getCurrentUser());
         }
 
@@ -722,13 +754,15 @@
                 cb.onBiometricAuthFailed(BiometricSourceType.FACE);
             }
         }
-        handleFaceHelp(-1, mContext.getString(R.string.kg_face_not_recognized));
+        handleFaceHelp(BIOMETRIC_HELP_FACE_NOT_RECOGNIZED,
+                mContext.getString(R.string.kg_face_not_recognized));
     }
 
     private void handleFaceAcquired(int acquireInfo) {
         if (acquireInfo != FaceManager.FACE_ACQUIRED_GOOD) {
             return;
         }
+        if (DEBUG_FACE) Log.d(TAG, "Face acquired");
         for (int i = 0; i < mCallbacks.size(); i++) {
             KeyguardUpdateMonitorCallback cb = mCallbacks.get(i).get();
             if (cb != null) {
@@ -740,6 +774,10 @@
     private void handleFaceAuthenticated(int authUserId) {
         Trace.beginSection("KeyGuardUpdateMonitor#handlerFaceAuthenticated");
         try {
+            if (mGoingToSleep) {
+                Log.d(TAG, "Aborted successful auth because device is going to sleep.");
+                return;
+            }
             final int userId;
             try {
                 userId = ActivityManager.getService().getCurrentUser().id;
@@ -755,6 +793,7 @@
                 Log.d(TAG, "Face authentication disabled by DPM for userId: " + userId);
                 return;
             }
+            if (DEBUG_FACE) Log.d(TAG, "Face auth succeeded for user " + userId);
             onFaceAuthenticated(userId);
         } finally {
             setFaceRunningState(BIOMETRIC_STATE_STOPPED);
@@ -763,6 +802,7 @@
     }
 
     private void handleFaceHelp(int msgId, String helpString) {
+        if (DEBUG_FACE) Log.d(TAG, "Face help received: " + helpString);
         for (int i = 0; i < mCallbacks.size(); i++) {
             KeyguardUpdateMonitorCallback cb = mCallbacks.get(i).get();
             if (cb != null) {
@@ -781,6 +821,7 @@
     };
 
     private void handleFaceError(int msgId, String errString) {
+        if (DEBUG_FACE) Log.d(TAG, "Face error received: " + errString);
         if (msgId == FaceManager.FACE_ERROR_CANCELED
                 && mFaceRunningState == BIOMETRIC_STATE_CANCELLING_RESTARTING) {
             setFaceRunningState(BIOMETRIC_STATE_STOPPED);
@@ -789,20 +830,25 @@
             setFaceRunningState(BIOMETRIC_STATE_STOPPED);
         }
 
-        if (msgId == FaceManager.FACE_ERROR_HW_UNAVAILABLE) {
-            if (mHardwareFaceUnavailableRetryCount < HW_UNAVAILABLE_RETRY_MAX) {
+        if (msgId == FaceManager.FACE_ERROR_HW_UNAVAILABLE
+                || msgId == FaceManager.FACE_ERROR_UNABLE_TO_PROCESS) {
+            if (mHardwareFaceUnavailableRetryCount < HAL_ERROR_RETRY_MAX) {
                 mHardwareFaceUnavailableRetryCount++;
                 mHandler.removeCallbacks(mRetryFaceAuthentication);
-                mHandler.postDelayed(mRetryFaceAuthentication, HW_UNAVAILABLE_TIMEOUT);
+                mHandler.postDelayed(mRetryFaceAuthentication, HAL_ERROR_RETRY_TIMEOUT);
             }
         }
 
         if (msgId == FaceManager.FACE_ERROR_LOCKOUT_PERMANENT) {
-            mLockPatternUtils.requireStrongAuth(
-                    LockPatternUtils.StrongAuthTracker.STRONG_AUTH_REQUIRED_AFTER_LOCKOUT,
+            mLockPatternUtils.requireStrongAuth(STRONG_AUTH_REQUIRED_AFTER_LOCKOUT,
                     getCurrentUser());
         }
 
+        // The face timeout message is not very actionable, let's ask the user to
+        // manually retry.
+        if (msgId == FaceManager.FACE_ERROR_TIMEOUT) {
+            errString = mContext.getString(R.string.keyguard_unlock);
+        }
         for (int i = 0; i < mCallbacks.size(); i++) {
             KeyguardUpdateMonitorCallback cb = mCallbacks.get(i).get();
             if (cb != null) {
@@ -913,8 +959,17 @@
     }
 
     public boolean isUserInLockdown(int userId) {
-        return mStrongAuthTracker.getStrongAuthForUser(userId)
-                == LockPatternUtils.StrongAuthTracker.STRONG_AUTH_REQUIRED_AFTER_USER_LOCKDOWN;
+        return containsFlag(mStrongAuthTracker.getStrongAuthForUser(userId),
+                STRONG_AUTH_REQUIRED_AFTER_USER_LOCKDOWN);
+    }
+
+    public boolean userNeedsStrongAuth() {
+        return mStrongAuthTracker.getStrongAuthForUser(getCurrentUser())
+                != LockPatternUtils.StrongAuthTracker.STRONG_AUTH_NOT_REQUIRED;
+    }
+
+    private boolean containsFlag(int haystack, int needle) {
+        return (haystack & needle) != 0;
     }
 
     public boolean needsSlowUnlockTransition() {
@@ -1044,6 +1099,8 @@
                 }
                 mHandler.sendMessage(
                         mHandler.obtainMessage(MSG_SERVICE_STATE_CHANGE, subId, 0, serviceState));
+            } else if (TelephonyIntents.ACTION_DEFAULT_DATA_SUBSCRIPTION_CHANGED.equals(action)) {
+                mHandler.sendEmptyMessage(MSG_SIM_SUBSCRIPTION_INFO_CHANGED);
             } else if (DevicePolicyManager.ACTION_DEVICE_POLICY_MANAGER_STATE_CHANGED.equals(
                     action)) {
                 mHandler.sendEmptyMessage(MSG_DEVICE_POLICY_MANAGER_STATE_CHANGED);
@@ -1454,6 +1511,7 @@
         filter.addAction(Intent.ACTION_AIRPLANE_MODE_CHANGED);
         filter.addAction(TelephonyIntents.ACTION_SIM_STATE_CHANGED);
         filter.addAction(TelephonyIntents.ACTION_SERVICE_STATE_CHANGED);
+        filter.addAction(TelephonyIntents.ACTION_DEFAULT_DATA_SUBSCRIPTION_CHANGED);
         filter.addAction(TelephonyManager.ACTION_PHONE_STATE_CHANGED);
         filter.addAction(AudioManager.RINGER_MODE_CHANGED_ACTION);
         filter.addAction(DevicePolicyManager.ACTION_DEVICE_POLICY_MANAGER_STATE_CHANGED);
@@ -1527,6 +1585,12 @@
         mDevicePolicyManager = context.getSystemService(DevicePolicyManager.class);
         mLogoutEnabled = mDevicePolicyManager.isLogoutEnabled();
         updateAirplaneModeState();
+
+        TelephonyManager telephony =
+                (TelephonyManager) context.getSystemService(Context.TELEPHONY_SERVICE);
+        if (telephony != null) {
+            telephony.listen(mPhoneStateListener, LISTEN_ACTIVE_DATA_SUBSCRIPTION_ID_CHANGE);
+        }
     }
 
     private void updateAirplaneModeState() {
@@ -1624,12 +1688,34 @@
     private boolean shouldListenForFace() {
         final boolean awakeKeyguard = mKeyguardIsVisible && mDeviceInteractive && !mGoingToSleep;
         final int user = getCurrentUser();
+        final int strongAuth = mStrongAuthTracker.getStrongAuthForUser(user);
+        final boolean isLockOutOrLockDown =
+                containsFlag(strongAuth, STRONG_AUTH_REQUIRED_AFTER_LOCKOUT)
+                        || containsFlag(strongAuth, STRONG_AUTH_REQUIRED_AFTER_DPM_LOCK_NOW)
+                        || containsFlag(strongAuth, STRONG_AUTH_REQUIRED_AFTER_USER_LOCKDOWN);
+        final boolean isEncryptedOrTimedOut =
+                containsFlag(strongAuth, STRONG_AUTH_REQUIRED_AFTER_BOOT)
+                        || containsFlag(strongAuth, STRONG_AUTH_REQUIRED_AFTER_TIMEOUT);
+
+        boolean canBypass = mKeyguardBypassController != null
+                && mKeyguardBypassController.canBypass();
+        // There's no reason to ask the HAL for authentication when the user can dismiss the
+        // bouncer, unless we're bypassing and need to auto-dismiss the lock screen even when
+        // TrustAgents or biometrics are keeping the device unlocked.
+        boolean becauseCannotSkipBouncer = !getUserCanSkipBouncer(user) || canBypass;
+
+        // Scan even when encrypted or timeout to show a preemptive bouncer when bypassing.
+        // Lockout/lockdown modes shouldn't scan, since they are more explicit.
+        boolean strongAuthAllowsScanning = (!isEncryptedOrTimedOut || canBypass && !mBouncer)
+                && !isLockOutOrLockDown;
+
         // Only listen if this KeyguardUpdateMonitor belongs to the primary user. There is an
         // instance of KeyguardUpdateMonitor for each user but KeyguardUpdateMonitor is user-aware.
         return (mBouncer || mAuthInterruptActive || awakeKeyguard || shouldListenForFaceAssistant())
-                && !mSwitchingUser && !getUserCanSkipBouncer(user) && !isFaceDisabled(user)
-                && !mKeyguardGoingAway && mFaceSettingEnabledForUser && !mLockIconPressed
-                && mUserManager.isUserUnlocked(user) && mIsPrimaryUser;
+                && !mSwitchingUser && !isFaceDisabled(user) && becauseCannotSkipBouncer
+                && !mKeyguardGoingAway && mFaceSettingEnabledForUser.get(user) && !mLockIconPressed
+                && strongAuthAllowsScanning && mIsPrimaryUser
+                && !mSecureCameraLaunched;
     }
 
     /**
@@ -1698,14 +1784,17 @@
                 && mFpm.getEnrolledFingerprints(userId).size() > 0;
     }
 
+    private boolean isUnlockWithFacePossible(int userId) {
+        return isFaceAuthEnabledForUser(userId) && !isFaceDisabled(userId);
+    }
+
     /**
-     * If face hardware is available and user has enrolled. Not considering encryption or
-     * lockdown state.
+     * If face hardware is available, user has enrolled and enabled auth via setting.
      */
-    public boolean isUnlockWithFacePossible(int userId) {
+    public boolean isFaceAuthEnabledForUser(int userId) {
         return mFaceManager != null && mFaceManager.isHardwareDetected()
-                && !isFaceDisabled(userId)
-                && mFaceManager.hasEnrolledTemplates(userId);
+                && mFaceManager.hasEnrolledTemplates(userId)
+                && mFaceSettingEnabledForUser.get(userId);
     }
 
     private void stopListeningForFingerprint() {
@@ -2077,6 +2166,11 @@
         checkIsHandlerThread();
         Log.d(TAG, "onKeyguardVisibilityChanged(" + showing + ")");
         mKeyguardIsVisible = showing;
+
+        if (showing) {
+            mSecureCameraLaunched = false;
+        }
+
         for (int i = 0; i < mCallbacks.size(); i++) {
             KeyguardUpdateMonitorCallback cb = mCallbacks.get(i).get();
             if (cb != null) {
@@ -2114,6 +2208,15 @@
         if (DEBUG) Log.d(TAG, "handleKeyguardBouncerChanged(" + bouncer + ")");
         boolean isBouncer = (bouncer == 1);
         mBouncer = isBouncer;
+
+        if (isBouncer) {
+            // If the bouncer is shown, always clear this flag. This can happen in the following
+            // situations: 1) Default camera with SHOW_WHEN_LOCKED is not chosen yet. 2) Secure
+            // camera requests dismiss keyguard (tapping on photos for example). When these happen,
+            // face auth should resume.
+            mSecureCameraLaunched = false;
+        }
+
         for (int i = 0; i < mCallbacks.size(); i++) {
             KeyguardUpdateMonitorCallback cb = mCallbacks.get(i).get();
             if (cb != null) {
@@ -2195,6 +2298,10 @@
         sendUpdates(callback);
     }
 
+    public void setKeyguardBypassController(KeyguardBypassController keyguardBypassController) {
+        mKeyguardBypassController = keyguardBypassController;
+    }
+
     public boolean isSwitchingUser() {
         return mSwitchingUser;
     }
@@ -2285,6 +2392,13 @@
         mUserFaceAuthenticated.clear();
         mTrustManager.clearAllBiometricRecognized(BiometricSourceType.FINGERPRINT);
         mTrustManager.clearAllBiometricRecognized(BiometricSourceType.FACE);
+
+        for (int i = 0; i < mCallbacks.size(); i++) {
+            KeyguardUpdateMonitorCallback cb = mCallbacks.get(i).get();
+            if (cb != null) {
+                cb.onBiometricsCleared();
+            }
+        }
     }
 
     public boolean isSimPinVoiceSecure() {
@@ -2548,7 +2662,8 @@
             pw.println("    possible=" + isUnlockWithFacePossible(userId));
             pw.println("    strongAuthFlags=" + Integer.toHexString(strongAuthFlags));
             pw.println("    trustManaged=" + getUserTrustIsManaged(userId));
-            pw.println("    enabledByUser=" + mFaceSettingEnabledForUser);
+            pw.println("    enabledByUser=" + mFaceSettingEnabledForUser.get(userId));
+            pw.println("    mSecureCameraLaunched=" + mSecureCameraLaunched);
         }
     }
 }
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitorCallback.java b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitorCallback.java
index 8696bb7..0fef755 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitorCallback.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitorCallback.java
@@ -314,4 +314,9 @@
      */
     public void onLogoutEnabledChanged() { }
 
+    /**
+     * Called when authenticated biometrics are cleared.
+     */
+    public void onBiometricsCleared() { }
+
 }
diff --git a/packages/SystemUI/src/com/android/keyguard/clock/AnalogClockController.java b/packages/SystemUI/src/com/android/keyguard/clock/AnalogClockController.java
index 558ac4b..9c5242c 100644
--- a/packages/SystemUI/src/com/android/keyguard/clock/AnalogClockController.java
+++ b/packages/SystemUI/src/com/android/keyguard/clock/AnalogClockController.java
@@ -75,6 +75,11 @@
     private TextClock mLockClock;
 
     /**
+     * Helper to extract colors from wallpaper palette for clock face.
+     */
+    private final ClockPalette mPalette = new ClockPalette();
+
+    /**
      * Create a BubbleClockController instance.
      *
      * @param res Resources contains title and thumbnail.
@@ -162,17 +167,21 @@
     public void setStyle(Style style) {}
 
     @Override
-    public void setTextColor(int color) { }
+    public void setTextColor(int color) {
+        updateColor();
+    }
 
     @Override
     public void setColorPalette(boolean supportsDarkText, int[] colorPalette) {
-        if (colorPalette == null || colorPalette.length == 0) {
-            return;
-        }
-        final int length = colorPalette.length;
-        mLockClock.setTextColor(colorPalette[Math.max(0, length - 2)]);
-        mAnalogClock.setClockColors(colorPalette[Math.max(0, length - 5)],
-                colorPalette[Math.max(0, length - 2)]);
+        mPalette.setColorPalette(supportsDarkText, colorPalette);
+        updateColor();
+    }
+
+    private void updateColor() {
+        final int primary = mPalette.getPrimaryColor();
+        final int secondary = mPalette.getSecondaryColor();
+        mLockClock.setTextColor(secondary);
+        mAnalogClock.setClockColors(primary, secondary);
     }
 
     @Override
@@ -184,6 +193,7 @@
 
     @Override
     public void setDarkAmount(float darkAmount) {
+        mPalette.setDarkAmount(darkAmount);
         mClockPosition.setDarkAmount(darkAmount);
         mBigClockView.setDarkAmount(darkAmount);
     }
diff --git a/packages/SystemUI/src/com/android/keyguard/clock/BubbleClockController.java b/packages/SystemUI/src/com/android/keyguard/clock/BubbleClockController.java
index bdf9dc4..8e81327 100644
--- a/packages/SystemUI/src/com/android/keyguard/clock/BubbleClockController.java
+++ b/packages/SystemUI/src/com/android/keyguard/clock/BubbleClockController.java
@@ -75,6 +75,11 @@
     private TextClock mLockClock;
 
     /**
+     * Helper to extract colors from wallpaper palette for clock face.
+     */
+    private final ClockPalette mPalette = new ClockPalette();
+
+    /**
      * Create a BubbleClockController instance.
      *
      * @param res Resources contains title and thumbnail.
@@ -162,21 +167,26 @@
     public void setStyle(Style style) {}
 
     @Override
-    public void setTextColor(int color) { }
+    public void setTextColor(int color) {
+        updateColor();
+    }
 
     @Override
     public void setColorPalette(boolean supportsDarkText, int[] colorPalette) {
-        if (colorPalette == null || colorPalette.length == 0) {
-            return;
-        }
-        final int length = colorPalette.length;
-        final int color = colorPalette[Math.max(0, length - 3)];
-        mLockClock.setTextColor(color);
-        mAnalogClock.setClockColors(color, color);
+        mPalette.setColorPalette(supportsDarkText, colorPalette);
+        updateColor();
+    }
+
+    private void updateColor() {
+        final int primary = mPalette.getPrimaryColor();
+        final int secondary = mPalette.getSecondaryColor();
+        mLockClock.setTextColor(secondary);
+        mAnalogClock.setClockColors(primary, secondary);
     }
 
     @Override
     public void setDarkAmount(float darkAmount) {
+        mPalette.setDarkAmount(darkAmount);
         mClockPosition.setDarkAmount(darkAmount);
         mView.setDarkAmount(darkAmount);
     }
diff --git a/packages/SystemUI/src/com/android/keyguard/clock/ClockLayout.java b/packages/SystemUI/src/com/android/keyguard/clock/ClockLayout.java
index 1908345..7485d33 100644
--- a/packages/SystemUI/src/com/android/keyguard/clock/ClockLayout.java
+++ b/packages/SystemUI/src/com/android/keyguard/clock/ClockLayout.java
@@ -94,7 +94,8 @@
                 getBurnInOffset(mBurnInPreventionOffsetX * 2, true) - mBurnInPreventionOffsetX,
                 mDarkAmount);
         final float offsetY = MathUtils.lerp(0f,
-                getBurnInOffset(mBurnInPreventionOffsetY * 2, false) - mBurnInPreventionOffsetY,
+                getBurnInOffset(mBurnInPreventionOffsetY * 2, false)
+                        - 0.5f * mBurnInPreventionOffsetY,
                 mDarkAmount);
 
         // Put the analog clock in the middle of the screen.
diff --git a/packages/SystemUI/src/com/android/keyguard/clock/ClockManager.java b/packages/SystemUI/src/com/android/keyguard/clock/ClockManager.java
index 9f4c403e..9e2464e 100644
--- a/packages/SystemUI/src/com/android/keyguard/clock/ClockManager.java
+++ b/packages/SystemUI/src/com/android/keyguard/clock/ClockManager.java
@@ -240,9 +240,9 @@
     }
 
     private void reload() {
-        mPreviewClocks.reload();
+        mPreviewClocks.reloadCurrentClock();
         mListeners.forEach((listener, clocks) -> {
-            clocks.reload();
+            clocks.reloadCurrentClock();
             ClockPlugin clock = clocks.getCurrentClock();
             if (clock instanceof DefaultClockController) {
                 listener.onClockChanged(null);
@@ -287,20 +287,13 @@
         @Override
         public void onPluginConnected(ClockPlugin plugin, Context pluginContext) {
             addClockPlugin(plugin);
-            reload();
-            if (plugin == mCurrentClock) {
-                ClockManager.this.reload();
-            }
+            reloadIfNeeded(plugin);
         }
 
         @Override
         public void onPluginDisconnected(ClockPlugin plugin) {
-            boolean isCurrentClock = plugin == mCurrentClock;
             removeClockPlugin(plugin);
-            reload();
-            if (isCurrentClock) {
-                ClockManager.this.reload();
-            }
+            reloadIfNeeded(plugin);
         }
 
         /**
@@ -347,10 +340,19 @@
             }
         }
 
+        private void reloadIfNeeded(ClockPlugin plugin) {
+            final boolean wasCurrentClock = plugin == mCurrentClock;
+            reloadCurrentClock();
+            final boolean isCurrentClock = plugin == mCurrentClock;
+            if (wasCurrentClock || isCurrentClock) {
+                ClockManager.this.reload();
+            }
+        }
+
         /**
          * Update the current clock.
          */
-        void reload() {
+        void reloadCurrentClock() {
             mCurrentClock = getClockPlugin();
         }
 
diff --git a/packages/SystemUI/src/com/android/keyguard/clock/ClockPalette.kt b/packages/SystemUI/src/com/android/keyguard/clock/ClockPalette.kt
new file mode 100644
index 0000000..5c5493a
--- /dev/null
+++ b/packages/SystemUI/src/com/android/keyguard/clock/ClockPalette.kt
@@ -0,0 +1,73 @@
+/*
+ * 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.keyguard.clock
+
+import android.graphics.Color
+import android.util.MathUtils
+
+private const val PRIMARY_INDEX = 5
+private const val SECONDARY_DARK_INDEX = 8
+private const val SECONDARY_LIGHT_INDEX = 2
+
+/**
+ * A helper class to extract colors from a clock face.
+ */
+class ClockPalette {
+
+    private var darkAmount: Float = 0f
+    private var accentPrimary: Int = Color.WHITE
+    private var accentSecondaryLight: Int = Color.WHITE
+    private var accentSecondaryDark: Int = Color.BLACK
+    private val lightHSV: FloatArray = FloatArray(3)
+    private val darkHSV: FloatArray = FloatArray(3)
+    private val hsv: FloatArray = FloatArray(3)
+
+    /** Returns a color from the palette as an RGB packed int. */
+    fun getPrimaryColor(): Int {
+        return accentPrimary
+    }
+
+    /** Returns either a light or dark color from the palette as an RGB packed int. */
+    fun getSecondaryColor(): Int {
+        Color.colorToHSV(accentSecondaryLight, lightHSV)
+        Color.colorToHSV(accentSecondaryDark, darkHSV)
+        for (i in 0..2) {
+            hsv[i] = MathUtils.lerp(darkHSV[i], lightHSV[i], darkAmount)
+        }
+        return Color.HSVToColor(hsv)
+    }
+
+    /** See {@link ClockPlugin#setColorPalette}. */
+    fun setColorPalette(supportsDarkText: Boolean, colorPalette: IntArray?) {
+        if (colorPalette == null || colorPalette.isEmpty()) {
+            accentPrimary = Color.WHITE
+            accentSecondaryLight = Color.WHITE
+            accentSecondaryDark = if (supportsDarkText) Color.BLACK else Color.WHITE
+            return
+        }
+        val length = colorPalette.size
+        accentPrimary = colorPalette[Math.max(0, length - PRIMARY_INDEX)]
+        accentSecondaryLight = colorPalette[Math.max(0, length - SECONDARY_LIGHT_INDEX)]
+        accentSecondaryDark = colorPalette[Math.max(0,
+                length - if (supportsDarkText) SECONDARY_DARK_INDEX else SECONDARY_LIGHT_INDEX)]
+    }
+
+    /** See {@link ClockPlugin#setDarkAmount}. */
+    fun setDarkAmount(darkAmount: Float) {
+        this.darkAmount = darkAmount
+    }
+}
diff --git a/packages/SystemUI/src/com/android/keyguard/clock/SettingsWrapper.java b/packages/SystemUI/src/com/android/keyguard/clock/SettingsWrapper.java
index e1c658be..096e943 100644
--- a/packages/SystemUI/src/com/android/keyguard/clock/SettingsWrapper.java
+++ b/packages/SystemUI/src/com/android/keyguard/clock/SettingsWrapper.java
@@ -15,21 +15,37 @@
  */
 package com.android.keyguard.clock;
 
+import android.annotation.Nullable;
 import android.content.ContentResolver;
 import android.provider.Settings;
+import android.util.Log;
+
+import com.android.internal.annotations.VisibleForTesting;
+
+import org.json.JSONException;
+import org.json.JSONObject;
 
 /**
  * Wrapper around Settings used for testing.
  */
 public class SettingsWrapper {
 
+    private static final String TAG = "ClockFaceSettings";
     private static final String CUSTOM_CLOCK_FACE = Settings.Secure.LOCK_SCREEN_CUSTOM_CLOCK_FACE;
     private static final String DOCKED_CLOCK_FACE = Settings.Secure.DOCKED_CLOCK_FACE;
+    private static final String CLOCK_FIELD = "clock";
 
-    private ContentResolver mContentResolver;
+    private final ContentResolver mContentResolver;
+    private final Migration mMigration;
 
-    public SettingsWrapper(ContentResolver contentResolver) {
+    SettingsWrapper(ContentResolver contentResolver) {
+        this(contentResolver, new Migrator(contentResolver));
+    }
+
+    @VisibleForTesting
+    SettingsWrapper(ContentResolver contentResolver, Migration migration) {
         mContentResolver = contentResolver;
+        mMigration = migration;
     }
 
     /**
@@ -37,8 +53,10 @@
      *
      * @param userId ID of the user.
      */
-    public String getLockScreenCustomClockFace(int userId) {
-        return Settings.Secure.getStringForUser(mContentResolver, CUSTOM_CLOCK_FACE, userId);
+    String getLockScreenCustomClockFace(int userId) {
+        return decode(
+                Settings.Secure.getStringForUser(mContentResolver, CUSTOM_CLOCK_FACE, userId),
+                userId);
     }
 
     /**
@@ -46,7 +64,74 @@
      *
      * @param userId ID of the user.
      */
-    public String getDockedClockFace(int userId) {
+    String getDockedClockFace(int userId) {
         return Settings.Secure.getStringForUser(mContentResolver, DOCKED_CLOCK_FACE, userId);
     }
+
+    /**
+     * Decodes the string stored in settings, which should be formatted as JSON.
+     * @param value String stored in settings. If value is not JSON, then the settings is
+     *              overwritten with JSON containing the prior value.
+     * @return ID of the clock face to show on AOD and lock screen. If value is not JSON, the value
+     *         is returned.
+     */
+    @VisibleForTesting
+    String decode(@Nullable String value, int userId) {
+        if (value == null) {
+            return value;
+        }
+        JSONObject json;
+        try {
+            json = new JSONObject(value);
+        } catch (JSONException ex) {
+            Log.e(TAG, "Settings value is not valid JSON", ex);
+            // The settings value isn't JSON since it didn't parse so migrate the value to JSON.
+            // TODO(b/135674383): Remove this migration path in the following release.
+            mMigration.migrate(value, userId);
+            return value;
+        }
+        try {
+            return json.getString(CLOCK_FIELD);
+        } catch (JSONException ex) {
+            Log.e(TAG, "JSON object does not contain clock field.", ex);
+            return null;
+        }
+    }
+
+    interface Migration {
+        void migrate(String value, int userId);
+    }
+
+    /**
+     * Implementation of {@link Migration} that writes valid JSON back to Settings.
+     */
+    private static final class Migrator implements Migration {
+
+        private final ContentResolver mContentResolver;
+
+        Migrator(ContentResolver contentResolver) {
+            mContentResolver = contentResolver;
+        }
+
+        /**
+         * Migrate settings values that don't parse by converting to JSON format.
+         *
+         * Values in settings must be JSON to be backed up and restored. To help users maintain
+         * their current settings, convert existing values into the JSON format.
+         *
+         * TODO(b/135674383): Remove this migration code in the following release.
+         */
+        @Override
+        public void migrate(String value, int userId) {
+            try {
+                JSONObject json = new JSONObject();
+                json.put(CLOCK_FIELD, value);
+                Settings.Secure.putStringForUser(mContentResolver, CUSTOM_CLOCK_FACE,
+                        json.toString(),
+                        userId);
+            } catch (JSONException ex) {
+                Log.e(TAG, "Failed migrating settings value to JSON format", ex);
+            }
+        }
+    }
 }
diff --git a/packages/SystemUI/src/com/android/keyguard/clock/SmallClockPosition.java b/packages/SystemUI/src/com/android/keyguard/clock/SmallClockPosition.java
index 9b15dc6..60ca945 100644
--- a/packages/SystemUI/src/com/android/keyguard/clock/SmallClockPosition.java
+++ b/packages/SystemUI/src/com/android/keyguard/clock/SmallClockPosition.java
@@ -67,7 +67,8 @@
      */
     int getPreferredY() {
         // On AOD, clock needs to appear below the status bar with enough room for pixel shifting
-        int aodY = mStatusBarHeight + mKeyguardLockPadding + mBurnInOffsetY;
+        int aodY = mStatusBarHeight + mKeyguardLockHeight + 2 * mKeyguardLockPadding
+                + mBurnInOffsetY;
         // On lock screen, clock needs to appear below the lock icon
         int lockY =  mStatusBarHeight + mKeyguardLockHeight + 2 * mKeyguardLockPadding;
         return (int) MathUtils.lerp(lockY, aodY, mDarkAmount);
diff --git a/packages/SystemUI/src/com/android/systemui/CornerHandleView.java b/packages/SystemUI/src/com/android/systemui/CornerHandleView.java
index 54a3635..a94952c 100644
--- a/packages/SystemUI/src/com/android/systemui/CornerHandleView.java
+++ b/packages/SystemUI/src/com/android/systemui/CornerHandleView.java
@@ -107,7 +107,9 @@
         mPaint.setColor((int) ArgbEvaluator.getInstance().evaluate(darkIntensity,
                 mLightColor,
                 mDarkColor));
-        invalidate();
+        if (getVisibility() == VISIBLE) {
+            invalidate();
+        }
     }
 
     @Override
diff --git a/packages/SystemUI/src/com/android/systemui/Dependency.java b/packages/SystemUI/src/com/android/systemui/Dependency.java
index 9f4a4e0..6c36bc9 100644
--- a/packages/SystemUI/src/com/android/systemui/Dependency.java
+++ b/packages/SystemUI/src/com/android/systemui/Dependency.java
@@ -53,7 +53,6 @@
 import com.android.systemui.shared.system.ActivityManagerWrapper;
 import com.android.systemui.shared.system.DevicePolicyManagerWrapper;
 import com.android.systemui.shared.system.PackageManagerWrapper;
-import com.android.systemui.statusbar.AmbientPulseManager;
 import com.android.systemui.statusbar.NavigationBarController;
 import com.android.systemui.statusbar.NotificationListener;
 import com.android.systemui.statusbar.NotificationLockscreenUserManager;
@@ -267,7 +266,6 @@
     @Inject Lazy<VisualStabilityManager> mVisualStabilityManager;
     @Inject Lazy<NotificationGutsManager> mNotificationGutsManager;
     @Inject Lazy<NotificationMediaManager> mNotificationMediaManager;
-    @Inject Lazy<AmbientPulseManager> mAmbientPulseManager;
     @Inject Lazy<NotificationBlockingHelperManager> mNotificationBlockingHelperManager;
     @Inject Lazy<NotificationRemoteInputManager> mNotificationRemoteInputManager;
     @Inject Lazy<SmartReplyConstants> mSmartReplyConstants;
@@ -447,7 +445,6 @@
                 mNotificationGroupAlertTransferHelper::get);
         mProviders.put(NotificationMediaManager.class, mNotificationMediaManager::get);
         mProviders.put(NotificationGutsManager.class, mNotificationGutsManager::get);
-        mProviders.put(AmbientPulseManager.class, mAmbientPulseManager::get);
         mProviders.put(NotificationBlockingHelperManager.class,
                 mNotificationBlockingHelperManager::get);
         mProviders.put(NotificationRemoteInputManager.class,
diff --git a/packages/SystemUI/src/com/android/systemui/ScreenDecorations.java b/packages/SystemUI/src/com/android/systemui/ScreenDecorations.java
index 73e57de..f38b4f2 100644
--- a/packages/SystemUI/src/com/android/systemui/ScreenDecorations.java
+++ b/packages/SystemUI/src/com/android/systemui/ScreenDecorations.java
@@ -305,7 +305,7 @@
 
         mAssistHintBlocked = blocked;
         if (mAssistHintVisible && mAssistHintBlocked) {
-            setAssistHintVisible(false);
+            hideAssistHandles();
         }
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/SystemUIApplication.java b/packages/SystemUI/src/com/android/systemui/SystemUIApplication.java
index 61a0f72..e89e6cb 100644
--- a/packages/SystemUI/src/com/android/systemui/SystemUIApplication.java
+++ b/packages/SystemUI/src/com/android/systemui/SystemUIApplication.java
@@ -37,6 +37,7 @@
 import com.android.systemui.plugins.OverlayPlugin;
 import com.android.systemui.plugins.PluginListener;
 import com.android.systemui.shared.plugins.PluginManager;
+import com.android.systemui.statusbar.phone.DozeParameters;
 import com.android.systemui.statusbar.phone.StatusBar;
 import com.android.systemui.statusbar.phone.StatusBarWindowController;
 import com.android.systemui.util.NotificationChannels;
@@ -215,7 +216,8 @@
                                 StatusBar statusBar = getComponent(StatusBar.class);
                                 if (statusBar != null) {
                                     plugin.setup(statusBar.getStatusBarWindow(),
-                                            statusBar.getNavigationBarView(), new Callback(plugin));
+                                            statusBar.getNavigationBarView(), new Callback(plugin),
+                                            DozeParameters.getInstance(getBaseContext()));
                                 }
                             }
                         });
diff --git a/packages/SystemUI/src/com/android/systemui/SystemUIFactory.java b/packages/SystemUI/src/com/android/systemui/SystemUIFactory.java
index d815d95..0d85a3f 100644
--- a/packages/SystemUI/src/com/android/systemui/SystemUIFactory.java
+++ b/packages/SystemUI/src/com/android/systemui/SystemUIFactory.java
@@ -22,6 +22,7 @@
 import android.annotation.Nullable;
 import android.app.AlarmManager;
 import android.content.Context;
+import android.content.pm.PackageManager;
 import android.os.Handler;
 import android.os.Looper;
 import android.util.Log;
@@ -48,10 +49,13 @@
 import com.android.systemui.statusbar.ScrimView;
 import com.android.systemui.statusbar.notification.NotificationEntryManager;
 import com.android.systemui.statusbar.notification.NotificationInterruptionStateProvider;
+import com.android.systemui.statusbar.notification.NotificationWakeUpCoordinator;
 import com.android.systemui.statusbar.notification.collection.NotificationData;
 import com.android.systemui.statusbar.phone.DozeParameters;
 import com.android.systemui.statusbar.phone.KeyguardBouncer;
+import com.android.systemui.statusbar.phone.KeyguardBypassController;
 import com.android.systemui.statusbar.phone.KeyguardEnvironmentImpl;
+import com.android.systemui.statusbar.phone.KeyguardLiftController;
 import com.android.systemui.statusbar.phone.LockIcon;
 import com.android.systemui.statusbar.phone.LockscreenWallpaper;
 import com.android.systemui.statusbar.phone.NotificationIconAreaController;
@@ -60,7 +64,10 @@
 import com.android.systemui.statusbar.phone.ShadeController;
 import com.android.systemui.statusbar.phone.StatusBar;
 import com.android.systemui.statusbar.phone.StatusBarKeyguardViewManager;
+import com.android.systemui.statusbar.phone.UnlockMethodCache;
 import com.android.systemui.statusbar.policy.DeviceProvisionedController;
+import com.android.systemui.statusbar.policy.KeyguardMonitor;
+import com.android.systemui.util.AsyncSensorManager;
 import com.android.systemui.util.InjectionInflationController;
 import com.android.systemui.util.leak.GarbageMonitor;
 import com.android.systemui.volume.VolumeDialogComponent;
@@ -127,10 +134,12 @@
     public KeyguardBouncer createKeyguardBouncer(Context context, ViewMediatorCallback callback,
             LockPatternUtils lockPatternUtils,  ViewGroup container,
             DismissCallbackRegistry dismissCallbackRegistry,
-            KeyguardBouncer.BouncerExpansionCallback expansionCallback) {
+            KeyguardBouncer.BouncerExpansionCallback expansionCallback,
+            KeyguardBypassController bypassController) {
         return new KeyguardBouncer(context, callback, lockPatternUtils, container,
                 dismissCallbackRegistry, FalsingManagerFactory.getInstance(context),
-                expansionCallback, KeyguardUpdateMonitor.getInstance(context),
+                expansionCallback, UnlockMethodCache.getInstance(context),
+                KeyguardUpdateMonitor.getInstance(context), bypassController,
                 new Handler(Looper.getMainLooper()));
     }
 
@@ -138,14 +147,18 @@
             LockscreenWallpaper lockscreenWallpaper,
             TriConsumer<ScrimState, Float, GradientColors> scrimStateListener,
             Consumer<Integer> scrimVisibleListener, DozeParameters dozeParameters,
-            AlarmManager alarmManager) {
+            AlarmManager alarmManager, KeyguardMonitor keyguardMonitor) {
         return new ScrimController(scrimBehind, scrimInFront, scrimStateListener,
-                scrimVisibleListener, dozeParameters, alarmManager);
+                scrimVisibleListener, dozeParameters, alarmManager, keyguardMonitor);
     }
 
     public NotificationIconAreaController createNotificationIconAreaController(Context context,
-            StatusBar statusBar, StatusBarStateController statusBarStateController) {
+            StatusBar statusBar,
+            NotificationWakeUpCoordinator wakeUpCoordinator,
+            KeyguardBypassController keyguardBypassController,
+            StatusBarStateController statusBarStateController) {
         return new NotificationIconAreaController(context, statusBar, statusBarStateController,
+                wakeUpCoordinator, keyguardBypassController,
                 Dependency.get(NotificationMediaManager.class));
     }
 
@@ -207,6 +220,18 @@
 
     @Singleton
     @Provides
+    @Nullable
+    public KeyguardLiftController provideKeyguardLiftController(Context context,
+            StatusBarStateController statusBarStateController,
+            AsyncSensorManager asyncSensorManager) {
+        if (!context.getPackageManager().hasSystemFeature(PackageManager.FEATURE_FACE)) {
+            return null;
+        }
+        return new KeyguardLiftController(context, statusBarStateController, asyncSensorManager);
+    }
+
+    @Singleton
+    @Provides
     public NotificationListener provideNotificationListener(Context context) {
         return new NotificationListener(context);
     }
diff --git a/packages/SystemUI/src/com/android/systemui/appops/AppOpsControllerImpl.java b/packages/SystemUI/src/com/android/systemui/appops/AppOpsControllerImpl.java
index afb8e74..7a74dba 100644
--- a/packages/SystemUI/src/com/android/systemui/appops/AppOpsControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/appops/AppOpsControllerImpl.java
@@ -61,6 +61,7 @@
     private H mBGHandler;
     private final List<AppOpsController.Callback> mCallbacks = new ArrayList<>();
     private final ArrayMap<Integer, Set<Callback>> mCallbacksByCode = new ArrayMap<>();
+    private boolean mListening;
 
     @GuardedBy("mActiveItems")
     private final List<AppOpItem> mActiveItems = new ArrayList<>();
@@ -93,6 +94,7 @@
 
     @VisibleForTesting
     protected void setListening(boolean listening) {
+        mListening = listening;
         if (listening) {
             mAppOps.startWatchingActive(OPS, this);
             mAppOps.startWatchingNoted(OPS, this);
@@ -279,6 +281,7 @@
     @Override
     public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
         pw.println("AppOpsController state:");
+        pw.println("  Listening: " + mListening);
         pw.println("  Active Items:");
         for (int i = 0; i < mActiveItems.size(); i++) {
             final AppOpItem item = mActiveItems.get(i);
diff --git a/packages/SystemUI/src/com/android/systemui/assist/AssistHandleBehaviorController.java b/packages/SystemUI/src/com/android/systemui/assist/AssistHandleBehaviorController.java
index 002d4f3..6da3818 100644
--- a/packages/SystemUI/src/com/android/systemui/assist/AssistHandleBehaviorController.java
+++ b/packages/SystemUI/src/com/android/systemui/assist/AssistHandleBehaviorController.java
@@ -74,6 +74,7 @@
 
     private boolean mHandlesShowing = false;
     private long mHandlesLastHiddenAt;
+    private long mShowAndGoEndsAt;
     /**
      * This should always be initialized as {@link AssistHandleBehavior#OFF} to ensure proper
      * behavior lifecycle.
@@ -144,7 +145,9 @@
 
     private void showAndGoInternal() {
         maybeShowHandles(/* ignoreThreshold = */ false);
-        mHandler.postDelayed(mHideHandles, getShowAndGoDuration());
+        long showAndGoDuration = getShowAndGoDuration();
+        mShowAndGoEndsAt = SystemClock.elapsedRealtime() + showAndGoDuration;
+        mHandler.postDelayed(mHideHandles, showAndGoDuration);
     }
 
     @Override // AssistHandleCallbacks
@@ -162,6 +165,10 @@
         mHandler.post(() -> maybeShowHandles(/* ignoreThreshold = */ true));
     }
 
+    public long getShowAndGoRemainingTimeMs() {
+        return Long.max(mShowAndGoEndsAt - SystemClock.elapsedRealtime(), 0);
+    }
+
     boolean areHandlesShowing() {
         return mHandlesShowing;
     }
@@ -271,6 +278,7 @@
     private void clearPendingCommands() {
         mHandler.removeCallbacks(mHideHandles);
         mHandler.removeCallbacks(mShowAndGo);
+        mShowAndGoEndsAt = 0;
     }
 
     @VisibleForTesting
diff --git a/packages/SystemUI/src/com/android/systemui/assist/AssistManager.java b/packages/SystemUI/src/com/android/systemui/assist/AssistManager.java
index d3580de..cf9c470 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();
     }
@@ -258,12 +258,8 @@
         }
         int phoneState = mPhoneStateMonitor.getPhoneState();
         args.putInt(INVOCATION_PHONE_STATE_KEY, phoneState);
-        args.putLong(INVOCATION_TIME_MS_KEY, SystemClock.uptimeMillis());
-        // Logs assistant start with invocation type.
-        MetricsLogger.action(
-                new LogMaker(MetricsEvent.ASSISTANT)
-                        .setType(MetricsEvent.TYPE_OPEN)
-                        .setSubtype(toLoggingSubType(invocationType, phoneState)));
+        args.putLong(INVOCATION_TIME_MS_KEY, SystemClock.elapsedRealtime());
+        logStartAssist(invocationType, phoneState);
         startAssistInternal(args, assistComponent, isService);
     }
 
@@ -444,12 +440,23 @@
         mAssistUtils.onLockscreenShown();
     }
 
+    public long getAssistHandleShowAndGoRemainingDurationMs() {
+        return mHandleController.getShowAndGoRemainingTimeMs();
+    }
+
     /** Returns the logging flags for the given Assistant invocation type. */
     public int toLoggingSubType(int invocationType) {
         return toLoggingSubType(invocationType, mPhoneStateMonitor.getPhoneState());
     }
 
-    private int toLoggingSubType(int invocationType, int phoneState) {
+    protected void logStartAssist(int invocationType, int phoneState) {
+        MetricsLogger.action(
+                new LogMaker(MetricsEvent.ASSISTANT)
+                        .setType(MetricsEvent.TYPE_OPEN)
+                        .setSubtype(toLoggingSubType(invocationType, phoneState)));
+    }
+
+    protected final int toLoggingSubType(int invocationType, int phoneState) {
         // Note that this logic will break if the number of Assistant invocation types exceeds 7.
         // There are currently 5 invocation types, but we will be migrating to the new logging
         // framework in the next update.
diff --git a/packages/SystemUI/src/com/android/systemui/assist/PhenotypeHelper.java b/packages/SystemUI/src/com/android/systemui/assist/PhenotypeHelper.java
index 61395f1..b3f57af 100644
--- a/packages/SystemUI/src/com/android/systemui/assist/PhenotypeHelper.java
+++ b/packages/SystemUI/src/com/android/systemui/assist/PhenotypeHelper.java
@@ -22,28 +22,28 @@
 
 import java.util.concurrent.Executor;
 
-class PhenotypeHelper {
+public class PhenotypeHelper {
 
-    PhenotypeHelper() {}
+    public PhenotypeHelper() {}
 
-    long getLong(String name, long defaultValue) {
+    public long getLong(String name, long defaultValue) {
         return DeviceConfig.getLong(DeviceConfig.NAMESPACE_SYSTEMUI, name, defaultValue);
     }
 
-    int getInt(String name, int defaultValue) {
+    public int getInt(String name, int defaultValue) {
         return DeviceConfig.getInt(DeviceConfig.NAMESPACE_SYSTEMUI, name, defaultValue);
     }
 
     @Nullable
-    String getString(String name, @Nullable String defaultValue) {
+    public String getString(String name, @Nullable String defaultValue) {
         return DeviceConfig.getString(DeviceConfig.NAMESPACE_SYSTEMUI, name, defaultValue);
     }
 
-    boolean getBoolean(String name, boolean defaultValue) {
+    public boolean getBoolean(String name, boolean defaultValue) {
         return DeviceConfig.getBoolean(DeviceConfig.NAMESPACE_SYSTEMUI, name, defaultValue);
     }
 
-    void addOnPropertiesChangedListener(
+    public void addOnPropertiesChangedListener(
             Executor executor, DeviceConfig.OnPropertiesChangedListener listener) {
         DeviceConfig.addOnPropertiesChangedListener(
                 DeviceConfig.NAMESPACE_SYSTEMUI, executor, listener);
diff --git a/packages/SystemUI/src/com/android/systemui/assist/ui/CircularCornerPathRenderer.java b/packages/SystemUI/src/com/android/systemui/assist/ui/CircularCornerPathRenderer.java
index 00346a3..e61e47a 100644
--- a/packages/SystemUI/src/com/android/systemui/assist/ui/CircularCornerPathRenderer.java
+++ b/packages/SystemUI/src/com/android/systemui/assist/ui/CircularCornerPathRenderer.java
@@ -16,6 +16,7 @@
 
 package com.android.systemui.assist.ui;
 
+import android.content.Context;
 import android.graphics.Path;
 
 /**
@@ -29,12 +30,11 @@
     private final int mWidth;
     private final Path mPath = new Path();
 
-    public CircularCornerPathRenderer(int cornerRadiusBottom, int cornerRadiusTop,
-            int width, int height) {
-        mCornerRadiusBottom = cornerRadiusBottom;
-        mCornerRadiusTop = cornerRadiusTop;
-        mHeight = height;
-        mWidth = width;
+    public CircularCornerPathRenderer(Context context) {
+        mCornerRadiusBottom = DisplayUtils.getCornerRadiusBottom(context);
+        mCornerRadiusTop = DisplayUtils.getCornerRadiusTop(context);
+        mHeight = DisplayUtils.getHeight(context);
+        mWidth = DisplayUtils.getWidth(context);
     }
 
     @Override // CornerPathRenderer
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/assist/ui/InvocationLightsView.java b/packages/SystemUI/src/com/android/systemui/assist/ui/InvocationLightsView.java
index 8ef7b6c..bc782a7 100644
--- a/packages/SystemUI/src/com/android/systemui/assist/ui/InvocationLightsView.java
+++ b/packages/SystemUI/src/com/android/systemui/assist/ui/InvocationLightsView.java
@@ -129,7 +129,7 @@
             float arcLengthNormalized = cornerLengthNormalized * MINIMUM_CORNER_RATIO;
             float arcOffsetNormalized = (cornerLengthNormalized - arcLengthNormalized) / 2f;
 
-            float minLightLength = arcLengthNormalized / 2;
+            float minLightLength = 0;
             float maxLightLength = mGuide.getRegionWidth(PerimeterPathGuide.Region.BOTTOM) / 4f;
 
             float lightLength = MathUtils.lerp(minLightLength, maxLightLength, progress);
@@ -247,13 +247,9 @@
      * To render corners that aren't circular, override this method in a subclass.
      */
     protected CornerPathRenderer createCornerPathRenderer(Context context) {
-        int displayWidth = DisplayUtils.getWidth(context);
-        int displayHeight = DisplayUtils.getHeight(context);
-        int cornerRadiusBottom = DisplayUtils.getCornerRadiusBottom(context);
-        int cornerRadiusTop = DisplayUtils.getCornerRadiusTop(context);
-        return new CircularCornerPathRenderer(
-                cornerRadiusBottom, cornerRadiusTop, displayWidth, displayHeight);
+        return new CircularCornerPathRenderer(context);
     }
+
     /**
      * Receives an intensity from 0 (lightest) to 1 (darkest) and sets the handle color
      * appropriately. Intention is to match the home handle color.
diff --git a/packages/SystemUI/src/com/android/systemui/assist/ui/PathSpecCornerPathRenderer.java b/packages/SystemUI/src/com/android/systemui/assist/ui/PathSpecCornerPathRenderer.java
new file mode 100644
index 0000000..2bad7fc
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/assist/ui/PathSpecCornerPathRenderer.java
@@ -0,0 +1,124 @@
+/*
+ * 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.systemui.assist.ui;
+
+import android.content.Context;
+import android.graphics.Matrix;
+import android.graphics.Path;
+import android.graphics.RectF;
+import android.util.Log;
+import android.util.PathParser;
+
+import com.android.systemui.R;
+
+/**
+ * Parses a path describing rounded corners from a string.
+ */
+public final class PathSpecCornerPathRenderer extends CornerPathRenderer {
+    private static final String TAG = "PathSpecCornerPathRenderer";
+
+    private final int mHeight;
+    private final int mWidth;
+    private final float mPathScale;
+    private final int mBottomCornerRadius;
+    private final int mTopCornerRadius;
+
+    private final Path mPath = new Path();
+    private final Path mRoundedPath;
+    private final Matrix mMatrix = new Matrix();
+
+    public PathSpecCornerPathRenderer(Context context) {
+        mWidth = DisplayUtils.getWidth(context);
+        mHeight = DisplayUtils.getHeight(context);
+
+        mBottomCornerRadius = DisplayUtils.getCornerRadiusBottom(context);
+        mTopCornerRadius = DisplayUtils.getCornerRadiusTop(context);
+
+        String pathData = context.getResources().getString(R.string.config_rounded_mask);
+        Path path = PathParser.createPathFromPathData(pathData);
+        if (path == null) {
+            Log.e(TAG, "No rounded corner path found!");
+            mRoundedPath = new Path();
+        } else {
+            mRoundedPath = path;
+
+        }
+
+        RectF bounds = new RectF();
+        mRoundedPath.computeBounds(bounds, true);
+
+        // we use this to scale the path such that the larger of its [width, height] is scaled to
+        // the corner radius (to account for asymmetric paths)
+        mPathScale = Math.min(
+                Math.abs(bounds.right - bounds.left),
+                Math.abs(bounds.top - bounds.bottom));
+    }
+
+    /**
+     * Scales and rotates each corner from the path specification to its correct position.
+     *
+     * Note: the rounded corners are passed in as the full shape (a curved triangle), but we only
+     * want the actual corner curve. Therefore we call getSegment to jump past the horizontal and
+     * vertical lines.
+     */
+    @Override
+    public Path getCornerPath(Corner corner) {
+        if (mRoundedPath.isEmpty()) {
+            return mRoundedPath;
+        }
+        int cornerRadius;
+        int rotateDegrees;
+        int translateX;
+        int translateY;
+        switch (corner) {
+            case TOP_LEFT:
+                cornerRadius = mTopCornerRadius;
+                rotateDegrees = 0;
+                translateX = 0;
+                translateY = 0;
+                break;
+            case TOP_RIGHT:
+                cornerRadius = mTopCornerRadius;
+                rotateDegrees = 90;
+                translateX = mWidth;
+                translateY = 0;
+                break;
+            case BOTTOM_RIGHT:
+                cornerRadius = mBottomCornerRadius;
+                rotateDegrees = 180;
+                translateX = mWidth;
+                translateY = mHeight;
+                break;
+            case BOTTOM_LEFT:
+            default:
+                cornerRadius = mBottomCornerRadius;
+                rotateDegrees = 270;
+                translateX = 0;
+                translateY = mHeight;
+                break;
+        }
+        mPath.reset();
+        mMatrix.reset();
+        mPath.addPath(mRoundedPath);
+
+        mMatrix.preScale(cornerRadius / mPathScale, cornerRadius / mPathScale);
+        mMatrix.postRotate(rotateDegrees);
+        mMatrix.postTranslate(translateX, translateY);
+        mPath.transform(mMatrix);
+        return mPath;
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/assist/ui/PerimeterPathGuide.java b/packages/SystemUI/src/com/android/systemui/assist/ui/PerimeterPathGuide.java
index 8eea368..fb41b1c 100644
--- a/packages/SystemUI/src/com/android/systemui/assist/ui/PerimeterPathGuide.java
+++ b/packages/SystemUI/src/com/android/systemui/assist/ui/PerimeterPathGuide.java
@@ -102,7 +102,7 @@
      * Sets the rotation.
      *
      * @param rotation one of Surface.ROTATION_0, Surface.ROTATION_90, Surface.ROTATION_180,
-     *                  Surface.ROTATION_270
+     *                 Surface.ROTATION_270
      */
     public void setRotation(int rotation) {
         if (rotation != mRotation) {
@@ -229,14 +229,14 @@
                     - mDeviceWidthPx) / 2, (mDeviceWidthPx - mDeviceHeightPx) / 2);
         }
 
-        CircularCornerPathRenderer.Corner screenBottomLeft = getRotatedCorner(
-                CircularCornerPathRenderer.Corner.BOTTOM_LEFT);
-        CircularCornerPathRenderer.Corner screenBottomRight = getRotatedCorner(
-                CircularCornerPathRenderer.Corner.BOTTOM_RIGHT);
-        CircularCornerPathRenderer.Corner screenTopLeft = getRotatedCorner(
-                CircularCornerPathRenderer.Corner.TOP_LEFT);
-        CircularCornerPathRenderer.Corner screenTopRight = getRotatedCorner(
-                CircularCornerPathRenderer.Corner.TOP_RIGHT);
+        CornerPathRenderer.Corner screenBottomLeft = getRotatedCorner(
+                CornerPathRenderer.Corner.BOTTOM_LEFT);
+        CornerPathRenderer.Corner screenBottomRight = getRotatedCorner(
+                CornerPathRenderer.Corner.BOTTOM_RIGHT);
+        CornerPathRenderer.Corner screenTopLeft = getRotatedCorner(
+                CornerPathRenderer.Corner.TOP_LEFT);
+        CornerPathRenderer.Corner screenTopRight = getRotatedCorner(
+                CornerPathRenderer.Corner.TOP_RIGHT);
 
         mRegions[Region.BOTTOM_LEFT.ordinal()].path =
                 mCornerPathRenderer.getInsetPath(screenBottomLeft, mEdgeInset);
@@ -287,9 +287,12 @@
         float accum = 0;
         for (int i = 0; i < mRegions.length; i++) {
             mRegions[i].normalizedLength = mRegions[i].absoluteLength / perimeterLength;
-            accum += mRegions[i].normalizedLength;
-            mRegions[i].endCoordinate = accum;
+            accum += mRegions[i].absoluteLength;
+            mRegions[i].endCoordinate = accum / perimeterLength;
         }
+        // Ensure that the last coordinate is 1. Setting it explicitly to avoid floating point
+        // error.
+        mRegions[mRegions.length - 1].endCoordinate = 1f;
     }
 
     private CircularCornerPathRenderer.Corner getRotatedCorner(
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/BiometricDialogView.java b/packages/SystemUI/src/com/android/systemui/biometrics/BiometricDialogView.java
index 18b8a9c..ce67577 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/BiometricDialogView.java
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/BiometricDialogView.java
@@ -16,6 +16,8 @@
 
 package com.android.systemui.biometrics;
 
+import static android.view.accessibility.AccessibilityEvent.CONTENT_CHANGE_TYPE_SUBTREE;
+
 import android.app.admin.DevicePolicyManager;
 import android.content.Context;
 import android.graphics.PixelFormat;
@@ -36,6 +38,8 @@
 import android.view.View;
 import android.view.ViewGroup;
 import android.view.WindowManager;
+import android.view.accessibility.AccessibilityEvent;
+import android.view.accessibility.AccessibilityManager;
 import android.view.animation.Interpolator;
 import android.widget.Button;
 import android.widget.ImageView;
@@ -55,6 +59,7 @@
 
     private static final String KEY_TRY_AGAIN_VISIBILITY = "key_try_again_visibility";
     private static final String KEY_CONFIRM_VISIBILITY = "key_confirm_visibility";
+    private static final String KEY_CONFIRM_ENABLED = "key_confirm_enabled";
     private static final String KEY_STATE = "key_state";
     private static final String KEY_ERROR_TEXT_VISIBILITY = "key_error_text_visibility";
     private static final String KEY_ERROR_TEXT_STRING = "key_error_text_string";
@@ -72,6 +77,7 @@
     protected static final int STATE_PENDING_CONFIRMATION = 3;
     protected static final int STATE_AUTHENTICATED = 4;
 
+    private final AccessibilityManager mAccessibilityManager;
     private final IBinder mWindowToken = new Binder();
     private final Interpolator mLinearOutSlowIn;
     private final WindowManager mWindowManager;
@@ -105,6 +111,9 @@
     protected boolean mRequireConfirmation;
     private int mUserId; // used to determine if we should show work background
 
+    private boolean mCompletedAnimatingIn;
+    private boolean mPendingDismissDialog;
+
     protected abstract int getHintStringResourceId();
     protected abstract int getAuthenticatedAccessibilityResourceId();
     protected abstract int getIconDescriptionResourceId();
@@ -150,6 +159,7 @@
         super(context);
         mCallback = callback;
         mLinearOutSlowIn = Interpolators.LINEAR_OUT_SLOW_IN;
+        mAccessibilityManager = mContext.getSystemService(AccessibilityManager.class);
         mWindowManager = mContext.getSystemService(WindowManager.class);
         mUserManager = mContext.getSystemService(UserManager.class);
         mDevicePolicyManager = mContext.getSystemService(DevicePolicyManager.class);
@@ -226,6 +236,10 @@
             handleResetMessage();
             updateState(STATE_AUTHENTICATING);
             showTryAgainButton(false /* show */);
+
+            mPositiveButton.setVisibility(View.VISIBLE);
+            mPositiveButton.setEnabled(false);
+
             mCallback.onTryAgainPressed();
         });
 
@@ -237,6 +251,7 @@
     public void onSaveState(Bundle bundle) {
         bundle.putInt(KEY_TRY_AGAIN_VISIBILITY, mTryAgainButton.getVisibility());
         bundle.putInt(KEY_CONFIRM_VISIBILITY, mPositiveButton.getVisibility());
+        bundle.putBoolean(KEY_CONFIRM_ENABLED, mPositiveButton.isEnabled());
         bundle.putInt(KEY_STATE, mState);
         bundle.putInt(KEY_ERROR_TEXT_VISIBILITY, mErrorText.getVisibility());
         bundle.putCharSequence(KEY_ERROR_TEXT_STRING, mErrorText.getText());
@@ -255,6 +270,7 @@
                     mContext.getTheme());
             image.setColorFilter(mDevicePolicyManager.getOrganizationColorForUser(mUserId),
                     PorterDuff.Mode.DARKEN);
+            backgroundView.setScaleType(ImageView.ScaleType.CENTER_CROP);
             backgroundView.setImageDrawable(image);
         } else {
             backgroundView.setImageDrawable(null);
@@ -269,9 +285,16 @@
 
         if (mRestoredState == null) {
             updateState(STATE_AUTHENTICATING);
-            mErrorText.setText(getHintStringResourceId());
-            mErrorText.setContentDescription(mContext.getString(getHintStringResourceId()));
-            mErrorText.setVisibility(View.VISIBLE);
+            mNegativeButton.setText(mBundle.getCharSequence(BiometricPrompt.KEY_NEGATIVE_TEXT));
+            final int hint = getHintStringResourceId();
+            if (hint != 0) {
+                mErrorText.setText(hint);
+                mErrorText.setContentDescription(mContext.getString(hint));
+                mErrorText.setVisibility(View.VISIBLE);
+            } else {
+                mErrorText.setVisibility(View.INVISIBLE);
+            }
+            announceAccessibilityEvent();
         } else {
             updateState(mState);
         }
@@ -284,6 +307,7 @@
         final CharSequence subtitleText = mBundle.getCharSequence(BiometricPrompt.KEY_SUBTITLE);
         if (TextUtils.isEmpty(subtitleText)) {
             mSubtitleText.setVisibility(View.GONE);
+            announceAccessibilityEvent();
         } else {
             mSubtitleText.setVisibility(View.VISIBLE);
             mSubtitleText.setText(subtitleText);
@@ -293,13 +317,12 @@
                 mBundle.getCharSequence(BiometricPrompt.KEY_DESCRIPTION);
         if (TextUtils.isEmpty(descriptionText)) {
             mDescriptionText.setVisibility(View.GONE);
+            announceAccessibilityEvent();
         } else {
             mDescriptionText.setVisibility(View.VISIBLE);
             mDescriptionText.setText(descriptionText);
         }
 
-        mNegativeButton.setText(mBundle.getCharSequence(BiometricPrompt.KEY_NEGATIVE_TEXT));
-
         if (requiresConfirmation() && mRestoredState == null) {
             mPositiveButton.setVisibility(View.VISIBLE);
             mPositiveButton.setEnabled(false);
@@ -312,6 +335,7 @@
             mDialog.setAlpha(1.0f);
             mDialog.setTranslationY(0);
             mLayout.setAlpha(1.0f);
+            mCompletedAnimatingIn = true;
         } else {
             // Dim the background and slide the dialog up
             mDialog.setTranslationY(mAnimationTranslationOffset);
@@ -332,6 +356,12 @@
     }
 
     public void startDismiss() {
+        if (!mCompletedAnimatingIn) {
+            Log.w(TAG, "startDismiss(): waiting for onDialogAnimatedIn");
+            mPendingDismissDialog = true;
+            return;
+        }
+
         mAnimatingAway = true;
 
         // This is where final cleanup should occur.
@@ -417,6 +447,7 @@
         mErrorText.setText(message);
         mErrorText.setTextColor(mErrorColor);
         mErrorText.setContentDescription(message);
+        mErrorText.setVisibility(View.VISIBLE);
         mHandler.sendMessageDelayed(mHandler.obtainMessage(MSG_RESET_MESSAGE),
                 BiometricPrompt.HIDE_DIALOG_DELAY);
     }
@@ -450,17 +481,24 @@
     public void updateState(int newState) {
         if (newState == STATE_PENDING_CONFIRMATION) {
             mHandler.removeMessages(MSG_RESET_MESSAGE);
-            mErrorText.setVisibility(View.INVISIBLE);
+            mErrorText.setTextColor(mTextColor);
+            mErrorText.setText(R.string.biometric_dialog_tap_confirm);
+            mErrorText.setContentDescription(
+                    getResources().getString(R.string.biometric_dialog_tap_confirm));
+            mErrorText.setVisibility(View.VISIBLE);
+            announceAccessibilityEvent();
             mPositiveButton.setVisibility(View.VISIBLE);
             mPositiveButton.setEnabled(true);
         } else if (newState == STATE_AUTHENTICATED) {
             mPositiveButton.setVisibility(View.GONE);
             mNegativeButton.setVisibility(View.GONE);
             mErrorText.setVisibility(View.INVISIBLE);
+            announceAccessibilityEvent();
         }
 
         if (newState == STATE_PENDING_CONFIRMATION || newState == STATE_AUTHENTICATED) {
             mNegativeButton.setText(R.string.cancel);
+            mNegativeButton.setContentDescription(getResources().getString(R.string.cancel));
         }
 
         updateIcon(mState, newState);
@@ -471,18 +509,33 @@
     }
 
     public void onDialogAnimatedIn() {
+        mCompletedAnimatingIn = true;
+
+        if (mPendingDismissDialog) {
+            Log.d(TAG, "onDialogAnimatedIn(): mPendingDismissDialog=true, dismissing now");
+            startDismiss();
+            mPendingDismissDialog = false;
+        }
     }
 
     public void restoreState(Bundle bundle) {
         mRestoredState = bundle;
-        mTryAgainButton.setVisibility(bundle.getInt(KEY_TRY_AGAIN_VISIBILITY));
-        mPositiveButton.setVisibility(bundle.getInt(KEY_CONFIRM_VISIBILITY));
+        final int tryAgainVisibility = bundle.getInt(KEY_TRY_AGAIN_VISIBILITY);
+        mTryAgainButton.setVisibility(tryAgainVisibility);
+        final int confirmVisibility = bundle.getInt(KEY_CONFIRM_VISIBILITY);
+        mPositiveButton.setVisibility(confirmVisibility);
+        final boolean confirmEnabled = bundle.getBoolean(KEY_CONFIRM_ENABLED);
+        mPositiveButton.setEnabled(confirmEnabled);
         mState = bundle.getInt(KEY_STATE);
         mErrorText.setText(bundle.getCharSequence(KEY_ERROR_TEXT_STRING));
         mErrorText.setContentDescription(bundle.getCharSequence(KEY_ERROR_TEXT_STRING));
-        mErrorText.setVisibility(bundle.getInt(KEY_ERROR_TEXT_VISIBILITY));
+        final int errorTextVisibility = bundle.getInt(KEY_ERROR_TEXT_VISIBILITY);
+        mErrorText.setVisibility(errorTextVisibility);
+        if (errorTextVisibility == View.INVISIBLE || tryAgainVisibility == View.INVISIBLE
+                || confirmVisibility == View.INVISIBLE) {
+            announceAccessibilityEvent();
+        }
         mErrorText.setTextColor(bundle.getInt(KEY_ERROR_TEXT_COLOR));
-
         if (bundle.getBoolean(KEY_ERROR_TEXT_IS_TEMPORARY)) {
             mHandler.sendMessageDelayed(mHandler.obtainMessage(MSG_RESET_MESSAGE),
                     BiometricPrompt.HIDE_DIALOG_DELAY);
@@ -505,4 +558,18 @@
         lp.token = mWindowToken;
         return lp;
     }
+
+    // Every time a view becomes invisible we need to announce an accessibility event.
+    // This is due to an issue in the framework, b/132298701 recommended this workaround.
+    protected void announceAccessibilityEvent() {
+        if (!mAccessibilityManager.isEnabled()) {
+            return;
+        }
+        AccessibilityEvent event = AccessibilityEvent.obtain();
+        event.setEventType(AccessibilityEvent.TYPE_WINDOW_CONTENT_CHANGED);
+        event.setContentChangeTypes(CONTENT_CHANGE_TYPE_SUBTREE);
+        mDialog.sendAccessibilityEventUnchecked(event);
+        mDialog.notifySubtreeAccessibilityStateChanged(mDialog, mDialog,
+                CONTENT_CHANGE_TYPE_SUBTREE);
+    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/FaceDialogView.java b/packages/SystemUI/src/com/android/systemui/biometrics/FaceDialogView.java
index 8f26f18..ae6cb5c 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/FaceDialogView.java
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/FaceDialogView.java
@@ -149,6 +149,7 @@
     private final Runnable mErrorToIdleAnimationRunnable = () -> {
         updateState(STATE_IDLE);
         mErrorText.setVisibility(View.INVISIBLE);
+        announceAccessibilityEvent();
     };
 
     public FaceDialogView(Context context,
@@ -188,6 +189,7 @@
             mDialog.invalidateOutline();
 
             mSize = newSize;
+            announceAccessibilityEvent();
         } else if (mSize == SIZE_SMALL && newSize == SIZE_BIG) {
             mSize = SIZE_GROWING;
 
@@ -287,14 +289,9 @@
 
     @Override
     protected void handleResetMessage() {
-        mErrorText.setText(getHintStringResourceId());
-        mErrorText.setContentDescription(mContext.getString(getHintStringResourceId()));
         mErrorText.setTextColor(mTextColor);
-        if (getState() == STATE_AUTHENTICATING) {
-            mErrorText.setVisibility(View.VISIBLE);
-        } else {
-            mErrorText.setVisibility(View.INVISIBLE);
-        }
+        mErrorText.setVisibility(View.INVISIBLE);
+        announceAccessibilityEvent();
     }
 
     @Override
@@ -368,17 +365,19 @@
                 mTryAgainButton.setVisibility(View.VISIBLE);
             } else {
                 mTryAgainButton.setVisibility(View.GONE);
+                announceAccessibilityEvent();
             }
         }
 
         if (show) {
             mPositiveButton.setVisibility(View.GONE);
+            announceAccessibilityEvent();
         }
     }
 
     @Override
     protected int getHintStringResourceId() {
-        return R.string.face_dialog_looking_for_face;
+        return 0;
     }
 
     @Override
@@ -403,7 +402,6 @@
             mHandler.removeCallbacks(mErrorToIdleAnimationRunnable);
             if (mDialogAnimatedIn) {
                 mIconController.startPulsing();
-                mErrorText.setVisibility(View.VISIBLE);
             } else {
                 mIconController.showIcon(R.drawable.face_dialog_pulse_dark_to_light);
             }
@@ -462,6 +460,7 @@
 
     @Override
     public void onDialogAnimatedIn() {
+        super.onDialogAnimatedIn();
         mDialogAnimatedIn = true;
         mIconController.startPulsing();
     }
diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/Bubble.java b/packages/SystemUI/src/com/android/systemui/bubbles/Bubble.java
index f60e95e..5c6c397 100644
--- a/packages/SystemUI/src/com/android/systemui/bubbles/Bubble.java
+++ b/packages/SystemUI/src/com/android/systemui/bubbles/Bubble.java
@@ -16,6 +16,8 @@
 package com.android.systemui.bubbles;
 
 
+import static android.view.Display.INVALID_DISPLAY;
+
 import static com.android.internal.annotations.VisibleForTesting.Visibility.PRIVATE;
 
 import android.content.Context;
@@ -129,6 +131,20 @@
         mInflated = true;
     }
 
+    /**
+     * Set visibility of bubble in the expanded state.
+     *
+     * @param visibility {@code true} if the expanded bubble should be visible on the screen.
+     *
+     * Note that this contents visibility doesn't affect visibility at {@link android.view.View},
+     * and setting {@code false} actually means rendering the expanded view in transparent.
+     */
+    void setContentVisibility(boolean visibility) {
+        if (expandedView != null) {
+            expandedView.setContentVisibility(visibility);
+        }
+    }
+
     void setDismissed() {
         entry.setBubbleDismissed(true);
         // TODO: move this somewhere where it can be guaranteed not to run until safe from flicker
@@ -168,6 +184,13 @@
     }
 
     /**
+     * @return the display id of the virtual display on which bubble contents is drawn.
+     */
+    int getDisplayId() {
+        return expandedView != null ? expandedView.getVirtualDisplayId() : INVALID_DISPLAY;
+    }
+
+    /**
      * Should be invoked whenever a Bubble is accessed (selected while expanded).
      */
     void markAsAccessedAt(long lastAccessedMillis) {
diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleController.java b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleController.java
index 392183b..a23c99e 100644
--- a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleController.java
+++ b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleController.java
@@ -672,17 +672,23 @@
      * status bar, otherwise returns {@link Display#INVALID_DISPLAY}.
      */
     public int getExpandedDisplayId(Context context) {
+        final Bubble bubble = getExpandedBubble(context);
+        return bubble != null ? bubble.getDisplayId() : INVALID_DISPLAY;
+    }
+
+    @Nullable
+    private Bubble getExpandedBubble(Context context) {
         if (mStackView == null) {
-            return INVALID_DISPLAY;
+            return null;
         }
-        boolean defaultDisplay = context.getDisplay() != null
+        final boolean defaultDisplay = context.getDisplay() != null
                 && context.getDisplay().getDisplayId() == DEFAULT_DISPLAY;
-        Bubble b = mStackView.getExpandedBubble();
-        if (defaultDisplay && b != null && isStackExpanded()
+        final Bubble expandedBubble = mStackView.getExpandedBubble();
+        if (defaultDisplay && expandedBubble != null && isStackExpanded()
                 && !mStatusBarWindowController.getPanelExpanded()) {
-            return b.expandedView.getVirtualDisplayId();
+            return expandedBubble;
         }
-        return INVALID_DISPLAY;
+        return null;
     }
 
     @VisibleForTesting
@@ -793,6 +799,14 @@
                 mBubbleData.setExpanded(false);
             }
         }
+
+        @Override
+        public void onSingleTaskDisplayDrawn(int displayId) {
+            final Bubble expandedBubble = getExpandedBubble(mContext);
+            if (expandedBubble != null && expandedBubble.getDisplayId() == displayId) {
+                expandedBubble.setContentVisibility(true);
+            }
+        }
     }
 
     private static boolean shouldAutoBubbleMessages(Context context) {
diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleExpandedView.java b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleExpandedView.java
index cbe6c99..923ca20 100644
--- a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleExpandedView.java
+++ b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleExpandedView.java
@@ -182,6 +182,8 @@
 
         mActivityView = new ActivityView(mContext, null /* attrs */, 0 /* defStyle */,
                 true /* singleTaskInstance */);
+
+        setContentVisibility(false);
         addView(mActivityView);
 
         // Expanded stack layout, top to bottom:
@@ -236,6 +238,22 @@
     }
 
     /**
+     * Set visibility of contents in the expanded state.
+     *
+     * @param visibility {@code true} if the contents should be visible on the screen.
+     *
+     * Note that this contents visibility doesn't affect visibility at {@link android.view.View},
+     * and setting {@code false} actually means rendering the contents in transparent.
+     */
+    void setContentVisibility(boolean visibility) {
+        final float alpha = visibility ? 1f : 0f;
+        mPointerView.setAlpha(alpha);
+        if (mActivityView != null) {
+            mActivityView.setAlpha(alpha);
+        }
+    }
+
+    /**
      * Called by {@link BubbleStackView} when the insets for the expanded state should be updated.
      * This should be done post-move and post-animation.
      */
@@ -307,6 +325,7 @@
                 parent.removeView(mNotifRow);
             }
             addView(mNotifRow, 1 /* index */);
+            mPointerView.setAlpha(1f);
         }
     }
 
@@ -333,6 +352,7 @@
                 removeView(mNotifRow);
                 mNotifRow = null;
             }
+            setContentVisibility(false);
             mActivityView.setVisibility(VISIBLE);
         } else if (DEBUG_ENABLE_AUTO_BUBBLE) {
             // Hide activity view if we had it previously
@@ -428,6 +448,7 @@
             mActivityView.onLocationChanged();
         } else if (mNotifRow != null) {
             applyRowState(mNotifRow);
+            mPointerView.setAlpha(1f);
         }
         updateHeight();
     }
@@ -478,7 +499,6 @@
         view.setHeadsUp(false);
         view.resetTranslation();
         view.setOnKeyguard(false);
-        view.setOnAmbient(false);
         view.setClipBottomAmount(0);
         view.setClipTopAmount(0);
         view.setContentTransformationAmount(0, false);
@@ -494,7 +514,6 @@
         viewState.gone = false;
         viewState.hidden = false;
         viewState.dimmed = false;
-        viewState.dark = false;
         viewState.alpha = 1f;
         viewState.notGoneIndex = -1;
         viewState.xTranslation = 0;
diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleStackView.java b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleStackView.java
index 771df2d..f87bcef 100644
--- a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleStackView.java
+++ b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleStackView.java
@@ -745,12 +745,16 @@
         }
         final Bubble previouslySelected = mExpandedBubble;
         mExpandedBubble = bubbleToSelect;
+
         if (mIsExpanded) {
             // Make the container of the expanded view transparent before removing the expanded view
             // from it. Otherwise a punch hole created by {@link android.view.SurfaceView} in the
             // expanded view becomes visible on the screen. See b/126856255
             mExpandedViewContainer.setAlpha(0.0f);
             mSurfaceSynchronizer.syncSurfaceAndRun(() -> {
+                if (previouslySelected != null) {
+                    previouslySelected.setContentVisibility(false);
+                }
                 updateExpandedBubble();
                 updatePointerPosition();
                 requestUpdate();
@@ -779,6 +783,14 @@
         }
         if (wasExpanded) {
             // Collapse the stack
+            mExpandedViewContainer.setAlpha(0.0f);
+            // TODO: In order to prevent flicker, code below should be executed after the alpha
+            // value set on the mExpandedViewContainer is reflected on the screen. However, we
+            // cannot just postpone the execution like #setSelectedBubble(), since some of member
+            // variables referred by the code are overridden before the execution.
+            if (mExpandedBubble != null) {
+                mExpandedBubble.setContentVisibility(false);
+            }
             animateExpansion(false /* expand */);
             logBubbleEvent(mExpandedBubble, StatsLog.BUBBLE_UICHANGED__ACTION__COLLAPSED);
         } else {
@@ -934,14 +946,10 @@
             if (shouldExpand) {
                 mExpandedViewContainer.setTranslationX(xStart);
                 mExpandedViewContainer.setTranslationY(yStart);
-                mExpandedViewContainer.setAlpha(0f);
             }
 
             mExpandedViewXAnim.animateToFinalPosition(shouldExpand ? 0f : xStart);
             mExpandedViewYAnim.animateToFinalPosition(shouldExpand ? yDest : yStart);
-            mExpandedViewContainer.animate()
-                    .setDuration(100)
-                    .alpha(shouldExpand ? 1f : 0f);
         }
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/classifier/FalsingManagerImpl.java b/packages/SystemUI/src/com/android/systemui/classifier/FalsingManagerImpl.java
index 382c5d5..fba0d50 100644
--- a/packages/SystemUI/src/com/android/systemui/classifier/FalsingManagerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/classifier/FalsingManagerImpl.java
@@ -67,8 +67,8 @@
             Sensor.TYPE_LIGHT,
             Sensor.TYPE_ROTATION_VECTOR,
     };
-    private static final String FALSING_REMAIN_LOCKED = "falsing_failure_after_attempts";
-    private static final String FALSING_SUCCESS = "falsing_success_after_attempts";
+    public static final String FALSING_REMAIN_LOCKED = "falsing_failure_after_attempts";
+    public static final String FALSING_SUCCESS = "falsing_success_after_attempts";
 
     private final Handler mHandler = new Handler(Looper.getMainLooper());
     private final Context mContext;
diff --git a/packages/SystemUI/src/com/android/systemui/classifier/FalsingManagerProxy.java b/packages/SystemUI/src/com/android/systemui/classifier/FalsingManagerProxy.java
index eb4edcc..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;
@@ -93,6 +94,7 @@
     public void setupFalsingManager(Context context) {
         boolean brightlineEnabled = DeviceConfig.getBoolean(
                 DeviceConfig.NAMESPACE_SYSTEMUI, BRIGHTLINE_FALSING_MANAGER_ENABLED, true);
+
         if (mInternalFalsingManager != null) {
             mInternalFalsingManager.cleanup();
         }
@@ -101,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 fbbba57..9e0b702 100644
--- a/packages/SystemUI/src/com/android/systemui/classifier/brightline/BrightLineFalsingManager.java
+++ b/packages/SystemUI/src/com/android/systemui/classifier/brightline/BrightLineFalsingManager.java
@@ -16,14 +16,21 @@
 
 package com.android.systemui.classifier.brightline;
 
+import static com.android.systemui.classifier.FalsingManagerImpl.FALSING_REMAIN_LOCKED;
+import static com.android.systemui.classifier.FalsingManagerImpl.FALSING_SUCCESS;
+
 import android.hardware.Sensor;
 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;
 
@@ -43,9 +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();
 
@@ -62,10 +73,28 @@
         }
     };
 
-    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);
         ProximityClassifier proximityClassifier = new ProximityClassifier(distanceClassifier,
@@ -103,6 +132,7 @@
         if (!mSessionStarted && !mShowingAod && mScreenOn) {
             logDebug("Starting Session");
             mSessionStarted = true;
+            mJustUnlockedWithFace = false;
             registerSensors();
             mClassifiers.forEach(FalsingClassifier::onSessionStarted);
         }
@@ -115,6 +145,10 @@
             unregisterSensors();
             mDataProvider.onSessionEnd();
             mClassifiers.forEach(FalsingClassifier::onSessionEnded);
+            if (mIsFalseTouchCalls != 0) {
+                mMetricsLogger.histogram(FALSING_REMAIN_LOCKED, mIsFalseTouchCalls);
+                mIsFalseTouchCalls = 0;
+            }
         }
     }
 
@@ -130,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");
@@ -161,6 +195,10 @@
 
     @Override
     public void onSucccessfulUnlock() {
+        if (mIsFalseTouchCalls != 0) {
+            mMetricsLogger.histogram(FALSING_SUCCESS, mIsFalseTouchCalls);
+            mIsFalseTouchCalls = 0;
+        }
         sessionEnd();
     }
 
@@ -320,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/classifier/brightline/ZigZagClassifier.java b/packages/SystemUI/src/com/android/systemui/classifier/brightline/ZigZagClassifier.java
index c58b7db..82ae30a 100644
--- a/packages/SystemUI/src/com/android/systemui/classifier/brightline/ZigZagClassifier.java
+++ b/packages/SystemUI/src/com/android/systemui/classifier/brightline/ZigZagClassifier.java
@@ -39,8 +39,8 @@
     // most swipes will follow somewhat of a 'C' or 'S' shape, we allow more deviance along the
     // `SECONDARY` axis.
     private static final float MAX_X_PRIMARY_DEVIANCE = .05f;
-    private static final float MAX_Y_PRIMARY_DEVIANCE = .05f;
-    private static final float MAX_X_SECONDARY_DEVIANCE = .3f;
+    private static final float MAX_Y_PRIMARY_DEVIANCE = .1f;
+    private static final float MAX_X_SECONDARY_DEVIANCE = .6f;
     private static final float MAX_Y_SECONDARY_DEVIANCE = .3f;
 
     private final float mMaxXPrimaryDeviance;
diff --git a/packages/SystemUI/src/com/android/systemui/colorextraction/SysuiColorExtractor.java b/packages/SystemUI/src/com/android/systemui/colorextraction/SysuiColorExtractor.java
index 6f56a53..d3e8b3d 100644
--- a/packages/SystemUI/src/com/android/systemui/colorextraction/SysuiColorExtractor.java
+++ b/packages/SystemUI/src/com/android/systemui/colorextraction/SysuiColorExtractor.java
@@ -67,19 +67,17 @@
         mBackdropColors = new GradientColors();
         mBackdropColors.setMainColor(Color.BLACK);
 
-        if (wallpaperManager != null) {
-            // Listen to all users instead of only the current one.
-            wallpaperManager.removeOnColorsChangedListener(this);
-            wallpaperManager.addOnColorsChangedListener(this, null /* handler */,
-                    UserHandle.USER_ALL);
-        }
+        // Listen to all users instead of only the current one.
+        wallpaperManager.removeOnColorsChangedListener(this);
+        wallpaperManager.addOnColorsChangedListener(this, null /* handler */,
+                UserHandle.USER_ALL);
     }
 
     @Override
     protected void extractWallpaperColors() {
         super.extractWallpaperColors();
         // mTonal is final but this method will be invoked by the base class during its ctor.
-        if (mTonal == null) {
+        if (mTonal == null || mNeutralColorsLock == null) {
             return;
         }
         mTonal.applyFallback(mLockColors == null ? mSystemColors : mLockColors, mNeutralColorsLock);
diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeAuthRemover.java b/packages/SystemUI/src/com/android/systemui/doze/DozeAuthRemover.java
new file mode 100644
index 0000000..e6a9e47
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/doze/DozeAuthRemover.java
@@ -0,0 +1,43 @@
+/*
+ * 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.systemui.doze;
+
+import android.content.Context;
+
+import com.android.keyguard.KeyguardUpdateMonitor;
+
+/**
+ * Controls removing Keyguard authorization when the phone goes to sleep.
+ */
+public class DozeAuthRemover implements DozeMachine.Part {
+
+    KeyguardUpdateMonitor mKeyguardUpdateMonitor;
+
+    public DozeAuthRemover(Context context) {
+        mKeyguardUpdateMonitor = KeyguardUpdateMonitor.getInstance(context);
+    }
+
+    @Override
+    public void transitionTo(DozeMachine.State oldState, DozeMachine.State newState) {
+        if (newState == DozeMachine.State.DOZE || newState == DozeMachine.State.DOZE_AOD) {
+            int currentUser = KeyguardUpdateMonitor.getCurrentUser();
+            if (mKeyguardUpdateMonitor.getUserUnlockedWithBiometric(currentUser)) {
+                mKeyguardUpdateMonitor.clearBiometricRecognized();
+            }
+        }
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeDockHandler.java b/packages/SystemUI/src/com/android/systemui/doze/DozeDockHandler.java
index 3c6dc73..1d7e9ea 100644
--- a/packages/SystemUI/src/com/android/systemui/doze/DozeDockHandler.java
+++ b/packages/SystemUI/src/com/android/systemui/doze/DozeDockHandler.java
@@ -43,6 +43,7 @@
     private final DockManager mDockManager;
 
     private int mDockState = DockManager.STATE_NONE;
+    private boolean mPulsePending;
 
     public DozeDockHandler(Context context, DozeMachine machine, DozeHost dozeHost,
             AmbientDisplayConfiguration config, Handler handler, DockManager dockManager) {
@@ -66,7 +67,8 @@
                 }
                 // continue below
             case DOZE:
-                if (mDockState == DockManager.STATE_DOCKED) {
+                if (mDockState == DockManager.STATE_DOCKED && !mPulsePending) {
+                    mPulsePending = true;
                     mHandler.post(() -> requestPulse(newState));
                 }
                 break;
@@ -79,11 +81,10 @@
     }
 
     private void requestPulse(State dozeState) {
-        if (mDozeHost.isPulsingBlocked() || !dozeState.canPulse()) {
-            return;
+        if (!mDozeHost.isPulsingBlocked() && dozeState.canPulse()) {
+            mMachine.requestPulse(DozeLog.PULSE_REASON_DOCKING);
         }
-
-        mMachine.requestPulse(DozeLog.PULSE_REASON_DOCKING);
+        mPulsePending = false;
     }
 
     private void requestPulseOutNow(State dozeState) {
diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeFactory.java b/packages/SystemUI/src/com/android/systemui/doze/DozeFactory.java
index 9c2adb3..d22d2c3 100644
--- a/packages/SystemUI/src/com/android/systemui/doze/DozeFactory.java
+++ b/packages/SystemUI/src/com/android/systemui/doze/DozeFactory.java
@@ -72,7 +72,8 @@
                 createDozeScreenBrightness(context, wrappedService, sensorManager, host, params,
                         handler),
                 new DozeWallpaperState(context, getBiometricUnlockController(dozeService)),
-                new DozeDockHandler(context, machine, host, config, handler, dockManager)
+                new DozeDockHandler(context, machine, host, config, handler, dockManager),
+                new DozeAuthRemover(dozeService)
         });
 
         return machine;
diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeHost.java b/packages/SystemUI/src/com/android/systemui/doze/DozeHost.java
index 3c9d4a9..07dd2cd 100644
--- a/packages/SystemUI/src/com/android/systemui/doze/DozeHost.java
+++ b/packages/SystemUI/src/com/android/systemui/doze/DozeHost.java
@@ -50,9 +50,23 @@
      */
     void onSlpiTap(float x, float y);
 
+    /**
+     * Artificially dim down the the display by changing scrim opacities.
+     * @param scrimOpacity opacity from 0 to 1.
+     */
     default void setAodDimmingScrim(float scrimOpacity) {}
+
+    /**
+     * Sets the actual display brightness.
+     * @param value from 0 to 255.
+     */
     void setDozeScreenBrightness(int value);
 
+    /**
+     * Makes scrims black and changes animation durations.
+     */
+    default void prepareForGentleWakeUp() {}
+
     void onIgnoreTouchWhilePulsing(boolean ignore);
 
     /**
@@ -63,8 +77,10 @@
     interface Callback {
         /**
          * Called when a high priority notification is added.
+         * @param onPulseSuppressedListener A listener that is invoked if the pulse is being
+         *                                  supressed.
          */
-        default void onNotificationAlerted() {}
+        default void onNotificationAlerted(Runnable onPulseSuppressedListener) {}
 
         /**
          * Called when battery state or power save mode changes.
diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeLog.java b/packages/SystemUI/src/com/android/systemui/doze/DozeLog.java
index 9bca3c7..c09e284 100644
--- a/packages/SystemUI/src/com/android/systemui/doze/DozeLog.java
+++ b/packages/SystemUI/src/com/android/systemui/doze/DozeLog.java
@@ -261,6 +261,12 @@
                 + state + " blocked=" + blocked);
     }
 
+    public static void tracePulseDropped(Context context, String why) {
+        if (!ENABLED) return;
+        init(context);
+        log("pulseDropped why=" + why);
+    }
+
     public static void tracePulseTouchDisabledByProx(Context context, boolean disabled) {
         if (!ENABLED) return;
         init(context);
diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeScreenState.java b/packages/SystemUI/src/com/android/systemui/doze/DozeScreenState.java
index 368451a..38ee2fe 100644
--- a/packages/SystemUI/src/com/android/systemui/doze/DozeScreenState.java
+++ b/packages/SystemUI/src/com/android/systemui/doze/DozeScreenState.java
@@ -36,13 +36,13 @@
      * Delay entering low power mode when animating to make sure that we'll have
      * time to move all elements into their final positions while still at 60 fps.
      */
-    private static final int ENTER_DOZE_DELAY = 6000;
+    private static final int ENTER_DOZE_DELAY = 4000;
     /**
      * Hide wallpaper earlier when entering low power mode. The gap between
      * hiding the wallpaper and changing the display mode is necessary to hide
      * the black frame that's inherent to hardware specs.
      */
-    public static final int ENTER_DOZE_HIDE_WALLPAPER_DELAY = 4500;
+    public static final int ENTER_DOZE_HIDE_WALLPAPER_DELAY = 2500;
 
     private final DozeMachine.Service mDozeService;
     private final Handler mHandler;
@@ -82,7 +82,10 @@
         boolean messagePending = mHandler.hasCallbacks(mApplyPendingScreenState);
         boolean pulseEnding = oldState  == DozeMachine.State.DOZE_PULSE_DONE
                 && newState == DozeMachine.State.DOZE_AOD;
-        if (messagePending || oldState == DozeMachine.State.INITIALIZED || pulseEnding) {
+        boolean turningOn = (oldState == DozeMachine.State.DOZE_AOD_PAUSED
+                || oldState  == DozeMachine.State.DOZE) && newState == DozeMachine.State.DOZE_AOD;
+        boolean justInitialized = oldState == DozeMachine.State.INITIALIZED;
+        if (messagePending || justInitialized || pulseEnding || turningOn) {
             // During initialization, we hide the navigation bar. That is however only applied after
             // a traversal; setting the screen state here is immediate however, so it can happen
             // that the screen turns on again before the navigation bar is hidden. To work around
@@ -91,7 +94,7 @@
 
             // Delay screen state transitions even longer while animations are running.
             boolean shouldDelayTransition = newState == DozeMachine.State.DOZE_AOD
-                    && mParameters.shouldControlScreenOff();
+                    && mParameters.shouldControlScreenOff() && !turningOn;
 
             if (shouldDelayTransition) {
                 mWakeLock.setAcquired(true);
diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeSensors.java b/packages/SystemUI/src/com/android/systemui/doze/DozeSensors.java
index a882309..092eb46 100644
--- a/packages/SystemUI/src/com/android/systemui/doze/DozeSensors.java
+++ b/packages/SystemUI/src/com/android/systemui/doze/DozeSensors.java
@@ -77,6 +77,8 @@
     private final ProxSensor mProxSensor;
     private long mDebounceFrom;
     private boolean mSettingRegistered;
+    private boolean mListening;
+    private boolean mPaused;
 
     public DozeSensors(Context context, AlarmManager alarmManager, SensorManager sensorManager,
             DozeParameters dozeParameters, AmbientDisplayConfiguration config, WakeLock wakeLock,
@@ -101,9 +103,12 @@
                 mPickupSensor = new TriggerSensor(
                         mSensorManager.getDefaultSensor(Sensor.TYPE_PICK_UP_GESTURE),
                         Settings.Secure.DOZE_PICK_UP_GESTURE,
+                        true /* settingDef */,
                         config.dozePickupSensorAvailable(),
                         DozeLog.REASON_SENSOR_PICKUP, false /* touchCoords */,
-                        false /* touchscreen */),
+                        false /* touchscreen */,
+                        false /* ignoresSetting */,
+                        mDozeParameters.getPickupPerformsProxCheck()),
                 new TriggerSensor(
                         findSensorWithType(config.doubleTapSensorType()),
                         Settings.Secure.DOZE_DOUBLE_TAP_GESTURE,
@@ -128,15 +133,15 @@
                         true /* touchscreen */),
                 new PluginSensor(
                         new SensorManagerPlugin.Sensor(TYPE_WAKE_DISPLAY),
-                        Settings.Secure.DOZE_WAKE_SCREEN_GESTURE,
+                        Settings.Secure.DOZE_WAKE_DISPLAY_GESTURE,
                         mConfig.wakeScreenGestureAvailable() && alwaysOn,
                         DozeLog.REASON_SENSOR_WAKE_UP,
                         false /* reports touch coordinates */,
                         false /* touchscreen */),
                 new PluginSensor(
                         new SensorManagerPlugin.Sensor(TYPE_WAKE_LOCK_SCREEN),
-                        Settings.Secure.DOZE_WAKE_SCREEN_GESTURE,
-                        mConfig.wakeScreenGestureAvailable() && alwaysOn,
+                        Settings.Secure.DOZE_WAKE_LOCK_SCREEN_GESTURE,
+                        mConfig.wakeScreenGestureAvailable(),
                         DozeLog.PULSE_REASON_SENSOR_WAKE_LOCK_SCREEN,
                         false /* reports touch coordinates */,
                         false /* touchscreen */, mConfig.getWakeLockScreenDebounce()),
@@ -171,11 +176,52 @@
         return null;
     }
 
+    /**
+     * If sensors should be registered and sending signals.
+     */
     public void setListening(boolean listen) {
-        for (TriggerSensor s : mSensors) {
-            s.setListening(listen);
+        if (mListening == listen) {
+            return;
         }
-        registerSettingsObserverIfNeeded(listen);
+        mListening = listen;
+        updateListening();
+    }
+
+    /**
+     * Unregister sensors, when listening, unless they are prox gated.
+     * @see #setListening(boolean)
+     */
+    public void setPaused(boolean paused) {
+        if (mPaused == paused) {
+            return;
+        }
+        mPaused = paused;
+        updateListening();
+    }
+
+    /**
+     * Registers/unregisters sensors based on internal state.
+     */
+    public void updateListening() {
+        boolean anyListening = false;
+        for (TriggerSensor s : mSensors) {
+            // We don't want to be listening while we're PAUSED (prox sensor is covered)
+            // except when the sensor is already gated by prox.
+            boolean listen = mListening && (!mPaused || s.performsProxCheck());
+            s.setListening(listen);
+            if (listen) {
+                anyListening = true;
+            }
+        }
+
+        if (!anyListening) {
+            mResolver.unregisterContentObserver(mSettingsObserver);
+        } else if (!mSettingRegistered) {
+            for (TriggerSensor s : mSensors) {
+                s.registerSettingsObserver(mSettingsObserver);
+            }
+        }
+        mSettingRegistered = anyListening;
     }
 
     /** Set the listening state of only the sensors that require the touchscreen. */
@@ -189,7 +235,7 @@
 
     public void onUserSwitched() {
         for (TriggerSensor s : mSensors) {
-            s.updateListener();
+            s.updateListening();
         }
     }
 
@@ -204,7 +250,7 @@
                 return;
             }
             for (TriggerSensor s : mSensors) {
-                s.updateListener();
+                s.updateListening();
             }
         }
     };
@@ -237,17 +283,6 @@
         return mProxSensor.mCurrentlyFar;
     }
 
-    private void registerSettingsObserverIfNeeded(boolean register) {
-        if (!register) {
-            mResolver.unregisterContentObserver(mSettingsObserver);
-        } else if (!mSettingRegistered) {
-            for (TriggerSensor s : mSensors) {
-                s.registerSettingsObserver(mSettingsObserver);
-            }
-        }
-        mSettingRegistered = register;
-    }
-
     private class ProxSensor implements SensorEventListener {
 
         boolean mRequested;
@@ -257,6 +292,7 @@
         final AlarmTimeout mCooldownTimer;
         final AlwaysOnDisplayPolicy mPolicy;
         final Sensor mSensor;
+        final boolean mUsingBrightnessSensor;
 
         public ProxSensor(AlwaysOnDisplayPolicy policy) {
             mPolicy = policy;
@@ -267,6 +303,7 @@
             // if available.
             Sensor sensor = DozeSensors.findSensorWithType(mSensorManager,
                     mContext.getString(R.string.doze_brightness_sensor_type));
+            mUsingBrightnessSensor = sensor != null;
             if (sensor == null) {
                 sensor = mSensorManager.getDefaultSensor(Sensor.TYPE_PROXIMITY);
             }
@@ -296,8 +333,7 @@
                 return;
             }
             if (register) {
-                mRegistered = mSensorManager.registerListener(this,
-                        mSensorManager.getDefaultSensor(Sensor.TYPE_PROXIMITY),
+                mRegistered = mSensorManager.registerListener(this, mSensor,
                         SensorManager.SENSOR_DELAY_NORMAL, mHandler);
             } else {
                 mSensorManager.unregisterListener(this);
@@ -310,7 +346,13 @@
         public void onSensorChanged(android.hardware.SensorEvent event) {
             if (DEBUG) Log.d(TAG, "onSensorChanged " + event);
 
-            mCurrentlyFar = event.values[0] >= event.sensor.getMaximumRange();
+            if (mUsingBrightnessSensor) {
+                // The custom brightness sensor is gated by the proximity sensor and will return 0
+                // whenever prox is covered.
+                mCurrentlyFar = event.values[0] > 0;
+            } else {
+                mCurrentlyFar = event.values[0] >= event.sensor.getMaximumRange();
+            }
             mProxCallback.accept(mCurrentlyFar);
 
             long now = SystemClock.elapsedRealtime();
@@ -345,10 +387,11 @@
         final Sensor mSensor;
         final boolean mConfigured;
         final int mPulseReason;
-        final String mSetting;
-        final boolean mReportsTouchCoordinates;
-        final boolean mSettingDefault;
-        final boolean mRequiresTouchscreen;
+        private final String mSetting;
+        private final boolean mReportsTouchCoordinates;
+        private final boolean mSettingDefault;
+        private final boolean mRequiresTouchscreen;
+        private final boolean mSensorPerformsProxCheck;
 
         protected boolean mRequested;
         protected boolean mRegistered;
@@ -365,12 +408,14 @@
                 boolean configured, int pulseReason, boolean reportsTouchCoordinates,
                 boolean requiresTouchscreen) {
             this(sensor, setting, settingDef, configured, pulseReason, reportsTouchCoordinates,
-                    requiresTouchscreen, false /* ignoresSetting */);
+                    requiresTouchscreen, false /* ignoresSetting */,
+                    false /* sensorPerformsProxCheck */);
         }
 
         private TriggerSensor(Sensor sensor, String setting, boolean settingDef,
                 boolean configured, int pulseReason, boolean reportsTouchCoordinates,
-                boolean requiresTouchscreen, boolean ignoresSetting) {
+                boolean requiresTouchscreen, boolean ignoresSetting,
+                boolean sensorPerformsProxCheck) {
             mSensor = sensor;
             mSetting = setting;
             mSettingDefault = settingDef;
@@ -379,27 +424,28 @@
             mReportsTouchCoordinates = reportsTouchCoordinates;
             mRequiresTouchscreen = requiresTouchscreen;
             mIgnoresSetting = ignoresSetting;
+            mSensorPerformsProxCheck = sensorPerformsProxCheck;
         }
 
         public void setListening(boolean listen) {
             if (mRequested == listen) return;
             mRequested = listen;
-            updateListener();
+            updateListening();
         }
 
         public void setDisabled(boolean disabled) {
             if (mDisabled == disabled) return;
             mDisabled = disabled;
-            updateListener();
+            updateListening();
         }
 
         public void ignoreSetting(boolean ignored) {
             if (mIgnoresSetting == ignored) return;
             mIgnoresSetting = ignored;
-            updateListener();
+            updateListening();
         }
 
-        public void updateListener() {
+        public void updateListening() {
             if (!mConfigured || mSensor == null) return;
             if (mRequested && !mDisabled && (enabledBySetting() || mIgnoresSetting)
                     && !mRegistered) {
@@ -438,14 +484,11 @@
             DozeLog.traceSensor(mContext, mPulseReason);
             mHandler.post(mWakeLock.wrap(() -> {
                 if (DEBUG) Log.d(TAG, "onTrigger: " + triggerEventToString(event));
-                boolean sensorPerformsProxCheck = false;
                 if (mSensor != null && mSensor.getType() == Sensor.TYPE_PICK_UP_GESTURE) {
                     int subType = (int) event.values[0];
                     MetricsLogger.action(
                             mContext, MetricsProto.MetricsEvent.ACTION_AMBIENT_GESTURE,
                             subType);
-                    sensorPerformsProxCheck =
-                            mDozeParameters.getPickupSubtypePerformsProxCheck(subType);
                 }
 
                 mRegistered = false;
@@ -455,14 +498,23 @@
                     screenX = event.values[0];
                     screenY = event.values[1];
                 }
-                mCallback.onSensorPulse(mPulseReason, sensorPerformsProxCheck, screenX, screenY,
+                mCallback.onSensorPulse(mPulseReason, mSensorPerformsProxCheck, screenX, screenY,
                         event.values);
                 if (!mRegistered) {
-                    updateListener();  // reregister, this sensor only fires once
+                    updateListening();  // reregister, this sensor only fires once
                 }
             }));
         }
 
+        /**
+         * If the sensor itself performs proximity checks, to avoid pocket dialing.
+         * Gated sensors don't need to be stopped when the {@link DozeMachine} is
+         * {@link DozeMachine.State#DOZE_AOD_PAUSED}.
+         */
+        public boolean performsProxCheck() {
+            return mSensorPerformsProxCheck;
+        }
+
         public void registerSettingsObserver(ContentObserver settingsObserver) {
             if (mConfigured && !TextUtils.isEmpty(mSetting)) {
                 mResolver.registerContentObserver(
@@ -510,7 +562,7 @@
         }
 
         @Override
-        public void updateListener() {
+        public void updateListening() {
             if (!mConfigured) return;
             AsyncSensorManager asyncSensorManager = (AsyncSensorManager) mSensorManager;
             if (mRequested && !mDisabled && (enabledBySetting() || mIgnoresSetting)
@@ -554,7 +606,7 @@
             mHandler.post(mWakeLock.wrap(() -> {
                 final long now = SystemClock.uptimeMillis();
                 if (now < mDebounceFrom + mDebounce) {
-                    if (DEBUG) Log.d(TAG, "onSensorEvent dropped: " + triggerEventToString(event));
+                    Log.d(TAG, "onSensorEvent dropped: " + triggerEventToString(event));
                     return;
                 }
                 if (DEBUG) Log.d(TAG, "onSensorEvent: " + triggerEventToString(event));
diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeTriggers.java b/packages/SystemUI/src/com/android/systemui/doze/DozeTriggers.java
index a381e7b..310f04a 100644
--- a/packages/SystemUI/src/com/android/systemui/doze/DozeTriggers.java
+++ b/packages/SystemUI/src/com/android/systemui/doze/DozeTriggers.java
@@ -106,14 +106,33 @@
         mDockManager = dockManager;
     }
 
-    private void onNotification() {
-        if (DozeMachine.DEBUG) Log.d(TAG, "requestNotificationPulse");
+    private void onNotification(Runnable onPulseSuppressedListener) {
+        if (DozeMachine.DEBUG) {
+            Log.d(TAG, "requestNotificationPulse");
+        }
+        if (!sWakeDisplaySensorState) {
+            Log.d(TAG, "Wake display false. Pulse denied.");
+            runIfNotNull(onPulseSuppressedListener);
+            DozeLog.tracePulseDropped(mContext, "wakeDisplaySensor");
+            return;
+        }
         mNotificationPulseTime = SystemClock.elapsedRealtime();
-        if (!mConfig.pulseOnNotificationEnabled(UserHandle.USER_CURRENT)) return;
-        requestPulse(DozeLog.PULSE_REASON_NOTIFICATION, false /* performedProxCheck */);
+        if (!mConfig.pulseOnNotificationEnabled(UserHandle.USER_CURRENT)) {
+            runIfNotNull(onPulseSuppressedListener);
+            DozeLog.tracePulseDropped(mContext, "pulseOnNotificationsDisabled");
+            return;
+        }
+        requestPulse(DozeLog.PULSE_REASON_NOTIFICATION, false /* performedProxCheck */,
+                onPulseSuppressedListener);
         DozeLog.traceNotificationPulse(mContext);
     }
 
+    private static void runIfNotNull(Runnable runnable) {
+        if (runnable != null) {
+            runnable.run();
+        }
+    }
+
     private void proximityCheckThenCall(IntConsumer callback,
             boolean alreadyPerformedProxCheck,
             int reason) {
@@ -150,10 +169,11 @@
         if (isWakeDisplay) {
             onWakeScreen(wakeEvent, mMachine.isExecutingTransition() ? null : mMachine.getState());
         } else if (isLongPress) {
-            requestPulse(pulseReason, sensorPerformedProxCheck);
+            requestPulse(pulseReason, sensorPerformedProxCheck, null /* onPulseSupressedListener */);
         } else if (isWakeLockScreen) {
             if (wakeEvent) {
-                requestPulse(pulseReason, sensorPerformedProxCheck);
+                requestPulse(pulseReason, sensorPerformedProxCheck,
+                        null /* onPulseSupressedListener */);
             }
         } else {
             proximityCheckThenCall((result) -> {
@@ -193,7 +213,7 @@
             // Let's prepare the display to wake-up by drawing black.
             // This will cover the hardware wake-up sequence, where the display
             // becomes black for a few frames.
-            mDozeHost.setAodDimmingScrim(255f);
+            mDozeHost.setAodDimmingScrim(1f);
         }
         mMachine.wakeUp();
     }
@@ -216,15 +236,21 @@
         if (state == DozeMachine.State.DOZE_PULSING
                 || state == DozeMachine.State.DOZE_PULSING_BRIGHT) {
             boolean ignoreTouch = near;
-            if (DEBUG) Log.i(TAG, "Prox changed, ignore touch = " + ignoreTouch);
+            if (DEBUG) {
+                Log.i(TAG, "Prox changed, ignore touch = " + ignoreTouch);
+            }
             mDozeHost.onIgnoreTouchWhilePulsing(ignoreTouch);
         }
 
         if (far && (paused || pausing)) {
-            if (DEBUG) Log.i(TAG, "Prox FAR, unpausing AOD");
+            if (DEBUG) {
+                Log.i(TAG, "Prox FAR, unpausing AOD");
+            }
             mMachine.requestState(DozeMachine.State.DOZE_AOD);
         } else if (near && aod) {
-            if (DEBUG) Log.i(TAG, "Prox NEAR, pausing AOD");
+            if (DEBUG) {
+                Log.i(TAG, "Prox NEAR, pausing AOD");
+            }
             mMachine.requestState(DozeMachine.State.DOZE_AOD_PAUSING);
         }
     }
@@ -282,6 +308,7 @@
             case DOZE_AOD:
                 mDozeSensors.setProxListening(newState != DozeMachine.State.DOZE);
                 mDozeSensors.setListening(true);
+                mDozeSensors.setPaused(false);
                 if (newState == DozeMachine.State.DOZE_AOD && !sWakeDisplaySensorState) {
                     onWakeScreen(false, newState);
                 }
@@ -289,15 +316,19 @@
             case DOZE_AOD_PAUSED:
             case DOZE_AOD_PAUSING:
                 mDozeSensors.setProxListening(true);
-                mDozeSensors.setListening(false);
+                mDozeSensors.setPaused(true);
                 break;
             case DOZE_PULSING:
             case DOZE_PULSING_BRIGHT:
                 mDozeSensors.setTouchscreenSensorsListening(false);
                 mDozeSensors.setProxListening(true);
+                mDozeSensors.setPaused(false);
                 break;
             case DOZE_PULSE_DONE:
                 mDozeSensors.requestTemporaryDisable();
+                // A pulse will temporarily disable sensors that require a touch screen.
+                // Let's make sure that they are re-enabled when the pulse is over.
+                mDozeSensors.updateListening();
                 break;
             case FINISH:
                 mBroadcastReceiver.unregister(mContext);
@@ -321,7 +352,8 @@
         }
     }
 
-    private void requestPulse(final int reason, boolean performedProxCheck) {
+    private void requestPulse(final int reason, boolean performedProxCheck,
+            Runnable onPulseSuppressedListener) {
         Assert.isMainThread();
         mDozeHost.extendPulse(reason);
 
@@ -338,6 +370,7 @@
                 DozeLog.tracePulseDropped(mContext, mPulsePending, mMachine.getState(),
                         mDozeHost.isPulsingBlocked());
             }
+            runIfNotNull(onPulseSuppressedListener);
             return;
         }
 
@@ -345,7 +378,9 @@
         proximityCheckThenCall((result) -> {
             if (result == ProximityCheck.RESULT_NEAR) {
                 // in pocket, abort pulse
+                DozeLog.tracePulseDropped(mContext, "inPocket");
                 mPulsePending = false;
+                runIfNotNull(onPulseSuppressedListener);
             } else {
                 // not in pocket, continue pulsing
                 continuePulseRequest(reason);
@@ -463,7 +498,8 @@
         public void onReceive(Context context, Intent intent) {
             if (PULSE_ACTION.equals(intent.getAction())) {
                 if (DozeMachine.DEBUG) Log.d(TAG, "Received pulse intent");
-                requestPulse(DozeLog.PULSE_REASON_INTENT, false /* performedProxCheck */);
+                requestPulse(DozeLog.PULSE_REASON_INTENT, false, /* performedProxCheck */
+                        null /* onPulseSupressedListener */);
             }
             if (UiModeManager.ACTION_ENTER_CAR_MODE.equals(intent.getAction())) {
                 mMachine.requestState(DozeMachine.State.FINISH);
@@ -513,8 +549,8 @@
 
     private DozeHost.Callback mHostCallback = new DozeHost.Callback() {
         @Override
-        public void onNotificationAlerted() {
-            onNotification();
+        public void onNotificationAlerted(Runnable onPulseSuppressedListener) {
+            onNotification(onPulseSuppressedListener);
         }
 
         @Override
diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeUi.java b/packages/SystemUI/src/com/android/systemui/doze/DozeUi.java
index 51e96d2..1f33af8 100644
--- a/packages/SystemUI/src/com/android/systemui/doze/DozeUi.java
+++ b/packages/SystemUI/src/com/android/systemui/doze/DozeUi.java
@@ -16,6 +16,7 @@
 
 package com.android.systemui.doze;
 
+import static com.android.systemui.doze.DozeMachine.State.DOZE;
 import static com.android.systemui.doze.DozeMachine.State.DOZE_AOD_PAUSED;
 
 import android.app.AlarmManager;
@@ -116,7 +117,7 @@
     public void transitionTo(DozeMachine.State oldState, DozeMachine.State newState) {
         switch (newState) {
             case DOZE_AOD:
-                if (oldState == DOZE_AOD_PAUSED) {
+                if (oldState == DOZE_AOD_PAUSED || oldState == DOZE) {
                     // Whenever turning on the display, it's necessary to push a new frame.
                     // The display buffers will be empty and need to be filled.
                     mHost.dozeTimeTick();
@@ -130,6 +131,7 @@
                 break;
             case DOZE:
             case DOZE_AOD_PAUSED:
+                mHost.prepareForGentleWakeUp();
                 unscheduleTimeTick();
                 break;
             case DOZE_REQUEST_PULSE:
diff --git a/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialog.java b/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialog.java
index dc97754..0e4c155 100644
--- a/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialog.java
+++ b/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialog.java
@@ -95,6 +95,7 @@
 import com.android.systemui.plugins.GlobalActions.GlobalActionsManager;
 import com.android.systemui.plugins.GlobalActionsPanelPlugin;
 import com.android.systemui.statusbar.phone.ScrimController;
+import com.android.systemui.statusbar.phone.StatusBarWindowController;
 import com.android.systemui.statusbar.phone.UnlockMethodCache;
 import com.android.systemui.statusbar.policy.ConfigurationController;
 import com.android.systemui.util.EmergencyDialerConstants;
@@ -1515,6 +1516,8 @@
         private boolean mShowing;
         private float mScrimAlpha;
         private ResetOrientationData mResetOrientationData;
+        private boolean mHadTopUi;
+        private final StatusBarWindowController mStatusBarWindowController;
 
         ActionsDialog(Context context, MyAdapter adapter,
                 GlobalActionsPanelPlugin.PanelViewController plugin) {
@@ -1523,6 +1526,7 @@
             mAdapter = adapter;
             mColorExtractor = Dependency.get(SysuiColorExtractor.class);
             mStatusBarService = Dependency.get(IStatusBarService.class);
+            mStatusBarWindowController = Dependency.get(StatusBarWindowController.class);
 
             // Window initialization
             Window window = getWindow();
@@ -1698,6 +1702,8 @@
         public void show() {
             super.show();
             mShowing = true;
+            mHadTopUi = mStatusBarWindowController.getForceHasTopUi();
+            mStatusBarWindowController.setForceHasTopUi(true);
             mBackgroundDrawable.setAlpha(0);
             mGlobalActionsLayout.setTranslationX(mGlobalActionsLayout.getAnimationOffsetX());
             mGlobalActionsLayout.setTranslationY(mGlobalActionsLayout.getAnimationOffsetY());
@@ -1730,7 +1736,7 @@
                     .translationX(mGlobalActionsLayout.getAnimationOffsetX())
                     .translationY(mGlobalActionsLayout.getAnimationOffsetY())
                     .setDuration(300)
-                    .withEndAction(super::dismiss)
+                    .withEndAction(this::completeDismiss)
                     .setInterpolator(new LogAccelerateInterpolator())
                     .setUpdateListener(animation -> {
                         int alpha = (int) ((1f - (Float) animation.getAnimatedValue())
@@ -1743,10 +1749,15 @@
         }
 
         void dismissImmediately() {
-            super.dismiss();
             mShowing = false;
             dismissPanel();
             resetOrientation();
+            completeDismiss();
+        }
+
+        private void completeDismiss() {
+            mStatusBarWindowController.setForceHasTopUi(mHadTopUi);
+            super.dismiss();
         }
 
         private void dismissPanel() {
diff --git a/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsImpl.java b/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsImpl.java
index 4065d5b..1f3403b 100644
--- a/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsImpl.java
@@ -30,6 +30,7 @@
 import com.android.internal.R;
 import com.android.internal.colorextraction.ColorExtractor.GradientColors;
 import com.android.internal.colorextraction.drawable.ScrimDrawable;
+import com.android.keyguard.KeyguardUpdateMonitor;
 import com.android.settingslib.Utils;
 import com.android.systemui.Dependency;
 import com.android.systemui.SysUiServiceProvider;
@@ -81,6 +82,7 @@
         mGlobalActions.showDialog(mKeyguardMonitor.isShowing(),
                 mDeviceProvisionedController.isDeviceProvisioned(),
                 mPanelExtension.get());
+        KeyguardUpdateMonitor.getInstance(mContext).requestFaceAuth();
     }
 
     @Override
diff --git a/packages/SystemUI/src/com/android/systemui/glwallpaper/EglHelper.java b/packages/SystemUI/src/com/android/systemui/glwallpaper/EglHelper.java
index d7411260..aac721e 100644
--- a/packages/SystemUI/src/com/android/systemui/glwallpaper/EglHelper.java
+++ b/packages/SystemUI/src/com/android/systemui/glwallpaper/EglHelper.java
@@ -146,7 +146,13 @@
      * @return true if EglSurface is ready.
      */
     public boolean createEglSurface(SurfaceHolder surfaceHolder) {
-        mEglSurface = eglCreateWindowSurface(mEglDisplay, mEglConfig, surfaceHolder, null, 0);
+        if (hasEglDisplay()) {
+            mEglSurface = eglCreateWindowSurface(mEglDisplay, mEglConfig, surfaceHolder, null, 0);
+        } else {
+            Log.w(TAG, "mEglDisplay is null");
+            return false;
+        }
+
         if (mEglSurface == null || mEglSurface == EGL_NO_SURFACE) {
             Log.w(TAG, "createWindowSurface failed: " + GLUtils.getEGLErrorString(eglGetError()));
             return false;
@@ -186,7 +192,13 @@
     public boolean createEglContext() {
         int[] attrib_list = new int[] {EGL_CONTEXT_CLIENT_VERSION, 2,
                 EGL_CONTEXT_PRIORITY_LEVEL_IMG, EGL_CONTEXT_PRIORITY_LOW_IMG, EGL_NONE};
-        mEglContext = eglCreateContext(mEglDisplay, mEglConfig, EGL_NO_CONTEXT, attrib_list, 0);
+        if (hasEglDisplay()) {
+            mEglContext = eglCreateContext(mEglDisplay, mEglConfig, EGL_NO_CONTEXT, attrib_list, 0);
+        } else {
+            Log.w(TAG, "mEglDisplay is null");
+            return false;
+        }
+
         if (mEglContext == EGL_NO_CONTEXT) {
             Log.w(TAG, "eglCreateContext failed: " + GLUtils.getEGLErrorString(eglGetError()));
             return false;
@@ -213,6 +225,14 @@
     }
 
     /**
+     * Check if we have EglDisplay.
+     * @return true if EglDisplay is ready.
+     */
+    public boolean hasEglDisplay() {
+        return mEglDisplay != null;
+    }
+
+    /**
      * Swap buffer to display.
      * @return true if swap successfully.
      */
@@ -235,7 +255,9 @@
         if (hasEglContext()) {
             destroyEglContext();
         }
-        eglTerminate(mEglDisplay);
+        if (hasEglDisplay()) {
+            eglTerminate(mEglDisplay);
+        }
         mEglReady = false;
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardSliceProvider.java b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardSliceProvider.java
index 0687b7d..48f32cf 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardSliceProvider.java
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardSliceProvider.java
@@ -53,6 +53,8 @@
 import com.android.systemui.plugins.statusbar.StatusBarStateController;
 import com.android.systemui.statusbar.NotificationMediaManager;
 import com.android.systemui.statusbar.StatusBarState;
+import com.android.systemui.statusbar.phone.DozeParameters;
+import com.android.systemui.statusbar.phone.KeyguardBypassController;
 import com.android.systemui.statusbar.policy.NextAlarmController;
 import com.android.systemui.statusbar.policy.NextAlarmControllerImpl;
 import com.android.systemui.statusbar.policy.ZenModeController;
@@ -61,7 +63,6 @@
 import com.android.systemui.util.wakelock.WakeLock;
 
 import java.util.Date;
-import java.util.HashSet;
 import java.util.Locale;
 import java.util.TimeZone;
 import java.util.concurrent.TimeUnit;
@@ -103,8 +104,8 @@
     private final Date mCurrentTime = new Date();
     private final Handler mHandler;
     private final AlarmManager.OnAlarmListener mUpdateNextAlarm = this::updateNextAlarm;
-    private final HashSet<Integer> mMediaInvisibleStates;
     private final Object mMediaToken = new Object();
+    private DozeParameters mDozeParameters;
     @VisibleForTesting
     protected SettableWakeLock mMediaWakeLock;
     @VisibleForTesting
@@ -123,6 +124,7 @@
     private PendingIntent mPendingIntent;
     protected NotificationMediaManager mMediaManager;
     private StatusBarStateController mStatusBarStateController;
+    private KeyguardBypassController mKeyguardBypassController;
     private CharSequence mMediaTitle;
     private CharSequence mMediaArtist;
     protected boolean mDozing;
@@ -184,11 +186,6 @@
         mAlarmUri = Uri.parse(KEYGUARD_NEXT_ALARM_URI);
         mDndUri = Uri.parse(KEYGUARD_DND_URI);
         mMediaUri = Uri.parse(KEYGUARD_MEDIA_URI);
-
-        mMediaInvisibleStates = new HashSet<>();
-        mMediaInvisibleStates.add(PlaybackState.STATE_NONE);
-        mMediaInvisibleStates.add(PlaybackState.STATE_STOPPED);
-        mMediaInvisibleStates.add(PlaybackState.STATE_PAUSED);
     }
 
     /**
@@ -200,11 +197,15 @@
      */
     public void initDependencies(
             NotificationMediaManager mediaManager,
-            StatusBarStateController statusBarStateController) {
+            StatusBarStateController statusBarStateController,
+            KeyguardBypassController keyguardBypassController,
+            DozeParameters dozeParameters) {
         mMediaManager = mediaManager;
         mMediaManager.addCallback(this);
         mStatusBarStateController = statusBarStateController;
         mStatusBarStateController.addCallback(this);
+        mKeyguardBypassController = keyguardBypassController;
+        mDozeParameters = dozeParameters;
     }
 
     @AnyThread
@@ -229,10 +230,13 @@
     }
 
     protected boolean needsMediaLocked() {
+        boolean keepWhenAwake = mKeyguardBypassController != null
+                && mKeyguardBypassController.getBypassEnabled() && mDozeParameters.getAlwaysOn();
         // Show header if music is playing and the status bar is in the shade state. This way, an
         // animation isn't necessary when pressing power and transitioning to AOD.
         boolean keepWhenShade = mStatusBarState == StatusBarState.SHADE && mMediaIsVisible;
-        return !TextUtils.isEmpty(mMediaTitle) && mMediaIsVisible && (mDozing || keepWhenShade);
+        return !TextUtils.isEmpty(mMediaTitle) && mMediaIsVisible && (mDozing || keepWhenAwake
+                || keepWhenShade);
     }
 
     protected void addMediaLocked(ListBuilder listBuilder) {
@@ -457,7 +461,7 @@
     @Override
     public void onMetadataOrStateChanged(MediaMetadata metadata, @PlaybackState.State int state) {
         synchronized (this) {
-            boolean nextVisible = !mMediaInvisibleStates.contains(state);
+            boolean nextVisible = NotificationMediaManager.isPlayingState(state);
             mHandler.removeCallbacksAndMessages(mMediaToken);
             if (mMediaIsVisible && !nextVisible && mStatusBarState != StatusBarState.SHADE) {
                 // We need to delay this event for a few millis when stopping to avoid jank in the
@@ -476,7 +480,7 @@
     }
 
     private void updateMediaStateLocked(MediaMetadata metadata, @PlaybackState.State int state) {
-        boolean nextVisible = !mMediaInvisibleStates.contains(state);
+        boolean nextVisible = NotificationMediaManager.isPlayingState(state);
         CharSequence title = null;
         if (metadata != null) {
             title = metadata.getText(MediaMetadata.METADATA_KEY_TITLE);
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
index 9616f0a..e9f99ac 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
@@ -61,6 +61,7 @@
 import android.util.Log;
 import android.util.Slog;
 import android.util.SparseArray;
+import android.view.View;
 import android.view.ViewGroup;
 import android.view.WindowManagerPolicyConstants;
 import android.view.animation.Animation;
@@ -85,9 +86,11 @@
 import com.android.systemui.UiOffloadThread;
 import com.android.systemui.classifier.FalsingManagerFactory;
 import com.android.systemui.statusbar.phone.BiometricUnlockController;
+import com.android.systemui.statusbar.phone.KeyguardBypassController;
 import com.android.systemui.statusbar.phone.NotificationPanelView;
 import com.android.systemui.statusbar.phone.StatusBar;
 import com.android.systemui.statusbar.phone.StatusBarKeyguardViewManager;
+import com.android.systemui.statusbar.phone.StatusBarWindowController;
 import com.android.systemui.util.InjectionInflationController;
 
 import java.io.FileDescriptor;
@@ -174,7 +177,7 @@
     /**
      * The default amount of time we stay awake (used for all key input)
      */
-    public static final int AWAKE_INTERVAL_DEFAULT_MS = 10000;
+    public static final int AWAKE_INTERVAL_BOUNCER_MS = 10000;
 
     /**
      * How long to wait after the screen turns off due to timeout before
@@ -202,12 +205,15 @@
     private AlarmManager mAlarmManager;
     private AudioManager mAudioManager;
     private StatusBarManager mStatusBarManager;
+    private final StatusBarWindowController mStatusBarWindowController =
+            Dependency.get(StatusBarWindowController.class);
     private final UiOffloadThread mUiOffloadThread = Dependency.get(UiOffloadThread.class);
 
     private boolean mSystemReady;
     private boolean mBootCompleted;
     private boolean mBootSendUserPresent;
     private boolean mShuttingDown;
+    private boolean mDozing;
 
     /** High level access to the power manager for WakeLocks */
     private PowerManager mPM;
@@ -711,11 +717,10 @@
                 com.android.keyguard.R.bool.config_enableKeyguardService)) {
             setShowingLocked(!shouldWaitForProvisioning()
                     && !mLockPatternUtils.isLockScreenDisabled(
-                            KeyguardUpdateMonitor.getCurrentUser()),
-                    mAodShowing, true /* forceCallbacks */);
+                            KeyguardUpdateMonitor.getCurrentUser()), true /* forceCallbacks */);
         } else {
             // The system's keyguard is disabled or missing.
-            setShowingLocked(false, mAodShowing, true);
+            setShowingLocked(false /* showing */, true /* forceCallbacks */);
         }
 
         mStatusBarKeyguardViewManager =
@@ -1324,7 +1329,7 @@
             if (mLockPatternUtils.checkVoldPassword(KeyguardUpdateMonitor.getCurrentUser())) {
                 if (DEBUG) Log.d(TAG, "Not showing lock screen since just decrypted");
                 // Without this, settings is not enabled until the lock screen first appears
-                setShowingLocked(false, mAodShowing);
+                setShowingLocked(false);
                 hideLocked();
                 return;
             }
@@ -1740,6 +1745,9 @@
 
     private void updateActivityLockScreenState(boolean showing, boolean aodShowing) {
         mUiOffloadThread.submit(() -> {
+            if (DEBUG) {
+                Log.d(TAG, "updateActivityLockScreenState(" + showing + ", " + aodShowing + ")");
+            }
             try {
                 ActivityTaskManager.getService().setLockScreenShown(showing, aodShowing);
             } catch (RemoteException e) {
@@ -1765,15 +1773,16 @@
                 if (DEBUG) Log.d(TAG, "handleShow");
             }
 
-            setShowingLocked(true, mAodShowing);
-            mStatusBarKeyguardViewManager.show(options);
             mHiding = false;
             mWakeAndUnlocking = false;
+            setShowingLocked(true);
+            mStatusBarKeyguardViewManager.show(options);
             resetKeyguardDonePendingLocked();
             mHideAnimationRun = false;
             adjustStatusBarLocked();
             userActivity();
             mUpdateMonitor.setKeyguardGoingAway(false /* away */);
+            mStatusBarWindowController.setKeyguardGoingAway(false /* goingAway */);
             mShowKeyguardWakeLock.release();
         }
         mKeyguardDisplayManager.show();
@@ -1800,8 +1809,13 @@
             if (mStatusBarKeyguardViewManager.isUnlockWithWallpaper()) {
                 flags |= WindowManagerPolicyConstants.KEYGUARD_GOING_AWAY_FLAG_WITH_WALLPAPER;
             }
+            if (mStatusBarKeyguardViewManager.shouldSubtleWindowAnimationsForUnlock()) {
+                flags |= WindowManagerPolicyConstants
+                        .KEYGUARD_GOING_AWAY_FLAG_SUBTLE_WINDOW_ANIMATIONS;
+            }
 
             mUpdateMonitor.setKeyguardGoingAway(true /* goingAway */);
+            mStatusBarWindowController.setKeyguardGoingAway(true /* goingAway */);
 
             // Don't actually hide the Keyguard at the moment, wait for window
             // manager until it tells us it's safe to do so with
@@ -1871,7 +1885,7 @@
 
             if (!mHiding) {
                 // Tell ActivityManager that we canceled the keyguardExitAnimation.
-                setShowingLocked(mShowing, mAodShowing, true /* force */);
+                setShowingLocked(mShowing, true /* force */);
                 return;
             }
             mHiding = false;
@@ -1892,8 +1906,8 @@
                 playSounds(false);
             }
 
+            setShowingLocked(false);
             mWakeAndUnlocking = false;
-            setShowingLocked(false, mAodShowing);
             mDismissCallbackRegistry.notifyDismissSucceeded();
             mStatusBarKeyguardViewManager.hide(startTime, fadeoutDuration);
             resetKeyguardDonePendingLocked();
@@ -1953,7 +1967,7 @@
         Trace.beginSection("KeyguardViewMediator#handleVerifyUnlock");
         synchronized (KeyguardViewMediator.this) {
             if (DEBUG) Log.d(TAG, "handleVerifyUnlock");
-            setShowingLocked(true, mAodShowing);
+            setShowingLocked(true);
             mStatusBarKeyguardViewManager.dismissAndCollapse();
         }
         Trace.endSection();
@@ -2056,9 +2070,11 @@
 
     public StatusBarKeyguardViewManager registerStatusBar(StatusBar statusBar,
             ViewGroup container, NotificationPanelView panelView,
-            BiometricUnlockController biometricUnlockController, ViewGroup lockIconContainer) {
+            BiometricUnlockController biometricUnlockController, ViewGroup lockIconContainer,
+            View notificationContainer, KeyguardBypassController bypassController) {
         mStatusBarKeyguardViewManager.registerStatusBar(statusBar, container, panelView,
-                biometricUnlockController, mDismissCallbackRegistry, lockIconContainer);
+                biometricUnlockController, mDismissCallbackRegistry, lockIconContainer,
+                notificationContainer, bypassController);
         return mStatusBarKeyguardViewManager;
     }
 
@@ -2098,6 +2114,8 @@
         pw.print("  mDeviceInteractive: "); pw.println(mDeviceInteractive);
         pw.print("  mGoingToSleep: "); pw.println(mGoingToSleep);
         pw.print("  mHiding: "); pw.println(mHiding);
+        pw.print("  mDozing: "); pw.println(mDozing);
+        pw.print("  mAodShowing: "); pw.println(mAodShowing);
         pw.print("  mWaitingUntilKeyguardVisible: "); pw.println(mWaitingUntilKeyguardVisible);
         pw.print("  mKeyguardDonePending: "); pw.println(mKeyguardDonePending);
         pw.print("  mHideAnimationRun: "); pw.println(mHideAnimationRun);
@@ -2108,10 +2126,14 @@
     }
 
     /**
-     * @param aodShowing true when AOD - or ambient mode - is showing.
+     * @param dozing true when AOD - or ambient mode - is showing.
      */
-    public void setAodShowing(boolean aodShowing) {
-        setShowingLocked(mShowing, aodShowing);
+    public void setDozing(boolean dozing) {
+        if (dozing == mDozing) {
+            return;
+        }
+        mDozing = dozing;
+        setShowingLocked(mShowing);
     }
 
     /**
@@ -2132,19 +2154,18 @@
         }
     }
 
-    private void setShowingLocked(boolean showing, boolean aodShowing) {
-        setShowingLocked(showing, aodShowing, false /* forceCallbacks */);
+    private void setShowingLocked(boolean showing) {
+        setShowingLocked(showing, false /* forceCallbacks */);
     }
 
-    private void setShowingLocked(boolean showing, boolean aodShowing, boolean forceCallbacks) {
+    private void setShowingLocked(boolean showing, boolean forceCallbacks) {
+        final boolean aodShowing = mDozing && !mWakeAndUnlocking;
         final boolean notifyDefaultDisplayCallbacks = showing != mShowing
                 || aodShowing != mAodShowing || forceCallbacks;
+        mShowing = showing;
+        mAodShowing = aodShowing;
         if (notifyDefaultDisplayCallbacks) {
-            mShowing = showing;
-            mAodShowing = aodShowing;
-            if (notifyDefaultDisplayCallbacks) {
-                notifyDefaultDisplayCallbacks(showing);
-            }
+            notifyDefaultDisplayCallbacks(showing);
             updateActivityLockScreenState(showing, aodShowing);
         }
     }
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/qs/QSAnimator.java b/packages/SystemUI/src/com/android/systemui/qs/QSAnimator.java
index ec2feba8..41f66f7 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSAnimator.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSAnimator.java
@@ -73,6 +73,7 @@
     private int mNumQuickTiles;
     private float mLastPosition;
     private QSTileHost mHost;
+    private boolean mShowCollapsedOnKeyguard;
 
     public QSAnimator(QS qs, QuickQSPanel quickPanel, QSPanel panel) {
         mQs = qs;
@@ -98,12 +99,32 @@
 
     public void setOnKeyguard(boolean onKeyguard) {
         mOnKeyguard = onKeyguard;
-        mQuickQsPanel.setVisibility(mOnKeyguard ? View.INVISIBLE : View.VISIBLE);
+        updateQQSVisibility();
         if (mOnKeyguard) {
             clearAnimationState();
         }
     }
 
+
+    /**
+     * Sets whether or not the keyguard is currently being shown with a collapsed header.
+     */
+    void setShowCollapsedOnKeyguard(boolean showCollapsedOnKeyguard) {
+        mShowCollapsedOnKeyguard = showCollapsedOnKeyguard;
+        updateQQSVisibility();
+        setCurrentPosition();
+    }
+
+
+    private void setCurrentPosition() {
+        setPosition(mLastPosition);
+    }
+
+    private void updateQQSVisibility() {
+        mQuickQsPanel.setVisibility(mOnKeyguard
+                && !mShowCollapsedOnKeyguard ? View.INVISIBLE : View.VISIBLE);
+    }
+
     public void setHost(QSTileHost qsh) {
         mHost = qsh;
         qsh.addCallback(this);
@@ -322,7 +343,11 @@
     public void setPosition(float position) {
         if (mFirstPageAnimator == null) return;
         if (mOnKeyguard) {
-            return;
+            if (mShowCollapsedOnKeyguard) {
+                position = 0;
+            } else {
+                position = 1;
+            }
         }
         mLastPosition = position;
         if (mOnFirstPage && mAllowFancy) {
@@ -356,7 +381,7 @@
 
     @Override
     public void onAnimationStarted() {
-        mQuickQsPanel.setVisibility(mOnKeyguard ? View.INVISIBLE : View.VISIBLE);
+        updateQQSVisibility();
         if (mOnFirstPage) {
             final int N = mQuickQsViews.size();
             for (int i = 0; i < N; i++) {
@@ -410,7 +435,7 @@
         @Override
         public void run() {
             updateAnimators();
-            setPosition(mLastPosition);
+            setCurrentPosition();
         }
     };
 }
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSFragment.java b/packages/SystemUI/src/com/android/systemui/qs/QSFragment.java
index 087a826..0a3b43a 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSFragment.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSFragment.java
@@ -40,8 +40,10 @@
 import com.android.systemui.R.id;
 import com.android.systemui.SysUiServiceProvider;
 import com.android.systemui.plugins.qs.QS;
+import com.android.systemui.plugins.statusbar.StatusBarStateController;
 import com.android.systemui.qs.customize.QSCustomizer;
 import com.android.systemui.statusbar.CommandQueue;
+import com.android.systemui.statusbar.StatusBarState;
 import com.android.systemui.statusbar.notification.stack.StackStateAnimator;
 import com.android.systemui.statusbar.phone.NotificationsQuickSettingsContainer;
 import com.android.systemui.statusbar.policy.RemoteInputQuickSettingsDisabler;
@@ -50,16 +52,17 @@
 
 import javax.inject.Inject;
 
-public class QSFragment extends LifecycleFragment implements QS, CommandQueue.Callbacks {
+public class QSFragment extends LifecycleFragment implements QS, CommandQueue.Callbacks,
+        StatusBarStateController.StateListener {
     private static final String TAG = "QS";
     private static final boolean DEBUG = false;
     private static final String EXTRA_EXPANDED = "expanded";
     private static final String EXTRA_LISTENING = "listening";
 
     private final Rect mQsBounds = new Rect();
+    private final StatusBarStateController mStatusBarStateController;
     private boolean mQsExpanded;
     private boolean mHeaderAnimating;
-    private boolean mKeyguardShowing;
     private boolean mStackScrollerOverscrolling;
 
     private long mDelay;
@@ -80,17 +83,27 @@
     private final RemoteInputQuickSettingsDisabler mRemoteInputQuickSettingsDisabler;
     private final InjectionInflationController mInjectionInflater;
     private final QSTileHost mHost;
+    private boolean mShowCollapsedOnKeyguard;
+    private boolean mLastKeyguardAndExpanded;
+    /**
+     * The last received state from the controller. This should not be used directly to check if
+     * we're on keyguard but use {@link #isKeyguardShowing()} instead since that is more accurate
+     * during state transitions which often call into us.
+     */
+    private int mState;
 
     @Inject
     public QSFragment(RemoteInputQuickSettingsDisabler remoteInputQsDisabler,
             InjectionInflationController injectionInflater,
             Context context,
-            QSTileHost qsTileHost) {
+            QSTileHost qsTileHost,
+            StatusBarStateController statusBarStateController) {
         mRemoteInputQuickSettingsDisabler = remoteInputQsDisabler;
         mInjectionInflater = injectionInflater;
         SysUiServiceProvider.getComponent(context, CommandQueue.class)
                 .observe(getLifecycle(), this);
         mHost = qsTileHost;
+        mStatusBarStateController = statusBarStateController;
     }
 
     @Override
@@ -126,11 +139,14 @@
             }
         }
         setHost(mHost);
+        mStatusBarStateController.addCallback(this);
+        onStateChanged(mStatusBarStateController.getState());
     }
 
     @Override
     public void onDestroy() {
         super.onDestroy();
+        mStatusBarStateController.removeCallback(this);
         if (mListening) {
             setListening(false);
         }
@@ -235,20 +251,43 @@
                 || mHeaderAnimating;
         mQSPanel.setExpanded(mQsExpanded);
         mQSDetail.setExpanded(mQsExpanded);
-        mHeader.setVisibility((mQsExpanded || !mKeyguardShowing || mHeaderAnimating)
+        boolean keyguardShowing = isKeyguardShowing();
+        mHeader.setVisibility((mQsExpanded || !keyguardShowing || mHeaderAnimating
+                || mShowCollapsedOnKeyguard)
                 ? View.VISIBLE
                 : View.INVISIBLE);
-        mHeader.setExpanded((mKeyguardShowing && !mHeaderAnimating)
+        mHeader.setExpanded((keyguardShowing && !mHeaderAnimating && !mShowCollapsedOnKeyguard)
                 || (mQsExpanded && !mStackScrollerOverscrolling));
         mFooter.setVisibility(
-                !mQsDisabled && (mQsExpanded || !mKeyguardShowing || mHeaderAnimating)
+                !mQsDisabled && (mQsExpanded || !keyguardShowing || mHeaderAnimating
+                        || mShowCollapsedOnKeyguard)
                 ? View.VISIBLE
                 : View.INVISIBLE);
-        mFooter.setExpanded((mKeyguardShowing && !mHeaderAnimating)
+        mFooter.setExpanded((keyguardShowing && !mHeaderAnimating && !mShowCollapsedOnKeyguard)
                 || (mQsExpanded && !mStackScrollerOverscrolling));
         mQSPanel.setVisibility(!mQsDisabled && expandVisually ? View.VISIBLE : View.INVISIBLE);
     }
 
+    private boolean isKeyguardShowing() {
+        // We want the freshest state here since otherwise we'll have some weirdness if earlier
+        // listeners trigger updates
+        return mStatusBarStateController.getState() == StatusBarState.KEYGUARD;
+    }
+
+    @Override
+    public void setShowCollapsedOnKeyguard(boolean showCollapsedOnKeyguard) {
+        if (showCollapsedOnKeyguard != mShowCollapsedOnKeyguard) {
+            mShowCollapsedOnKeyguard = showCollapsedOnKeyguard;
+            updateQsState();
+            if (mQSAnimator != null) {
+                mQSAnimator.setShowCollapsedOnKeyguard(showCollapsedOnKeyguard);
+            }
+            if (!showCollapsedOnKeyguard && isKeyguardShowing()) {
+                setQsExpansion(mLastQSExpansion, 0);
+            }
+        }
+    }
+
     public QSPanel getQsPanel() {
         return mQSPanel;
     }
@@ -280,10 +319,8 @@
         updateQsState();
     }
 
-    @Override
-    public void setKeyguardShowing(boolean keyguardShowing) {
+    private void setKeyguardShowing(boolean keyguardShowing) {
         if (DEBUG) Log.d(TAG, "setKeyguardShowing " + keyguardShowing);
-        mKeyguardShowing = keyguardShowing;
         mLastQSExpansion = -1;
 
         if (mQSAnimator != null) {
@@ -321,16 +358,18 @@
         if (DEBUG) Log.d(TAG, "setQSExpansion " + expansion + " " + headerTranslation);
         mContainer.setExpansion(expansion);
         final float translationScaleY = expansion - 1;
-        if (!mHeaderAnimating) {
+        boolean onKeyguardAndExpanded = isKeyguardShowing() && !mShowCollapsedOnKeyguard;
+        if (!mHeaderAnimating && !headerWillBeAnimating()) {
             getView().setTranslationY(
-                    mKeyguardShowing
+                    onKeyguardAndExpanded
                             ? translationScaleY * mHeader.getHeight()
                             : headerTranslation);
         }
-        if (expansion == mLastQSExpansion) {
+        if (expansion == mLastQSExpansion && mLastKeyguardAndExpanded == onKeyguardAndExpanded) {
             return;
         }
         mLastQSExpansion = expansion;
+        mLastKeyguardAndExpanded = onKeyguardAndExpanded;
 
         boolean fullyExpanded = expansion == 1;
         int heightDiff = mQSPanel.getBottom() - mHeader.getBottom() + mHeader.getPaddingBottom()
@@ -338,8 +377,9 @@
         float panelTranslationY = translationScaleY * heightDiff;
 
         // Let the views animate their contents correctly by giving them the necessary context.
-        mHeader.setExpansion(mKeyguardShowing, expansion, panelTranslationY);
-        mFooter.setExpansion(mKeyguardShowing ? 1 : expansion);
+        mHeader.setExpansion(onKeyguardAndExpanded, expansion,
+                panelTranslationY);
+        mFooter.setExpansion(onKeyguardAndExpanded ? 1 : expansion);
         mQSPanel.getQsTileRevealController().setExpansion(expansion);
         mQSPanel.getTileLayout().setExpansion(expansion);
         mQSPanel.setTranslationY(translationScaleY * heightDiff);
@@ -361,12 +401,17 @@
         }
     }
 
+    private boolean headerWillBeAnimating() {
+        return mState == StatusBarState.KEYGUARD && mShowCollapsedOnKeyguard
+                && !isKeyguardShowing();
+    }
+
     @Override
     public void animateHeaderSlidingIn(long delay) {
         if (DEBUG) Log.d(TAG, "animateHeaderSlidingIn");
         // If the QS is already expanded we don't need to slide in the header as it's already
         // visible.
-        if (!mQsExpanded) {
+        if (!mQsExpanded && getView().getTranslationY() != 0) {
             mHeaderAnimating = true;
             mDelay = delay;
             getView().getViewTreeObserver().addOnPreDrawListener(mStartHeaderSlidingIn);
@@ -376,6 +421,9 @@
     @Override
     public void animateHeaderSlidingOut() {
         if (DEBUG) Log.d(TAG, "animateHeaderSlidingOut");
+        if (getView().getY() == -mHeader.getHeight()) {
+            return;
+        }
         mHeaderAnimating = true;
         getView().animate().y(-mHeader.getHeight())
                 .setStartDelay(0)
@@ -463,7 +511,6 @@
                     .setInterpolator(Interpolators.FAST_OUT_SLOW_IN)
                     .setListener(mAnimateHeaderSlidingInListener)
                     .start();
-            getView().setY(-mHeader.getHeight());
             return true;
         }
     };
@@ -476,4 +523,10 @@
             updateQsState();
         }
     };
+
+    @Override
+    public void onStateChanged(int newState) {
+        mState = newState;
+        setKeyguardShowing(newState == StatusBarState.KEYGUARD);
+    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeader.java b/packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeader.java
index d59e251..a28b60d 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeader.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeader.java
@@ -348,19 +348,19 @@
     /**
      * Animates the inner contents based on the given expansion details.
      *
-     * @param isKeyguardShowing whether or not we're showing the keyguard (a.k.a. lockscreen)
+     * @param forceExpanded whether we should show the state expanded forcibly
      * @param expansionFraction how much the QS panel is expanded/pulled out (up to 1f)
      * @param panelTranslationY how much the panel has physically moved down vertically (required
      *                          for keyguard animations only)
      */
-    public void setExpansion(boolean isKeyguardShowing, float expansionFraction,
+    public void setExpansion(boolean forceExpanded, float expansionFraction,
                              float panelTranslationY) {
-        final float keyguardExpansionFraction = isKeyguardShowing ? 1f : expansionFraction;
+        final float keyguardExpansionFraction = forceExpanded ? 1f : expansionFraction;
         if (mStatusIconsAlphaAnimator != null) {
             mStatusIconsAlphaAnimator.setPosition(keyguardExpansionFraction);
         }
 
-        if (isKeyguardShowing) {
+        if (forceExpanded) {
             // If the keyguard is showing, we want to offset the text so that it comes in at the
             // same time as the panel as it slides down.
             mHeaderTextContainerView.setTranslationY(panelTranslationY);
diff --git a/packages/SystemUI/src/com/android/systemui/qs/customize/QSCustomizer.java b/packages/SystemUI/src/com/android/systemui/qs/customize/QSCustomizer.java
index c209b31..83b000d 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/customize/QSCustomizer.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/customize/QSCustomizer.java
@@ -296,10 +296,13 @@
         mY = y - containerLocation[1];
     }
 
-    private final Callback mKeyguardCallback = () -> {
-        if (!isAttachedToWindow()) return;
-        if (Dependency.get(KeyguardMonitor.class).isShowing() && !mOpening) {
-            hide();
+    private final Callback mKeyguardCallback = new Callback() {
+        @Override
+        public void onKeyguardShowingChanged() {
+            if (!isAttachedToWindow()) return;
+            if (Dependency.get(KeyguardMonitor.class).isShowing() && !mOpening) {
+                hide();
+            }
         }
     };
 
diff --git a/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java b/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java
index e5caf68..16f0b15 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java
@@ -119,7 +119,9 @@
     private boolean mIsEnabled;
     private int mCurrentBoundedUserId = -1;
     private float mNavBarButtonAlpha;
-    private MotionEvent mStatusBarGestureDownEvent;
+    private boolean mInputFocusTransferStarted;
+    private float mInputFocusTransferStartY;
+    private long mInputFocusTransferStartMillis;
     private float mWindowCornerRadius;
     private boolean mSupportsRoundedCornersOnWindows;
     private int mNavBarMode = NAV_BAR_MODE_3BUTTON;
@@ -164,6 +166,7 @@
             }
         }
 
+        // TODO: change the method signature to use (boolean inputFocusTransferStarted)
         @Override
         public void onStatusBarMotionEvent(MotionEvent event) {
             if (!verifyCaller("onStatusBarMotionEvent")) {
@@ -175,15 +178,19 @@
                 mHandler.post(()->{
                     StatusBar bar = SysUiServiceProvider.getComponent(mContext, StatusBar.class);
                     if (bar != null) {
-                        bar.dispatchNotificationsPanelTouchEvent(event);
 
                         int action = event.getActionMasked();
                         if (action == ACTION_DOWN) {
-                            mStatusBarGestureDownEvent = MotionEvent.obtain(event);
+                            mInputFocusTransferStarted = true;
+                            mInputFocusTransferStartY = event.getY();
+                            mInputFocusTransferStartMillis = event.getEventTime();
+                            bar.onInputFocusTransfer(mInputFocusTransferStarted, 0 /* velocity */);
                         }
                         if (action == ACTION_UP || action == ACTION_CANCEL) {
-                            mStatusBarGestureDownEvent.recycle();
-                            mStatusBarGestureDownEvent = null;
+                            mInputFocusTransferStarted = false;
+                            bar.onInputFocusTransfer(mInputFocusTransferStarted,
+                                    (event.getY() - mInputFocusTransferStartY)
+                                    / (event.getEventTime() - mInputFocusTransferStartMillis));
                         }
                         event.recycle();
                     }
@@ -539,7 +546,8 @@
             navBarFragment.updateSystemUiStateFlags(-1);
         }
         if (navBarView != null) {
-            navBarView.updateSystemUiStateFlags();
+            navBarView.updatePanelSystemUiStateFlags();
+            navBarView.updateDisabledSystemUiStateFlags();
         }
         if (mStatusBarWinController != null) {
             mStatusBarWinController.notifyStateChangedCallbacks();
@@ -590,14 +598,12 @@
     }
 
     public void cleanupAfterDeath() {
-        if (mStatusBarGestureDownEvent != null) {
+        if (mInputFocusTransferStarted) {
             mHandler.post(()-> {
                 StatusBar bar = SysUiServiceProvider.getComponent(mContext, StatusBar.class);
                 if (bar != null) {
-                    mStatusBarGestureDownEvent.setAction(MotionEvent.ACTION_CANCEL);
-                    bar.dispatchNotificationsPanelTouchEvent(mStatusBarGestureDownEvent);
-                    mStatusBarGestureDownEvent.recycle();
-                    mStatusBarGestureDownEvent = null;
+                    mInputFocusTransferStarted = false;
+                    bar.onInputFocusTransfer(false, 0 /* velocity */);
                 }
             });
         }
@@ -746,6 +752,8 @@
         try {
             if (mOverviewProxy != null) {
                 mOverviewProxy.onAssistantVisibilityChanged(visibility);
+            } else {
+                Log.e(TAG_OPS, "Failed to get overview proxy for assistant visibility.");
             }
         } catch (RemoteException e) {
             Log.e(TAG_OPS, "Failed to call onAssistantVisibilityChanged()", e);
@@ -780,6 +788,7 @@
         pw.println(QuickStepContract.isBackGestureDisabled(mSysUiStateFlags));
         pw.print("    assistantGestureDisabled=");
         pw.println(QuickStepContract.isAssistantGestureDisabled(mSysUiStateFlags));
+        pw.print(" mInputFocusTransferStarted="); pw.println(mInputFocusTransferStarted);
     }
 
     public interface OverviewProxyListener {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/AmbientPulseManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/AmbientPulseManager.java
deleted file mode 100644
index 5f878ce..0000000
--- a/packages/SystemUI/src/com/android/systemui/statusbar/AmbientPulseManager.java
+++ /dev/null
@@ -1,162 +0,0 @@
-/*
- * Copyright (C) 2018 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.systemui.statusbar;
-
-import static com.android.systemui.statusbar.notification.row.NotificationContentInflater.FLAG_CONTENT_VIEW_AMBIENT;
-
-import android.annotation.NonNull;
-import android.content.Context;
-import android.content.res.Resources;
-import android.util.ArraySet;
-
-import com.android.internal.annotations.VisibleForTesting;
-import com.android.systemui.R;
-import com.android.systemui.statusbar.notification.collection.NotificationEntry;
-import com.android.systemui.statusbar.notification.row.NotificationContentInflater.InflationFlag;
-
-import javax.inject.Inject;
-import javax.inject.Singleton;
-
-/**
- * Manager which handles high priority notifications that should "pulse" in when the device is
- * dozing and/or in AOD.  The pulse uses the notification's ambient view and pops in briefly
- * before automatically dismissing the alert.
- */
-@Singleton
-public class AmbientPulseManager extends AlertingNotificationManager {
-
-    protected final ArraySet<OnAmbientChangedListener> mListeners = new ArraySet<>();
-    @VisibleForTesting
-    protected long mExtensionTime;
-
-    @Inject
-    public AmbientPulseManager(@NonNull final Context context) {
-        Resources resources = context.getResources();
-        mAutoDismissNotificationDecay = resources.getInteger(R.integer.ambient_notification_decay);
-        mMinimumDisplayTime = resources.getInteger(R.integer.ambient_notification_minimum_time);
-        mExtensionTime = resources.getInteger(R.integer.ambient_notification_extension_time);
-    }
-
-    /**
-     * Adds an OnAmbientChangedListener to observe events.
-     */
-    public void addListener(@NonNull OnAmbientChangedListener listener) {
-        mListeners.add(listener);
-    }
-
-    /**
-     * Removes the OnAmbientChangedListener from the observer list.
-     */
-    public void removeListener(@NonNull OnAmbientChangedListener listener) {
-        mListeners.remove(listener);
-    }
-
-    /**
-     * Extends the lifetime of the currently showing pulsing notification so that the pulse lasts
-     * longer.
-     */
-    public void extendPulse() {
-        AmbientEntry topEntry = getTopEntry();
-        if (topEntry == null) {
-            return;
-        }
-        topEntry.extendPulse();
-    }
-
-    public @InflationFlag int getContentFlag() {
-        return FLAG_CONTENT_VIEW_AMBIENT;
-    }
-
-    @Override
-    protected void onAlertEntryAdded(AlertEntry alertEntry) {
-        NotificationEntry entry = alertEntry.mEntry;
-        entry.setAmbientPulsing(true);
-        for (OnAmbientChangedListener listener : mListeners) {
-            listener.onAmbientStateChanged(entry, true);
-        }
-    }
-
-    @Override
-    protected void onAlertEntryRemoved(AlertEntry alertEntry) {
-        NotificationEntry entry = alertEntry.mEntry;
-        entry.setAmbientPulsing(false);
-        for (OnAmbientChangedListener listener : mListeners) {
-            listener.onAmbientStateChanged(entry, false);
-        }
-        entry.freeContentViewWhenSafe(FLAG_CONTENT_VIEW_AMBIENT);
-    }
-
-    @Override
-    protected AlertEntry createAlertEntry() {
-        return new AmbientEntry();
-    }
-
-    /**
-     * Get the top pulsing entry.  This should be the currently showing one if there are multiple.
-     * @return the currently showing entry
-     */
-    private AmbientEntry getTopEntry() {
-        if (mAlertEntries.isEmpty()) {
-            return null;
-        }
-        AlertEntry topEntry = null;
-        for (AlertEntry entry : mAlertEntries.values()) {
-            if (topEntry == null || entry.compareTo(topEntry) < 0) {
-                topEntry = entry;
-            }
-        }
-        return (AmbientEntry) topEntry;
-    }
-
-    /**
-     * Observer interface for any changes in the ambient entries.
-     */
-    public interface OnAmbientChangedListener {
-        /**
-         * Called when an entry starts or stops pulsing.
-         * @param entry the entry that changed
-         * @param isPulsing true if the entry is now pulsing, false otherwise
-         */
-        void onAmbientStateChanged(@NonNull NotificationEntry entry, boolean isPulsing);
-    }
-
-    private final class AmbientEntry extends AlertEntry {
-        private boolean extended;
-
-        /**
-         * Extend the lifetime of the alertEntry so that it auto-removes later.  Can only be
-         * extended once.
-         */
-        private void extendPulse() {
-            if (!extended) {
-                extended = true;
-                updateEntry(false);
-            }
-        }
-
-        @Override
-        public void reset() {
-            super.reset();
-            extended = false;
-        }
-
-        @Override
-        protected long calculateFinishTime() {
-            return super.calculateFinishTime() + (extended ? mExtensionTime : 0);
-        }
-    }
-}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/CrossFadeHelper.java b/packages/SystemUI/src/com/android/systemui/statusbar/CrossFadeHelper.java
index 04534ba..164215b 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/CrossFadeHelper.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/CrossFadeHelper.java
@@ -28,6 +28,10 @@
 public class CrossFadeHelper {
     public static final long ANIMATION_DURATION_LENGTH = 210;
 
+    public static void fadeOut(final View view) {
+        fadeOut(view, null);
+    }
+
     public static void fadeOut(final View view, final Runnable endRunnable) {
         fadeOut(view, ANIMATION_DURATION_LENGTH, 0, endRunnable);
     }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/DragDownHelper.java b/packages/SystemUI/src/com/android/systemui/statusbar/DragDownHelper.java
index 514a2ae..8385c8e 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/DragDownHelper.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/DragDownHelper.java
@@ -92,7 +92,7 @@
                     mInitialTouchY = y;
                     mInitialTouchX = x;
                     mDragDownCallback.onTouchSlopExceeded();
-                    return true;
+                    return mStartingChild != null || mDragDownCallback.isDragDownAnywhereEnabled();
                 }
                 break;
         }
@@ -162,7 +162,11 @@
         if (mStartingChild == null) {
             mStartingChild = findView(x, y);
             if (mStartingChild != null) {
-                mCallback.setUserLockedChild(mStartingChild, true);
+                if (mDragDownCallback.isDragDownEnabledForView(mStartingChild)) {
+                    mCallback.setUserLockedChild(mStartingChild, true);
+                } else {
+                    mStartingChild = null;
+                }
             }
         }
     }
@@ -237,6 +241,10 @@
         return mDraggingDown;
     }
 
+    public boolean isDragDownEnabled() {
+        return mDragDownCallback.isDragDownEnabledForView(null);
+    }
+
     public interface DragDownCallback {
 
         /**
@@ -253,5 +261,16 @@
         void onTouchSlopExceeded();
         void setEmptyDragAmount(float amount);
         boolean isFalsingCheckNeeded();
+
+        /**
+         * Is dragging down enabled on a given view
+         * @param view The view to check or {@code null} to check if it's enabled at all
+         */
+        boolean isDragDownEnabledForView(ExpandableView view);
+
+        /**
+         * @return if drag down is enabled anywhere, not just on selected views.
+         */
+        boolean isDragDownAnywhereEnabled();
     }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/HeadsUpStatusBarView.java b/packages/SystemUI/src/com/android/systemui/statusbar/HeadsUpStatusBarView.java
index 3f1ff33..4597b16 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/HeadsUpStatusBarView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/HeadsUpStatusBarView.java
@@ -43,7 +43,6 @@
     private static final String HEADS_UP_STATUS_BAR_VIEW_SUPER_PARCELABLE =
             "heads_up_status_bar_view_super_parcelable";
     private static final String FIRST_LAYOUT = "first_layout";
-    private static final String PUBLIC_MODE = "public_mode";
     private static final String VISIBILITY = "visibility";
     private static final String ALPHA = "alpha";
     private int mAbsoluteStartPadding;
@@ -54,7 +53,6 @@
     private Rect mLayoutedIconRect = new Rect();
     private int[] mTmpPosition = new int[2];
     private boolean mFirstLayout = true;
-    private boolean mPublicMode;
     private int mMaxWidth;
     private View mRootView;
     private int mSysWinInset;
@@ -121,7 +119,6 @@
         bundle.putParcelable(HEADS_UP_STATUS_BAR_VIEW_SUPER_PARCELABLE,
                 super.onSaveInstanceState());
         bundle.putBoolean(FIRST_LAYOUT, mFirstLayout);
-        bundle.putBoolean(PUBLIC_MODE, mPublicMode);
         bundle.putInt(VISIBILITY, getVisibility());
         bundle.putFloat(ALPHA, getAlpha());
 
@@ -139,7 +136,6 @@
         Parcelable superState = bundle.getParcelable(HEADS_UP_STATUS_BAR_VIEW_SUPER_PARCELABLE);
         super.onRestoreInstanceState(superState);
         mFirstLayout = bundle.getBoolean(FIRST_LAYOUT, true);
-        mPublicMode = bundle.getBoolean(PUBLIC_MODE, false);
         if (bundle.containsKey(VISIBILITY)) {
             setVisibility(bundle.getInt(VISIBILITY));
         }
@@ -166,11 +162,13 @@
         if (entry != null) {
             mShowingEntry = entry;
             CharSequence text = entry.headsUpStatusBarText;
-            if (mPublicMode) {
+            if (entry.isSensitive()) {
                 text = entry.headsUpStatusBarTextPublic;
             }
             mTextView.setText(text);
-        } else {
+            mShowingEntry.setOnSensitiveChangedListener(() -> setEntry(entry));
+        } else if (mShowingEntry != null){
+            mShowingEntry.setOnSensitiveChangedListener(null);
             mShowingEntry = null;
         }
     }
@@ -273,10 +271,6 @@
         mTextView.setTextColor(DarkIconDispatcher.getTint(area, this, tint));
     }
 
-    public void setPublicMode(boolean publicMode) {
-        mPublicMode = publicMode;
-    }
-
     public void setOnDrawingRectChangedListener(Runnable onDrawingRectChangedListener) {
         mOnDrawingRectChangedListener = onDrawingRectChangedListener;
     }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java b/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java
index ca12deb..4be93df 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java
@@ -79,7 +79,9 @@
 
     private static final int MSG_HIDE_TRANSIENT = 1;
     private static final int MSG_CLEAR_BIOMETRIC_MSG = 2;
+    private static final int MSG_SWIPE_UP_TO_UNLOCK = 3;
     private static final long TRANSIENT_BIOMETRIC_ERROR_TIMEOUT = 1300;
+    private static final float BOUNCE_ANIMATION_FINAL_Y = 0f;
 
     private final Context mContext;
     private final ShadeController mShadeController;
@@ -326,6 +328,7 @@
         mTransientIndication = transientIndication;
         mTransientTextColorState = textColorState;
         mHandler.removeMessages(MSG_HIDE_TRANSIENT);
+        mHandler.removeMessages(MSG_SWIPE_UP_TO_UNLOCK);
         if (mDozing && !TextUtils.isEmpty(mTransientIndication)) {
             // Make sure this doesn't get stuck and burns in. Acquire wakelock until its cleared.
             mWakeLock.setAcquired(true);
@@ -420,7 +423,6 @@
         int animateDownDuration = mContext.getResources().getInteger(
                 R.integer.wired_charging_keyguard_text_animation_duration_down);
         textView.animate().cancel();
-        float translation = textView.getTranslationY();
         ViewClippingUtil.setClippingDeactivated(textView, true, mClippingParams);
         textView.animate()
                 .translationYBy(yTranslation)
@@ -436,7 +438,7 @@
 
                     @Override
                     public void onAnimationCancel(Animator animation) {
-                        textView.setTranslationY(translation);
+                        textView.setTranslationY(BOUNCE_ANIMATION_FINAL_Y);
                         mCancelled = true;
                     }
 
@@ -450,15 +452,11 @@
                         textView.animate()
                                 .setDuration(animateDownDuration)
                                 .setInterpolator(Interpolators.BOUNCE)
-                                .translationY(translation)
+                                .translationY(BOUNCE_ANIMATION_FINAL_Y)
                                 .setListener(new AnimatorListenerAdapter() {
                                     @Override
-                                    public void onAnimationCancel(Animator animation) {
-                                        textView.setTranslationY(translation);
-                                    }
-
-                                    @Override
                                     public void onAnimationEnd(Animator animation) {
+                                        textView.setTranslationY(BOUNCE_ANIMATION_FINAL_Y);
                                         ViewClippingUtil.setClippingDeactivated(textView, false,
                                                 mClippingParams);
                                     }
@@ -553,10 +551,26 @@
                 hideTransientIndication();
             } else if (msg.what == MSG_CLEAR_BIOMETRIC_MSG) {
                 mLockIcon.setTransientBiometricsError(false);
+            } else if (msg.what == MSG_SWIPE_UP_TO_UNLOCK) {
+                showSwipeUpToUnlock();
             }
         }
     };
 
+    private void showSwipeUpToUnlock() {
+        if (mDozing) {
+            return;
+        }
+
+        String message = mContext.getString(R.string.keyguard_unlock);
+        if (mStatusBarKeyguardViewManager.isBouncerShowing()) {
+            mStatusBarKeyguardViewManager.showBouncerMessage(message, mInitialTextColorState);
+        } else if (mKeyguardUpdateMonitor.isScreenOn()) {
+            showTransientIndication(message);
+            hideTransientIndicationDelayed(BaseKeyguardCallback.HIDE_DELAY_MS);
+        }
+    }
+
     public void setDozing(boolean dozing) {
         if (mDozing == dozing) {
             return;
@@ -637,12 +651,20 @@
                 return;
             }
             animatePadlockError();
+            boolean showSwipeToUnlock =
+                    msgId == KeyguardUpdateMonitor.BIOMETRIC_HELP_FACE_NOT_RECOGNIZED;
             if (mStatusBarKeyguardViewManager.isBouncerShowing()) {
                 mStatusBarKeyguardViewManager.showBouncerMessage(helpString,
                         mInitialTextColorState);
             } else if (updateMonitor.isScreenOn()) {
                 showTransientIndication(helpString);
-                hideTransientIndicationDelayed(TRANSIENT_BIOMETRIC_ERROR_TIMEOUT);
+                if (!showSwipeToUnlock) {
+                    hideTransientIndicationDelayed(TRANSIENT_BIOMETRIC_ERROR_TIMEOUT);
+                }
+            }
+            if (showSwipeToUnlock) {
+                mHandler.sendMessageDelayed(mHandler.obtainMessage(MSG_SWIPE_UP_TO_UNLOCK),
+                        TRANSIENT_BIOMETRIC_ERROR_TIMEOUT);
             }
         }
 
@@ -732,13 +754,5 @@
                 updateIndication(false);
             }
         }
-
-        @Override
-        public void onKeyguardBouncerChanged(boolean bouncer) {
-            if (mLockIcon == null) {
-                return;
-            }
-            mLockIcon.setBouncerVisible(bouncer);
-        }
-    };
+    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/MediaArtworkProcessor.kt b/packages/SystemUI/src/com/android/systemui/statusbar/MediaArtworkProcessor.kt
index 4b2d131..aaf4849 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/MediaArtworkProcessor.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/MediaArtworkProcessor.kt
@@ -25,6 +25,7 @@
 import android.renderscript.Element
 import android.renderscript.RenderScript
 import android.renderscript.ScriptIntrinsicBlur
+import android.util.Log
 import android.util.MathUtils
 import com.android.internal.graphics.ColorUtils
 import com.android.systemui.statusbar.notification.MediaNotificationProcessor
@@ -32,6 +33,7 @@
 import javax.inject.Inject
 import javax.inject.Singleton
 
+private const val TAG = "MediaArtworkProcessor"
 private const val COLOR_ALPHA = (255 * 0.7f).toInt()
 private const val BLUR_RADIUS = 25f
 private const val DOWNSAMPLE = 6
@@ -42,45 +44,54 @@
     private val mTmpSize = Point()
     private var mArtworkCache: Bitmap? = null
 
-    fun processArtwork(context: Context, artwork: Bitmap): Bitmap {
+    fun processArtwork(context: Context, artwork: Bitmap): Bitmap? {
         if (mArtworkCache != null) {
-            return mArtworkCache!!
+            return mArtworkCache
         }
-
-        context.display.getSize(mTmpSize)
         val renderScript = RenderScript.create(context)
-        val rect = Rect(0, 0, artwork.width, artwork.height)
-        MathUtils.fitRect(rect, Math.max(mTmpSize.x / DOWNSAMPLE, mTmpSize.y / DOWNSAMPLE))
-        var inBitmap = Bitmap.createScaledBitmap(artwork, rect.width(), rect.height(),
-                true /* filter */)
-        // Render script blurs only support ARGB_8888, we need a conversion if we got a
-        // different bitmap config.
-        if (inBitmap.config != Bitmap.Config.ARGB_8888) {
-            val oldIn = inBitmap
-            inBitmap = oldIn.copy(Bitmap.Config.ARGB_8888, false /* isMutable */)
-            oldIn.recycle()
-        }
-        val input = Allocation.createFromBitmap(renderScript, inBitmap,
-                Allocation.MipmapControl.MIPMAP_NONE, Allocation.USAGE_GRAPHICS_TEXTURE)
-        val outBitmap = Bitmap.createBitmap(inBitmap.width, inBitmap.height,
-                Bitmap.Config.ARGB_8888)
-        val output = Allocation.createFromBitmap(renderScript, outBitmap)
         val blur = ScriptIntrinsicBlur.create(renderScript, Element.U8_4(renderScript))
-        blur.setRadius(BLUR_RADIUS)
-        blur.setInput(input)
-        blur.forEach(output)
-        output.copyTo(outBitmap)
+        var input: Allocation? = null
+        var output: Allocation? = null
+        var inBitmap: Bitmap? = null
+        try {
+            context.display.getSize(mTmpSize)
+            val rect = Rect(0, 0, artwork.width, artwork.height)
+            MathUtils.fitRect(rect, Math.max(mTmpSize.x / DOWNSAMPLE, mTmpSize.y / DOWNSAMPLE))
+            inBitmap = Bitmap.createScaledBitmap(artwork, rect.width(), rect.height(),
+                    true /* filter */)
+            // Render script blurs only support ARGB_8888, we need a conversion if we got a
+            // different bitmap config.
+            if (inBitmap.config != Bitmap.Config.ARGB_8888) {
+                val oldIn = inBitmap
+                inBitmap = oldIn.copy(Bitmap.Config.ARGB_8888, false /* isMutable */)
+                oldIn.recycle()
+            }
+            val outBitmap = Bitmap.createBitmap(inBitmap.width, inBitmap.height,
+                    Bitmap.Config.ARGB_8888)
 
-        val swatch = MediaNotificationProcessor.findBackgroundSwatch(artwork)
+            input = Allocation.createFromBitmap(renderScript, inBitmap,
+                    Allocation.MipmapControl.MIPMAP_NONE, Allocation.USAGE_GRAPHICS_TEXTURE)
+            output = Allocation.createFromBitmap(renderScript, outBitmap)
 
-        input.destroy()
-        output.destroy()
-        inBitmap.recycle()
-        blur.destroy()
+            blur.setRadius(BLUR_RADIUS)
+            blur.setInput(input)
+            blur.forEach(output)
+            output.copyTo(outBitmap)
 
-        val canvas = Canvas(outBitmap)
-        canvas.drawColor(ColorUtils.setAlphaComponent(swatch.rgb, COLOR_ALPHA))
-        return outBitmap
+            val swatch = MediaNotificationProcessor.findBackgroundSwatch(artwork)
+
+            val canvas = Canvas(outBitmap)
+            canvas.drawColor(ColorUtils.setAlphaComponent(swatch.rgb, COLOR_ALPHA))
+            return outBitmap
+        } catch (ex: IllegalArgumentException) {
+            Log.e(TAG, "error while processing artwork", ex)
+            return null
+        } finally {
+            input?.destroy()
+            output?.destroy()
+            blur.destroy()
+            inBitmap?.recycle()
+        }
     }
 
     fun clearCache() {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationMediaManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationMediaManager.java
index 6c36ab9..00a12a9 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationMediaManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationMediaManager.java
@@ -17,6 +17,10 @@
 
 import static com.android.systemui.Dependency.MAIN_HANDLER;
 import static com.android.systemui.statusbar.StatusBarState.KEYGUARD;
+import static com.android.systemui.statusbar.phone.BiometricUnlockController.MODE_UNLOCK_FADING;
+import static com.android.systemui.statusbar.phone.BiometricUnlockController.MODE_WAKE_AND_UNLOCK;
+import static com.android.systemui.statusbar.phone.BiometricUnlockController
+        .MODE_WAKE_AND_UNLOCK_PULSING;
 import static com.android.systemui.statusbar.phone.StatusBar.DEBUG_MEDIA_FAKE_ARTWORK;
 import static com.android.systemui.statusbar.phone.StatusBar.ENABLE_LOCKSCREEN_WALLPAPER;
 import static com.android.systemui.statusbar.phone.StatusBar.SHOW_LOCKSCREEN_MEDIA_ARTWORK;
@@ -57,6 +61,7 @@
 import com.android.systemui.statusbar.notification.NotificationEntryManager;
 import com.android.systemui.statusbar.notification.collection.NotificationEntry;
 import com.android.systemui.statusbar.phone.BiometricUnlockController;
+import com.android.systemui.statusbar.phone.KeyguardBypassController;
 import com.android.systemui.statusbar.phone.LockscreenWallpaper;
 import com.android.systemui.statusbar.phone.ScrimController;
 import com.android.systemui.statusbar.phone.ScrimState;
@@ -68,6 +73,7 @@
 import java.io.PrintWriter;
 import java.lang.ref.WeakReference;
 import java.util.ArrayList;
+import java.util.HashSet;
 import java.util.List;
 import java.util.Set;
 
@@ -89,6 +95,15 @@
             = Dependency.get(StatusBarStateController.class);
     private final SysuiColorExtractor mColorExtractor = Dependency.get(SysuiColorExtractor.class);
     private final KeyguardMonitor mKeyguardMonitor = Dependency.get(KeyguardMonitor.class);
+    private final KeyguardBypassController mKeyguardBypassController;
+    private static final HashSet<Integer> PAUSED_MEDIA_STATES = new HashSet<>();
+    static {
+        PAUSED_MEDIA_STATES.add(PlaybackState.STATE_NONE);
+        PAUSED_MEDIA_STATES.add(PlaybackState.STATE_STOPPED);
+        PAUSED_MEDIA_STATES.add(PlaybackState.STATE_PAUSED);
+        PAUSED_MEDIA_STATES.add(PlaybackState.STATE_ERROR);
+    }
+
 
     // Late binding
     private NotificationEntryManager mEntryManager;
@@ -173,9 +188,11 @@
             Lazy<ShadeController> shadeController,
             Lazy<StatusBarWindowController> statusBarWindowController,
             NotificationEntryManager notificationEntryManager,
-            MediaArtworkProcessor mediaArtworkProcessor) {
+            MediaArtworkProcessor mediaArtworkProcessor,
+            KeyguardBypassController keyguardBypassController) {
         mContext = context;
         mMediaArtworkProcessor = mediaArtworkProcessor;
+        mKeyguardBypassController = keyguardBypassController;
         mMediaListeners = new ArrayList<>();
         mMediaSessionManager
                 = (MediaSessionManager) mContext.getSystemService(Context.MEDIA_SESSION_SERVICE);
@@ -203,6 +220,10 @@
                 mPropertiesChangedListener);
     }
 
+    public static boolean isPlayingState(int state) {
+        return !PAUSED_MEDIA_STATES.contains(state);
+    }
+
     public void setUpWithPresenter(NotificationPresenter presenter) {
         mPresenter = presenter;
     }
@@ -457,7 +478,7 @@
         }
 
         Bitmap artworkBitmap = null;
-        if (mediaMetadata != null) {
+        if (mediaMetadata != null && !mKeyguardBypassController.getBypassEnabled()) {
             artworkBitmap = mediaMetadata.getBitmap(MediaMetadata.METADATA_KEY_ART);
             if (artworkBitmap == null) {
                 artworkBitmap = mediaMetadata.getBitmap(MediaMetadata.METADATA_KEY_ALBUM_ART);
@@ -578,9 +599,11 @@
                 boolean cannotAnimateDoze = shadeController != null
                         && shadeController.isDozing()
                         && !ScrimState.AOD.getAnimateChange();
-                if (mBiometricUnlockController != null && mBiometricUnlockController.getMode()
+                boolean needsBypassFading = mKeyguardMonitor.isBypassFadingAnimation();
+                if (((mBiometricUnlockController != null && mBiometricUnlockController.getMode()
                         == BiometricUnlockController.MODE_WAKE_AND_UNLOCK_PULSING
-                        || hideBecauseOccluded || cannotAnimateDoze) {
+                                || cannotAnimateDoze) && !needsBypassFading)
+                        || hideBecauseOccluded) {
 
                     // We are unlocking directly - no animation!
                     mBackdrop.setVisibility(View.GONE);
@@ -605,9 +628,7 @@
                             });
                     if (mKeyguardMonitor.isKeyguardFadingAway()) {
                         mBackdrop.animate()
-                                // Make it disappear faster, as the focus should be on the activity
-                                // behind.
-                                .setDuration(mKeyguardMonitor.getKeyguardFadingAwayDuration() / 2)
+                                .setDuration(mKeyguardMonitor.getShortenedFadingAwayDuration())
                                 .setStartDelay(mKeyguardMonitor.getKeyguardFadingAwayDelay())
                                 .setInterpolator(Interpolators.LINEAR)
                                 .start();
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationPresenter.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationPresenter.java
index f34b912..3cb2a2a 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationPresenter.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationPresenter.java
@@ -63,11 +63,6 @@
     int getMaxNotificationsWhileLocked(boolean recompute);
 
     /**
-     * True if the presenter is currently locked.
-     */
-    boolean isPresenterLocked();
-
-    /**
      * Called when the row states are updated by {@link NotificationViewHierarchyManager}.
      */
     void onUpdateRowStates();
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationRemoteInputManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationRemoteInputManager.java
index 1440803..c9050d4 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationRemoteInputManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationRemoteInputManager.java
@@ -52,6 +52,7 @@
 import com.android.internal.statusbar.NotificationVisibility;
 import com.android.systemui.Dumpable;
 import com.android.systemui.R;
+import com.android.systemui.plugins.statusbar.StatusBarStateController;
 import com.android.systemui.statusbar.notification.NotificationEntryListener;
 import com.android.systemui.statusbar.notification.NotificationEntryManager;
 import com.android.systemui.statusbar.notification.collection.NotificationEntry;
@@ -121,6 +122,7 @@
     protected final Context mContext;
     private final UserManager mUserManager;
     private final KeyguardManager mKeyguardManager;
+    private final StatusBarStateController mStatusBarStateController;
 
     protected RemoteInputController mRemoteInputController;
     protected NotificationLifetimeExtender.NotificationSafeToRemoveCallback
@@ -259,6 +261,7 @@
             SmartReplyController smartReplyController,
             NotificationEntryManager notificationEntryManager,
             Lazy<ShadeController> shadeController,
+            StatusBarStateController statusBarStateController,
             @Named(MAIN_HANDLER_NAME) Handler mainHandler) {
         mContext = context;
         mLockscreenUserManager = lockscreenUserManager;
@@ -271,6 +274,7 @@
         mUserManager = (UserManager) mContext.getSystemService(Context.USER_SERVICE);
         addLifetimeExtenders();
         mKeyguardManager = context.getSystemService(KeyguardManager.class);
+        mStatusBarStateController = statusBarStateController;
 
         notificationEntryManager.addNotificationEntryListener(new NotificationEntryListener() {
             @Override
@@ -380,7 +384,10 @@
 
         if (!mLockscreenUserManager.shouldAllowLockscreenRemoteInput()) {
             final int userId = pendingIntent.getCreatorUserHandle().getIdentifier();
-            if (mLockscreenUserManager.isLockscreenPublicMode(userId)) {
+            if (mLockscreenUserManager.isLockscreenPublicMode(userId)
+                    || mStatusBarStateController.getState() == StatusBarState.KEYGUARD) {
+                // Even if we don't have security we should go through this flow, otherwise we won't
+                // go to the shade
                 mCallback.onLockedRemoteInput(row, view);
                 return true;
             }
@@ -391,6 +398,11 @@
             }
         }
 
+        if (riv != null && !riv.isAttachedToWindow()) {
+            // the remoteInput isn't attached to the window anymore :/ Let's focus on the expanded
+            // one instead if it's available
+            riv = null;
+        }
         if (riv == null) {
             riv = findRemoteInputView(row.getPrivateLayout().getExpandedChild());
             if (riv == null) {
@@ -405,6 +417,10 @@
             return true;
         }
 
+        if (!riv.isAttachedToWindow()) {
+            // if we still didn't find a view that is attached, let's abort.
+            return false;
+        }
         int width = view.getWidth();
         if (view instanceof TextView) {
             // Center the reveal on the text which might be off-center from the TextView
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShelf.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShelf.java
index 165c64e..99682fc 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShelf.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShelf.java
@@ -18,6 +18,7 @@
 
 import static com.android.systemui.Interpolators.FAST_OUT_SLOW_IN_REVERSE;
 import static com.android.systemui.statusbar.phone.NotificationIconContainer.IconState.NO_VALUE;
+import static com.android.systemui.util.InjectionInflationController.VIEW_CONTEXT;
 
 import android.content.Context;
 import android.content.res.Configuration;
@@ -48,8 +49,12 @@
 import com.android.systemui.statusbar.notification.stack.ExpandableViewState;
 import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayout;
 import com.android.systemui.statusbar.notification.stack.ViewState;
+import com.android.systemui.statusbar.phone.KeyguardBypassController;
 import com.android.systemui.statusbar.phone.NotificationIconContainer;
 
+import javax.inject.Inject;
+import javax.inject.Named;
+
 /**
  * A notification shelf view that is placed inside the notification scroller. It manages the
  * overflow icons that don't fit into the regular list anymore.
@@ -63,15 +68,13 @@
             = SystemProperties.getBoolean("debug.icon_scroll_animations", true);
     private static final int TAG_CONTINUOUS_CLIPPING = R.id.continuous_clipping_tag;
     private static final String TAG = "NotificationShelf";
-    private static final long SHELF_IN_TRANSLATION_DURATION = 200;
+    private final KeyguardBypassController mBypassController;
 
     private NotificationIconContainer mShelfIcons;
     private int[] mTmp = new int[2];
     private boolean mHideBackground;
     private int mIconAppearTopPadding;
-    private int mShelfAppearTranslation;
-    private float mDarkShelfPadding;
-    private float mDarkShelfIconSize;
+    private float mHiddenShelfIconSize;
     private int mStatusBarHeight;
     private int mStatusBarPaddingStart;
     private AmbientState mAmbientState;
@@ -96,8 +99,12 @@
     private int mCutoutHeight;
     private int mGapHeight;
 
-    public NotificationShelf(Context context, AttributeSet attrs) {
+    @Inject
+    public NotificationShelf(@Named(VIEW_CONTEXT) Context context,
+            AttributeSet attrs,
+            KeyguardBypassController keyguardBypassController) {
         super(context, attrs);
+        mBypassController = keyguardBypassController;
     }
 
     @Override
@@ -140,8 +147,6 @@
         mStatusBarHeight = res.getDimensionPixelOffset(R.dimen.status_bar_height);
         mStatusBarPaddingStart = res.getDimensionPixelOffset(R.dimen.status_bar_padding_start);
         mPaddingBetweenElements = res.getDimensionPixelSize(R.dimen.notification_divider_height);
-        mShelfAppearTranslation = res.getDimensionPixelSize(R.dimen.shelf_appear_translation);
-        mDarkShelfPadding = res.getDimensionPixelSize(R.dimen.widget_bottom_separator_padding);
 
         ViewGroup.LayoutParams layoutParams = getLayoutParams();
         layoutParams.height = res.getDimensionPixelOffset(R.dimen.notification_shelf_height);
@@ -152,7 +157,7 @@
         mScrollFastThreshold = res.getDimensionPixelOffset(R.dimen.scroll_fast_threshold);
         mShowNotificationShelf = res.getBoolean(R.bool.config_showNotificationShelf);
         mIconSize = res.getDimensionPixelSize(com.android.internal.R.dimen.status_bar_icon_size);
-        mDarkShelfIconSize = res.getDimensionPixelOffset(R.dimen.dark_shelf_icon_size);
+        mHiddenShelfIconSize = res.getDimensionPixelOffset(R.dimen.hidden_shelf_icon_size);
         mGapHeight = res.getDimensionPixelSize(R.dimen.qs_notification_padding);
 
         if (!mShowNotificationShelf) {
@@ -167,33 +172,6 @@
     }
 
     @Override
-    public void setDark(boolean dark, boolean fade, long delay) {
-        if (mDark == dark) return;
-        super.setDark(dark, fade, delay);
-        mShelfIcons.setDark(dark, fade, delay);
-        updateInteractiveness();
-        updateOutline();
-    }
-
-    /**
-     * Alpha animation with translation played when this view is visible on AOD.
-     */
-    public void fadeInTranslating() {
-        mShelfIcons.setTranslationY(-mShelfAppearTranslation);
-        mShelfIcons.setAlpha(0);
-        mShelfIcons.animate()
-                .setInterpolator(Interpolators.DECELERATE_QUINT)
-                .translationY(0)
-                .setDuration(SHELF_IN_TRANSLATION_DURATION)
-                .start();
-        mShelfIcons.animate()
-                .alpha(1)
-                .setInterpolator(Interpolators.LINEAR)
-                .setDuration(SHELF_IN_TRANSLATION_DURATION)
-                .start();
-    }
-
-    @Override
     protected View getContentView() {
         return mShelfIcons;
     }
@@ -219,11 +197,8 @@
             viewState.copyFrom(lastViewState);
             viewState.height = getIntrinsicHeight();
 
-            float awakenTranslation = Math.max(Math.min(viewEnd, maxShelfEnd) - viewState.height,
+            viewState.yTranslation = Math.max(Math.min(viewEnd, maxShelfEnd) - viewState.height,
                     getFullyClosedTranslation());
-            float yRatio = mAmbientState.hasPulsingNotifications() ?
-                    0 : mAmbientState.getDarkAmount();
-            viewState.yTranslation = awakenTranslation + mDarkShelfPadding * yRatio;
             viewState.zTranslation = ambientState.getBaseZHeight();
             // For the small display size, it's not enough to make the icon not covered by
             // the top cutout so the denominator add the height of cutout.
@@ -344,7 +319,10 @@
                     colorTwoBefore = previousColor;
                     transitionAmount = inShelfAmount;
                 }
-                if (isLastChild) {
+                // We don't want to modify the color if the notification is hun'd
+                boolean canModifyColor = mAmbientState.isShadeExpanded()
+                        && !(mAmbientState.isOnKeyguard() && mBypassController.getBypassEnabled());
+                if (isLastChild && canModifyColor) {
                     if (colorOfViewBeforeLast == NO_COLOR) {
                         colorOfViewBeforeLast = ownColorUntinted;
                     }
@@ -396,6 +374,10 @@
         clipTransientViews();
 
         setClipTopAmount(clipTopAmount);
+        boolean isHidden = getViewState().hidden || clipTopAmount >= getIntrinsicHeight();
+        if (mShowNotificationShelf) {
+            setVisibility(isHidden ? View.INVISIBLE : View.VISIBLE);
+        }
         setBackgroundTop(backgroundTop);
         setFirstElementRoundness(firstElementRoundness);
         mShelfIcons.setSpeedBumpIndex(mAmbientState.getSpeedBumpIndex());
@@ -452,7 +434,7 @@
         }
         StatusBarIconView icon = row.getEntry().expandedIcon;
         float shelfIconPosition = getTranslationY() + icon.getTop() + icon.getTranslationY();
-        if (shelfIconPosition < maxTop && !mAmbientState.isFullyDark()) {
+        if (shelfIconPosition < maxTop && !mAmbientState.isFullyHidden()) {
             int top = (int) (maxTop - shelfIconPosition);
             Rect clipRect = new Rect(0, top, icon.getWidth(), Math.max(top, icon.getHeight()));
             icon.setClipBounds(clipRect);
@@ -463,7 +445,7 @@
 
     private void updateContinuousClipping(final ExpandableNotificationRow row) {
         StatusBarIconView icon = row.getEntry().expandedIcon;
-        boolean needsContinuousClipping = ViewState.isAnimatingY(icon) && !mAmbientState.isDark();
+        boolean needsContinuousClipping = ViewState.isAnimatingY(icon) && !mAmbientState.isDozing();
         boolean isContinuousClipping = icon.getTag(TAG_CONTINUOUS_CLIPPING) != null;
         if (needsContinuousClipping && !isContinuousClipping) {
             final ViewTreeObserver observer = icon.getViewTreeObserver();
@@ -512,8 +494,12 @@
         float viewEnd = row.getTranslationY() + row.getActualHeight();
         boolean isPinned = (row.isPinned() || row.isHeadsUpAnimatingAway())
                 && !mAmbientState.isDozingAndNotPulsing(row);
-        boolean shouldClipOwnTop = row.showingAmbientPulsing() && !mAmbientState.isFullyDark()
-                || (mAmbientState.isPulseExpanding() && childIndex == 0);
+        boolean shouldClipOwnTop;
+        if (mAmbientState.isPulseExpanding()) {
+            shouldClipOwnTop = childIndex == 0;
+        } else {
+            shouldClipOwnTop = row.showingPulsing();
+        }
         if (viewEnd > notificationClipEnd && !shouldClipOwnTop
                 && (mAmbientState.isShadeExpanded() || !isPinned)) {
             int clipBottomAmount = (int) (viewEnd - notificationClipEnd);
@@ -666,8 +652,8 @@
             iconState.translateContent = false;
         }
         float transitionAmount;
-        if (mAmbientState.isDarkAtAll() && !row.isInShelf()) {
-            transitionAmount = mAmbientState.isFullyDark() ? 1 : 0;
+        if (mAmbientState.isHiddenAtAll() && !row.isInShelf()) {
+            transitionAmount = mAmbientState.isFullyHidden() ? 1 : 0;
         } else if (isLastChild || !USE_ANIMATIONS_WHEN_OPENING || iconState.useFullTransitionAmount
                 || iconState.useLinearTransitionAmount) {
             transitionAmount = iconTransitionAmount;
@@ -682,7 +668,7 @@
                 ? fullTransitionAmount
                 : transitionAmount;
         iconState.clampedAppearAmount = clampedAmount;
-        float contentTransformationAmount = !row.isAboveShelf()
+        float contentTransformationAmount = !row.isAboveShelf() && !row.showingPulsing()
                     && (isLastChild || iconState.translateContent)
                 ? iconTransitionAmount
                 : 0.0f;
@@ -717,7 +703,7 @@
         }
         notificationIconPosition += iconTopPadding;
         float shelfIconPosition = getTranslationY() + icon.getTop();
-        float iconSize = mDark ? mDarkShelfIconSize : mIconSize;
+        float iconSize = mAmbientState.isFullyHidden() ? mHiddenShelfIconSize : mIconSize;
         shelfIconPosition += (icon.getHeight() - icon.getIconScale() * iconSize) / 2.0f;
         float iconYTranslation = NotificationUtils.interpolate(
                 notificationIconPosition - shelfIconPosition,
@@ -752,9 +738,10 @@
                 iconState.scaleY = 1.0f;
                 iconState.hidden = false;
             }
-            if ((row.isAboveShelf() || (!row.isInShelf() && (isLastChild && row.areGutsExposed()
-                    || row.getTranslationZ() > mAmbientState.getBaseZHeight())))
-                        && !mAmbientState.isFullyDark()) {
+            if (row.isAboveShelf()
+                    || row.showingPulsing()
+                    || (!row.isInShelf() && (isLastChild && row.areGutsExposed()
+                    || row.getTranslationZ() > mAmbientState.getBaseZHeight()))) {
                 iconState.hidden = true;
             }
             int backgroundColor = getBackgroundColorWithoutTint();
@@ -795,12 +782,12 @@
 
     @Override
     protected boolean needsOutline() {
-        return !mHideBackground && !mDark && super.needsOutline();
+        return !mHideBackground && super.needsOutline();
     }
 
     @Override
     protected boolean shouldHideBackground() {
-        return super.shouldHideBackground() || mHideBackground || mDark;
+        return super.shouldHideBackground() || mHideBackground;
     }
 
     @Override
@@ -840,7 +827,7 @@
     private void setOpenedAmount(float openedAmount) {
         mNoAnimationsInThisFrame = openedAmount == 1.0f && mOpenedAmount == 0.0f;
         mOpenedAmount = openedAmount;
-        if (!mAmbientState.isPanelFullWidth() || mAmbientState.isDark()) {
+        if (!mAmbientState.isPanelFullWidth() || mAmbientState.isDozing()) {
             // We don't do a transformation at all, lets just assume we are fully opened
             openedAmount = 1.0f;
         }
@@ -911,8 +898,7 @@
     }
 
     private void updateInteractiveness() {
-        mInteractive = mStatusBarState == StatusBarState.KEYGUARD && mHasItemsInStableShelf
-                && !mDark;
+        mInteractive = mStatusBarState == StatusBarState.KEYGUARD && mHasItemsInStableShelf;
         setClickable(mInteractive);
         setFocusable(mInteractive);
         setImportantForAccessibility(mInteractive ? View.IMPORTANT_FOR_ACCESSIBILITY_YES
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationViewHierarchyManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationViewHierarchyManager.java
index 9c3ee96..6e75c03 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationViewHierarchyManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationViewHierarchyManager.java
@@ -36,6 +36,7 @@
 import com.android.systemui.statusbar.notification.collection.NotificationEntry;
 import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
 import com.android.systemui.statusbar.notification.stack.NotificationListContainer;
+import com.android.systemui.statusbar.phone.KeyguardBypassController;
 import com.android.systemui.statusbar.phone.NotificationGroupManager;
 import com.android.systemui.statusbar.phone.ShadeController;
 import com.android.systemui.util.Assert;
@@ -86,6 +87,7 @@
     private final boolean mAlwaysExpandNonGroupedNotification;
     private final BubbleData mBubbleData;
     private final DynamicPrivacyController mDynamicPrivacyController;
+    private final KeyguardBypassController mBypassController;
 
     private NotificationPresenter mPresenter;
     private NotificationListContainer mListContainer;
@@ -106,9 +108,11 @@
             NotificationEntryManager notificationEntryManager,
             Lazy<ShadeController> shadeController,
             BubbleData bubbleData,
+            KeyguardBypassController bypassController,
             DynamicPrivacyController privacyController) {
         mHandler = mainHandler;
         mLockscreenUserManager = notificationLockscreenUserManager;
+        mBypassController = bypassController;
         mGroupManager = groupManager;
         mVisualStabilityManager = visualStabilityManager;
         mStatusBarStateController = (SysuiStatusBarStateController) statusBarStateController;
@@ -168,7 +172,7 @@
             boolean deviceSensitive = devicePublic
                     && !mLockscreenUserManager.userAllowsPrivateNotificationsInPublic(
                     currentUserId);
-            ent.getRow().setSensitive(sensitive, deviceSensitive);
+            ent.setSensitive(sensitive, deviceSensitive);
             ent.getRow().setNeedsRedaction(needsRedaction);
             if (mGroupManager.isChildInGroupWithSummary(ent.notification)) {
                 NotificationEntry summary = mGroupManager.getGroupSummary(ent.notification);
@@ -362,7 +366,7 @@
         int visibleNotifications = 0;
         boolean onKeyguard = mStatusBarStateController.getState() == StatusBarState.KEYGUARD;
         int maxNotifications = -1;
-        if (onKeyguard) {
+        if (onKeyguard && !mBypassController.getBypassEnabled()) {
             maxNotifications = mPresenter.getMaxNotificationsWhileLocked(true /* recompute */);
         }
         mListContainer.setMaxDisplayedNotifications(maxNotifications);
@@ -390,7 +394,6 @@
                         && !row.isLowPriority()));
             }
 
-            entry.getRow().setOnAmbient(mShadeController.get().isDozing());
             int userId = entry.notification.getUserId();
             boolean suppressedSummary = mGroupManager.isSummaryOfSuppressedGroup(
                     entry.notification) && !entry.isRowRemoved();
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/PulseExpansionHandler.kt b/packages/SystemUI/src/com/android/systemui/statusbar/PulseExpansionHandler.kt
index a9d4fde..986486a 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/PulseExpansionHandler.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/PulseExpansionHandler.kt
@@ -25,6 +25,7 @@
 import android.os.PowerManager.WAKE_REASON_GESTURE
 import android.os.SystemClock
 import android.view.MotionEvent
+import android.view.VelocityTracker
 import android.view.ViewConfiguration
 
 import com.android.systemui.Gefingerpoken
@@ -35,8 +36,12 @@
 import com.android.systemui.statusbar.notification.NotificationWakeUpCoordinator
 import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow
 import com.android.systemui.statusbar.notification.row.ExpandableView
+import com.android.systemui.statusbar.notification.stack.NotificationRoundnessManager
 import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayout
+import com.android.systemui.statusbar.phone.HeadsUpManagerPhone
+import com.android.systemui.statusbar.phone.KeyguardBypassController
 import com.android.systemui.statusbar.phone.ShadeController
+import com.android.systemui.statusbar.policy.HeadsUpManager
 
 import javax.inject.Inject
 import javax.inject.Singleton
@@ -48,22 +53,46 @@
 @Singleton
 class PulseExpansionHandler @Inject
 constructor(context: Context,
-            private val mWakeUpCoordinator: NotificationWakeUpCoordinator) : Gefingerpoken {
+            private val wakeUpCoordinator: NotificationWakeUpCoordinator,
+            private val bypassController: KeyguardBypassController,
+            private val headsUpManager: HeadsUpManagerPhone,
+            private val roundnessManager: NotificationRoundnessManager) : Gefingerpoken {
     companion object {
         private val RUBBERBAND_FACTOR_STATIC = 0.25f
         private val SPRING_BACK_ANIMATION_LENGTH_MS = 375
     }
     private val mPowerManager: PowerManager?
-    private var mShadeController: ShadeController? = null
+    private lateinit var shadeController: ShadeController
 
     private val mMinDragDistance: Int
     private var mInitialTouchX: Float = 0.0f
     private var mInitialTouchY: Float = 0.0f
     var isExpanding: Boolean = false
+        private set(value) {
+            val changed = field != value
+            field = value
+            bypassController.isPulseExpanding = value
+            if (changed) {
+                if (value) {
+                    val topEntry = headsUpManager.topEntry
+                    topEntry?.let {
+                        roundnessManager.setTrackingHeadsUp(it.row)
+                    }
+                } else {
+                    roundnessManager.setTrackingHeadsUp(null)
+                    if (!leavingLockscreen) {
+                        bypassController.maybePerformPendingUnlock()
+                        pulseExpandAbortListener?.run()
+                    }
+                }
+                headsUpManager.unpinAll(true /* userUnPinned */)
+            }
+        }
+    var leavingLockscreen: Boolean = false
         private set
     private val mTouchSlop: Float
-    private var mExpansionCallback: ExpansionCallback? = null
-    private lateinit var mStackScroller: NotificationStackScrollLayout
+    private lateinit var expansionCallback: ExpansionCallback
+    private lateinit var stackScroller: NotificationStackScrollLayout
     private val mTemp2 = IntArray(2)
     private var mDraggedFarEnough: Boolean = false
     private var mStartingChild: ExpandableView? = null
@@ -74,9 +103,13 @@
     private var mEmptyDragAmount: Float = 0.0f
     private var mWakeUpHeight: Float = 0.0f
     private var mReachedWakeUpHeight: Boolean = false
+    private var velocityTracker: VelocityTracker? = null
 
     private val isFalseTouch: Boolean
         get() = mFalsingManager.isFalseTouch
+    var qsExpanded: Boolean = false
+    var pulseExpandAbortListener: Runnable? = null
+    var bouncerShowing: Boolean = false
 
     init {
         mMinDragDistance = context.resources.getDimensionPixelSize(
@@ -91,9 +124,14 @@
     }
 
     private fun maybeStartExpansion(event: MotionEvent): Boolean {
-        if (!mPulsing) {
+        if (!wakeUpCoordinator.canShowPulsingHuns || qsExpanded
+                || bouncerShowing) {
             return false
         }
+        if (velocityTracker == null) {
+            velocityTracker = VelocityTracker.obtain()
+        }
+        velocityTracker!!.addMovement(event)
         val x = event.x
         val y = event.y
 
@@ -101,6 +139,7 @@
             MotionEvent.ACTION_DOWN -> {
                 mDraggedFarEnough = false
                 isExpanding = false
+                leavingLockscreen = false
                 mStartingChild = null
                 mInitialTouchY = y
                 mInitialTouchX = x
@@ -114,29 +153,52 @@
                     captureStartingChild(mInitialTouchX, mInitialTouchY)
                     mInitialTouchY = y
                     mInitialTouchX = x
-                    mWakeUpHeight = mWakeUpCoordinator.getWakeUpHeight()
+                    mWakeUpHeight = wakeUpCoordinator.getWakeUpHeight()
                     mReachedWakeUpHeight = false
                     return true
                 }
             }
+
+            MotionEvent.ACTION_UP -> {
+                recycleVelocityTracker();
+            }
+
+            MotionEvent.ACTION_CANCEL -> {
+                recycleVelocityTracker();
+            }
         }
         return false
     }
 
+    private fun recycleVelocityTracker() {
+        velocityTracker?.recycle();
+        velocityTracker = null
+    }
+
     override fun onTouchEvent(event: MotionEvent): Boolean {
         if (!isExpanding) {
             return maybeStartExpansion(event)
         }
+        velocityTracker!!.addMovement(event)
         val y = event.y
 
+        val moveDistance = y - mInitialTouchY
         when (event.actionMasked) {
-            MotionEvent.ACTION_MOVE -> updateExpansionHeight(y - mInitialTouchY)
-            MotionEvent.ACTION_UP -> if (!mFalsingManager.isUnlockingDisabled && !isFalseTouch) {
-                finishExpansion()
-            } else {
-                cancelExpansion()
+            MotionEvent.ACTION_MOVE -> updateExpansionHeight(moveDistance)
+            MotionEvent.ACTION_UP -> {
+                velocityTracker!!.computeCurrentVelocity(1000 /* units */)
+                val canExpand = moveDistance > 0 && velocityTracker!!.getYVelocity() > -1000
+                if (!mFalsingManager.isUnlockingDisabled && !isFalseTouch && canExpand) {
+                    finishExpansion()
+                } else {
+                    cancelExpansion()
+                }
+                recycleVelocityTracker()
             }
-            MotionEvent.ACTION_CANCEL -> cancelExpansion()
+            MotionEvent.ACTION_CANCEL -> {
+                cancelExpansion()
+                recycleVelocityTracker()
+            }
         }
         return isExpanding
     }
@@ -147,12 +209,15 @@
             setUserLocked(mStartingChild!!, false)
             mStartingChild = null
         }
+        if (shadeController.isDozing) {
+            isWakingToShadeLocked = true
+            wakeUpCoordinator.willWakeUp = true
+            mPowerManager!!.wakeUp(SystemClock.uptimeMillis(), WAKE_REASON_GESTURE,
+                    "com.android.systemui:PULSEDRAG")
+        }
+        shadeController.goToLockedShade(mStartingChild)
+        leavingLockscreen = true;
         isExpanding = false
-        isWakingToShadeLocked = true
-        mWakeUpCoordinator.willWakeUp = true
-        mPowerManager!!.wakeUp(SystemClock.uptimeMillis(), WAKE_REASON_GESTURE,
-                "com.android.systemui:PULSEDRAG")
-        mShadeController!!.goToLockedShade(mStartingChild)
         if (mStartingChild is ExpandableNotificationRow) {
             val row = mStartingChild as ExpandableNotificationRow?
             row!!.onExpandedByGesture(true /* userExpanded */)
@@ -172,17 +237,17 @@
             expansionHeight = max(newHeight.toFloat(), expansionHeight)
         } else {
             val target = if (mReachedWakeUpHeight) mWakeUpHeight else 0.0f
-            mWakeUpCoordinator.setNotificationsVisibleForExpansion(height > target,
+            wakeUpCoordinator.setNotificationsVisibleForExpansion(height > target,
                     true /* animate */,
                     true /* increaseSpeed */)
             expansionHeight = max(mWakeUpHeight, expansionHeight)
         }
-        val emptyDragAmount = mWakeUpCoordinator.setPulseHeight(expansionHeight)
+        val emptyDragAmount = wakeUpCoordinator.setPulseHeight(expansionHeight)
         setEmptyDragAmount(emptyDragAmount * RUBBERBAND_FACTOR_STATIC)
     }
 
     private fun captureStartingChild(x: Float, y: Float) {
-        if (mStartingChild == null) {
+        if (mStartingChild == null && !bypassController.bypassEnabled) {
             mStartingChild = findView(x, y)
             if (mStartingChild != null) {
                 setUserLocked(mStartingChild!!, true)
@@ -192,7 +257,7 @@
 
     private fun setEmptyDragAmount(amount: Float) {
         mEmptyDragAmount = amount
-        mExpansionCallback!!.setEmptyDragAmount(amount)
+        expansionCallback.setEmptyDragAmount(amount)
     }
 
     private fun reset(child: ExpandableView) {
@@ -227,6 +292,7 @@
     }
 
     private fun cancelExpansion() {
+        isExpanding = false
         mFalsingManager.onExpansionFromPulseStopped()
         if (mStartingChild != null) {
             reset(mStartingChild!!)
@@ -234,30 +300,29 @@
         } else {
             resetClock()
         }
-        mWakeUpCoordinator.setNotificationsVisibleForExpansion(false /* visible */,
+        wakeUpCoordinator.setNotificationsVisibleForExpansion(false /* visible */,
                 true /* animate */,
                 false /* increaseSpeed */)
-        isExpanding = false
     }
 
     private fun findView(x: Float, y: Float): ExpandableView? {
         var totalX = x
         var totalY = y
-        mStackScroller.getLocationOnScreen(mTemp2)
+        stackScroller.getLocationOnScreen(mTemp2)
         totalX += mTemp2[0].toFloat()
         totalY += mTemp2[1].toFloat()
-        val childAtRawPosition = mStackScroller.getChildAtRawPosition(totalX, totalY)
+        val childAtRawPosition = stackScroller.getChildAtRawPosition(totalX, totalY)
         return if (childAtRawPosition != null && childAtRawPosition.isContentExpandable) {
             childAtRawPosition
         } else null
     }
 
-    fun setUp(notificationStackScroller: NotificationStackScrollLayout,
-             expansionCallback: ExpansionCallback,
-             shadeController: ShadeController) {
-        mExpansionCallback = expansionCallback
-        mShadeController = shadeController
-        mStackScroller = notificationStackScroller
+    fun setUp(stackScroller: NotificationStackScrollLayout,
+              expansionCallback: ExpansionCallback,
+              shadeController: ShadeController) {
+        this.expansionCallback = expansionCallback
+        this.shadeController = shadeController
+        this.stackScroller = stackScroller
     }
 
     fun setPulsing(pulsing: Boolean) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarIconView.java b/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarIconView.java
index 6552fe6..f4af9ae 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarIconView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarIconView.java
@@ -112,7 +112,7 @@
     };
 
     private boolean mAlwaysScaleIcon;
-    private int mStatusBarIconDrawingSizeDark = 1;
+    private int mStatusBarIconDrawingSizeIncreased = 1;
     private int mStatusBarIconDrawingSize = 1;
     private int mStatusBarIconSize = 1;
     private StatusBarIcon mIcon;
@@ -139,7 +139,7 @@
     private int mDrawableColor;
     private int mIconColor;
     private int mDecorColor;
-    private float mDarkAmount;
+    private float mDozeAmount;
     private ValueAnimator mColorAnimator;
     private int mCurrentSetColor = NO_COLOR;
     private int mAnimationStartColor = NO_COLOR;
@@ -158,6 +158,7 @@
     private Runnable mLayoutRunnable;
     private boolean mDismissed;
     private Runnable mOnDismissListener;
+    private boolean mIncreasedSize;
 
     public StatusBarIconView(Context context, String slot, StatusBarNotification sbn) {
         this(context, slot, sbn, false);
@@ -196,12 +197,10 @@
     }
 
     private void updateIconScaleForNotifications() {
-        final float imageBounds = NotificationUtils.interpolate(
-                mStatusBarIconDrawingSize,
-                mStatusBarIconDrawingSizeDark,
-                mDarkAmount);
+        final float imageBounds = mIncreasedSize ?
+                mStatusBarIconDrawingSizeIncreased : mStatusBarIconDrawingSize;
         final int outerBounds = mStatusBarIconSize;
-        mIconScale = (float)imageBounds / (float)outerBounds;
+        mIconScale = imageBounds / (float)outerBounds;
         updatePivot();
     }
 
@@ -225,8 +224,8 @@
         }
     }
 
-    public float getIconScaleFullyDark() {
-        return (float) mStatusBarIconDrawingSizeDark / mStatusBarIconDrawingSize;
+    public float getIconScaleIncreased() {
+        return (float) mStatusBarIconDrawingSizeIncreased / mStatusBarIconDrawingSize;
     }
 
     public float getIconScale() {
@@ -256,7 +255,7 @@
         Resources res = getResources();
         mStaticDotRadius = res.getDimensionPixelSize(R.dimen.overflow_dot_radius);
         mStatusBarIconSize = res.getDimensionPixelSize(R.dimen.status_bar_icon_size);
-        mStatusBarIconDrawingSizeDark =
+        mStatusBarIconDrawingSizeIncreased =
                 res.getDimensionPixelSize(R.dimen.status_bar_icon_drawing_size_dark);
         mStatusBarIconDrawingSize =
                 res.getDimensionPixelSize(R.dimen.status_bar_icon_drawing_size);
@@ -584,7 +583,7 @@
     }
 
     private void updateDecorColor() {
-        int color = NotificationUtils.interpolateColors(mDecorColor, Color.WHITE, mDarkAmount);
+        int color = NotificationUtils.interpolateColors(mDecorColor, Color.WHITE, mDozeAmount);
         if (mDotPaint.getColor() != color) {
             mDotPaint.setColor(color);
 
@@ -618,13 +617,13 @@
                 mMatrixColorFilter = new ColorMatrixColorFilter(mMatrix);
             }
             int color = NotificationUtils.interpolateColors(
-                    mCurrentSetColor, Color.WHITE, mDarkAmount);
-            updateTintMatrix(mMatrix, color, DARK_ALPHA_BOOST * mDarkAmount);
+                    mCurrentSetColor, Color.WHITE, mDozeAmount);
+            updateTintMatrix(mMatrix, color, DARK_ALPHA_BOOST * mDozeAmount);
             mMatrixColorFilter.setColorMatrixArray(mMatrix);
             setColorFilter(null);  // setColorFilter only invalidates if the instance changed.
             setColorFilter(mMatrixColorFilter);
         } else {
-            mDozer.updateGrayscale(this, mDarkAmount);
+            mDozer.updateGrayscale(this, mDozeAmount);
         }
     }
 
@@ -855,19 +854,18 @@
         mOnVisibilityChangedListener = listener;
     }
 
-    public void setDark(boolean dark, boolean fade, long delay) {
-        mDozer.setIntensityDark(f -> {
-            mDarkAmount = f;
-            maybeUpdateIconScaleDimens();
+    public void setDozing(boolean dozing, boolean fade, long delay) {
+        mDozer.setDozing(f -> {
+            mDozeAmount = f;
             updateDecorColor();
             updateIconColor();
             updateAllowAnimation();
-        }, dark, fade, delay, this);
+        }, dozing, fade, delay, this);
     }
 
     private void updateAllowAnimation() {
-        if (mDarkAmount == 0 || mDarkAmount == 1) {
-            setAllowAnimation(mDarkAmount == 0);
+        if (mDozeAmount == 0 || mDozeAmount == 1) {
+            setAllowAnimation(mDozeAmount == 0);
         }
     }
 
@@ -949,6 +947,11 @@
         return mBlocked;
     }
 
+    public void setIncreasedSize(boolean increasedSize) {
+        mIncreasedSize = increasedSize;
+        maybeUpdateIconScaleDimens();
+    }
+
     public interface OnVisibilityChangedListener {
         void onVisibilityChanged(int newVisibility);
     }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarStateControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarStateControllerImpl.java
index eb386dc..f0eeb04 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarStateControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarStateControllerImpl.java
@@ -20,6 +20,7 @@
 import android.animation.ValueAnimator;
 import android.text.format.DateFormat;
 import android.util.FloatProperty;
+import android.view.View;
 import android.view.animation.Interpolator;
 
 import com.android.internal.annotations.GuardedBy;
@@ -77,6 +78,16 @@
     private HistoricalState[] mHistoricalRecords = new HistoricalState[HISTORY_SIZE];
 
     /**
+     * Current SystemUiVisibility
+     */
+    private int mSystemUiVisibility = View.SYSTEM_UI_FLAG_VISIBLE;
+
+    /**
+     * If the device is currently pulsing (AOD2).
+     */
+    private boolean mPulsing;
+
+    /**
      * If the device is currently dozing or not.
      */
     private boolean mIsDozing;
@@ -292,6 +303,30 @@
         return mKeyguardRequested;
     }
 
+    @Override
+    public void setSystemUiVisibility(int visibility) {
+        if (mSystemUiVisibility != visibility) {
+            mSystemUiVisibility = visibility;
+            synchronized (mListeners) {
+                for (RankedListener rl : new ArrayList<>(mListeners)) {
+                    rl.mListener.onSystemUiVisibilityChanged(mSystemUiVisibility);
+                }
+            }
+        }
+    }
+
+    @Override
+    public void setPulsing(boolean pulsing) {
+        if (mPulsing != pulsing) {
+            mPulsing = pulsing;
+            synchronized (mListeners) {
+                for (RankedListener rl : new ArrayList<>(mListeners)) {
+                    rl.mListener.onPulsingChanged(pulsing);
+                }
+            }
+        }
+    }
+
     /**
      * Returns String readable state of status bar from {@link StatusBarState}
      */
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/SysuiStatusBarStateController.java b/packages/SystemUI/src/com/android/systemui/statusbar/SysuiStatusBarStateController.java
index dc5e1e9..2ad979ab 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/SysuiStatusBarStateController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/SysuiStatusBarStateController.java
@@ -111,6 +111,16 @@
     boolean isKeyguardRequested();
 
     /**
+     * Set systemui visibility
+     */
+    void setSystemUiVisibility(int visibility);
+
+    /**
+     * Set pulsing
+     */
+    void setPulsing(boolean visibility);
+
+    /**
      * Listener with rankings SbStateListenerRank that have dependencies so must be updated
      * in a certain order
      */
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/BypassHeadsUpNotifier.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/BypassHeadsUpNotifier.kt
new file mode 100644
index 0000000..314dc04
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/BypassHeadsUpNotifier.kt
@@ -0,0 +1,143 @@
+/*
+ * 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.systemui.statusbar.notification
+
+import android.content.Context
+import android.media.MediaMetadata
+import android.provider.Settings
+import com.android.keyguard.KeyguardUpdateMonitor
+import com.android.systemui.plugins.statusbar.StatusBarStateController
+import com.android.systemui.statusbar.NotificationLockscreenUserManager
+import com.android.systemui.statusbar.NotificationMediaManager
+import com.android.systemui.statusbar.StatusBarState
+import com.android.systemui.statusbar.notification.collection.NotificationEntry
+import com.android.systemui.statusbar.phone.HeadsUpManagerPhone
+import com.android.systemui.statusbar.phone.KeyguardBypassController
+import com.android.systemui.tuner.TunerService
+import javax.inject.Inject
+import javax.inject.Singleton
+
+/**
+ * A class that automatically creates heads up for important notification when bypassing the
+ * lockscreen
+ */
+@Singleton
+class BypassHeadsUpNotifier @Inject constructor(
+        private val context: Context,
+        private val bypassController: KeyguardBypassController,
+        private val statusBarStateController: StatusBarStateController,
+        private val headsUpManager: HeadsUpManagerPhone,
+        private val notificationLockscreenUserManager: NotificationLockscreenUserManager,
+        private val mediaManager: NotificationMediaManager,
+        tunerService: TunerService) : StatusBarStateController.StateListener,
+        NotificationMediaManager.MediaListener {
+
+    private lateinit var entryManager: NotificationEntryManager
+    private var currentMediaEntry: NotificationEntry? = null
+    private var enabled = true
+
+    var fullyAwake = false
+        set(value) {
+            field = value
+            if (value) {
+                updateAutoHeadsUp(currentMediaEntry)
+            }
+        }
+
+    init {
+        statusBarStateController.addCallback(this)
+        tunerService.addTunable(
+                TunerService.Tunable { _, _ ->
+                    enabled = Settings.Secure.getIntForUser(
+                            context.contentResolver,
+                            Settings.Secure.SHOW_MEDIA_WHEN_BYPASSING,
+                            0 /* default */,
+                            KeyguardUpdateMonitor.getCurrentUser()) != 0
+                }, Settings.Secure.SHOW_MEDIA_WHEN_BYPASSING)
+    }
+
+    fun setUp(entryManager: NotificationEntryManager) {
+        this.entryManager = entryManager
+        mediaManager.addCallback(this)
+    }
+
+    override fun onMetadataOrStateChanged(metadata: MediaMetadata?, state: Int) {
+        val previous = currentMediaEntry
+        var newEntry = entryManager.notificationData.get(mediaManager.mediaNotificationKey)
+        if (!NotificationMediaManager.isPlayingState(state)) {
+            newEntry = null
+        }
+        currentMediaEntry = newEntry
+        updateAutoHeadsUp(previous)
+        updateAutoHeadsUp(currentMediaEntry)
+    }
+
+    private fun updateAutoHeadsUp(entry: NotificationEntry?) {
+        entry?.let {
+            val autoHeadsUp = it == currentMediaEntry && canAutoHeadsUp(it)
+            it.isAutoHeadsUp = autoHeadsUp
+            if (autoHeadsUp) {
+                headsUpManager.showNotification(it)
+            }
+        }
+    }
+
+    /**
+     * @return {@code true} if this entry be autoHeadsUpped right now.
+     */
+    private fun canAutoHeadsUp(entry: NotificationEntry): Boolean {
+        if (!isAutoHeadsUpAllowed()) {
+            return false;
+        }
+        if (entry.isSensitive) {
+            // filter sensitive notifications
+            return false
+        }
+        if (!notificationLockscreenUserManager.shouldShowOnKeyguard(entry)) {
+            // filter notifications invisible on Keyguard
+            return false
+        }
+        if (!entryManager.notificationData.activeNotifications.contains(entry)) {
+            // filter notifications not the active list currently
+            return false
+        }
+        return true
+    }
+
+    override fun onStatePostChange() {
+        updateAutoHeadsUp(currentMediaEntry)
+    }
+
+    /**
+     * @return {@code true} if autoHeadsUp is possible right now.
+     */
+    private fun isAutoHeadsUpAllowed() : Boolean {
+        if (!enabled) {
+            return false
+        }
+        if (!bypassController.bypassEnabled) {
+            return false
+        }
+        if (statusBarStateController.state != StatusBarState.KEYGUARD) {
+            return false
+        }
+        if (!fullyAwake) {
+            return false
+        }
+        return true
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/DynamicPrivacyController.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/DynamicPrivacyController.java
index 16bd884..d9328fa 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/DynamicPrivacyController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/DynamicPrivacyController.java
@@ -20,8 +20,12 @@
 import android.util.ArraySet;
 
 import com.android.internal.annotations.VisibleForTesting;
+import com.android.systemui.plugins.statusbar.StatusBarStateController;
 import com.android.systemui.statusbar.NotificationLockscreenUserManager;
+import com.android.systemui.statusbar.StatusBarState;
+import com.android.systemui.statusbar.phone.StatusBarKeyguardViewManager;
 import com.android.systemui.statusbar.phone.UnlockMethodCache;
+import com.android.systemui.statusbar.policy.KeyguardMonitor;
 
 import javax.inject.Inject;
 import javax.inject.Singleton;
@@ -34,22 +38,33 @@
 
     private final UnlockMethodCache mUnlockMethodCache;
     private final NotificationLockscreenUserManager mLockscreenUserManager;
+    private final StatusBarStateController mStateController;
+    private final KeyguardMonitor mKeyguardMonitor;
     private ArraySet<Listener> mListeners = new ArraySet<>();
 
     private boolean mLastDynamicUnlocked;
     private boolean mCacheInvalid;
+    private StatusBarKeyguardViewManager mStatusBarKeyguardViewManager;
 
     @Inject
     DynamicPrivacyController(Context context,
-            NotificationLockscreenUserManager notificationLockscreenUserManager) {
-        this(notificationLockscreenUserManager, UnlockMethodCache.getInstance(context));
+            KeyguardMonitor keyguardMonitor,
+            NotificationLockscreenUserManager notificationLockscreenUserManager,
+            StatusBarStateController stateController) {
+        this(notificationLockscreenUserManager, keyguardMonitor,
+                UnlockMethodCache.getInstance(context),
+                stateController);
     }
 
     @VisibleForTesting
     DynamicPrivacyController(NotificationLockscreenUserManager notificationLockscreenUserManager,
-            UnlockMethodCache unlockMethodCache) {
+            KeyguardMonitor keyguardMonitor,
+            UnlockMethodCache unlockMethodCache,
+            StatusBarStateController stateController) {
         mLockscreenUserManager = notificationLockscreenUserManager;
+        mStateController = stateController;
         mUnlockMethodCache = unlockMethodCache;
+        mKeyguardMonitor = keyguardMonitor;
         mUnlockMethodCache.addListener(this);
         mLastDynamicUnlocked = isDynamicallyUnlocked();
     }
@@ -77,13 +92,39 @@
     }
 
     public boolean isDynamicallyUnlocked() {
-        return mUnlockMethodCache.canSkipBouncer() && isDynamicPrivacyEnabled();
+        return (mUnlockMethodCache.canSkipBouncer() || mKeyguardMonitor.isKeyguardGoingAway()
+                || mKeyguardMonitor.isKeyguardFadingAway())
+                && isDynamicPrivacyEnabled();
     }
 
     public void addListener(Listener listener) {
         mListeners.add(listener);
     }
 
+    /**
+     * Is the notification shade currently in a locked down mode where it's fully showing but the
+     * contents aren't revealed yet?
+     */
+    public boolean isInLockedDownShade() {
+        if (!mStatusBarKeyguardViewManager.isShowing()
+                || !mStatusBarKeyguardViewManager.isSecure()) {
+            return false;
+        }
+        int state = mStateController.getState();
+        if (state != StatusBarState.SHADE && state != StatusBarState.SHADE_LOCKED) {
+            return false;
+        }
+        if (!isDynamicPrivacyEnabled() || isDynamicallyUnlocked()) {
+            return false;
+        }
+        return true;
+    }
+
+    public void setStatusBarKeyguardViewManager(
+            StatusBarKeyguardViewManager statusBarKeyguardViewManager) {
+        mStatusBarKeyguardViewManager = statusBarKeyguardViewManager;
+    }
+
     public interface Listener {
         void onDynamicPrivacyChanged();
     }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationAlertingManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationAlertingManager.java
index f6d3cdf..d71d407 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationAlertingManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationAlertingManager.java
@@ -17,7 +17,6 @@
 package com.android.systemui.statusbar.notification;
 
 import static com.android.systemui.statusbar.NotificationRemoteInputManager.FORCE_REMOTE_INPUT_HISTORY;
-import static com.android.systemui.statusbar.notification.row.NotificationContentInflater.FLAG_CONTENT_VIEW_AMBIENT;
 import static com.android.systemui.statusbar.notification.row.NotificationContentInflater.FLAG_CONTENT_VIEW_HEADS_UP;
 
 import android.app.Notification;
@@ -25,8 +24,6 @@
 import android.util.Log;
 
 import com.android.internal.statusbar.NotificationVisibility;
-import com.android.systemui.statusbar.AlertingNotificationManager;
-import com.android.systemui.statusbar.AmbientPulseManager;
 import com.android.systemui.statusbar.NotificationListener;
 import com.android.systemui.statusbar.NotificationRemoteInputManager;
 import com.android.systemui.statusbar.notification.collection.NotificationEntry;
@@ -45,7 +42,6 @@
 
     private static final String TAG = "NotifAlertManager";
 
-    private final AmbientPulseManager mAmbientPulseManager;
     private final NotificationRemoteInputManager mRemoteInputManager;
     private final VisualStabilityManager mVisualStabilityManager;
     private final Lazy<ShadeController> mShadeController;
@@ -57,13 +53,11 @@
     @Inject
     public NotificationAlertingManager(
             NotificationEntryManager notificationEntryManager,
-            AmbientPulseManager ambientPulseManager,
             NotificationRemoteInputManager remoteInputManager,
             VisualStabilityManager visualStabilityManager,
             Lazy<ShadeController> shadeController,
             NotificationInterruptionStateProvider notificationInterruptionStateProvider,
             NotificationListener notificationListener) {
-        mAmbientPulseManager = ambientPulseManager;
         mRemoteInputManager = remoteInputManager;
         mVisualStabilityManager = visualStabilityManager;
         mShadeController = shadeController;
@@ -108,44 +102,31 @@
             // If it does and we no longer need to heads up, we should free the view.
             if (mNotificationInterruptionStateProvider.shouldHeadsUp(entry)) {
                 mHeadsUpManager.showNotification(entry);
-                // Mark as seen immediately
-                setNotificationShown(entry.notification);
+                if (!mShadeController.get().isDozing()) {
+                    // Mark as seen immediately
+                    setNotificationShown(entry.notification);
+                }
             } else {
                 entry.freeContentViewWhenSafe(FLAG_CONTENT_VIEW_HEADS_UP);
             }
         }
-        if ((inflatedFlags & FLAG_CONTENT_VIEW_AMBIENT) != 0) {
-            if (mNotificationInterruptionStateProvider.shouldPulse(entry)) {
-                mAmbientPulseManager.showNotification(entry);
-            } else {
-                entry.freeContentViewWhenSafe(FLAG_CONTENT_VIEW_AMBIENT);
-            }
-        }
     }
 
     private void updateAlertState(NotificationEntry entry) {
         boolean alertAgain = alertAgain(entry, entry.notification.getNotification());
-        AlertingNotificationManager alertManager;
         boolean shouldAlert;
-        if (mShadeController.get().isDozing()) {
-            alertManager = mAmbientPulseManager;
-            shouldAlert = mNotificationInterruptionStateProvider.shouldPulse(entry);
-        } else {
-            alertManager = mHeadsUpManager;
-            shouldAlert = mNotificationInterruptionStateProvider.shouldHeadsUp(entry);
-        }
-        final boolean wasAlerting = alertManager.isAlerting(entry.key);
+        shouldAlert = mNotificationInterruptionStateProvider.shouldHeadsUp(entry);
+        final boolean wasAlerting = mHeadsUpManager.isAlerting(entry.key);
         if (wasAlerting) {
-            if (!shouldAlert) {
+            if (shouldAlert) {
+                mHeadsUpManager.updateNotification(entry.key, alertAgain);
+            } else if (!mHeadsUpManager.isEntryAutoHeadsUpped(entry.key)) {
                 // We don't want this to be interrupting anymore, let's remove it
-                alertManager.removeNotification(entry.key,
-                        false /* ignoreEarliestRemovalTime */);
-            } else {
-                alertManager.updateNotification(entry.key, alertAgain);
+                mHeadsUpManager.removeNotification(entry.key, false /* removeImmediately */);
             }
         } else if (shouldAlert && alertAgain) {
             // This notification was updated to be alerting, show it!
-            alertManager.showNotification(entry);
+            mHeadsUpManager.showNotification(entry);
         }
     }
 
@@ -171,7 +152,7 @@
     }
 
     private void stopAlerting(final String key) {
-        // Attempt to remove notifications from their alert managers (heads up, ambient pulse).
+        // Attempt to remove notifications from their alert manager.
         // Though the remove itself may fail, it lets the manager know to remove as soon as
         // possible.
         if (mHeadsUpManager.isAlerting(key)) {
@@ -185,8 +166,5 @@
                             || !mVisualStabilityManager.isReorderingAllowed();
             mHeadsUpManager.removeNotification(key, ignoreEarliestRemovalTime);
         }
-        if (mAmbientPulseManager.isAlerting(key)) {
-            mAmbientPulseManager.removeNotification(key, false /* ignoreEarliestRemovalTime */);
-        }
     }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationDozeHelper.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationDozeHelper.java
index ef042ba..63bb73a 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationDozeHelper.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationDozeHelper.java
@@ -79,10 +79,11 @@
         animator.start();
     }
 
-    public void setIntensityDark(Consumer<Float> listener, boolean dark,
+    public void setDozing(Consumer<Float> listener, boolean dozing,
             boolean animate, long delay, View view) {
         if (animate) {
-            startIntensityAnimation(a -> listener.accept((Float) a.getAnimatedValue()), dark, delay,
+            startIntensityAnimation(a -> listener.accept((Float) a.getAnimatedValue()), dozing,
+                    delay,
                     new AnimatorListenerAdapter() {
 
                         @Override
@@ -100,7 +101,7 @@
             if (animator != null) {
                 animator.cancel();
             }
-            listener.accept(dark ? 1f : 0f);
+            listener.accept(dozing ? 1f : 0f);
         }
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationEntryListener.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationEntryListener.java
index 1aa6bc9..dfc6450 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationEntryListener.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationEntryListener.java
@@ -24,6 +24,8 @@
 import com.android.systemui.statusbar.notification.collection.NotificationEntry;
 import com.android.systemui.statusbar.notification.row.NotificationContentInflater.InflationFlag;
 
+import androidx.annotation.NonNull;
+
 /**
  * Listener interface for changes sent by NotificationEntryManager.
  */
@@ -45,7 +47,7 @@
     /**
      * Called when a new entry is created.
      */
-    default void onNotificationAdded(NotificationEntry entry) {
+    default void onNotificationAdded(@NonNull NotificationEntry entry) {
     }
 
     /**
@@ -61,7 +63,7 @@
     /**
      * Called when a notification was updated, after any filtering of notifications have occurred.
      */
-    default void onPostEntryUpdated(NotificationEntry entry) {
+    default void onPostEntryUpdated(@NonNull NotificationEntry entry) {
     }
 
     /**
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationInterruptionStateProvider.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationInterruptionStateProvider.java
index 926d4b6..4fc6461 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationInterruptionStateProvider.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationInterruptionStateProvider.java
@@ -23,7 +23,6 @@
 import android.content.Context;
 import android.database.ContentObserver;
 import android.hardware.display.AmbientDisplayConfiguration;
-import android.os.Bundle;
 import android.os.PowerManager;
 import android.os.RemoteException;
 import android.os.ServiceManager;
@@ -32,13 +31,13 @@
 import android.service.dreams.DreamService;
 import android.service.dreams.IDreamManager;
 import android.service.notification.StatusBarNotification;
-import android.text.TextUtils;
 import android.util.Log;
 
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.systemui.Dependency;
 import com.android.systemui.plugins.statusbar.StatusBarStateController;
 import com.android.systemui.statusbar.NotificationPresenter;
+import com.android.systemui.statusbar.StatusBarState;
 import com.android.systemui.statusbar.notification.collection.NotificationEntry;
 import com.android.systemui.statusbar.phone.ShadeController;
 import com.android.systemui.statusbar.policy.HeadsUpManager;
@@ -50,6 +49,7 @@
 
     private static final String TAG = "InterruptionStateProvider";
     private static final boolean DEBUG = false;
+    private static final boolean DEBUG_HEADS_UP = true;
     private static final boolean ENABLE_HEADS_UP = true;
     private static final String SETTING_HEADS_UP_TICKER = "ticker_gets_heads_up";
 
@@ -186,18 +186,19 @@
      * @return true if the entry should heads up, false otherwise
      */
     public boolean shouldHeadsUp(NotificationEntry entry) {
-        StatusBarNotification sbn = entry.notification;
-
-        if (getShadeController().isDozing()) {
-            if (DEBUG) {
-                Log.d(TAG, "No heads up: device is dozing: " + sbn.getKey());
-            }
-            return false;
+        if (mStatusBarStateController.isDozing()) {
+            return shouldHeadsUpWhenDozing(entry);
+        } else {
+            return shouldHeadsUpWhenAwake(entry);
         }
+    }
+
+    private boolean shouldHeadsUpWhenAwake(NotificationEntry entry) {
+        StatusBarNotification sbn = entry.notification;
 
         boolean inShade = mStatusBarStateController.getState() == SHADE;
         if (entry.isBubble() && inShade) {
-            if (DEBUG) {
+            if (DEBUG_HEADS_UP) {
                 Log.d(TAG, "No heads up: in unlocked shade where notification is shown as a "
                         + "bubble: " + sbn.getKey());
             }
@@ -205,7 +206,7 @@
         }
 
         if (!canAlertCommon(entry)) {
-            if (DEBUG) {
+            if (DEBUG_HEADS_UP) {
                 Log.d(TAG, "No heads up: notification shouldn't alert: " + sbn.getKey());
             }
             return false;
@@ -216,7 +217,7 @@
         }
 
         if (entry.importance < NotificationManager.IMPORTANCE_HIGH) {
-            if (DEBUG) {
+            if (DEBUG_HEADS_UP) {
                 Log.d(TAG, "No heads up: unimportant notification: " + sbn.getKey());
             }
             return false;
@@ -231,13 +232,16 @@
         boolean inUse = mPowerManager.isScreenOn() && !isDreaming;
 
         if (!inUse) {
-            if (DEBUG) {
+            if (DEBUG_HEADS_UP) {
                 Log.d(TAG, "No heads up: not in use: " + sbn.getKey());
             }
             return false;
         }
 
         if (!mHeadsUpSuppressor.canHeadsUp(entry, sbn)) {
+            if (DEBUG_HEADS_UP) {
+                Log.d(TAG, "No heads up: aborted by suppressor: " + sbn.getKey());
+            }
             return false;
         }
 
@@ -251,61 +255,44 @@
      * @param entry the entry to check
      * @return true if the entry should ambient pulse, false otherwise
      */
-    public boolean shouldPulse(NotificationEntry entry) {
+    private boolean shouldHeadsUpWhenDozing(NotificationEntry entry) {
         StatusBarNotification sbn = entry.notification;
 
         if (!mAmbientDisplayConfiguration.pulseOnNotificationEnabled(UserHandle.USER_CURRENT)) {
-            if (DEBUG) {
+            if (DEBUG_HEADS_UP) {
                 Log.d(TAG, "No pulsing: disabled by setting: " + sbn.getKey());
             }
             return false;
         }
 
-        if (!getShadeController().isDozing()) {
-            if (DEBUG) {
-                Log.d(TAG, "No pulsing: not dozing: " + sbn.getKey());
-            }
-            return false;
-        }
-
         if (!canAlertCommon(entry)) {
-            if (DEBUG) {
+            if (DEBUG_HEADS_UP) {
                 Log.d(TAG, "No pulsing: notification shouldn't alert: " + sbn.getKey());
             }
             return false;
         }
 
         if (entry.shouldSuppressAmbient()) {
-            if (DEBUG) {
+            if (DEBUG_HEADS_UP) {
                 Log.d(TAG, "No pulsing: ambient effect suppressed: " + sbn.getKey());
             }
             return false;
         }
 
         if (entry.importance < NotificationManager.IMPORTANCE_DEFAULT) {
-            if (DEBUG) {
+            if (DEBUG_HEADS_UP) {
                 Log.d(TAG, "No pulsing: not important enough: " + sbn.getKey());
             }
             return false;
         }
-
-        Bundle extras = sbn.getNotification().extras;
-        CharSequence title = extras.getCharSequence(Notification.EXTRA_TITLE);
-        CharSequence text = extras.getCharSequence(Notification.EXTRA_TEXT);
-        if (TextUtils.isEmpty(title) && TextUtils.isEmpty(text)) {
-            if (DEBUG) {
-                Log.d(TAG, "No pulsing: title and text are empty: " + sbn.getKey());
-            }
-            return false;
-        }
-
-        return true;
+         return true;
     }
 
     /**
-     * Common checks between heads up alerting and ambient pulse alerting.  See
+     * Common checks between regular heads up and when pulsing.  See
      * {@link #shouldHeadsUp(NotificationEntry)} and
-     * {@link #shouldPulse(NotificationEntry)}.  Notifications that fail any of these checks
+     * {@link #shouldHeadsUpWhenDozing(NotificationEntry)}.  Notifications that fail any of these
+     * checks
      * should not alert at all.
      *
      * @param entry the entry to check
@@ -315,7 +302,7 @@
         StatusBarNotification sbn = entry.notification;
 
         if (mNotificationFilter.shouldFilterOut(entry)) {
-            if (DEBUG) {
+            if (DEBUG || DEBUG_HEADS_UP) {
                 Log.d(TAG, "No alerting: filtered notification: " + sbn.getKey());
             }
             return false;
@@ -323,7 +310,7 @@
 
         // Don't alert notifications that are suppressed due to group alert behavior
         if (sbn.isGroup() && sbn.getNotification().suppressAlertingDueToGrouping()) {
-            if (DEBUG) {
+            if (DEBUG || DEBUG_HEADS_UP) {
                 Log.d(TAG, "No alerting: suppressed due to group alert behavior");
             }
             return false;
@@ -345,28 +332,28 @@
         StatusBarNotification sbn = entry.notification;
 
         if (!mUseHeadsUp || mPresenter.isDeviceInVrMode()) {
-            if (DEBUG) {
+            if (DEBUG_HEADS_UP) {
                 Log.d(TAG, "No heads up: no huns or vr mode");
             }
             return false;
         }
 
         if (entry.shouldSuppressPeek()) {
-            if (DEBUG) {
+            if (DEBUG_HEADS_UP) {
                 Log.d(TAG, "No heads up: suppressed by DND: " + sbn.getKey());
             }
             return false;
         }
 
         if (isSnoozedPackage(sbn)) {
-            if (DEBUG) {
+            if (DEBUG_HEADS_UP) {
                 Log.d(TAG, "No heads up: snoozed package: " + sbn.getKey());
             }
             return false;
         }
 
         if (entry.hasJustLaunchedFullScreenIntent()) {
-            if (DEBUG) {
+            if (DEBUG_HEADS_UP) {
                 Log.d(TAG, "No heads up: recent fullscreen: " + sbn.getKey());
             }
             return false;
@@ -389,6 +376,19 @@
         return mPresenter;
     }
 
+    /**
+     * When an entry was added, should we launch its fullscreen intent? Examples are Alarms or
+     * incoming calls.
+     *
+     * @param entry the entry that was added
+     * @return {@code true} if we should launch the full screen intent
+     */
+    public boolean shouldLaunchFullScreenIntentWhenAdded(NotificationEntry entry) {
+        return entry.notification.getNotification().fullScreenIntent != null
+            && (!shouldHeadsUp(entry)
+                || mStatusBarStateController.getState() == StatusBarState.KEYGUARD);
+    }
+
     /** A component which can suppress heads-up notifications due to the overall state of the UI. */
     public interface HeadsUpSuppressor {
         /**
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationWakeUpCoordinator.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationWakeUpCoordinator.kt
index 7c193b1..2f67f90 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationWakeUpCoordinator.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationWakeUpCoordinator.kt
@@ -21,12 +21,16 @@
 import android.util.FloatProperty
 import com.android.systemui.Interpolators
 import com.android.systemui.plugins.statusbar.StatusBarStateController
-import com.android.systemui.statusbar.AmbientPulseManager
-import com.android.systemui.statusbar.SysuiStatusBarStateController
+import com.android.systemui.statusbar.StatusBarState
 import com.android.systemui.statusbar.notification.collection.NotificationEntry
 import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayout
 import com.android.systemui.statusbar.notification.stack.StackStateAnimator
 import com.android.systemui.statusbar.phone.DozeParameters
+import com.android.systemui.statusbar.phone.HeadsUpManagerPhone
+import com.android.systemui.statusbar.phone.KeyguardBypassController
+import com.android.systemui.statusbar.phone.NotificationIconAreaController
+import com.android.systemui.statusbar.phone.PanelExpansionListener
+import com.android.systemui.statusbar.policy.OnHeadsUpChangedListener
 
 import javax.inject.Inject
 import javax.inject.Singleton
@@ -34,9 +38,11 @@
 @Singleton
 class NotificationWakeUpCoordinator @Inject constructor(
         private val mContext: Context,
-        private val mAmbientPulseManager: AmbientPulseManager,
-        private val mStatusBarStateController: StatusBarStateController)
-    : AmbientPulseManager.OnAmbientChangedListener, StatusBarStateController.StateListener {
+        private val mHeadsUpManagerPhone: HeadsUpManagerPhone,
+        private val statusBarStateController: StatusBarStateController,
+        private val bypassController: KeyguardBypassController)
+    : OnHeadsUpChangedListener, StatusBarStateController.StateListener,
+        PanelExpansionListener {
 
     private val mNotificationVisibility
             = object : FloatProperty<NotificationWakeUpCoordinator>("notificationVisibility") {
@@ -57,12 +63,36 @@
     private var mNotificationVisibleAmount = 0.0f
     private var mNotificationsVisible = false
     private var mNotificationsVisibleForExpansion = false
-    private var mDarkAnimator: ObjectAnimator? = null
+    private var mVisibilityAnimator: ObjectAnimator? = null
     private var mVisibilityAmount = 0.0f
     private var mLinearVisibilityAmount = 0.0f
-    private var mWakingUp = false
     private val mEntrySetToClearWhenFinished = mutableSetOf<NotificationEntry>()
-    private val mDozeParameters: DozeParameters;
+    private val mDozeParameters: DozeParameters
+    private var pulseExpanding: Boolean = false
+    private val wakeUpListeners = arrayListOf<WakeUpListener>()
+    private var state: Int = StatusBarState.KEYGUARD
+
+    var fullyAwake: Boolean = false
+
+    var wakingUp = false
+        set(value) {
+            field = value
+            willWakeUp = false
+            if (value) {
+                if (mNotificationsVisible && !mNotificationsVisibleForExpansion
+                        && !bypassController.bypassEnabled) {
+                    // We're waking up while pulsing, let's make sure the animation looks nice
+                    mStackScroller.wakeUpFromPulse();
+                }
+                if (bypassController.bypassEnabled && !mNotificationsVisible) {
+                    // Let's make sure our huns become visible once we are waking up in case
+                    // they were blocked by the proximity sensor
+                    updateNotificationVisibility(animate = shouldAnimateVisibility(),
+                            increaseSpeed = false)
+                }
+            }
+        }
+
     var willWakeUp = false
         set(value) {
             if (!value || mDozeAmount != 0.0f) {
@@ -70,6 +100,9 @@
             }
         }
 
+    private var collapsedEnoughToHide: Boolean = false
+    lateinit var iconAreaController : NotificationIconAreaController
+
     var pulsing: Boolean = false
         set(value) {
             field = value
@@ -82,17 +115,66 @@
             }
         }
 
+    var notificationsFullyHidden: Boolean = false
+        private set(value) {
+            if (field != value) {
+                field = value
+                for (listener in wakeUpListeners) {
+                    listener.onFullyHiddenChanged(value)
+                }
+            }
+        }
+    /**
+     * True if we can show pulsing heads up notifications
+     */
+    var canShowPulsingHuns: Boolean = false
+        private set
+        get() {
+            var canShow = pulsing
+            if (bypassController.bypassEnabled) {
+                // We also allow pulsing on the lock screen!
+                canShow = canShow || (wakingUp || willWakeUp || fullyAwake)
+                        && statusBarStateController.state == StatusBarState.KEYGUARD
+                // We want to hide the notifications when collapsed too much
+                if (collapsedEnoughToHide) {
+                    canShow = false
+                }
+            }
+            return canShow
+        }
 
     init {
-        mAmbientPulseManager.addListener(this)
-        mStatusBarStateController.addCallback(this)
+        mHeadsUpManagerPhone.addListener(this)
+        statusBarStateController.addCallback(this)
         mDozeParameters = DozeParameters.getInstance(mContext)
+        addListener(object : WakeUpListener {
+            override fun onFullyHiddenChanged(isFullyHidden: Boolean) {
+                if (isFullyHidden && mNotificationsVisibleForExpansion) {
+                    // When the notification becomes fully invisible, let's make sure our expansion
+                    // flag also changes. This can happen if the bouncer shows when dragging down
+                    // and then the screen turning off, where we don't reset this state.
+                    setNotificationsVisibleForExpansion(visible = false, animate = false,
+                            increaseSpeed = false)
+                }
+            }
+        });
     }
 
     fun setStackScroller(stackScroller: NotificationStackScrollLayout) {
         mStackScroller = stackScroller
+        pulseExpanding = stackScroller.isPulseExpanding
+        stackScroller.setOnPulseHeightChangedListener {
+            val nowExpanding = isPulseExpanding()
+            val changed = nowExpanding != pulseExpanding
+            pulseExpanding = nowExpanding
+            for (listener in wakeUpListeners) {
+                listener.onPulseExpansionChanged(changed)
+            }
+        }
     }
 
+    fun isPulseExpanding(): Boolean = mStackScroller.isPulseExpanding
+
     /**
      * @param visible should notifications be visible
      * @param animate should this change be animated
@@ -106,14 +188,24 @@
             // If we stopped expanding and we're still visible because we had a pulse that hasn't
             // times out, let's release them all to make sure were not stuck in a state where
             // notifications are visible
-            mAmbientPulseManager.releaseAllImmediately()
+            mHeadsUpManagerPhone.releaseAllImmediately()
         }
     }
 
+    fun addListener(listener: WakeUpListener) {
+        wakeUpListeners.add(listener);
+    }
+
+    fun removeListener(listener: WakeUpListener) {
+        wakeUpListeners.remove(listener);
+    }
+
     private fun updateNotificationVisibility(animate: Boolean, increaseSpeed: Boolean) {
-        var visible = (mNotificationsVisibleForExpansion || mAmbientPulseManager.hasNotifications())
-                && pulsing;
-        if (!visible && mNotificationsVisible && (mWakingUp || willWakeUp) && mDozeAmount != 0.0f) {
+        // TODO: handle Lockscreen wakeup for bypass when we're not pulsing anymore
+        var visible = mNotificationsVisibleForExpansion || mHeadsUpManagerPhone.hasNotifications()
+        visible = visible && canShowPulsingHuns
+
+        if (!visible && mNotificationsVisible && (wakingUp || willWakeUp) && mDozeAmount != 0.0f) {
             // let's not make notifications invisible while waking up, otherwise the animation
             // is strange
             return;
@@ -127,7 +219,7 @@
             return
         }
         mNotificationsVisible = visible
-        mDarkAnimator?.cancel();
+        mVisibilityAnimator?.cancel();
         if (animate) {
             notifyAnimationStart(visible)
             startVisibilityAnimation(increaseSpeed)
@@ -137,22 +229,67 @@
     }
 
     override fun onDozeAmountChanged(linear: Float, eased: Float) {
+        if (updateDozeAmountIfBypass()) {
+            return
+        }
         if (linear != 1.0f && linear != 0.0f
                 && (mLinearDozeAmount == 0.0f || mLinearDozeAmount == 1.0f)) {
             // Let's notify the scroller that an animation started
             notifyAnimationStart(mLinearDozeAmount == 1.0f)
         }
+        setDozeAmount(linear, eased)
+    }
+
+    fun setDozeAmount(linear: Float, eased: Float) {
+        val changed = linear != mLinearDozeAmount
         mLinearDozeAmount = linear
         mDozeAmount = eased
         mStackScroller.setDozeAmount(mDozeAmount)
-        updateDarkAmount()
-        if (linear == 0.0f) {
+        updateHideAmount()
+        if (changed && linear == 0.0f) {
             setNotificationsVisible(visible = false, animate = false, increaseSpeed = false);
             setNotificationsVisibleForExpansion(visible = false, animate = false,
                     increaseSpeed = false)
         }
     }
 
+    override fun onStateChanged(newState: Int) {
+        updateDozeAmountIfBypass();
+        if (bypassController.bypassEnabled &&
+                newState == StatusBarState.KEYGUARD && state == StatusBarState.SHADE_LOCKED
+                && (!statusBarStateController.isDozing || shouldAnimateVisibility())) {
+            // We're leaving shade locked. Let's animate the notifications away
+            setNotificationsVisible(visible = true, increaseSpeed = false, animate = false)
+            setNotificationsVisible(visible = false, increaseSpeed = false, animate = true)
+        }
+        this.state = newState
+    }
+
+    override fun onPanelExpansionChanged(expansion: Float, tracking: Boolean) {
+        val collapsedEnough = expansion <= 0.9f
+        if (collapsedEnough != this.collapsedEnoughToHide) {
+            val couldShowPulsingHuns = canShowPulsingHuns;
+            this.collapsedEnoughToHide = collapsedEnough
+            if (couldShowPulsingHuns && !canShowPulsingHuns) {
+                updateNotificationVisibility(animate = true, increaseSpeed = true)
+                mHeadsUpManagerPhone.releaseAllImmediately()
+            }
+        }
+    }
+
+    private fun updateDozeAmountIfBypass(): Boolean {
+        if (bypassController.bypassEnabled) {
+            var amount = 1.0f;
+            if (statusBarStateController.state == StatusBarState.SHADE
+                    || statusBarStateController.state == StatusBarState.SHADE_LOCKED) {
+                amount = 0.0f;
+            }
+            setDozeAmount(amount,  amount)
+            return true
+        }
+        return false
+    }
+
     private fun startVisibilityAnimation(increaseSpeed: Boolean) {
         if (mNotificationVisibleAmount == 0f || mNotificationVisibleAmount == 1f) {
             mVisibilityInterpolator = if (mNotificationsVisible)
@@ -161,15 +298,15 @@
                 Interpolators.FAST_OUT_SLOW_IN_REVERSE
         }
         val target = if (mNotificationsVisible) 1.0f else 0.0f
-        val darkAnimator = ObjectAnimator.ofFloat(this, mNotificationVisibility, target)
-        darkAnimator.setInterpolator(Interpolators.LINEAR)
+        val visibilityAnimator = ObjectAnimator.ofFloat(this, mNotificationVisibility, target)
+        visibilityAnimator.setInterpolator(Interpolators.LINEAR)
         var duration = StackStateAnimator.ANIMATION_DURATION_WAKEUP.toLong()
         if (increaseSpeed) {
             duration = (duration.toFloat() / 1.5F).toLong();
         }
-        darkAnimator.setDuration(duration)
-        darkAnimator.start()
-        mDarkAnimator = darkAnimator
+        visibilityAnimator.setDuration(duration)
+        visibilityAnimator.start()
+        mVisibilityAnimator = visibilityAnimator
     }
 
     private fun setVisibilityAmount(visibilityAmount: Float) {
@@ -177,28 +314,29 @@
         mVisibilityAmount = mVisibilityInterpolator.getInterpolation(
                 visibilityAmount)
         handleAnimationFinished();
-        updateDarkAmount()
+        updateHideAmount()
     }
 
     private fun handleAnimationFinished() {
         if (mLinearDozeAmount == 0.0f || mLinearVisibilityAmount == 0.0f) {
-            mEntrySetToClearWhenFinished.forEach { it.setAmbientGoingAway(false) }
+            mEntrySetToClearWhenFinished.forEach { it.setHeadsUpAnimatingAway(false) }
             mEntrySetToClearWhenFinished.clear()
         }
     }
 
     fun getWakeUpHeight() : Float {
-        return mStackScroller.pulseHeight
+        return mStackScroller.wakeUpHeight
     }
 
-    private fun updateDarkAmount() {
+    private fun updateHideAmount() {
         val linearAmount = Math.min(1.0f - mLinearVisibilityAmount, mLinearDozeAmount)
         val amount = Math.min(1.0f - mVisibilityAmount, mDozeAmount)
-        mStackScroller.setDarkAmount(linearAmount, amount)
+        mStackScroller.setHideAmount(linearAmount, amount)
+        notificationsFullyHidden = linearAmount == 1.0f;
     }
 
     private fun notifyAnimationStart(awake: Boolean) {
-        mStackScroller.notifyDarkAnimationStart(!awake)
+        mStackScroller.notifyHideAnimationStart(!awake)
     }
 
     override fun onDozingChanged(isDozing: Boolean) {
@@ -207,39 +345,50 @@
         }
     }
 
+    /**
+     * Set the height how tall notifications are pulsing. This is only set whenever we are expanding
+     * from a pulse and determines how much the notifications are expanded.
+     */
     fun setPulseHeight(height: Float): Float {
-        return mStackScroller.setPulseHeight(height)
+        val overflow = mStackScroller.setPulseHeight(height)
+        //  no overflow for the bypass experience
+        return if (bypassController.bypassEnabled) 0.0f else overflow
     }
 
-    fun setWakingUp(wakingUp: Boolean) {
-        willWakeUp = false
-        mWakingUp = wakingUp
-        if (wakingUp && mNotificationsVisible && !mNotificationsVisibleForExpansion) {
-            // We're waking up while pulsing, let's make sure the animation looks nice
-            mStackScroller.wakeUpFromPulse();
-        }
-    }
-
-    override fun onAmbientStateChanged(entry: NotificationEntry, isPulsing: Boolean) {
+    override fun onHeadsUpStateChanged(entry: NotificationEntry, isHeadsUp: Boolean) {
         var animate = shouldAnimateVisibility()
-        if (!isPulsing) {
+        if (!isHeadsUp) {
             if (mLinearDozeAmount != 0.0f && mLinearVisibilityAmount != 0.0f) {
                 if (entry.isRowDismissed) {
                     // if we animate, we see the shelf briefly visible. Instead we fully animate
                     // the notification and its background out
                     animate = false
-                } else if (!mWakingUp && !willWakeUp){
-                    entry.setAmbientGoingAway(true)
+                } else if (!wakingUp && !willWakeUp){
+                    // TODO: look that this is done properly and not by anyone else
+                    entry.setHeadsUpAnimatingAway(true)
                     mEntrySetToClearWhenFinished.add(entry)
                 }
             }
         } else if (mEntrySetToClearWhenFinished.contains(entry)) {
             mEntrySetToClearWhenFinished.remove(entry)
-            entry.setAmbientGoingAway(false)
+            entry.setHeadsUpAnimatingAway(false)
         }
         updateNotificationVisibility(animate, increaseSpeed = false)
     }
 
     private fun shouldAnimateVisibility() =
             mDozeParameters.getAlwaysOn() && !mDozeParameters.getDisplayNeedsBlanking()
+
+    interface WakeUpListener {
+        /**
+         * Called whenever the notifications are fully hidden or shown
+         */
+        @JvmDefault fun onFullyHiddenChanged(isFullyHidden: Boolean) {}
+
+        /**
+         * Called whenever the pulseExpansion changes
+         * @param expandingChanged if the user has started or stopped expanding
+         */
+        @JvmDefault fun onPulseExpansionChanged(expandingChanged: Boolean) {}
+    }
 }
\ No newline at end of file
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/PropertyAnimator.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/PropertyAnimator.java
index aacb22d..fe56552 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/PropertyAnimator.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/PropertyAnimator.java
@@ -115,7 +115,20 @@
         view.setTag(animationEndTag, newEndValue);
     }
 
-    public static <T extends View> boolean isAnimating(T view, AnimatableProperty property) {
-        return  view.getTag(property.getAnimatorTag()) != null;
+    public static <T extends View> void applyImmediately(T view, AnimatableProperty property,
+            float newValue) {
+        cancelAnimation(view, property);
+        property.getProperty().set(view, newValue);
+    }
+
+    public static void cancelAnimation(View view, AnimatableProperty property) {
+        ValueAnimator animator = (ValueAnimator) view.getTag(property.getAnimatorTag());
+        if (animator != null) {
+            animator.cancel();
+        }
+    }
+
+    public static boolean isAnimating(View view, AnimatableProperty property) {
+        return view.getTag(property.getAnimatorTag()) != null;
     }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/ViewGroupFadeHelper.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/ViewGroupFadeHelper.kt
new file mode 100644
index 0000000..847d1cc
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/ViewGroupFadeHelper.kt
@@ -0,0 +1,147 @@
+/*
+ * 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.systemui.statusbar.notification
+
+import android.animation.Animator
+import android.animation.AnimatorListenerAdapter
+import android.animation.ValueAnimator
+import android.view.View
+import android.view.ViewGroup
+import com.android.systemui.Interpolators
+import com.android.systemui.R
+
+/**
+ * Class to help with fading of view groups without fading one subview
+ */
+class ViewGroupFadeHelper {
+    companion object {
+        private val visibilityIncluder = {
+            view: View -> view.visibility == View.VISIBLE
+        }
+
+        /**
+         * Fade out all views of a root except a single child. This will iterate over all children
+         * of the view and make sure that the animation works smoothly.
+         * @param root the view root to fade the children away
+         * @param excludedView which view should remain
+         * @param duration the duration of the animation
+         */
+        @JvmStatic
+        fun fadeOutAllChildrenExcept(root: ViewGroup, excludedView: View, duration: Long,
+                                     endRunnable: Runnable?) {
+            // starting from the view going up, we are adding the siblings of the child to the set
+            // of views that need to be faded.
+            val viewsToFadeOut = gatherViews(root, excludedView, visibilityIncluder)
+
+            // Applying the right layertypes for the animation
+            for (viewToFade in viewsToFadeOut) {
+                if (viewToFade.hasOverlappingRendering
+                        && viewToFade.layerType == View.LAYER_TYPE_NONE) {
+                    viewToFade.setLayerType(View.LAYER_TYPE_HARDWARE, null)
+                    viewToFade.setTag(R.id.view_group_fade_helper_hardware_layer, true)
+                }
+            }
+
+            val animator = ValueAnimator.ofFloat(1.0f, 0.0f).apply {
+                this.duration = duration
+                interpolator = Interpolators.ALPHA_OUT
+                addUpdateListener { animation ->
+                    val previousSetAlpha = root.getTag(
+                            R.id.view_group_fade_helper_previous_value_tag) as Float?
+                    val newAlpha = animation.animatedValue as Float
+                    for (viewToFade in viewsToFadeOut) {
+                        if (viewToFade.alpha != previousSetAlpha) {
+                            // A value was set that wasn't set from our view, let's store it and restore
+                            // it at the end
+                            viewToFade.setTag(R.id.view_group_fade_helper_restore_tag, viewToFade.alpha)
+                        }
+                        viewToFade.alpha = newAlpha
+                    }
+                    root.setTag(R.id.view_group_fade_helper_previous_value_tag, newAlpha)
+                }
+                addListener(object : AnimatorListenerAdapter() {
+                    override fun onAnimationEnd(animation: Animator?) {
+                        endRunnable?.run()
+                    }
+                })
+                start()
+            }
+            root.setTag(R.id.view_group_fade_helper_modified_views, viewsToFadeOut)
+            root.setTag(R.id.view_group_fade_helper_animator, animator)
+        }
+
+        private fun gatherViews(root: ViewGroup, excludedView: View,
+                                shouldInclude: (View) -> Boolean): MutableSet<View> {
+            val viewsToFadeOut = mutableSetOf<View>()
+            var parent = excludedView.parent as ViewGroup?
+            var viewContainingExcludedView = excludedView;
+            while (parent != null) {
+                for (i in 0 until parent.childCount) {
+                    val child = parent.getChildAt(i)
+                    if (shouldInclude.invoke(child) && viewContainingExcludedView != child) {
+                        viewsToFadeOut.add(child)
+                    }
+                }
+                if (parent == root) {
+                    break;
+                }
+                viewContainingExcludedView = parent
+                parent = parent.parent as ViewGroup?
+            }
+            return viewsToFadeOut
+        }
+
+        /**
+         * Reset all view alphas for views previously transformed away.
+         */
+        @JvmStatic
+        fun reset(root: ViewGroup) {
+            @Suppress("UNCHECKED_CAST")
+            val modifiedViews = root.getTag(R.id.view_group_fade_helper_modified_views)
+                    as MutableSet<View>?
+            val animator = root.getTag(R.id.view_group_fade_helper_animator) as Animator?
+            if (modifiedViews == null || animator == null) {
+                // nothing to restore
+                return
+            }
+            animator.cancel()
+            val lastSetValue = root.getTag(
+                    R.id.view_group_fade_helper_previous_value_tag) as Float?
+            for (viewToFade in modifiedViews) {
+                val restoreAlpha = viewToFade.getTag(
+                        R.id.view_group_fade_helper_restore_tag) as Float?
+                if (restoreAlpha == null) {
+                    continue
+                }
+                if (lastSetValue == viewToFade.alpha) {
+                    // it was modified after the transition!
+                    viewToFade.alpha = restoreAlpha
+                }
+                val needsLayerReset = viewToFade.getTag(
+                        R.id.view_group_fade_helper_hardware_layer) as Boolean?
+                if (needsLayerReset == true) {
+                    viewToFade.setLayerType(View.LAYER_TYPE_NONE, null)
+                    viewToFade.setTag(R.id.view_group_fade_helper_hardware_layer, null)
+                }
+                viewToFade.setTag(R.id.view_group_fade_helper_restore_tag, null)
+            }
+            root.setTag(R.id.view_group_fade_helper_modified_views, null)
+            root.setTag(R.id.view_group_fade_helper_previous_value_tag, null)
+            root.setTag(R.id.view_group_fade_helper_animator, null)
+        }
+    }
+}
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 fb10084..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
@@ -122,8 +122,6 @@
             } else if (aHeadsUp) {
                 // Provide consistent ranking with headsUpManager
                 return mHeadsUpManager.compare(a, b);
-            } else if (a.getRow().showingAmbientPulsing() != b.getRow().showingAmbientPulsing()) {
-                return a.getRow().showingAmbientPulsing() ? -1 : 1;
             } else if (aMedia != bMedia) {
                 // Upsort current media notification.
                 return aMedia ? -1 : 1;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotificationEntry.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotificationEntry.java
index d157f06c..fe88541 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotificationEntry.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotificationEntry.java
@@ -96,6 +96,7 @@
     public StatusBarIconView icon;
     public StatusBarIconView expandedIcon;
     public StatusBarIconView centeredIcon;
+    public StatusBarIconView aodIcon;
     private boolean interruption;
     public boolean autoRedacted; // whether the redacted notification was generated by us
     public int targetSdk;
@@ -175,6 +176,11 @@
 
     private boolean mIsTopBucket;
 
+    private boolean mSensitive = true;
+    private Runnable mOnSensitiveChangedListener;
+    private boolean mAutoHeadsUp;
+    private boolean mPulseSupressed;
+
     public NotificationEntry(StatusBarNotification n) {
         this(n, null);
     }
@@ -350,6 +356,12 @@
                 sbn.getPackageName() + "/0x" + Integer.toHexString(sbn.getId()), sbn);
         expandedIcon.setScaleType(ImageView.ScaleType.CENTER_INSIDE);
 
+        // Construct the expanded icon.
+        aodIcon = new StatusBarIconView(context,
+                sbn.getPackageName() + "/0x" + Integer.toHexString(sbn.getId()), sbn);
+        aodIcon.setScaleType(ImageView.ScaleType.CENTER_INSIDE);
+        aodIcon.setIncreasedSize(true);
+
         final StatusBarIcon ic = new StatusBarIcon(
                 sbn.getUser(),
                 sbn.getPackageName(),
@@ -358,10 +370,11 @@
                 n.number,
                 StatusBarIconView.contentDescForNotification(context, n));
 
-        if (!icon.set(ic) || !expandedIcon.set(ic)) {
+        if (!icon.set(ic) || !expandedIcon.set(ic) || !aodIcon.set(ic)) {
             icon = null;
             expandedIcon = null;
             centeredIcon = null;
+            aodIcon = null;
             throw new InflationException("Couldn't create icon: " + ic);
         }
         expandedIcon.setVisibility(View.INVISIBLE);
@@ -394,6 +407,10 @@
         if (centeredIcon != null) {
             centeredIcon.setTag(key, tag);
         }
+
+        if (aodIcon != null) {
+            aodIcon.setTag(key, tag);
+        }
     }
 
     /**
@@ -417,7 +434,8 @@
                     StatusBarIconView.contentDescForNotification(context, n));
             icon.setNotification(sbn);
             expandedIcon.setNotification(sbn);
-            if (!icon.set(ic) || !expandedIcon.set(ic)) {
+            aodIcon.setNotification(sbn);
+            if (!icon.set(ic) || !expandedIcon.set(ic) || !aodIcon.set(ic)) {
                 throw new InflationException("Couldn't update icon: " + ic);
             }
 
@@ -629,10 +647,6 @@
         if (row != null) row.freeContentViewWhenSafe(inflationFlag);
     }
 
-    public void setAmbientPulsing(boolean pulsing) {
-        if (row != null) row.setAmbientPulsing(pulsing);
-    }
-
     public boolean rowExists() {
         return row != null;
     }
@@ -661,23 +675,37 @@
         if (row != null) row.setPinned(pinned);
     }
 
-    public boolean isRowAnimatingAway() {
-        return row != null && row.isHeadsUpAnimatingAway();
-    }
-
     public boolean isRowHeadsUp() {
         return row != null && row.isHeadsUp();
     }
 
+    public boolean showingPulsing() {
+        return row != null && row.showingPulsing();
+    }
+
     public void setHeadsUp(boolean shouldHeadsUp) {
         if (row != null) row.setHeadsUp(shouldHeadsUp);
     }
 
-
-    public void setAmbientGoingAway(boolean goingAway) {
-        if (row != null) row.setAmbientGoingAway(goingAway);
+    public void setHeadsUpAnimatingAway(boolean animatingAway) {
+        if (row != null) row.setHeadsUpAnimatingAway(animatingAway);
     }
 
+    /**
+     * Set that this notification was automatically heads upped. This happens for example when
+     * the user bypasses the lockscreen and media is playing.
+     */
+    public void setAutoHeadsUp(boolean autoHeadsUp) {
+        mAutoHeadsUp = autoHeadsUp;
+    }
+
+    /**
+     * @return if this notification was automatically heads upped. This happens for example when
+     *      * the user bypasses the lockscreen and media is playing.
+     */
+    public boolean isAutoHeadsUp() {
+        return mAutoHeadsUp;
+    }
 
     public boolean mustStayOnScreen() {
         return row != null && row.mustStayOnScreen();
@@ -864,6 +892,38 @@
         return Objects.equals(n.category, category);
     }
 
+    /**
+     * Set this notification to be sensitive.
+     *
+     * @param sensitive true if the content of this notification is sensitive right now
+     * @param deviceSensitive true if the device in general is sensitive right now
+     */
+    public void setSensitive(boolean sensitive, boolean deviceSensitive) {
+        getRow().setSensitive(sensitive, deviceSensitive);
+        if (sensitive != mSensitive) {
+            mSensitive = sensitive;
+            if (mOnSensitiveChangedListener != null) {
+                mOnSensitiveChangedListener.run();
+            }
+        }
+    }
+
+    public boolean isSensitive() {
+        return mSensitive;
+    }
+
+    public void setOnSensitiveChangedListener(Runnable listener) {
+        mOnSensitiveChangedListener = listener;
+    }
+
+    public boolean isPulseSuppressed() {
+        return mPulseSupressed;
+    }
+
+    public void setPulseSuppressed(boolean suppressed) {
+        mPulseSupressed = suppressed;
+    }
+
     /** Information about a suggestion that is being edited. */
     public static class EditedSuggestionInfo {
 
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotificationRowBinderImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotificationRowBinderImpl.java
index d3e5af8..247c31f 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotificationRowBinderImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotificationRowBinderImpl.java
@@ -18,7 +18,6 @@
 
 import static com.android.internal.util.Preconditions.checkNotNull;
 import static com.android.systemui.statusbar.NotificationRemoteInputManager.ENABLE_REMOTE_INPUT;
-import static com.android.systemui.statusbar.notification.row.NotificationContentInflater.FLAG_CONTENT_VIEW_AMBIENT;
 import static com.android.systemui.statusbar.notification.row.NotificationContentInflater.FLAG_CONTENT_VIEW_HEADS_UP;
 
 import android.annotation.Nullable;
@@ -34,6 +33,7 @@
 import com.android.systemui.Dependency;
 import com.android.systemui.R;
 import com.android.systemui.UiOffloadThread;
+import com.android.systemui.plugins.statusbar.StatusBarStateController;
 import com.android.systemui.statusbar.NotificationLockscreenUserManager;
 import com.android.systemui.statusbar.NotificationPresenter;
 import com.android.systemui.statusbar.NotificationRemoteInputManager;
@@ -47,6 +47,7 @@
 import com.android.systemui.statusbar.notification.row.NotificationGutsManager;
 import com.android.systemui.statusbar.notification.row.RowInflaterTask;
 import com.android.systemui.statusbar.notification.stack.NotificationListContainer;
+import com.android.systemui.statusbar.phone.KeyguardBypassController;
 import com.android.systemui.statusbar.phone.NotificationGroupManager;
 import com.android.systemui.statusbar.phone.StatusBar;
 import com.android.systemui.statusbar.policy.HeadsUpManager;
@@ -69,6 +70,8 @@
     private final ExpandableNotificationRow.ExpansionLogger mExpansionLogger =
             this::logNotificationExpansion;
     private final boolean mAllowLongPress;
+    private final KeyguardBypassController mKeyguardBypassController;
+    private final StatusBarStateController mStatusBarStateController;
 
     private NotificationRemoteInputManager mRemoteInputManager;
     private NotificationPresenter mPresenter;
@@ -80,10 +83,14 @@
     private NotificationClicker mNotificationClicker;
     private final NotificationLogger mNotificationLogger = Dependency.get(NotificationLogger.class);
 
-    public NotificationRowBinderImpl(Context context, boolean allowLongPress) {
+    public NotificationRowBinderImpl(Context context, boolean allowLongPress,
+            KeyguardBypassController keyguardBypassController,
+            StatusBarStateController statusBarStateController) {
         mContext = context;
         mMessagingUtil = new NotificationMessagingUtil(context);
         mAllowLongPress = allowLongPress;
+        mKeyguardBypassController = keyguardBypassController;
+        mStatusBarStateController = statusBarStateController;
     }
 
     private NotificationRemoteInputManager getRemoteInputManager() {
@@ -144,6 +151,8 @@
             StatusBarNotification sbn, ExpandableNotificationRow row,
             Runnable onDismissRunnable) {
         row.setExpansionLogger(mExpansionLogger, entry.notification.getKey());
+        row.setBypassController(mKeyguardBypassController);
+        row.setStatusBarStateController(mStatusBarStateController);
         row.setGroupManager(mGroupManager);
         row.setHeadsUpManager(mHeadsUpManager);
         row.setOnExpandClickListener(mPresenter);
@@ -249,9 +258,6 @@
         if (mNotificationInterruptionStateProvider.shouldHeadsUp(entry)) {
             row.updateInflationFlag(FLAG_CONTENT_VIEW_HEADS_UP, true /* shouldInflate */);
         }
-        if (mNotificationInterruptionStateProvider.shouldPulse(entry)) {
-            row.updateInflationFlag(FLAG_CONTENT_VIEW_AMBIENT, true /* shouldInflate */);
-        }
         row.setNeedsRedaction(
                 Dependency.get(NotificationLockscreenUserManager.class).needsRedaction(entry));
         row.inflateViews();
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/logging/NotificationLogger.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/logging/NotificationLogger.java
index 94f7e65..81275fd 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/logging/NotificationLogger.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/logging/NotificationLogger.java
@@ -101,7 +101,7 @@
 
     // Tracks notifications currently visible in mNotificationStackScroller and
     // emits visibility events via NoMan on changes.
-    protected final Runnable mVisibilityReporter = new Runnable() {
+    protected Runnable mVisibilityReporter = new Runnable() {
         private final ArraySet<NotificationVisibility> mTmpNewlyVisibleNotifications =
                 new ArraySet<>();
         private final ArraySet<NotificationVisibility> mTmpCurrentlyVisibleNotifications =
@@ -407,6 +407,11 @@
         mExpansionStateLogger.onExpansionChanged(key, isUserAction, isExpanded, location);
     }
 
+    @VisibleForTesting
+    public void setVisibilityReporter(Runnable visibilityReporter) {
+        mVisibilityReporter = visibilityReporter;
+    }
+
     /**
      * A listener that is notified when some child locations might have changed.
      */
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ActivatableNotificationView.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ActivatableNotificationView.java
index 94face2..dca152f 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ActivatableNotificationView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ActivatableNotificationView.java
@@ -52,7 +52,6 @@
 
     private static final int BACKGROUND_ANIMATION_LENGTH_MS = 220;
     private static final int ACTIVATE_ANIMATION_LENGTH = 220;
-    private static final long DARK_ANIMATION_LENGTH = StackStateAnimator.ANIMATION_DURATION_WAKEUP;
 
     /**
      * The amount of width, which is kept in the end when performing a disappear animation (also
@@ -85,11 +84,6 @@
     private static final float VERTICAL_ANIMATION_START = 1.0f;
 
     /**
-     * Scale for the background to animate from when exiting dark mode.
-     */
-    private static final float DARK_EXIT_SCALE_START = 0.93f;
-
-    /**
      * A sentinel value when no color should be used. Can be used with {@link #setTintColor(int)}
      * or {@link #setOverrideTintColor(int, float)}.
      */
@@ -105,7 +99,6 @@
     private final DoubleTapHelper mDoubleTapHelper;
 
     private boolean mDimmed;
-    protected boolean mDark;
 
     protected int mBgTint = NO_COLOR;
     private float mBgAlpha = 1f;
@@ -440,16 +433,6 @@
         return true;
     }
 
-    public void setDark(boolean dark, boolean fade, long delay) {
-        super.setDark(dark, fade, delay);
-        if (mDark == dark) {
-            return;
-        }
-        mDark = dark;
-        updateBackground();
-        updateBackgroundTint(false);
-    }
-
     private void updateOutlineAlpha() {
         float alpha = NotificationStackScrollLayout.BACKGROUND_ALPHA_DIMMED;
         alpha = (alpha + (1.0f - alpha) * mNormalBackgroundVisibilityAmount);
@@ -542,10 +525,6 @@
      *                       used and the background color not at all.
      */
     public void setOverrideTintColor(int color, float overrideAmount) {
-        if (mDark) {
-            color = NO_COLOR;
-            overrideAmount = 0;
-        }
         mOverrideTint = color;
         mOverrideAmount = overrideAmount;
         int newColor = calculateBgColor();
@@ -1057,6 +1036,14 @@
         return false;
     }
 
+    public boolean isHeadsUp() {
+        return false;
+    }
+
+    public int getHeadsUpHeightWithoutHeader() {
+        return getHeight();
+    }
+
     public interface OnActivatedListener {
         void onActivated(ActivatableNotificationView view);
         void onActivationReset(ActivatableNotificationView view);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ChannelEditorDialogController.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ChannelEditorDialogController.kt
index 8e68227..782aad1 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ChannelEditorDialogController.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ChannelEditorDialogController.kt
@@ -23,6 +23,7 @@
 import android.app.NotificationChannelGroup
 import android.app.NotificationManager.IMPORTANCE_NONE
 import android.content.Context
+import android.content.DialogInterface
 import android.graphics.Color
 import android.graphics.PixelFormat
 import android.graphics.drawable.Drawable
@@ -171,7 +172,6 @@
     private fun done() {
         resetState()
         dialog.dismiss()
-        onFinishListener?.onChannelEditorDialogFinished()
     }
 
     private fun resetState() {
@@ -261,6 +261,11 @@
         dialog.apply {
             setContentView(R.layout.notif_half_shelf)
             setCanceledOnTouchOutside(true)
+            setOnDismissListener(object : DialogInterface.OnDismissListener {
+                override fun onDismiss(dialog: DialogInterface?) {
+                    onFinishListener?.onChannelEditorDialogFinished()
+                }
+            })
             findViewById<ChannelEditorListView>(R.id.half_shelf_container).apply {
                 controller = this@ChannelEditorDialogController
                 appIcon = this@ChannelEditorDialogController.appIcon
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 d625b31..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
@@ -17,11 +17,9 @@
 package com.android.systemui.statusbar.notification.row;
 
 import static com.android.systemui.statusbar.notification.ActivityLaunchAnimator.ExpandAnimationParameters;
-import static com.android.systemui.statusbar.notification.row.NotificationContentInflater.FLAG_CONTENT_VIEW_AMBIENT;
 import static com.android.systemui.statusbar.notification.row.NotificationContentInflater.FLAG_CONTENT_VIEW_HEADS_UP;
 import static com.android.systemui.statusbar.notification.row.NotificationContentInflater.FLAG_CONTENT_VIEW_PUBLIC;
 import static com.android.systemui.statusbar.notification.row.NotificationContentInflater.InflationCallback;
-import static com.android.systemui.statusbar.notification.row.NotificationContentView.VISIBLE_TYPE_AMBIENT;
 import static com.android.systemui.statusbar.notification.row.NotificationContentView.VISIBLE_TYPE_CONTRACTED;
 import static com.android.systemui.statusbar.notification.row.NotificationContentView.VISIBLE_TYPE_HEADSUP;
 
@@ -81,6 +79,7 @@
 import com.android.systemui.plugins.PluginListener;
 import com.android.systemui.plugins.statusbar.NotificationMenuRowPlugin;
 import com.android.systemui.plugins.statusbar.NotificationMenuRowPlugin.MenuItem;
+import com.android.systemui.plugins.statusbar.StatusBarStateController;
 import com.android.systemui.shared.plugins.PluginManager;
 import com.android.systemui.statusbar.NotificationMediaManager;
 import com.android.systemui.statusbar.RemoteInputController;
@@ -98,6 +97,7 @@
 import com.android.systemui.statusbar.notification.stack.ExpandableViewState;
 import com.android.systemui.statusbar.notification.stack.NotificationChildrenContainer;
 import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayout;
+import com.android.systemui.statusbar.phone.KeyguardBypassController;
 import com.android.systemui.statusbar.phone.NotificationGroupManager;
 import com.android.systemui.statusbar.phone.StatusBar;
 import com.android.systemui.statusbar.policy.HeadsUpManager;
@@ -127,14 +127,16 @@
     private static final long RECENTLY_ALERTED_THRESHOLD_MS = TimeUnit.SECONDS.toMillis(30);
     private boolean mUpdateBackgroundOnUpdate;
     private boolean mNotificationTranslationFinished = false;
-
     /**
      * Listener for when {@link ExpandableNotificationRow} is laid out.
      */
     public interface LayoutListener {
         void onLayout();
+
     }
 
+    private StatusBarStateController mStatusbarStateController;
+    private KeyguardBypassController mBypassController;
     private LayoutListener mLayoutListener;
     private final NotificationContentInflater mNotificationInflater;
     private int mIconTransformContentShift;
@@ -187,11 +189,6 @@
      */
     private boolean mOnKeyguard;
 
-    /**
-     * Whether or not the row is currently on the doze screen.
-     */
-    private boolean mOnAmbient;
-
     private Animator mTranslateAnim;
     private ArrayList<View> mTranslateableViews;
     private NotificationContentView mPublicLayout;
@@ -211,17 +208,6 @@
     private boolean mIsHeadsUp;
 
     /**
-     * Whether or not the notification is using the ambient display view and is pulsing.  This
-     * occurs when a high priority notification alerts while the phone is dozing or is on AOD.
-     */
-    private boolean mIsAmbientPulsing;
-
-    /**
-     * Happens when the notification was pulsing before and goes away to ensure smooth animations.
-     */
-    private boolean mAmbientGoingAway;
-
-    /**
      * Whether or not the notification should be redacted on the lock screen, i.e has sensitive
      * content which should be redacted on the lock screen.
      */
@@ -341,7 +327,6 @@
 
     private SystemNotificationAsyncTask mSystemNotificationAsyncTask =
             new SystemNotificationAsyncTask();
-    private int mStatusBarState = -1;
 
     /**
      * Returns whether the given {@code statusBarNotification} is a system notification.
@@ -487,12 +472,6 @@
                 getPrivateLayout().performWhenContentInactive(VISIBLE_TYPE_HEADSUP,
                         freeViewRunnable);
                 break;
-            case FLAG_CONTENT_VIEW_AMBIENT:
-                getPrivateLayout().performWhenContentInactive(VISIBLE_TYPE_AMBIENT,
-                        freeViewRunnable);
-                getPublicLayout().performWhenContentInactive(VISIBLE_TYPE_AMBIENT,
-                        freeViewRunnable);
-                break;
             case FLAG_CONTENT_VIEW_PUBLIC:
                 getPublicLayout().performWhenContentInactive(VISIBLE_TYPE_CONTRACTED,
                         freeViewRunnable);
@@ -648,7 +627,7 @@
         if (!getShowingLayout().isDimmable()) {
             return false;
         }
-        if (showingAmbientPulsing()) {
+        if (showingPulsing()) {
             return false;
         }
         return super.isDimmable();
@@ -698,7 +677,7 @@
         if (headsUpWrapper != null) {
             headsUpHeight = Math.max(headsUpHeight, headsUpWrapper.getMinLayoutHeight());
         }
-        layout.setHeights(minHeight, headsUpHeight, mNotificationMaxHeight, headsUpHeight);
+        layout.setHeights(minHeight, headsUpHeight, mNotificationMaxHeight);
     }
 
     public StatusBarNotification getStatusBarNotification() {
@@ -709,6 +688,7 @@
         return mEntry;
     }
 
+    @Override
     public boolean isHeadsUp() {
         return mIsHeadsUp;
     }
@@ -734,14 +714,18 @@
     }
 
     @Override
-    public boolean showingAmbientPulsing() {
-        return mIsAmbientPulsing || mAmbientGoingAway;
+    public boolean showingPulsing() {
+        return isHeadsUpState() && (isDozing() || (mOnKeyguard && isBypassEnabled()));
     }
 
-    public void setAmbientPulsing(boolean isAmbientPulsing) {
-        mIsAmbientPulsing = isAmbientPulsing;
+    /**
+     * @return if the view is in heads up state, i.e either still heads upped or it's disappearing.
+     */
+    public boolean isHeadsUpState() {
+        return mIsHeadsUp || mHeadsupDisappearRunning;
     }
 
+
     public void setGroupManager(NotificationGroupManager groupManager) {
         mGroupManager = groupManager;
         mPrivateLayout.setGroupManager(groupManager);
@@ -1383,7 +1367,9 @@
         if (isChildInGroup()) {
             mTranslationWhenRemoved += getNotificationParent().getTranslationY();
         }
-        mPrivateLayout.setRemoved();
+        for (NotificationContentView l : mLayouts) {
+            l.setRemoved();
+        }
     }
 
     public boolean wasChildInGroupWhenRemoved() {
@@ -1660,6 +1646,14 @@
         initDimens();
     }
 
+    public void setBypassController(KeyguardBypassController bypassController) {
+        mBypassController = bypassController;
+    }
+
+    public void setStatusBarStateController(StatusBarStateController statusBarStateController) {
+        mStatusbarStateController = statusBarStateController;
+    }
+
     private void initDimens() {
         mNotificationMinHeightBeforeN = NotificationUtils.getFontScaledHeight(mContext,
                 R.dimen.notification_min_height_legacy);
@@ -2050,23 +2044,6 @@
         return false;
     }
 
-    @Override
-    public void setDark(boolean dark, boolean fade, long delay) {
-        if (mDark == dark) {
-            return;
-        }
-        super.setDark(dark, fade, delay);
-        if (!mIsAmbientPulsing) {
-            // Only fade the showing view of the pulsing notification.
-            fade = false;
-        }
-        final NotificationContentView showing = getShowingLayout();
-        if (showing != null) {
-            showing.setDark(dark, fade, delay);
-        }
-        updateShelfIconColor();
-    }
-
     public void applyExpandAnimationParams(ExpandAnimationParameters params) {
         if (params == null) {
             return;
@@ -2180,7 +2157,9 @@
      */
     @Override
     public boolean isSoundEffectsEnabled() {
-        final boolean mute = mDark && mSecureStateProvider != null &&
+        final boolean mute = mStatusbarStateController != null
+                && mStatusbarStateController.isDozing()
+                && mSecureStateProvider != null &&
                 !mSecureStateProvider.getAsBoolean();
         return !mute && super.isSoundEffectsEnabled();
     }
@@ -2345,9 +2324,9 @@
             return mPrivateLayout.getMinHeight();
         } else if (mSensitive && mHideSensitiveForIntrinsicHeight) {
             return getMinHeight();
-        } else if (mIsSummaryWithChildren && !mOnKeyguard) {
+        } else if (mIsSummaryWithChildren) {
             return mChildrenContainer.getIntrinsicHeight();
-        } else if (isHeadsUpAllowed() && (mIsHeadsUp || mHeadsupDisappearRunning)) {
+        } else if (canShowHeadsUp() && isHeadsUpState()) {
             if (isPinned() || mHeadsupDisappearRunning) {
                 return getPinnedHeadsUpHeight(true /* atLeastMinHeight */);
             } else if (isExpanded()) {
@@ -2362,24 +2341,29 @@
         }
     }
 
-    private boolean isHeadsUpAllowed() {
-        return !mOnKeyguard && !mOnAmbient;
+    /**
+     * @return {@code true} if the notification can show it's heads up layout. This is mostly true
+     *         except for legacy use cases.
+     */
+    public boolean canShowHeadsUp() {
+        if (mOnKeyguard && !isDozing() && !isBypassEnabled()) {
+            return false;
+        }
+        return true;
+    }
+
+    private boolean isBypassEnabled() {
+        return mBypassController == null || mBypassController.getBypassEnabled();
+    }
+
+    private boolean isDozing() {
+        return mStatusbarStateController != null && mStatusbarStateController.isDozing();
     }
 
     private boolean isShownAsBubble() {
         return mEntry.isBubble() && !mEntry.showInShadeWhenBubble() && !mEntry.isBubbleDismissed();
     }
 
-    /**
-     * Set the current status bar state.
-     * @param state should be from {@link com.android.systemui.statusbar.StatusBarState}.
-     */
-    public void setStatusBarState(int state) {
-        if (mStatusBarState != state) {
-            mStatusBarState = state;
-        }
-    }
-
     @Override
     public boolean isGroupExpanded() {
         return mGroupManager.isGroupExpanded(mStatusBarNotification);
@@ -2563,7 +2547,6 @@
         showingLayout.updateBackgroundColor(animated);
         mPrivateLayout.updateExpandButtons(isExpandable());
         updateShelfIconColor();
-        showingLayout.setDark(isDark(), false /* animate */, 0 /* delay */);
         mShowingPublicInitialized = true;
     }
 
@@ -2656,7 +2639,7 @@
 
 
     private int getHeadsUpHeight() {
-        return getShowingLayout().getHeadsUpHeight();
+        return getShowingLayout().getHeadsUpHeight(false /* forceNoHeader */);
     }
 
     public boolean areGutsExposed() {
@@ -2717,6 +2700,8 @@
                 l.setAlpha(1.0f);
                 l.setLayerType(LAYER_TYPE_NONE, null);
             }
+        } else {
+            setHeadsUpAnimatingAway(false);
         }
     }
 
@@ -2773,12 +2758,12 @@
     public int getMinHeight(boolean ignoreTemporaryStates) {
         if (!ignoreTemporaryStates && mGuts != null && mGuts.isExposed()) {
             return mGuts.getIntrinsicHeight();
-        } else if (!ignoreTemporaryStates && isHeadsUpAllowed() && mIsHeadsUp
+        } else if (!ignoreTemporaryStates && canShowHeadsUp() && mIsHeadsUp
                 && mHeadsUpManager.isTrackingHeadsUp()) {
                 return getPinnedHeadsUpHeight(false /* atLeastMinHeight */);
         } else if (mIsSummaryWithChildren && !isGroupExpanded() && !shouldShowPublic()) {
             return mChildrenContainer.getMinHeight();
-        } else if (!ignoreTemporaryStates && isHeadsUpAllowed() && mIsHeadsUp) {
+        } else if (!ignoreTemporaryStates && canShowHeadsUp() && mIsHeadsUp) {
             return getHeadsUpHeight();
         }
         NotificationContentView showingLayout = getShowingLayout();
@@ -2794,6 +2779,17 @@
     }
 
     @Override
+    public int getHeadsUpHeightWithoutHeader() {
+        if (!canShowHeadsUp() || !mIsHeadsUp) {
+            return getCollapsedHeight();
+        }
+        if (mIsSummaryWithChildren && !shouldShowPublic()) {
+            return mChildrenContainer.getCollapsedHeightWithoutHeader();
+        }
+        return getShowingLayout().getHeadsUpHeight(true /* forceNoHeader */);
+    }
+
+    @Override
     public void setClipTopAmount(int clipTopAmount) {
         super.setClipTopAmount(clipTopAmount);
         for (NotificationContentView l : mLayouts) {
@@ -3050,18 +3046,11 @@
 
     @Override
     public boolean isAboveShelf() {
-        return showingAmbientPulsing() || (!isOnKeyguard()
+        return (canShowHeadsUp()
                 && (mIsPinned || mHeadsupDisappearRunning || (mIsHeadsUp && mAboveShelf)
                 || mExpandAnimationRunning || mChildIsExpanding));
     }
 
-    public void setOnAmbient(boolean onAmbient) {
-        if (onAmbient != mOnAmbient) {
-            mOnAmbient = onAmbient;
-            notifyHeightChanged(false /* needsAnimation */);
-        }
-    }
-
     @Override
     public boolean topAmountNeedsClipping() {
         if (isGroupExpanded()) {
@@ -3125,10 +3114,6 @@
         return getCurrentBottomRoundness() == 0.0f && getCurrentTopRoundness() == 0.0f;
     }
 
-    public boolean isOnAmbient() {
-        return mOnAmbient;
-    }
-
     //TODO: this logic can't depend on layout if we are recycling!
     public boolean isMediaRow() {
         return getExpandedContentView() != null
@@ -3206,10 +3191,6 @@
         }
     }
 
-    public void setAmbientGoingAway(boolean goingAway) {
-        mAmbientGoingAway = goingAway;
-    }
-
     /**
      * Returns the Smart Suggestions backing the smart suggestion buttons in the notification.
      */
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableView.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableView.java
index cac41da..a0fef00 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableView.java
@@ -49,7 +49,6 @@
     protected int mClipBottomAmount;
     protected int mMinimumHeightForClipping = 0;
     protected float mExtraWidthForClipping = 0;
-    private boolean mDark;
     private ArrayList<View> mMatchParentViews = new ArrayList<View>();
     private static Rect mClipRect = new Rect();
     private boolean mWillBeGone;
@@ -212,21 +211,6 @@
     public void setDimmed(boolean dimmed, boolean fade) {
     }
 
-    /**
-     * Sets the notification as dark. The default implementation does nothing.
-     *
-     * @param dark Whether the notification should be dark.
-     * @param fade Whether an animation should be played to change the state.
-     * @param delay If fading, the delay of the animation.
-     */
-    public void setDark(boolean dark, boolean fade, long delay) {
-        mDark = dark;
-    }
-
-    public boolean isDark() {
-        return mDark;
-    }
-
     public boolean isRemoved() {
         return false;
     }
@@ -527,7 +511,7 @@
     public void setHeadsUpIsVisible() {
     }
 
-    public boolean showingAmbientPulsing() {
+    public boolean showingPulsing() {
         return false;
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationContentInflater.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationContentInflater.java
index 396cd73..48a8295 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationContentInflater.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationContentInflater.java
@@ -16,7 +16,6 @@
 
 package com.android.systemui.statusbar.notification.row;
 
-import static com.android.systemui.statusbar.notification.row.NotificationContentView.VISIBLE_TYPE_AMBIENT;
 import static com.android.systemui.statusbar.notification.row.NotificationContentView.VISIBLE_TYPE_CONTRACTED;
 import static com.android.systemui.statusbar.notification.row.NotificationContentView.VISIBLE_TYPE_HEADSUP;
 
@@ -51,12 +50,6 @@
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
 import java.util.HashMap;
-import java.util.concurrent.Executor;
-import java.util.concurrent.LinkedBlockingQueue;
-import java.util.concurrent.ThreadFactory;
-import java.util.concurrent.ThreadPoolExecutor;
-import java.util.concurrent.TimeUnit;
-import java.util.concurrent.atomic.AtomicInteger;
 
 /**
  * A utility that inflates the right kind of contentView based on the state
@@ -72,7 +65,6 @@
                 FLAG_CONTENT_VIEW_CONTRACTED,
                 FLAG_CONTENT_VIEW_EXPANDED,
                 FLAG_CONTENT_VIEW_HEADS_UP,
-                FLAG_CONTENT_VIEW_AMBIENT,
                 FLAG_CONTENT_VIEW_PUBLIC,
                 FLAG_CONTENT_VIEW_ALL})
     public @interface InflationFlag {}
@@ -93,17 +85,11 @@
     public static final int FLAG_CONTENT_VIEW_HEADS_UP = 1 << 2;
 
     /**
-     * The ambient view.  Seen when a high priority notification is received and the phone
-     * is dozing.
-     */
-    public static final int FLAG_CONTENT_VIEW_AMBIENT = 1 << 3;
-
-    /**
      * The public view.  This is a version of the contracted view that hides sensitive
      * information and is used on the lock screen if we determine that the notification's
      * content should be hidden.
      */
-    public static final int FLAG_CONTENT_VIEW_PUBLIC = 1 << 4;
+    public static final int FLAG_CONTENT_VIEW_PUBLIC = 1 << 3;
 
     public static final int FLAG_CONTENT_VIEW_ALL = ~0;
 
@@ -128,7 +114,6 @@
     private RemoteViews.OnClickHandler mRemoteViewClickHandler;
     private boolean mIsChildInGroup;
     private InflationCallback mCallback;
-    private boolean mRedactAmbient;
     private boolean mInflateSynchronously = false;
     private final ArrayMap<Integer, RemoteViews> mCachedContentViews = new ArrayMap<>();
 
@@ -169,21 +154,18 @@
 
     /**
      * Update whether or not the notification is redacted on the lock screen.  If the notification
-     * is now redacted, we should inflate the public contracted view and public ambient view to
-     * now show on the lock screen.
+     * is now redacted, we should inflate the public contracted view to now show on the lock screen.
      *
      * @param needsRedaction true if the notification should now be redacted on the lock screen
      */
     public void updateNeedsRedaction(boolean needsRedaction) {
-        mRedactAmbient = needsRedaction;
         if (mRow.getEntry() == null) {
             return;
         }
-        int flags = FLAG_CONTENT_VIEW_AMBIENT;
         if (needsRedaction) {
-            flags |= FLAG_CONTENT_VIEW_PUBLIC;
+            int flags = FLAG_CONTENT_VIEW_PUBLIC;
+            inflateNotificationViews(flags);
         }
-        inflateNotificationViews(flags);
     }
 
     /**
@@ -263,7 +245,6 @@
                 mIsChildInGroup,
                 mUsesIncreasedHeight,
                 mUsesIncreasedHeadsUpHeight,
-                mRedactAmbient,
                 mCallback,
                 mRemoteViewClickHandler);
         if (mInflateSynchronously) {
@@ -281,7 +262,7 @@
             Context packageContext) {
         InflationProgress result = createRemoteViews(reInflateFlags, builder, mIsLowPriority,
                 mIsChildInGroup, mUsesIncreasedHeight, mUsesIncreasedHeadsUpHeight,
-                mRedactAmbient, packageContext);
+                packageContext);
         result = inflateSmartReplyViews(result, reInflateFlags, mRow.getEntry(),
                 mRow.getContext(), mRow.getHeadsUpManager(),
                 mRow.getExistingSmartRepliesAndActions());
@@ -291,7 +272,6 @@
                 reInflateFlags,
                 mCachedContentViews,
                 mRow,
-                mRedactAmbient,
                 mRemoteViewClickHandler,
                 null);
         return result;
@@ -316,21 +296,6 @@
                     mRow.getPrivateLayout().setHeadsUpInflatedSmartReplies(null);
                 }
                 break;
-            case FLAG_CONTENT_VIEW_AMBIENT:
-                boolean privateSafeToRemove = mRow.getPrivateLayout().isContentViewInactive(
-                        VISIBLE_TYPE_AMBIENT);
-                boolean publicSafeToRemove = mRow.getPublicLayout().isContentViewInactive(
-                        VISIBLE_TYPE_AMBIENT);
-                if (privateSafeToRemove) {
-                    mRow.getPrivateLayout().setAmbientChild(null);
-                }
-                if (publicSafeToRemove) {
-                    mRow.getPublicLayout().setAmbientChild(null);
-                }
-                if (privateSafeToRemove && publicSafeToRemove) {
-                    mCachedContentViews.remove(FLAG_CONTENT_VIEW_AMBIENT);
-                }
-                break;
             case FLAG_CONTENT_VIEW_PUBLIC:
                 if (mRow.getPublicLayout().isContentViewInactive(VISIBLE_TYPE_CONTRACTED)) {
                     mRow.getPublicLayout().setContractedChild(null);
@@ -366,7 +331,7 @@
 
     private static InflationProgress createRemoteViews(@InflationFlag int reInflateFlags,
             Notification.Builder builder, boolean isLowPriority, boolean isChildInGroup,
-            boolean usesIncreasedHeight, boolean usesIncreasedHeadsUpHeight, boolean redactAmbient,
+            boolean usesIncreasedHeight, boolean usesIncreasedHeadsUpHeight,
             Context packageContext) {
         InflationProgress result = new InflationProgress();
         isLowPriority = isLowPriority && !isChildInGroup;
@@ -384,13 +349,9 @@
         }
 
         if ((reInflateFlags & FLAG_CONTENT_VIEW_PUBLIC) != 0) {
-            result.newPublicView = builder.makePublicContentView();
+            result.newPublicView = builder.makePublicContentView(isLowPriority);
         }
 
-        if ((reInflateFlags & FLAG_CONTENT_VIEW_AMBIENT) != 0) {
-            result.newAmbientView = redactAmbient ? builder.makePublicAmbientNotification()
-                    : builder.makeAmbientNotification();
-        }
         result.packageContext = packageContext;
         result.headsUpStatusBarText = builder.getHeadsUpStatusBarText(false /* showingPublic */);
         result.headsUpStatusBarTextPublic = builder.getHeadsUpStatusBarText(
@@ -404,7 +365,6 @@
             @InflationFlag int reInflateFlags,
             ArrayMap<Integer, RemoteViews> cachedContentViews,
             ExpandableNotificationRow row,
-            boolean redactAmbient,
             RemoteViews.OnClickHandler remoteViewClickHandler,
             @Nullable InflationCallback callback) {
         NotificationContentView privateLayout = row.getPrivateLayout();
@@ -428,7 +388,7 @@
                 }
             };
             applyRemoteView(inflateSynchronously, result, reInflateFlags, flag, cachedContentViews,
-                    row, redactAmbient, isNewView, remoteViewClickHandler, callback, privateLayout,
+                    row, isNewView, remoteViewClickHandler, callback, privateLayout,
                     privateLayout.getContractedChild(), privateLayout.getVisibleWrapper(
                             NotificationContentView.VISIBLE_TYPE_CONTRACTED),
                     runningInflations, applyCallback);
@@ -452,7 +412,7 @@
                     }
                 };
                 applyRemoteView(inflateSynchronously, result, reInflateFlags, flag,
-                        cachedContentViews, row, redactAmbient, isNewView, remoteViewClickHandler,
+                        cachedContentViews, row, isNewView, remoteViewClickHandler,
                         callback, privateLayout, privateLayout.getExpandedChild(),
                         privateLayout.getVisibleWrapper(
                                 NotificationContentView.VISIBLE_TYPE_EXPANDED), runningInflations,
@@ -478,7 +438,7 @@
                     }
                 };
                 applyRemoteView(inflateSynchronously, result, reInflateFlags, flag,
-                        cachedContentViews, row, redactAmbient, isNewView, remoteViewClickHandler,
+                        cachedContentViews, row, isNewView, remoteViewClickHandler,
                         callback, privateLayout, privateLayout.getHeadsUpChild(),
                         privateLayout.getVisibleWrapper(
                                 VISIBLE_TYPE_HEADSUP), runningInflations,
@@ -503,39 +463,14 @@
                 }
             };
             applyRemoteView(inflateSynchronously, result, reInflateFlags, flag, cachedContentViews,
-                    row, redactAmbient, isNewView, remoteViewClickHandler, callback,
+                    row, isNewView, remoteViewClickHandler, callback,
                     publicLayout, publicLayout.getContractedChild(),
                     publicLayout.getVisibleWrapper(NotificationContentView.VISIBLE_TYPE_CONTRACTED),
                     runningInflations, applyCallback);
         }
 
-        flag = FLAG_CONTENT_VIEW_AMBIENT;
-        if ((reInflateFlags & flag) != 0) {
-            NotificationContentView newParent = redactAmbient ? publicLayout : privateLayout;
-            boolean isNewView = (!canReapplyAmbient(row, redactAmbient)
-                    || !canReapplyRemoteView(result.newAmbientView,
-                            cachedContentViews.get(FLAG_CONTENT_VIEW_AMBIENT)));
-            ApplyCallback applyCallback = new ApplyCallback() {
-                @Override
-                public void setResultView(View v) {
-                    result.inflatedAmbientView = v;
-                }
-
-                @Override
-                public RemoteViews getRemoteView() {
-                    return result.newAmbientView;
-                }
-            };
-            applyRemoteView(inflateSynchronously, result, reInflateFlags, flag, cachedContentViews,
-                    row, redactAmbient, isNewView, remoteViewClickHandler, callback,
-                    newParent, newParent.getAmbientChild(), newParent.getVisibleWrapper(
-                            NotificationContentView.VISIBLE_TYPE_AMBIENT), runningInflations,
-                    applyCallback);
-        }
-
         // Let's try to finish, maybe nobody is even inflating anything
-        finishIfDone(result, reInflateFlags, cachedContentViews, runningInflations, callback, row,
-                redactAmbient);
+        finishIfDone(result, reInflateFlags, cachedContentViews, runningInflations, callback, row);
         CancellationSignal cancellationSignal = new CancellationSignal();
         cancellationSignal.setOnCancelListener(
                 () -> runningInflations.values().forEach(CancellationSignal::cancel));
@@ -550,7 +485,6 @@
             @InflationFlag int inflationId,
             final ArrayMap<Integer, RemoteViews> cachedContentViews,
             final ExpandableNotificationRow row,
-            final boolean redactAmbient,
             boolean isNewView,
             RemoteViews.OnClickHandler remoteViewClickHandler,
             @Nullable final InflationCallback callback,
@@ -603,7 +537,7 @@
                 }
                 runningInflations.remove(inflationId);
                 finishIfDone(result, reInflateFlags, cachedContentViews, runningInflations,
-                        callback, row, redactAmbient);
+                        callback, row);
             }
 
             @Override
@@ -670,8 +604,7 @@
     private static boolean finishIfDone(InflationProgress result,
             @InflationFlag int reInflateFlags, ArrayMap<Integer, RemoteViews> cachedContentViews,
             HashMap<Integer, CancellationSignal> runningInflations,
-            @Nullable InflationCallback endListener, ExpandableNotificationRow row,
-            boolean redactAmbient) {
+            @Nullable InflationCallback endListener, ExpandableNotificationRow row) {
         Assert.isMainThread();
         NotificationEntry entry = row.getEntry();
         NotificationContentView privateLayout = row.getPrivateLayout();
@@ -735,19 +668,6 @@
                 }
             }
 
-            if ((reInflateFlags & FLAG_CONTENT_VIEW_AMBIENT) != 0) {
-                if (result.inflatedAmbientView != null) {
-                    NotificationContentView newParent = redactAmbient
-                            ? publicLayout : privateLayout;
-                    NotificationContentView otherParent = !redactAmbient
-                            ? publicLayout : privateLayout;
-                    newParent.setAmbientChild(result.inflatedAmbientView);
-                    otherParent.setAmbientChild(null);
-                    cachedContentViews.put(FLAG_CONTENT_VIEW_AMBIENT, result.newAmbientView);
-                } else if (cachedContentViews.get(FLAG_CONTENT_VIEW_AMBIENT) != null) {
-                    cachedContentViews.put(FLAG_CONTENT_VIEW_AMBIENT, result.newAmbientView);
-                }
-            }
             entry.headsUpStatusBarText = result.headsUpStatusBarText;
             entry.headsUpStatusBarTextPublic = result.headsUpStatusBarTextPublic;
             if (endListener != null) {
@@ -827,12 +747,6 @@
         mInflateSynchronously = inflateSynchronously;
     }
 
-    private static boolean canReapplyAmbient(ExpandableNotificationRow row, boolean redactAmbient) {
-        NotificationContentView ambientView = redactAmbient ? row.getPublicLayout()
-                : row.getPrivateLayout();
-        return ambientView.getAmbientChild() != null;
-    }
-
     public static class AsyncInflationTask extends AsyncTask<Void, Void, InflationProgress>
             implements InflationCallback, InflationTask {
 
@@ -844,7 +758,6 @@
         private final boolean mUsesIncreasedHeight;
         private final InflationCallback mCallback;
         private final boolean mUsesIncreasedHeadsUpHeight;
-        private final boolean mRedactAmbient;
         private @InflationFlag int mReInflateFlags;
         private final ArrayMap<Integer, RemoteViews> mCachedContentViews;
         private ExpandableNotificationRow mRow;
@@ -862,7 +775,6 @@
                 boolean isChildInGroup,
                 boolean usesIncreasedHeight,
                 boolean usesIncreasedHeadsUpHeight,
-                boolean redactAmbient,
                 InflationCallback callback,
                 RemoteViews.OnClickHandler remoteViewClickHandler) {
             mRow = row;
@@ -875,7 +787,6 @@
             mIsChildInGroup = isChildInGroup;
             mUsesIncreasedHeight = usesIncreasedHeight;
             mUsesIncreasedHeadsUpHeight = usesIncreasedHeadsUpHeight;
-            mRedactAmbient = redactAmbient;
             mRemoteViewClickHandler = remoteViewClickHandler;
             mCallback = callback;
             NotificationEntry entry = row.getEntry();
@@ -903,9 +814,8 @@
                     processor.processNotification(notification, recoveredBuilder);
                 }
                 InflationProgress inflationProgress = createRemoteViews(mReInflateFlags,
-                        recoveredBuilder, mIsLowPriority,
-                        mIsChildInGroup, mUsesIncreasedHeight, mUsesIncreasedHeadsUpHeight,
-                        mRedactAmbient, packageContext);
+                        recoveredBuilder, mIsLowPriority, mIsChildInGroup, mUsesIncreasedHeight,
+                        mUsesIncreasedHeadsUpHeight, packageContext);
                 return inflateSmartReplyViews(inflationProgress, mReInflateFlags, mRow.getEntry(),
                         mRow.getContext(), mRow.getHeadsUpManager(),
                         mRow.getExistingSmartRepliesAndActions());
@@ -919,7 +829,7 @@
         protected void onPostExecute(InflationProgress result) {
             if (mError == null) {
                 mCancellationSignal = apply(mInflateSynchronously, result, mReInflateFlags,
-                        mCachedContentViews, mRow, mRedactAmbient, mRemoteViewClickHandler, this);
+                        mCachedContentViews, mRow, mRemoteViewClickHandler, this);
             } else {
                 handleError(mError);
             }
@@ -974,7 +884,6 @@
         private RemoteViews newContentView;
         private RemoteViews newHeadsUpView;
         private RemoteViews newExpandedView;
-        private RemoteViews newAmbientView;
         private RemoteViews newPublicView;
 
         @VisibleForTesting
@@ -983,7 +892,6 @@
         private View inflatedContentView;
         private View inflatedHeadsUpView;
         private View inflatedExpandedView;
-        private View inflatedAmbientView;
         private View inflatedPublicView;
         private CharSequence headsUpStatusBarText;
         private CharSequence headsUpStatusBarTextPublic;
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 354ed2d..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
@@ -71,7 +71,6 @@
     public static final int VISIBLE_TYPE_EXPANDED = 1;
     public static final int VISIBLE_TYPE_HEADSUP = 2;
     private static final int VISIBLE_TYPE_SINGLELINE = 3;
-    public static final int VISIBLE_TYPE_AMBIENT = 4;
     public static final int UNDEFINED = -1;
 
     private final Rect mClipBounds = new Rect();
@@ -82,7 +81,6 @@
     private View mExpandedChild;
     private View mHeadsUpChild;
     private HybridNotificationView mSingleLineView;
-    private View mAmbientChild;
 
     private RemoteInputView mExpandedRemoteInput;
     private RemoteInputView mHeadsUpRemoteInput;
@@ -98,12 +96,10 @@
     private NotificationViewWrapper mContractedWrapper;
     private NotificationViewWrapper mExpandedWrapper;
     private NotificationViewWrapper mHeadsUpWrapper;
-    private NotificationViewWrapper mAmbientWrapper;
     private HybridGroupManager mHybridGroupManager;
     private int mClipTopAmount;
     private int mContentHeight;
     private int mVisibleType = VISIBLE_TYPE_CONTRACTED;
-    private boolean mDark;
     private boolean mAnimate;
     private boolean mIsHeadsUp;
     private boolean mLegacy;
@@ -111,7 +107,6 @@
     private int mSmallHeight;
     private int mHeadsUpHeight;
     private int mNotificationMaxHeight;
-    private int mNotificationAmbientHeight;
     private StatusBarNotification mStatusBarNotification;
     private NotificationGroupManager mGroupManager;
     private RemoteInputController mRemoteInputController;
@@ -166,7 +161,6 @@
     private int mUnrestrictedContentHeight;
     private MediaTransferManager mMediaTransferManager;
 
-
     public NotificationContentView(Context context, AttributeSet attrs) {
         super(context, attrs);
         mHybridGroupManager = new HybridGroupManager(getContext(), this);
@@ -183,12 +177,10 @@
                 com.android.internal.R.dimen.notification_content_margin_end);
     }
 
-    public void setHeights(int smallHeight, int headsUpMaxHeight, int maxHeight,
-            int ambientHeight) {
+    public void setHeights(int smallHeight, int headsUpMaxHeight, int maxHeight) {
         mSmallHeight = smallHeight;
         mHeadsUpHeight = headsUpMaxHeight;
         mNotificationMaxHeight = maxHeight;
-        mNotificationAmbientHeight = ambientHeight;
     }
 
     @Override
@@ -286,20 +278,6 @@
                     MeasureSpec.makeMeasureSpec(mNotificationMaxHeight, MeasureSpec.AT_MOST));
             maxChildHeight = Math.max(maxChildHeight, mSingleLineView.getMeasuredHeight());
         }
-        if (mAmbientChild != null) {
-            int size = mNotificationAmbientHeight;
-            ViewGroup.LayoutParams layoutParams = mAmbientChild.getLayoutParams();
-            boolean useExactly = false;
-            if (layoutParams.height >= 0) {
-                // An actual height is set
-                size = Math.min(size, layoutParams.height);
-                useExactly = true;
-            }
-            mAmbientChild.measure(widthMeasureSpec,
-                    MeasureSpec.makeMeasureSpec(size, useExactly ? MeasureSpec.EXACTLY
-                            : MeasureSpec.AT_MOST));
-            maxChildHeight = Math.max(maxChildHeight, mAmbientChild.getMeasuredHeight());
-        }
         int ownHeight = Math.min(maxChildHeight, maxSize);
         setMeasuredDimension(width, ownHeight);
     }
@@ -394,10 +372,6 @@
         return mHeadsUpChild;
     }
 
-    public View getAmbientChild() {
-        return mAmbientChild;
-    }
-
     /**
      * Sets the contracted view. Child may be null to remove the content view.
      *
@@ -432,9 +406,6 @@
         if (child == mHeadsUpChild) {
             return mHeadsUpWrapper;
         }
-        if (child == mAmbientChild) {
-            return mAmbientWrapper;
-        }
         return null;
     }
 
@@ -514,33 +485,6 @@
                 mContainingNotification);
     }
 
-    /**
-     * Sets the ambient view. Child may be null to remove the content view.
-     *
-     * @param child ambient content view to set
-     */
-    public void setAmbientChild(@Nullable View child) {
-        if (mAmbientChild != null) {
-            mAmbientChild.animate().cancel();
-            removeView(mAmbientChild);
-        }
-        if (child == null) {
-            mAmbientChild = null;
-            mAmbientWrapper = null;
-            if (mTransformationStartVisibleType == VISIBLE_TYPE_AMBIENT) {
-                mTransformationStartVisibleType = UNDEFINED;
-            }
-            if (mVisibleType == VISIBLE_TYPE_AMBIENT) {
-                selectLayout(false /* animate */, true /* force */);
-            }
-            return;
-        }
-        addView(child);
-        mAmbientChild = child;
-        mAmbientWrapper = NotificationViewWrapper.wrap(getContext(), child,
-                mContainingNotification);
-    }
-
     @Override
     public void onViewAdded(View child) {
         super.onViewAdded(child);
@@ -645,7 +589,7 @@
                     isTransitioningFromTo(VISIBLE_TYPE_EXPANDED, VISIBLE_TYPE_HEADSUP);
             boolean pinned = !isVisibleOrTransitioning(VISIBLE_TYPE_CONTRACTED)
                     && (mIsHeadsUp || mHeadsUpAnimatingAway)
-                    && !mContainingNotification.isOnKeyguard();
+                    && mContainingNotification.canShowHeadsUp();
             if (transitioningBetweenHunAndExpanded || pinned) {
                 return Math.min(getViewHeight(VISIBLE_TYPE_HEADSUP),
                         getViewHeight(VISIBLE_TYPE_EXPANDED));
@@ -659,9 +603,7 @@
         }
 
         int hint;
-        if (mAmbientChild != null && isVisibleOrTransitioning(VISIBLE_TYPE_AMBIENT)) {
-            hint = mAmbientChild.getHeight();
-        }  else if (mHeadsUpChild != null && isVisibleOrTransitioning(VISIBLE_TYPE_HEADSUP)) {
+        if (mHeadsUpChild != null && isVisibleOrTransitioning(VISIBLE_TYPE_HEADSUP)) {
             hint = getViewHeight(VISIBLE_TYPE_HEADSUP);
         } else if (mExpandedChild != null) {
             hint = getViewHeight(VISIBLE_TYPE_EXPANDED);
@@ -761,9 +703,7 @@
         if (mExpandedChild != null) {
             return getViewHeight(VISIBLE_TYPE_EXPANDED)
                     + getExtraRemoteInputHeight(mExpandedRemoteInput);
-        } else if (mContainingNotification.isOnAmbient() && getShowingAmbientView() != null) {
-            return getShowingAmbientView().getHeight();
-        } else if (mIsHeadsUp && mHeadsUpChild != null && !mContainingNotification.isOnKeyguard()) {
+        } else if (mIsHeadsUp && mHeadsUpChild != null && mContainingNotification.canShowHeadsUp()) {
             return getViewHeight(VISIBLE_TYPE_HEADSUP)
                     + getExtraRemoteInputHeight(mHeadsUpRemoteInput);
         } else if (mContractedChild != null) {
@@ -773,11 +713,15 @@
     }
 
     private int getViewHeight(int visibleType) {
+        return getViewHeight(visibleType, false /* forceNoHeader */);
+    }
+
+    private int getViewHeight(int visibleType, boolean forceNoHeader) {
         View view = getViewForVisibleType(visibleType);
         int height = view.getHeight();
         NotificationViewWrapper viewWrapper = getWrapperForView(view);
         if (viewWrapper != null) {
-            height += viewWrapper.getHeaderTranslation();
+            height += viewWrapper.getHeaderTranslation(forceNoHeader);
         }
         return height;
     }
@@ -787,9 +731,7 @@
     }
 
     public int getMinHeight(boolean likeGroupExpanded) {
-        if (mContainingNotification.isOnAmbient() && getShowingAmbientView() != null) {
-            return getShowingAmbientView().getHeight();
-        } else if (likeGroupExpanded || !mIsChildInGroup || isGroupExpanded()) {
+        if (likeGroupExpanded || !mIsChildInGroup || isGroupExpanded()) {
             return mContractedChild != null
                     ? getViewHeight(VISIBLE_TYPE_CONTRACTED) : mMinContractedHeight;
         } else {
@@ -797,15 +739,6 @@
         }
     }
 
-    public View getShowingAmbientView() {
-        View v = mIsChildInGroup ? mSingleLineView : mAmbientChild;
-        if (v != null) {
-            return v;
-        } else {
-            return mContractedChild;
-        }
-    }
-
     private boolean isGroupExpanded() {
         return mGroupManager.isGroupExpanded(mStatusBarNotification);
     }
@@ -887,7 +820,6 @@
         forceUpdateVisibility(VISIBLE_TYPE_EXPANDED, mExpandedChild, mExpandedWrapper);
         forceUpdateVisibility(VISIBLE_TYPE_HEADSUP, mHeadsUpChild, mHeadsUpWrapper);
         forceUpdateVisibility(VISIBLE_TYPE_SINGLELINE, mSingleLineView, mSingleLineView);
-        forceUpdateVisibility(VISIBLE_TYPE_AMBIENT, mAmbientChild, mAmbientWrapper);
         fireExpandedVisibleListenerIfVisible();
         // forceUpdateVisibilities cancels outstanding animations without updating the
         // mAnimationStartVisibleType. Do so here instead.
@@ -963,8 +895,6 @@
                 mHeadsUpChild, mHeadsUpWrapper);
         updateViewVisibility(visibleType, VISIBLE_TYPE_SINGLELINE,
                 mSingleLineView, mSingleLineView);
-        updateViewVisibility(visibleType, VISIBLE_TYPE_AMBIENT,
-                mAmbientChild, mAmbientWrapper);
         fireExpandedVisibleListenerIfVisible();
         // updateViewVisibilities cancels outstanding animations without updating the
         // mAnimationStartVisibleType. Do so here instead.
@@ -1025,8 +955,6 @@
                 return mHeadsUpWrapper;
             case VISIBLE_TYPE_SINGLELINE:
                 return mSingleLineView;
-            case VISIBLE_TYPE_AMBIENT:
-                return mAmbientWrapper;
             default:
                 return mContractedWrapper;
         }
@@ -1044,8 +972,6 @@
                 return mHeadsUpChild;
             case VISIBLE_TYPE_SINGLELINE:
                 return mSingleLineView;
-            case VISIBLE_TYPE_AMBIENT:
-                return mAmbientChild;
             default:
                 return mContractedChild;
         }
@@ -1059,8 +985,6 @@
                 return mHeadsUpWrapper;
             case VISIBLE_TYPE_CONTRACTED:
                 return mContractedWrapper;
-            case VISIBLE_TYPE_AMBIENT:
-                return mAmbientWrapper;
             default:
                 return null;
         }
@@ -1100,26 +1024,23 @@
         if (!noExpandedChild && viewHeight == getViewHeight(VISIBLE_TYPE_EXPANDED)) {
             return VISIBLE_TYPE_EXPANDED;
         }
-        boolean onAmbient = mContainingNotification.isOnAmbient();
         if (!mUserExpanding && mIsChildInGroup && !isGroupExpanded()) {
             return VISIBLE_TYPE_SINGLELINE;
         }
 
         if ((mIsHeadsUp || mHeadsUpAnimatingAway) && mHeadsUpChild != null
-                && !mContainingNotification.isOnKeyguard()) {
+                && mContainingNotification.canShowHeadsUp()) {
             if (viewHeight <= getViewHeight(VISIBLE_TYPE_HEADSUP) || noExpandedChild) {
                 return VISIBLE_TYPE_HEADSUP;
             } else {
                 return VISIBLE_TYPE_EXPANDED;
             }
         } else {
-            int collapsedType = onAmbient && mAmbientChild != null ? VISIBLE_TYPE_AMBIENT :
-                    VISIBLE_TYPE_CONTRACTED;
             if (noExpandedChild || (mContractedChild != null
-                    && viewHeight <= getViewHeight(collapsedType)
+                    && viewHeight <= getViewHeight(VISIBLE_TYPE_CONTRACTED)
                     && (!mIsChildInGroup || isGroupExpanded()
                             || !mContainingNotification.isExpanded(true /* allowOnKeyguard */)))) {
-                return collapsedType;
+                return VISIBLE_TYPE_CONTRACTED;
             } else {
                 return VISIBLE_TYPE_EXPANDED;
             }
@@ -1130,14 +1051,6 @@
         return mIsContentExpandable;
     }
 
-    public void setDark(boolean dark, boolean fade, long delay) {
-        if (mContractedChild == null) {
-            return;
-        }
-        mDark = dark;
-        selectLayout(!dark && fade /* animate */, false /* force */);
-    }
-
     public void setHeadsUp(boolean headsUp) {
         mIsHeadsUp = headsUp;
         selectLayout(false /* animate */, true /* force */);
@@ -1180,9 +1093,6 @@
         if (mHeadsUpChild != null) {
             mHeadsUpWrapper.setIsChildInGroup(mIsChildInGroup);
         }
-        if (mAmbientChild != null) {
-            mAmbientWrapper.setIsChildInGroup(mIsChildInGroup);
-        }
         updateAllSingleLineViews();
     }
 
@@ -1201,14 +1111,10 @@
         if (mHeadsUpChild != null) {
             mHeadsUpWrapper.onContentUpdated(row);
         }
-        if (mAmbientChild != null) {
-            mAmbientWrapper.onContentUpdated(row);
-        }
         applyRemoteInputAndSmartReply(entry);
         applyMediaTransfer(entry);
         updateLegacy();
         mForceSelectNextLayout = true;
-        setDark(mDark, false /* animate */, 0 /* delay */);
         mPreviousExpandedRemoteInputIntent = null;
         mPreviousHeadsUpRemoteInputIntent = null;
     }
@@ -1514,7 +1420,7 @@
         // if the expanded child has the same height as the collapsed one we hide it.
         if (mExpandedChild != null && mExpandedChild.getHeight() != 0) {
             if ((!mIsHeadsUp && !mHeadsUpAnimatingAway)
-                    || mHeadsUpChild == null || mContainingNotification.isOnKeyguard()) {
+                    || mHeadsUpChild == null || !mContainingNotification.canShowHeadsUp()) {
                 if (mExpandedChild.getHeight() <= mContractedChild.getHeight()) {
                     expandable = false;
                 }
@@ -1545,9 +1451,6 @@
         if (header == null && mHeadsUpChild != null) {
             header = mHeadsUpWrapper.getNotificationHeader();
         }
-        if (header == null && mAmbientChild != null) {
-            header = mAmbientWrapper.getNotificationHeader();
-        }
         return header;
     }
 
@@ -1639,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) {
@@ -1849,14 +1761,15 @@
         return getViewHeight(viewType) + getExtraRemoteInputHeight(mExpandedRemoteInput);
     }
 
-    public int getHeadsUpHeight() {
+    public int getHeadsUpHeight(boolean forceNoHeader) {
         int viewType = VISIBLE_TYPE_HEADSUP;
         if (mHeadsUpChild == null) {
             viewType = VISIBLE_TYPE_CONTRACTED;
         }
         // The headsUp remote input quickly switches to the expanded one, so lets also include that
         // one
-        return getViewHeight(viewType) + getExtraRemoteInputHeight(mHeadsUpRemoteInput)
+        return getViewHeight(viewType, forceNoHeader)
+                + getExtraRemoteInputHeight(mHeadsUpRemoteInput)
                 + getExtraRemoteInputHeight(mExpandedRemoteInput);
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationGutsManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationGutsManager.java
index b5a8aad..8f7671a 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationGutsManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationGutsManager.java
@@ -419,9 +419,6 @@
         }
 
         final ExpandableNotificationRow row = (ExpandableNotificationRow) view;
-        if (row.isDark()) {
-            return false;
-        }
         view.performHapticFeedback(HapticFeedbackConstants.LONG_PRESS);
         if (row.areGutsExposed()) {
             closeAndSaveGuts(false /* removeLeavebehind */, false /* force */,
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationMenuRow.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationMenuRow.java
index d911e1a..b4ccb56 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationMenuRow.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationMenuRow.java
@@ -346,8 +346,7 @@
         if (mShouldShowMenu
                 && !NotificationStackScrollLayout.isPinnedHeadsUp(getParent())
                 && !mParent.areGutsExposed()
-                && !mParent.isDark()
-                && !mParent.showingAmbientPulsing()
+                && !mParent.showingPulsing()
                 && (mCheckForDrag == null || !mHandler.hasCallbacks(mCheckForDrag))) {
             // Only show the menu if we're not a heads up view and guts aren't exposed.
             mCheckForDrag = new CheckForDrag();
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/NotificationTemplateViewWrapper.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationTemplateViewWrapper.java
index 7ebdb93..97d8443 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationTemplateViewWrapper.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationTemplateViewWrapper.java
@@ -51,7 +51,7 @@
  */
 public class NotificationTemplateViewWrapper extends NotificationHeaderViewWrapper {
 
-    private final int mTranslationForHeader;
+    private final int mFullHeaderTranslation;
     protected ImageView mPicture;
     private ProgressBar mProgressBar;
     private TextView mTitle;
@@ -135,7 +135,7 @@
                     }
 
                 }, TRANSFORMING_VIEW_TEXT);
-        mTranslationForHeader = ctx.getResources().getDimensionPixelSize(
+        mFullHeaderTranslation = ctx.getResources().getDimensionPixelSize(
                 com.android.internal.R.dimen.notification_content_margin)
                 - ctx.getResources().getDimensionPixelSize(
                 com.android.internal.R.dimen.notification_content_margin_top);
@@ -340,20 +340,20 @@
 
             // We also need to compensate for any header translation, since we're always at the end.
             mActionsContainer.setTranslationY(constrainedContentHeight - mView.getHeight()
-                    - getHeaderTranslation());
+                    - getHeaderTranslation(false /* forceNoHeader */));
         }
     }
 
     @Override
-    public int getHeaderTranslation() {
-        return (int) mHeaderTranslation;
+    public int getHeaderTranslation(boolean forceNoHeader) {
+        return forceNoHeader ? mFullHeaderTranslation : (int) mHeaderTranslation;
     }
 
     @Override
     public void setHeaderVisibleAmount(float headerVisibleAmount) {
         super.setHeaderVisibleAmount(headerVisibleAmount);
         mNotificationHeader.setAlpha(headerVisibleAmount);
-        mHeaderTranslation = (1.0f - headerVisibleAmount) * mTranslationForHeader;
+        mHeaderTranslation = (1.0f - headerVisibleAmount) * mFullHeaderTranslation;
         mView.setTranslationY(mHeaderTranslation);
     }
 
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 3808702..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
@@ -224,7 +224,7 @@
         return null;
     }
 
-    public int getHeaderTranslation() {
+    public int getHeaderTranslation(boolean forceNoHeader) {
         return 0;
     }
 
@@ -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/notification/stack/AmbientState.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/AmbientState.java
index 78dc9a0..f3d068a 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/AmbientState.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/AmbientState.java
@@ -24,7 +24,6 @@
 
 import com.android.systemui.Dependency;
 import com.android.systemui.R;
-import com.android.systemui.statusbar.AmbientPulseManager;
 import com.android.systemui.statusbar.NotificationShelf;
 import com.android.systemui.statusbar.StatusBarState;
 import com.android.systemui.statusbar.notification.collection.NotificationEntry;
@@ -32,6 +31,7 @@
 import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
 import com.android.systemui.statusbar.notification.row.ExpandableView;
 import com.android.systemui.statusbar.notification.stack.StackScrollAlgorithm.SectionProvider;
+import com.android.systemui.statusbar.policy.HeadsUpManager;
 
 import java.util.ArrayList;
 
@@ -52,9 +52,8 @@
     private float mOverScrollTopAmount;
     private float mOverScrollBottomAmount;
     private int mSpeedBumpIndex = -1;
-    private boolean mDark;
+    private boolean mDozing;
     private boolean mHideSensitive;
-    private AmbientPulseManager mAmbientPulseManager = Dependency.get(AmbientPulseManager.class);
     private float mStackTranslation;
     private int mLayoutHeight;
     private int mTopPadding;
@@ -79,15 +78,19 @@
     private int mIntrinsicPadding;
     private int mExpandAnimationTopChange;
     private ExpandableNotificationRow mExpandingNotification;
-    private float mDarkAmount;
+    private float mHideAmount;
     private boolean mAppearing;
     private float mPulseHeight = MAX_PULSE_HEIGHT;
     private float mDozeAmount = 0.0f;
+    private HeadsUpManager mHeadUpManager;
+    private Runnable mOnPulseHeightChangedListener;
 
     public AmbientState(
             Context context,
-            @NonNull SectionProvider sectionProvider) {
+            @NonNull SectionProvider sectionProvider,
+            HeadsUpManager headsUpManager) {
         mSectionProvider = sectionProvider;
+        mHeadUpManager = headsUpManager;
         reload(context);
     }
 
@@ -180,23 +183,23 @@
         mDimmed = dimmed;
     }
 
-    /** In dark mode, we draw as little as possible, assuming a black background */
-    public void setDark(boolean dark) {
-        mDark = dark;
+    /** While dozing, we draw as little as possible, assuming a black background */
+    public void setDozing(boolean dozing) {
+        mDozing = dozing;
     }
 
-    /** Dark ratio of the status bar **/
-    public void setDarkAmount(float darkAmount) {
-        if (darkAmount == 1.0f && mDarkAmount != darkAmount) {
-            // Whenever we are fully dark, let's reset the pulseHeight again
-            mPulseHeight = MAX_PULSE_HEIGHT;
+    /** Hide ratio of the status bar **/
+    public void setHideAmount(float hidemount) {
+        if (hidemount == 1.0f && mHideAmount != hidemount) {
+            // Whenever we are fully hidden, let's reset the pulseHeight again
+            setPulseHeight(MAX_PULSE_HEIGHT);
         }
-        mDarkAmount = darkAmount;
+        mHideAmount = hidemount;
     }
 
-    /** Returns the dark ratio of the status bar */
-    public float getDarkAmount() {
-        return mDarkAmount;
+    /** Returns the hide ratio of the status bar */
+    public float getHideAmount() {
+        return mHideAmount;
     }
 
     public void setHideSensitive(boolean hideSensitive) {
@@ -217,8 +220,8 @@
         return mDimmed && !(isPulseExpanding() && mDozeAmount == 1.0f);
     }
 
-    public boolean isDark() {
-        return mDark;
+    public boolean isDozing() {
+        return mDozing;
     }
 
     public boolean isHideSensitive() {
@@ -295,7 +298,7 @@
     }
 
     public boolean isPulseExpanding() {
-        return mPulseHeight != MAX_PULSE_HEIGHT && mDozeAmount != 0.0f && mDarkAmount != 1.0f;
+        return mPulseHeight != MAX_PULSE_HEIGHT && mDozeAmount != 0.0f && mHideAmount != 1.0f;
     }
 
     public boolean isShadeExpanded() {
@@ -389,8 +392,7 @@
     }
 
     public boolean hasPulsingNotifications() {
-        return mPulsing && mAmbientPulseManager != null
-                && mAmbientPulseManager.hasNotifications();
+        return mPulsing && mHeadUpManager != null && mHeadUpManager.hasNotifications();
     }
 
     public void setPulsing(boolean hasPulsing) {
@@ -405,10 +407,10 @@
     }
 
     public boolean isPulsing(NotificationEntry entry) {
-        if (!mPulsing || mAmbientPulseManager == null) {
+        if (!mPulsing || mHeadUpManager == null) {
             return false;
         }
-        return mAmbientPulseManager.isAlerting(entry.key);
+        return mHeadUpManager.isAlerting(entry.key);
     }
 
     public boolean isPanelTracking() {
@@ -461,7 +463,7 @@
      * @return whether a row is dozing and not pulsing right now
      */
     public boolean isDozingAndNotPulsing(ExpandableNotificationRow row) {
-        return isDark() && !isPulsing(row.getEntry());
+        return isDozing() && !isPulsing(row.getEntry());
     }
 
     public void setExpandAnimationTopChange(int expandAnimationTopChange) {
@@ -481,14 +483,15 @@
     }
 
     /**
-     * @return {@code true } when shade is completely dark: in AOD or ambient display.
+     * @return {@code true } when shade is completely hidden: in AOD, ambient display or when
+     * bypassing.
      */
-    public boolean isFullyDark() {
-        return mDarkAmount == 1;
+    public boolean isFullyHidden() {
+        return mHideAmount == 1;
     }
 
-    public boolean isDarkAtAll() {
-        return mDarkAmount != 0;
+    public boolean isHiddenAtAll() {
+        return mHideAmount != 0;
     }
 
     public void setAppearing(boolean appearing) {
@@ -500,7 +503,20 @@
     }
 
     public void setPulseHeight(float height) {
-        mPulseHeight = height;
+        if (height != mPulseHeight) {
+            mPulseHeight = height;
+            if (mOnPulseHeightChangedListener != null) {
+                mOnPulseHeightChangedListener.run();
+            }
+        }
+    }
+
+    public float getPulseHeight() {
+        if (mPulseHeight == MAX_PULSE_HEIGHT) {
+            // If we're not pulse expanding, the height should be 0
+            return 0;
+        }
+        return mPulseHeight;
     }
 
     public void setDozeAmount(float dozeAmount) {
@@ -508,7 +524,7 @@
             mDozeAmount = dozeAmount;
             if (dozeAmount == 0.0f || dozeAmount == 1.0f) {
                 // We woke all the way up, let's reset the pulse height
-                mPulseHeight = MAX_PULSE_HEIGHT;
+                setPulseHeight(MAX_PULSE_HEIGHT);
             }
         }
     }
@@ -520,4 +536,12 @@
     public boolean isFullyAwake() {
         return mDozeAmount == 0.0f;
     }
+
+    public void setOnPulseHeightChangedListener(Runnable onPulseHeightChangedListener) {
+        mOnPulseHeightChangedListener = onPulseHeightChangedListener;
+    }
+
+    public Runnable getOnPulseHeightChangedListener() {
+        return mOnPulseHeightChangedListener;
+    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/AnimationFilter.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/AnimationFilter.java
index a471d87..6cd2290 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/AnimationFilter.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/AnimationFilter.java
@@ -36,7 +36,6 @@
     boolean animateHeight;
     boolean animateTopInset;
     boolean animateDimmed;
-    boolean animateDark;
     boolean animateHideSensitive;
     boolean hasDelays;
     boolean hasGoToFullShadeEvent;
@@ -89,11 +88,6 @@
         return this;
     }
 
-    public AnimationFilter animateDark() {
-        animateDark = true;
-        return this;
-    }
-
     public AnimationFilter animateHideSensitive() {
         animateHideSensitive = true;
         return this;
@@ -145,7 +139,6 @@
         animateHeight |= filter.animateHeight;
         animateTopInset |= filter.animateTopInset;
         animateDimmed |= filter.animateDimmed;
-        animateDark |= filter.animateDark;
         animateHideSensitive |= filter.animateHideSensitive;
         hasDelays |= filter.hasDelays;
         mAnimatedProperties.addAll(filter.mAnimatedProperties);
@@ -160,7 +153,6 @@
         animateHeight = false;
         animateTopInset = false;
         animateDimmed = false;
-        animateDark = false;
         animateHideSensitive = false;
         hasDelays = false;
         hasGoToFullShadeEvent = false;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ExpandableViewState.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ExpandableViewState.java
index f28e556..72ef7f9 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ExpandableViewState.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ExpandableViewState.java
@@ -85,7 +85,6 @@
 
     public int height;
     public boolean dimmed;
-    public boolean dark;
     public boolean hideSensitive;
     public boolean belowSpeedBump;
     public boolean inShelf;
@@ -121,7 +120,6 @@
             ExpandableViewState svs = (ExpandableViewState) viewState;
             height = svs.height;
             dimmed = svs.dimmed;
-            dark = svs.dark;
             hideSensitive = svs.hideSensitive;
             belowSpeedBump = svs.belowSpeedBump;
             clipTopAmount = svs.clipTopAmount;
@@ -158,9 +156,6 @@
             // apply below shelf speed bump
             expandableView.setBelowSpeedBump(this.belowSpeedBump);
 
-            // apply dark
-            expandableView.setDark(this.dark, false /* animate */, 0 /* delay */);
-
             // apply clipping
             float oldClipTopAmount = expandableView.getClipTopAmount();
             if (oldClipTopAmount != this.clipTopAmount) {
@@ -209,9 +204,6 @@
         expandableView.setHideSensitive(this.hideSensitive, animationFilter.animateHideSensitive,
                 properties.delay, properties.duration);
 
-        // start dark animation
-        expandableView.setDark(this.dark, animationFilter.animateDark, properties.delay);
-
         if (properties.wasAdded(child) && !hidden) {
             expandableView.performAddAnimation(properties.delay, properties.duration,
                     false /* isHeadsUpAppear */);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationChildrenContainer.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationChildrenContainer.java
index 6632ae6..45f7b3a 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationChildrenContainer.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationChildrenContainer.java
@@ -567,7 +567,6 @@
                     ? parentState.zTranslation
                     : 0;
             childState.dimmed = parentState.dimmed;
-            childState.dark = parentState.dark;
             childState.hideSensitive = parentState.hideSensitive;
             childState.belowSpeedBump = parentState.belowSpeedBump;
             childState.clipTopAmount = 0;
@@ -662,8 +661,10 @@
                 && !showingAsLowPriority()) {
             return NUMBER_OF_CHILDREN_WHEN_CHILDREN_EXPANDED;
         }
-        if (mIsLowPriority || !mContainingNotification.isOnKeyguard()
-                && (mContainingNotification.isExpanded() || mContainingNotification.isHeadsUp())) {
+        if (mIsLowPriority
+                || (!mContainingNotification.isOnKeyguard() && mContainingNotification.isExpanded())
+                || (mContainingNotification.isHeadsUpState()
+                        && mContainingNotification.canShowHeadsUp())) {
             return NUMBER_OF_CHILDREN_WHEN_SYSTEM_EXPANDED;
         }
         return NUMBER_OF_CHILDREN_WHEN_COLLAPSED;
@@ -1066,6 +1067,11 @@
                 false /* likeHighPriority */);
     }
 
+    public int getCollapsedHeightWithoutHeader() {
+        return getMinHeight(getMaxAllowedVisibleChildren(true /* forceCollapsed */),
+                false /* likeHighPriority */, 0);
+    }
+
     /**
      * Get the minimum Height for this group.
      *
@@ -1073,10 +1079,22 @@
      * @param likeHighPriority if the height should be calculated as if it were not low priority
      */
     private int getMinHeight(int maxAllowedVisibleChildren, boolean likeHighPriority) {
+        return getMinHeight(maxAllowedVisibleChildren, likeHighPriority, mCurrentHeaderTranslation);
+    }
+
+    /**
+     * Get the minimum Height for this group.
+     *
+     * @param maxAllowedVisibleChildren the number of children that should be visible
+     * @param likeHighPriority if the height should be calculated as if it were not low priority
+     * @param headerTranslation the translation amount of the header
+     */
+    private int getMinHeight(int maxAllowedVisibleChildren, boolean likeHighPriority,
+            int headerTranslation) {
         if (!likeHighPriority && showingAsLowPriority()) {
             return mNotificationHeaderLowPriority.getHeight();
         }
-        int minExpandHeight = mNotificationHeaderMargin + mCurrentHeaderTranslation;
+        int minExpandHeight = mNotificationHeaderMargin + headerTranslation;
         int visibleChildren = 0;
         boolean firstChild = true;
         int childCount = mChildren.size();
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationListContainer.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationListContainer.java
index 212808d..15cc72c 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationListContainer.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationListContainer.java
@@ -184,4 +184,6 @@
     default boolean containsView(View v) {
         return true;
     }
+
+    default void setWillExpand(boolean willExpand) {};
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationRoundnessManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationRoundnessManager.java
index c5ab9f6..4221846 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationRoundnessManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationRoundnessManager.java
@@ -18,11 +18,14 @@
 
 import static com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayout.NUM_SECTIONS;
 
-import com.android.systemui.statusbar.AmbientPulseManager;
+
+import android.util.MathUtils;
+
 import com.android.systemui.statusbar.notification.collection.NotificationEntry;
 import com.android.systemui.statusbar.notification.row.ActivatableNotificationView;
 import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
 import com.android.systemui.statusbar.notification.row.ExpandableView;
+import com.android.systemui.statusbar.phone.KeyguardBypassController;
 import com.android.systemui.statusbar.policy.OnHeadsUpChangedListener;
 
 import java.util.HashSet;
@@ -34,27 +37,26 @@
  * A class that manages the roundness for notification views
  */
 @Singleton
-class NotificationRoundnessManager implements OnHeadsUpChangedListener,
-        AmbientPulseManager.OnAmbientChangedListener {
+public class NotificationRoundnessManager implements OnHeadsUpChangedListener {
 
     private final ActivatableNotificationView[] mFirstInSectionViews;
     private final ActivatableNotificationView[] mLastInSectionViews;
     private final ActivatableNotificationView[] mTmpFirstInSectionViews;
     private final ActivatableNotificationView[] mTmpLastInSectionViews;
+    private final KeyguardBypassController mBypassController;
     private boolean mExpanded;
     private HashSet<ExpandableView> mAnimatedChildren;
     private Runnable mRoundingChangedCallback;
     private ExpandableNotificationRow mTrackedHeadsUp;
-    private ActivatableNotificationView mTrackedAmbient;
     private float mAppearFraction;
 
     @Inject
-    NotificationRoundnessManager(AmbientPulseManager ambientPulseManager) {
+    NotificationRoundnessManager(KeyguardBypassController keyguardBypassController) {
         mFirstInSectionViews = new ActivatableNotificationView[NUM_SECTIONS];
         mLastInSectionViews = new ActivatableNotificationView[NUM_SECTIONS];
         mTmpFirstInSectionViews = new ActivatableNotificationView[NUM_SECTIONS];
         mTmpLastInSectionViews = new ActivatableNotificationView[NUM_SECTIONS];
-        ambientPulseManager.addListener(this);
+        mBypassController = keyguardBypassController;
     }
 
     @Override
@@ -73,14 +75,8 @@
     }
 
     @Override
-    public void onAmbientStateChanged(NotificationEntry entry, boolean isPulsing) {
-        ActivatableNotificationView row = entry.getRow();
-        if (isPulsing) {
-            mTrackedAmbient = row;
-        } else if (mTrackedAmbient == row) {
-            mTrackedAmbient = null;
-        }
-        updateView(row, false /* animate */);
+    public void onHeadsUpStateChanged(NotificationEntry entry, boolean isHeadsUp) {
+        updateView(entry.getRow(), false /* animate */);
     }
 
     private void updateView(ActivatableNotificationView view, boolean animate) {
@@ -140,12 +136,12 @@
         if (isLastInSection(view, true /* include last section */) && !top) {
             return 1.0f;
         }
-        if (view == mTrackedHeadsUp && mAppearFraction <= 0.0f) {
+        if (view == mTrackedHeadsUp) {
             // If we're pushing up on a headsup the appear fraction is < 0 and it needs to still be
             // rounded.
-            return 1.0f;
+            return MathUtils.saturate(1.0f - mAppearFraction);
         }
-        if (view == mTrackedAmbient) {
+        if (view.showingPulsing() && !mBypassController.getBypassEnabled()) {
             return 1.0f;
         }
         return 0.0f;
@@ -242,6 +238,10 @@
     }
 
     public void setTrackingHeadsUp(ExpandableNotificationRow row) {
+        ExpandableNotificationRow previous = mTrackedHeadsUp;
         mTrackedHeadsUp = row;
+        if (previous != null) {
+            updateView(previous, true /* animate */);
+        }
     }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationSection.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationSection.java
index cbcfdd4..f39ed2e 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationSection.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationSection.java
@@ -254,7 +254,7 @@
                 newTop = (int) Math.ceil(firstView.getTranslationY());
             }
             top = Math.max(newTop, top);
-            if (firstView.showingAmbientPulsing()) {
+            if (firstView.showingPulsing()) {
                 // If we're pulsing, the notification can actually go below!
                 bottom = Math.max(bottom, finalTranslationY
                         + ExpandableViewState.getFinalActualHeight(firstView));
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java
index 237825e..f50790f 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java
@@ -96,7 +96,6 @@
 import com.android.systemui.plugins.statusbar.NotificationSwipeActionHelper;
 import com.android.systemui.plugins.statusbar.StatusBarStateController;
 import com.android.systemui.plugins.statusbar.StatusBarStateController.StateListener;
-import com.android.systemui.statusbar.AmbientPulseManager;
 import com.android.systemui.statusbar.CommandQueue;
 import com.android.systemui.statusbar.DragDownHelper.DragDownCallback;
 import com.android.systemui.statusbar.EmptyShadeView;
@@ -125,10 +124,10 @@
 import com.android.systemui.statusbar.notification.row.NotificationGutsManager;
 import com.android.systemui.statusbar.notification.row.NotificationSnooze;
 import com.android.systemui.statusbar.notification.row.StackScrollerDecorView;
-import com.android.systemui.statusbar.phone.DozeParameters;
 import com.android.systemui.statusbar.phone.HeadsUpAppearanceController;
 import com.android.systemui.statusbar.phone.HeadsUpManagerPhone;
 import com.android.systemui.statusbar.phone.HeadsUpTouchHelper;
+import com.android.systemui.statusbar.phone.KeyguardBypassController;
 import com.android.systemui.statusbar.phone.LockscreenGestureLogger;
 import com.android.systemui.statusbar.phone.NotificationGroupManager;
 import com.android.systemui.statusbar.phone.NotificationGroupManager.OnGroupChangeListener;
@@ -180,7 +179,9 @@
      * gap is drawn between them). In this case we don't want to round their corners.
      */
     private static final int DISTANCE_BETWEEN_ADJACENT_SECTIONS_PX = 1;
-    private final AmbientPulseManager mAmbientPulseManager;
+    private final KeyguardBypassController mKeyguardBypassController;
+    private final DynamicPrivacyController mDynamicPrivacyController;
+    private final SysuiStatusBarStateController mStatusbarStateController;
 
     private ExpandHelper mExpandHelper;
     private final NotificationSwipeHelper mSwipeHelper;
@@ -267,8 +268,6 @@
     private boolean mTopPaddingNeedsAnimation;
     private boolean mDimmedNeedsAnimation;
     private boolean mHideSensitiveNeedsAnimation;
-    private boolean mDarkNeedsAnimation;
-    private int mDarkAnimationOriginIndex;
     private boolean mActivateNeedsAnimation;
     private boolean mGoToFullShadeNeedsAnimation;
     private boolean mIsExpanded = true;
@@ -409,12 +408,13 @@
     private final ViewOutlineProvider mOutlineProvider = new ViewOutlineProvider() {
         @Override
         public void getOutline(View view, Outline outline) {
-            if (mAmbientState.isDarkAtAll()) {
-                float xProgress = mDarkXInterpolator.getInterpolation(
-                        (1 - mLinearDarkAmount) * mBackgroundXFactor);
+            if (mAmbientState.isHiddenAtAll()) {
+                float xProgress = mHideXInterpolator.getInterpolation(
+                        (1 - mLinearHideAmount) * mBackgroundXFactor);
                 outline.setRoundRect(mBackgroundAnimationRect,
                         MathUtils.lerp(mCornerRadius / 2.0f, mCornerRadius,
                                 xProgress));
+                outline.setAlpha(1.0f - mAmbientState.getHideAmount());
             } else {
                 ViewOutlineProvider.BACKGROUND.getOutline(view, outline);
             }
@@ -427,14 +427,14 @@
     private View mForcedScroll;
 
     /**
-     * @see #setDarkAmount(float, float)
+     * @see #setHideAmount(float, float)
      */
-    private float mInterpolatedDarkAmount = 0f;
+    private float mInterpolatedHideAmount = 0f;
 
     /**
-     * @see #setDarkAmount(float, float)
+     * @see #setHideAmount(float, float)
      */
-    private float mLinearDarkAmount = 0f;
+    private float mLinearHideAmount = 0f;
 
     /**
      * How fast the background scales in the X direction as a factor of the Y expansion.
@@ -469,12 +469,10 @@
     private int mCornerRadius;
     private int mSidePaddings;
     private final Rect mBackgroundAnimationRect = new Rect();
-    private int mAntiBurnInOffsetX;
     private ArrayList<BiConsumer<Float, Float>> mExpandedHeightListeners = new ArrayList<>();
     private int mHeadsUpInset;
     private HeadsUpAppearanceController mHeadsUpAppearanceController;
     private NotificationIconAreaController mIconAreaController;
-    private float mHorizontalPanelTranslation;
     private final NotificationLockscreenUserManager mLockscreenUserManager =
             Dependency.get(NotificationLockscreenUserManager.class);
     private final Rect mTmpRect = new Rect();
@@ -495,17 +493,17 @@
             Dependency.get(VisualStabilityManager.class);
     protected boolean mClearAllEnabled;
 
-    private Interpolator mDarkXInterpolator = Interpolators.FAST_OUT_SLOW_IN;
+    private Interpolator mHideXInterpolator = Interpolators.FAST_OUT_SLOW_IN;
     private NotificationPanelView mNotificationPanel;
     private final ShadeController mShadeController = Dependency.get(ShadeController.class);
 
     private final NotificationGutsManager
             mNotificationGutsManager = Dependency.get(NotificationGutsManager.class);
     private final NotificationSectionsManager mSectionsManager;
-    /**
-     * If the {@link NotificationShelf} should be visible when dark.
-     */
     private boolean mAnimateBottomOnLayout;
+    private float mLastSentAppear;
+    private float mLastSentExpandedHeight;
+    private boolean mWillExpand;
 
     @Inject
     public NotificationStackScrollLayout(
@@ -513,11 +511,12 @@
             AttributeSet attrs,
             @Named(ALLOW_NOTIFICATION_LONG_PRESS_NAME) boolean allowLongPress,
             NotificationRoundnessManager notificationRoundnessManager,
-            AmbientPulseManager ambientPulseManager,
             DynamicPrivacyController dynamicPrivacyController,
             ConfigurationController configurationController,
             ActivityStarter activityStarter,
-            StatusBarStateController statusBarStateController) {
+            StatusBarStateController statusBarStateController,
+            HeadsUpManagerPhone headsUpManager,
+            KeyguardBypassController keyguardBypassController) {
         super(context, attrs, 0, 0);
         Resources res = getResources();
 
@@ -526,8 +525,12 @@
         for (int i = 0; i < NUM_SECTIONS; i++) {
             mSections[i] = new NotificationSection(this);
         }
+        mRoundnessManager = notificationRoundnessManager;
 
-        mAmbientPulseManager = ambientPulseManager;
+        mHeadsUpManager = headsUpManager;
+        mHeadsUpManager.addListener(mRoundnessManager);
+        mHeadsUpManager.setAnimationStateHandler(this::setHeadsUpGoingAwayAnimationsAllowed);
+        mKeyguardBypassController = keyguardBypassController;
 
         mSectionsManager =
                 new NotificationSectionsManager(
@@ -543,8 +546,7 @@
             clearNotifications(ROWS_GENTLE, closeShade);
         });
 
-        mAmbientState = new AmbientState(context, mSectionsManager);
-        mRoundnessManager = notificationRoundnessManager;
+        mAmbientState = new AmbientState(context, mSectionsManager, mHeadsUpManager);
         mBgColor = context.getColor(R.color.notification_shade_background_color);
         int minHeight = res.getDimensionPixelSize(R.dimen.notification_min_height);
         int maxHeight = res.getDimensionPixelSize(R.dimen.notification_max_height);
@@ -563,17 +565,18 @@
                 res.getBoolean(R.bool.config_fadeNotificationsOnDismiss);
         mRoundnessManager.setAnimatedChildren(mChildrenToAddAnimated);
         mRoundnessManager.setOnRoundingChangedCallback(this::invalidate);
-        addOnExpandedHeightListener(mRoundnessManager::setExpanded);
+        addOnExpandedHeightChangedListener(mRoundnessManager::setExpanded);
         setOutlineProvider(mOutlineProvider);
 
         // Blocking helper manager wants to know the expanded state, update as well.
         NotificationBlockingHelperManager blockingHelperManager =
                 Dependency.get(NotificationBlockingHelperManager.class);
-        addOnExpandedHeightListener((height, unused) -> {
+        addOnExpandedHeightChangedListener((height, unused) -> {
             blockingHelperManager.setNotificationShadeExpanded(height);
         });
 
-        updateWillNotDraw();
+        boolean willDraw = mShouldDrawNotificationBackground || DEBUG;
+        setWillNotDraw(!willDraw);
         mBackgroundPaint.setAntiAlias(true);
         if (DEBUG) {
             mDebugPaint = new Paint();
@@ -604,6 +607,8 @@
             }
         });
         dynamicPrivacyController.addListener(this);
+        mDynamicPrivacyController = dynamicPrivacyController;
+        mStatusbarStateController = (SysuiStatusBarStateController) statusBarStateController;
     }
 
     private void updateDismissRtlSetting(boolean dismissRtl) {
@@ -632,10 +637,14 @@
     /**
      * @return the height at which we will wake up when pulsing
      */
-    public float getPulseHeight() {
+    public float getWakeUpHeight() {
         ActivatableNotificationView firstChild = getFirstChildWithBackground();
         if (firstChild != null) {
-            return firstChild.getCollapsedHeight();
+            if (mKeyguardBypassController.getBypassEnabled()) {
+                return firstChild.getHeadsUpHeightWithoutHeader();
+            } else {
+                return firstChild.getCollapsedHeight();
+            }
         }
         return 0f;
     }
@@ -690,6 +699,9 @@
      */
     @ShadeViewRefactor(RefactorComponent.SHADE_VIEW)
     public boolean hasActiveClearableNotifications(@SelectedRows int selection) {
+        if (mDynamicPrivacyController.isInLockedDownShade()) {
+            return false;
+        }
         int childCount = getChildCount();
         for (int i = 0; i < childCount; i++) {
             View child = getChildAt(i);
@@ -762,7 +774,7 @@
         if (mShouldDrawNotificationBackground
                 && (mSections[0].getCurrentBounds().top
                 < mSections[NUM_SECTIONS - 1].getCurrentBounds().bottom
-                || mAmbientState.isDark())) {
+                || mAmbientState.isDozing())) {
             drawBackground(canvas);
         } else if (mInHeadsUpPinnedMode || mHeadsUpAnimatingAway) {
             drawHeadsUpBackground(canvas);
@@ -796,7 +808,7 @@
                 canvas.drawLine(0, y, getWidth(), y, mDebugPaint);
             }
             canvas.drawText(Integer.toString(getMaxNegativeScrollAmount()), getWidth() - 100,
-                    getIntrinsicPadding() + 30, mDebugPaint);
+                    getTopPadding() + 30, mDebugPaint);
             canvas.drawText(Integer.toString(getMaxPositiveScrollAmount()), getWidth() - 100,
                     getHeight() - 30, mDebugPaint);
         }
@@ -808,17 +820,17 @@
         int lockScreenRight = getWidth() - mSidePaddings;
         int lockScreenTop = mSections[0].getCurrentBounds().top;
         int lockScreenBottom = mSections[NUM_SECTIONS - 1].getCurrentBounds().bottom;
-        int darkLeft = getWidth() / 2;
-        int darkTop = mTopPadding;
+        int hiddenLeft = getWidth() / 2;
+        int hiddenTop = mTopPadding;
 
-        float yProgress = 1 - mInterpolatedDarkAmount;
-        float xProgress = mDarkXInterpolator.getInterpolation(
-                (1 - mLinearDarkAmount) * mBackgroundXFactor);
+        float yProgress = 1 - mInterpolatedHideAmount;
+        float xProgress = mHideXInterpolator.getInterpolation(
+                (1 - mLinearHideAmount) * mBackgroundXFactor);
 
-        int left = (int) MathUtils.lerp(darkLeft, lockScreenLeft, xProgress);
-        int right = (int) MathUtils.lerp(darkLeft, lockScreenRight, xProgress);
-        int top = (int) MathUtils.lerp(darkTop, lockScreenTop, yProgress);
-        int bottom = (int) MathUtils.lerp(darkTop, lockScreenBottom, yProgress);
+        int left = (int) MathUtils.lerp(hiddenLeft, lockScreenLeft, xProgress);
+        int right = (int) MathUtils.lerp(hiddenLeft, lockScreenRight, xProgress);
+        int top = (int) MathUtils.lerp(hiddenTop, lockScreenTop, yProgress);
+        int bottom = (int) MathUtils.lerp(hiddenTop, lockScreenBottom, yProgress);
         mBackgroundAnimationRect.set(
                 left,
                 top,
@@ -834,7 +846,13 @@
                 break;
             }
         }
-        if (!mAmbientState.isDark() || anySectionHasVisibleChild) {
+        boolean shouldDrawBackground;
+        if (mKeyguardBypassController.getBypassEnabled() && onKeyguard()) {
+            shouldDrawBackground = isPulseExpanding();
+        } else {
+            shouldDrawBackground = !mAmbientState.isDozing() || anySectionHasVisibleChild;
+        }
+        if (shouldDrawBackground) {
             drawBackgroundRects(canvas, left, right, top, backgroundTopAnimationOffset);
         }
 
@@ -934,7 +952,7 @@
         // Interpolate between semi-transparent notification panel background color
         // and white AOD separator.
         float colorInterpolation = MathUtils.smoothStep(0.4f /* start */, 1f /* end */,
-                mLinearDarkAmount);
+                mLinearHideAmount);
         int color = ColorUtils.blendARGB(mBgColor, Color.WHITE, colorInterpolation);
 
         if (mCachedBackgroundColor != color) {
@@ -988,6 +1006,10 @@
         }
     }
 
+    public boolean isPulseExpanding() {
+        return mAmbientState.isPulseExpanding();
+    }
+
     @Override
     @ShadeViewRefactor(RefactorComponent.SHADE_VIEW)
     protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
@@ -1030,6 +1052,7 @@
         requestChildrenUpdate();
         updateFirstAndLastBackgroundViews();
         updateAlgorithmLayoutMinHeight();
+        updateOwnTranslationZ();
     }
 
     @ShadeViewRefactor(RefactorComponent.STATE_RESOLVER)
@@ -1303,7 +1326,7 @@
                 stackHeight = (int) height;
             }
         } else {
-            appearFraction = getAppearFraction(height);
+            appearFraction = calculateAppearFraction(height);
             if (appearFraction >= 0) {
                 translationY = NotificationUtils.interpolate(getExpandTranslationStart(), 0,
                         appearFraction);
@@ -1326,9 +1349,26 @@
             requestChildrenUpdate();
         }
         setStackTranslation(translationY);
-        for (int i = 0; i < mExpandedHeightListeners.size(); i++) {
-            BiConsumer<Float, Float> listener = mExpandedHeightListeners.get(i);
-            listener.accept(mExpandedHeight, appearFraction);
+        notifyAppearChangedListeners();
+    }
+
+    private void notifyAppearChangedListeners() {
+        float appear;
+        float expandAmount;
+        if (mKeyguardBypassController.getBypassEnabled() && onKeyguard()) {
+            appear = calculateAppearFractionBypass();
+            expandAmount = getPulseHeight();
+        } else {
+            appear = MathUtils.saturate(calculateAppearFraction(mExpandedHeight));
+            expandAmount = mExpandedHeight;
+        }
+        if (appear != mLastSentAppear || expandAmount != mLastSentExpandedHeight) {
+            mLastSentAppear = appear;
+            mLastSentExpandedHeight = expandAmount;
+            for (int i = 0; i < mExpandedHeightListeners.size(); i++) {
+                BiConsumer<Float, Float> listener = mExpandedHeightListeners.get(i);
+                listener.accept(expandAmount, appear);
+            }
         }
     }
 
@@ -1355,11 +1395,12 @@
             mIsClipped = clipped;
         }
 
-        if (!mPulsing && mAmbientState.isFullyDark()) {
-            setClipBounds(null);
-        } else if (mAmbientState.isDarkAtAll()) {
+        if (mAmbientState.isHiddenAtAll()) {
             clipToOutline = true;
             invalidateOutline();
+            if (isFullyHidden()) {
+                setClipBounds(null);
+            }
         } else if (clipped) {
             setClipBounds(mRequestedClipBounds);
         } else {
@@ -1423,7 +1464,7 @@
         int notGoneChildCount = getNotGoneChildCount();
         if (mEmptyShadeView.getVisibility() == GONE && notGoneChildCount != 0) {
             if (isHeadsUpTransition()
-                    || (mHeadsUpManager.hasPinnedHeadsUp() && !mAmbientState.isDark())) {
+                    || (mHeadsUpManager.hasPinnedHeadsUp() && !mAmbientState.isDozing())) {
                 appearPosition = getTopHeadsUpPinnedHeight();
             } else {
                 appearPosition = 0;
@@ -1449,7 +1490,7 @@
      * @return the fraction of the appear animation that has been performed
      */
     @ShadeViewRefactor(RefactorComponent.COORDINATOR)
-    public float getAppearFraction(float height) {
+    public float calculateAppearFraction(float height) {
         float appearEndPosition = getAppearEndPosition();
         float appearStartPosition = getAppearStartPosition();
         return (height - appearStartPosition)
@@ -2388,7 +2429,9 @@
         }
         mIntrinsicContentHeight = height;
 
-        mContentHeight = height + mTopPadding + mBottomMargin;
+        // The topPadding can be bigger than the regular padding when qs is expanded, in that
+        // state the maxPanelHeight and the contentHeight should be bigger
+        mContentHeight = height + Math.max(mIntrinsicPadding, mTopPadding) + mBottomMargin;
         updateScrollability();
         clampScrollPosition();
         mAmbientState.setLayoutMaxHeight(mContentHeight);
@@ -2426,7 +2469,7 @@
     @ShadeViewRefactor(RefactorComponent.SHADE_VIEW)
     private void updateBackground() {
         // No need to update the background color if it's not being drawn.
-        if (!mShouldDrawNotificationBackground || mAmbientState.isFullyDark()) {
+        if (!mShouldDrawNotificationBackground) {
             return;
         }
 
@@ -2518,7 +2561,8 @@
         }
         int minTopPosition;
         NotificationSection lastSection = getLastVisibleSection();
-        if (mStatusBarState != StatusBarState.KEYGUARD) {
+        boolean onKeyguard = mStatusBarState == StatusBarState.KEYGUARD;
+        if (!onKeyguard) {
             minTopPosition = (int) (mTopPadding + mStackTranslation);
         } else if (lastSection == null) {
             minTopPosition = mTopPadding;
@@ -2531,7 +2575,9 @@
                     false /* shiftPulsingWithFirst */);
             minTopPosition = firstVisibleSection.getBounds().top;
         }
-        boolean shiftPulsingWithFirst = mAmbientPulseManager.getAllEntries().count() <= 1;
+        boolean shiftPulsingWithFirst = mHeadsUpManager.getAllEntries().count() <= 1
+                && (mAmbientState.isDozing()
+                        || (mKeyguardBypassController.getBypassEnabled() && onKeyguard));
         for (NotificationSection section : mSections) {
             int minBottomPosition = minTopPosition;
             if (section == lastSection) {
@@ -2776,12 +2822,9 @@
      *
      * @param qsHeight               the top padding imposed by the quick settings panel
      * @param animate                whether to animate the change
-     * @param ignoreIntrinsicPadding if true, {@link #getIntrinsicPadding()} is ignored and
-     *                               {@code qsHeight} is the final top padding
      */
     @ShadeViewRefactor(RefactorComponent.COORDINATOR)
-    public void updateTopPadding(float qsHeight, boolean animate,
-            boolean ignoreIntrinsicPadding) {
+    public void updateTopPadding(float qsHeight, boolean animate) {
         int topPadding = (int) qsHeight;
         int minStackHeight = getLayoutMinHeight();
         if (topPadding + minStackHeight > getHeight()) {
@@ -2789,8 +2832,7 @@
         } else {
             mTopPaddingOverflow = 0;
         }
-        setTopPadding(ignoreIntrinsicPadding ? topPadding : clampPadding(topPadding),
-                animate);
+        setTopPadding(topPadding, animate && !mKeyguardBypassController.getBypassEnabled());
         setExpandedHeight(mExpandedHeight);
     }
 
@@ -3226,7 +3268,6 @@
     private void updateNotificationAnimationStates() {
         boolean running = mAnimationsEnabled || hasPulsingNotifications();
         mShelf.setAnimationsEnabled(running);
-        mIconAreaController.setAnimationsEnabled(running);
         int childCount = getChildCount();
         for (int i = 0; i < childCount; i++) {
             View child = getChildAt(i);
@@ -3286,7 +3327,7 @@
     @Override
     @ShadeViewRefactor(RefactorComponent.STATE_RESOLVER)
     public void generateAddAnimation(ExpandableView child, boolean fromMoreCard) {
-        if (mIsExpanded && mAnimationsEnabled && !mChangePositionInProgress) {
+        if (mIsExpanded && mAnimationsEnabled && !mChangePositionInProgress && !isFullyHidden()) {
             // Generate Animations
             mChildrenToAddAnimated.add(child);
             if (fromMoreCard) {
@@ -3294,7 +3335,8 @@
             }
             mNeedsAnimation = true;
         }
-        if (isHeadsUp(child) && mAnimationsEnabled && !mChangePositionInProgress) {
+        if (isHeadsUp(child) && mAnimationsEnabled && !mChangePositionInProgress
+                && !isFullyHidden()) {
             mAddedHeadsUpChildren.add(child);
             mChildrenToAddAnimated.remove(child);
         }
@@ -3367,7 +3409,6 @@
         generateActivateEvent();
         generateDimmedEvent();
         generateHideSensitiveEvent();
-        generateDarkEvent();
         generateGoToFullShadeEvent();
         generateViewResizeEvent();
         generateGroupExpansionEvent();
@@ -3379,10 +3420,20 @@
         for (Pair<ExpandableNotificationRow, Boolean> eventPair : mHeadsUpChangeAnimations) {
             ExpandableNotificationRow row = eventPair.first;
             boolean isHeadsUp = eventPair.second;
+            if (isHeadsUp != row.isHeadsUp()) {
+                // For cases where we have a heads up showing and appearing again we shouldn't
+                // do the animations at all.
+                continue;
+            }
             int type = AnimationEvent.ANIMATION_TYPE_HEADS_UP_OTHER;
             boolean onBottom = false;
             boolean pinnedAndClosed = row.isPinned() && !mIsExpanded;
-            if (!mIsExpanded && !isHeadsUp) {
+            boolean performDisappearAnimation = !mIsExpanded
+                    // Only animate if we still have pinned heads up, otherwise we just have the
+                    // regular collapse animation of the lock screen
+                    || (mKeyguardBypassController.getBypassEnabled() && onKeyguard()
+                            && mHeadsUpManager.hasPinnedHeadsUp());
+            if (performDisappearAnimation && !isHeadsUp) {
                 type = row.wasJustClicked()
                         ? AnimationEvent.ANIMATION_TYPE_HEADS_UP_DISAPPEAR_CLICK
                         : AnimationEvent.ANIMATION_TYPE_HEADS_UP_DISAPPEAR;
@@ -3532,7 +3583,7 @@
     private void generateTopPaddingEvent() {
         if (mTopPaddingNeedsAnimation) {
             AnimationEvent event;
-            if (mAmbientState.isDark()) {
+            if (mAmbientState.isDozing()) {
                 event = new AnimationEvent(null /* view */,
                         AnimationEvent.ANIMATION_TYPE_TOP_PADDING_CHANGED,
                         KeyguardSliceView.DEFAULT_ANIM_DURATION);
@@ -3582,20 +3633,6 @@
     }
 
     @ShadeViewRefactor(RefactorComponent.STATE_RESOLVER)
-    private void generateDarkEvent() {
-        if (mDarkNeedsAnimation) {
-            AnimationEvent ev = new AnimationEvent(null,
-                    AnimationEvent.ANIMATION_TYPE_DARK,
-                    new AnimationFilter()
-                            .animateDark()
-                            .animateY(mShelf));
-            ev.darkAnimationOriginIndex = mDarkAnimationOriginIndex;
-            mAnimationEvents.add(ev);
-        }
-        mDarkNeedsAnimation = false;
-    }
-
-    @ShadeViewRefactor(RefactorComponent.STATE_RESOLVER)
     private void generateGoToFullShadeEvent() {
         if (mGoToFullShadeNeedsAnimation) {
             mAnimationEvents.add(
@@ -4379,6 +4416,7 @@
         mStateAnimator.setShadeExpanded(isExpanded);
         mSwipeHelper.setIsExpanded(isExpanded);
         if (changed) {
+            mWillExpand = false;
             if (!mIsExpanded) {
                 mGroupManager.collapseAllGroups();
                 mExpandHelper.cancelImmediately();
@@ -4697,14 +4735,6 @@
         return mIntrinsicPadding;
     }
 
-    /**
-     * @return the y position of the first notification
-     */
-    @ShadeViewRefactor(RefactorComponent.COORDINATOR)
-    public float getNotificationsTopY() {
-        return mTopPadding + getStackTranslation();
-    }
-
     @Override
     @ShadeViewRefactor(RefactorComponent.SHADE_VIEW)
     public boolean shouldDelayChildPressedState() {
@@ -4712,126 +4742,82 @@
     }
 
     /**
-     * See {@link AmbientState#setDark}.
+     * See {@link AmbientState#setDozing}.
      */
     @ShadeViewRefactor(RefactorComponent.SHADE_VIEW)
-    public void setDark(boolean dark, boolean animate, @Nullable PointF touchWakeUpScreenLocation) {
-        if (mAmbientState.isDark() == dark) {
+    public void setDozing(boolean dozing, boolean animate,
+            @Nullable PointF touchWakeUpScreenLocation) {
+        if (mAmbientState.isDozing() == dozing) {
             return;
         }
-        mAmbientState.setDark(dark);
-        if (animate && mAnimationsEnabled) {
-            mDarkNeedsAnimation = true;
-            mDarkAnimationOriginIndex = findDarkAnimationOriginIndex(touchWakeUpScreenLocation);
-            mNeedsAnimation = true;
-        } else {
-            setDarkAmount(dark ? 1f : 0f);
-            updateBackground();
-        }
+        mAmbientState.setDozing(dozing);
         requestChildrenUpdate();
-        updateWillNotDraw();
         notifyHeightChangeListener(mShelf);
     }
 
-    @ShadeViewRefactor(RefactorComponent.SHADE_VIEW)
-    private void updatePanelTranslation() {
-        setTranslationX(mHorizontalPanelTranslation + mAntiBurnInOffsetX * mInterpolatedDarkAmount);
-    }
-
-    @ShadeViewRefactor(RefactorComponent.SHADE_VIEW)
-    public void setHorizontalPanelTranslation(float verticalPanelTranslation) {
-        mHorizontalPanelTranslation = verticalPanelTranslation;
-        updatePanelTranslation();
-    }
-
     /**
-     * Updates whether or not this Layout will perform its own custom drawing (i.e. whether or
-     * not {@link #onDraw(Canvas)} is called). This method should be called whenever the
-     * {@link #mAmbientState}'s dark mode is toggled.
-     */
-    @ShadeViewRefactor(RefactorComponent.SHADE_VIEW)
-    private void updateWillNotDraw() {
-        boolean willDraw = mShouldDrawNotificationBackground || DEBUG;
-        setWillNotDraw(!willDraw);
-    }
-
-    @ShadeViewRefactor(RefactorComponent.SHADE_VIEW)
-    private void setDarkAmount(float darkAmount) {
-        setDarkAmount(darkAmount, darkAmount);
-    }
-
-    /**
-     * Sets the current dark amount.
+     * Sets the current hide amount.
      *
-     * @param linearDarkAmount       The dark amount that follows linear interpoloation in the
+     * @param linearHideAmount       The hide amount that follows linear interpoloation in the
      *                               animation,
      *                               i.e. animates from 0 to 1 or vice-versa in a linear manner.
-     * @param interpolatedDarkAmount The dark amount that follows the actual interpolation of the
+     * @param interpolatedHideAmount The hide amount that follows the actual interpolation of the
      *                               animation curve.
      */
     @ShadeViewRefactor(RefactorComponent.SHADE_VIEW)
-    public void setDarkAmount(float linearDarkAmount, float interpolatedDarkAmount) {
-        mLinearDarkAmount = linearDarkAmount;
-        mInterpolatedDarkAmount = interpolatedDarkAmount;
-        boolean wasFullyDark = mAmbientState.isFullyDark();
-        boolean wasDarkAtAll = mAmbientState.isDarkAtAll();
-        mAmbientState.setDarkAmount(interpolatedDarkAmount);
-        boolean nowFullyDark = mAmbientState.isFullyDark();
-        boolean nowDarkAtAll = mAmbientState.isDarkAtAll();
-        if (nowFullyDark != wasFullyDark) {
-            updateContentHeight();
-            if (nowFullyDark) {
-                updateDarkShelfVisibility();
-            }
+    public void setHideAmount(float linearHideAmount, float interpolatedHideAmount) {
+        mLinearHideAmount = linearHideAmount;
+        mInterpolatedHideAmount = interpolatedHideAmount;
+        boolean wasFullyHidden = mAmbientState.isFullyHidden();
+        boolean wasHiddenAtAll = mAmbientState.isHiddenAtAll();
+        mAmbientState.setHideAmount(interpolatedHideAmount);
+        boolean nowFullyHidden = mAmbientState.isFullyHidden();
+        boolean nowHiddenAtAll = mAmbientState.isHiddenAtAll();
+        if (nowFullyHidden != wasFullyHidden) {
+            updateVisibility();
         }
-        if (!wasDarkAtAll && nowDarkAtAll) {
+        if (!wasHiddenAtAll && nowHiddenAtAll) {
             resetExposedMenuView(true /* animate */, true /* animate */);
         }
-        if (nowFullyDark != wasFullyDark || wasDarkAtAll != nowDarkAtAll) {
+        if (nowFullyHidden != wasFullyHidden || wasHiddenAtAll != nowHiddenAtAll) {
             invalidateOutline();
         }
         updateAlgorithmHeightAndPadding();
         updateBackgroundDimming();
-        updatePanelTranslation();
         requestChildrenUpdate();
+        updateOwnTranslationZ();
     }
 
-    private void updateDarkShelfVisibility() {
-        DozeParameters dozeParameters = DozeParameters.getInstance(mContext);
-        if (dozeParameters.shouldControlScreenOff()) {
-            mShelf.fadeInTranslating();
+    private void updateOwnTranslationZ() {
+        // Since we are clipping to the outline we need to make sure that the shadows aren't
+        // clipped when pulsing
+        float ownTranslationZ = 0;
+        if (mKeyguardBypassController.getBypassEnabled() && mAmbientState.isHiddenAtAll()) {
+            ExpandableView firstChildNotGone = getFirstChildNotGone();
+            if (firstChildNotGone != null && firstChildNotGone.showingPulsing()) {
+                ownTranslationZ = firstChildNotGone.getTranslationZ();
+            }
         }
-        updateClipping();
+        setTranslationZ(ownTranslationZ);
+    }
+
+    private void updateVisibility() {
+        boolean shouldShow = !mAmbientState.isFullyHidden() || !onKeyguard();
+        setVisibility(shouldShow ? View.VISIBLE : View.INVISIBLE);
     }
 
     @ShadeViewRefactor(RefactorComponent.STATE_RESOLVER)
-    public void notifyDarkAnimationStart(boolean dark) {
-        // We only swap the scaling factor if we're fully dark or fully awake to avoid
+    public void notifyHideAnimationStart(boolean hide) {
+        // We only swap the scaling factor if we're fully hidden or fully awake to avoid
         // interpolation issues when playing with the power button.
-        if (mInterpolatedDarkAmount == 0 || mInterpolatedDarkAmount == 1) {
-            mBackgroundXFactor = dark ? 1.8f : 1.5f;
-            mDarkXInterpolator = dark
+        if (mInterpolatedHideAmount == 0 || mInterpolatedHideAmount == 1) {
+            mBackgroundXFactor = hide ? 1.8f : 1.5f;
+            mHideXInterpolator = hide
                     ? Interpolators.FAST_OUT_SLOW_IN_REVERSE
                     : Interpolators.FAST_OUT_SLOW_IN;
         }
     }
 
-    @ShadeViewRefactor(RefactorComponent.STATE_RESOLVER)
-    private int findDarkAnimationOriginIndex(@Nullable PointF screenLocation) {
-        if (screenLocation == null || screenLocation.y < mTopPadding) {
-            return AnimationEvent.DARK_ANIMATION_ORIGIN_INDEX_ABOVE;
-        }
-        if (screenLocation.y > getBottomMostNotificationBottom()) {
-            return AnimationEvent.DARK_ANIMATION_ORIGIN_INDEX_BELOW;
-        }
-        View child = getClosestChildAtRawPosition(screenLocation.x, screenLocation.y);
-        if (child != null) {
-            return getNotGoneIndex(child);
-        } else {
-            return AnimationEvent.DARK_ANIMATION_ORIGIN_INDEX_ABOVE;
-        }
-    }
-
     @ShadeViewRefactor(RefactorComponent.SHADE_VIEW)
     private int getNotGoneIndex(View child) {
         int count = getChildCount();
@@ -5084,13 +5070,6 @@
         mAnimationFinishedRunnables.add(runnable);
     }
 
-    @ShadeViewRefactor(RefactorComponent.SHADE_VIEW)
-    public void setHeadsUpManager(HeadsUpManagerPhone headsUpManager) {
-        mHeadsUpManager = headsUpManager;
-        mHeadsUpManager.addListener(mRoundnessManager);
-        mHeadsUpManager.setAnimationStateHandler(this::setHeadsUpGoingAwayAnimationsAllowed);
-    }
-
     public void generateHeadsUpAnimation(NotificationEntry entry, boolean isHeadsUp) {
         ExpandableNotificationRow row = entry.getHeadsUpAnimationView();
         generateHeadsUpAnimation(row, isHeadsUp);
@@ -5101,7 +5080,7 @@
         if (mAnimationsEnabled && (isHeadsUp || mHeadsUpGoingAwayAnimationsAllowed)) {
             mHeadsUpChangeAnimations.add(new Pair<>(row, isHeadsUp));
             mNeedsAnimation = true;
-            if (!mIsExpanded && !isHeadsUp) {
+            if (!mIsExpanded && !mWillExpand && !isHeadsUp) {
                 row.setHeadsUpAnimatingAway(true);
             }
             requestChildrenUpdate();
@@ -5122,6 +5101,11 @@
         requestChildrenUpdate();
     }
 
+    @Override
+    public void setWillExpand(boolean willExpand) {
+        mWillExpand = willExpand;
+    }
+
     @ShadeViewRefactor(RefactorComponent.SHADE_VIEW)
     public void setTrackingHeadsUp(ExpandableNotificationRow row) {
         mTrackingHeadsUp = row != null;
@@ -5169,7 +5153,6 @@
             return;
         }
         mPulsing = pulsing;
-        updateClipping();
         mAmbientState.setPulsing(pulsing);
         mSwipeHelper.setPulsing(pulsing);
         updateNotificationAnimationStates();
@@ -5318,7 +5301,7 @@
         boolean publicMode = mLockscreenUserManager.isAnyProfilePublicMode();
 
         if (mHeadsUpAppearanceController != null) {
-            mHeadsUpAppearanceController.setPublicMode(publicMode);
+            mHeadsUpAppearanceController.onStateChanged();
         }
 
         SysuiStatusBarStateController state = (SysuiStatusBarStateController)
@@ -5336,6 +5319,7 @@
         onUpdateRowStates();
 
         mEntryManager.updateNotifications();
+        updateVisibility();
     }
 
     @ShadeViewRefactor(RefactorComponent.SHADE_VIEW)
@@ -5374,12 +5358,6 @@
     }
 
     @ShadeViewRefactor(RefactorComponent.SHADE_VIEW)
-    public void setAntiBurnInOffsetX(int antiBurnInOffsetX) {
-        mAntiBurnInOffsetX = antiBurnInOffsetX;
-        updatePanelTranslation();
-    }
-
-    @ShadeViewRefactor(RefactorComponent.SHADE_VIEW)
     public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
         pw.println(String.format("[%s: pulsing=%s qsCustomizerShowing=%s visibility=%s"
                         + " alpha:%f scrollY:%d maxTopPadding:%d showShelfOnly=%s"
@@ -5432,18 +5410,18 @@
     }
 
     @ShadeViewRefactor(RefactorComponent.SHADE_VIEW)
-    public boolean isFullyDark() {
-        return mAmbientState.isFullyDark();
+    public boolean isFullyHidden() {
+        return mAmbientState.isFullyHidden();
     }
 
     /**
-     * Add a listener whenever the expanded height changes. The first value passed as an argument
-     * is the expanded height and the second one is the appearFraction.
+     * Add a listener whenever the expanded height changes. The first value passed as an
+     * argument is the expanded height and the second one is the appearFraction.
      *
      * @param listener the listener to notify.
      */
     @ShadeViewRefactor(RefactorComponent.SHADE_VIEW)
-    public void addOnExpandedHeightListener(BiConsumer<Float, Float> listener) {
+    public void addOnExpandedHeightChangedListener(BiConsumer<Float, Float> listener) {
         mExpandedHeightListeners.add(listener);
     }
 
@@ -5451,7 +5429,7 @@
      * Stop a listener from listening to the expandedHeight.
      */
     @ShadeViewRefactor(RefactorComponent.SHADE_VIEW)
-    public void removeOnExpandedHeightListener(BiConsumer<Float, Float> listener) {
+    public void removeOnExpandedHeightChangedListener(BiConsumer<Float, Float> listener) {
         mExpandedHeightListeners.remove(listener);
     }
 
@@ -5672,12 +5650,19 @@
      */
     public float setPulseHeight(float height) {
         mAmbientState.setPulseHeight(height);
+        if (mKeyguardBypassController.getBypassEnabled()) {
+            notifyAppearChangedListeners();
+        }
         requestChildrenUpdate();
         return Math.max(0, height - mAmbientState.getInnerHeight(true /* ignorePulseHeight */));
     }
 
+    public float getPulseHeight() {
+        return mAmbientState.getPulseHeight();
+    }
+
     /**
-     * Set the amount how much we're dozing. This is different from how dark the shade is, when
+     * Set the amount how much we're dozing. This is different from how hidden the shade is, when
      * the notification is pulsing.
      */
     public void setDozeAmount(float dozeAmount) {
@@ -5687,7 +5672,7 @@
     }
 
     public void wakeUpFromPulse() {
-        setPulseHeight(getPulseHeight());
+        setPulseHeight(getWakeUpHeight());
         // Let's place the hidden views at the end of the pulsing notification to make sure we have
         // a smooth animation
         boolean firstVisibleView = true;
@@ -5721,6 +5706,25 @@
             // The bottom might change because we're using the final actual height of the view
             mAnimateBottomOnLayout = true;
         }
+        // Let's update the footer once the notifications have been updated (in the next frame)
+        post(() -> {
+            updateFooter();
+            updateSectionBoundaries();
+        });
+    }
+
+    public void setOnPulseHeightChangedListener(Runnable listener) {
+        mAmbientState.setOnPulseHeightChangedListener(listener);
+    }
+
+    public float calculateAppearFractionBypass() {
+        float pulseHeight = getPulseHeight();
+        float wakeUpHeight = getWakeUpHeight();
+        float dragDownAmount = pulseHeight - wakeUpHeight;
+
+        // The total distance required to fully reveal the header
+        float totalDistance = getIntrinsicPadding();
+        return MathUtils.smoothStep(0, totalDistance, dragDownAmount);
     }
 
     /**
@@ -5896,9 +5900,6 @@
                         .animateY()
                         .animateZ(),
 
-                // ANIMATION_TYPE_DARK
-                null, // Unused
-
                 // ANIMATION_TYPE_GO_TO_FULL_SHADE
                 new AnimationFilter()
                         .animateHeight()
@@ -5960,7 +5961,6 @@
                 // ANIMATION_TYPE_EVERYTHING
                 new AnimationFilter()
                         .animateAlpha()
-                        .animateDark()
                         .animateDimmed()
                         .animateHideSensitive()
                         .animateHeight()
@@ -5992,9 +5992,6 @@
                 // ANIMATION_TYPE_CHANGE_POSITION
                 StackStateAnimator.ANIMATION_DURATION_STANDARD,
 
-                // ANIMATION_TYPE_DARK
-                StackStateAnimator.ANIMATION_DURATION_WAKEUP,
-
                 // ANIMATION_TYPE_GO_TO_FULL_SHADE
                 StackStateAnimator.ANIMATION_DURATION_GO_TO_FULL_SHADE,
 
@@ -6030,19 +6027,15 @@
         static final int ANIMATION_TYPE_ACTIVATED_CHILD = 4;
         static final int ANIMATION_TYPE_DIMMED = 5;
         static final int ANIMATION_TYPE_CHANGE_POSITION = 6;
-        static final int ANIMATION_TYPE_DARK = 7;
-        static final int ANIMATION_TYPE_GO_TO_FULL_SHADE = 8;
-        static final int ANIMATION_TYPE_HIDE_SENSITIVE = 9;
-        static final int ANIMATION_TYPE_VIEW_RESIZE = 10;
-        static final int ANIMATION_TYPE_GROUP_EXPANSION_CHANGED = 11;
-        static final int ANIMATION_TYPE_HEADS_UP_APPEAR = 12;
-        static final int ANIMATION_TYPE_HEADS_UP_DISAPPEAR = 13;
-        static final int ANIMATION_TYPE_HEADS_UP_DISAPPEAR_CLICK = 14;
-        static final int ANIMATION_TYPE_HEADS_UP_OTHER = 15;
-        static final int ANIMATION_TYPE_EVERYTHING = 16;
-
-        static final int DARK_ANIMATION_ORIGIN_INDEX_ABOVE = -1;
-        static final int DARK_ANIMATION_ORIGIN_INDEX_BELOW = -2;
+        static final int ANIMATION_TYPE_GO_TO_FULL_SHADE = 7;
+        static final int ANIMATION_TYPE_HIDE_SENSITIVE = 8;
+        static final int ANIMATION_TYPE_VIEW_RESIZE = 9;
+        static final int ANIMATION_TYPE_GROUP_EXPANSION_CHANGED = 10;
+        static final int ANIMATION_TYPE_HEADS_UP_APPEAR = 11;
+        static final int ANIMATION_TYPE_HEADS_UP_DISAPPEAR = 12;
+        static final int ANIMATION_TYPE_HEADS_UP_DISAPPEAR_CLICK = 13;
+        static final int ANIMATION_TYPE_HEADS_UP_OTHER = 14;
+        static final int ANIMATION_TYPE_EVERYTHING = 15;
 
         final long eventStartTime;
         final ExpandableView mChangingView;
@@ -6050,7 +6043,6 @@
         final AnimationFilter filter;
         final long length;
         View viewAfterChangingView;
-        int darkAnimationOriginIndex;
         boolean headsUpFromBottom;
 
         AnimationEvent(ExpandableView view, int type) {
@@ -6305,6 +6297,15 @@
             mAmbientState.onDragFinished(animView);
             updateContinuousShadowDrawing();
             updateContinuousBackgroundDrawing();
+            if (animView instanceof ExpandableNotificationRow) {
+                ExpandableNotificationRow row = (ExpandableNotificationRow) animView;
+                if (row.isPinned() && !canChildBeDismissed(row)
+                        && row.getStatusBarNotification().getNotification().fullScreenIntent
+                                == null) {
+                    mHeadsUpManager.removeNotification(row.getStatusBarNotification().getKey(),
+                            true /* removeImmediately */);
+                }
+            }
         }
 
         @Override
@@ -6355,7 +6356,7 @@
                         (int) (dragLengthY / mDisplayMetrics.density),
                         0 /* velocityDp - N/A */);
 
-                if (!mAmbientState.isDark() || startingChild != null) {
+                if (!mAmbientState.isDozing() || startingChild != null) {
                     // We have notifications, go to locked shade.
                     mShadeController.goToLockedShade(startingChild);
                     if (startingChild instanceof ExpandableNotificationRow) {
@@ -6365,6 +6366,11 @@
                 }
 
                 return true;
+            } else if (mDynamicPrivacyController.isInLockedDownShade()) {
+                mStatusbarStateController.setLeaveOpenOnKeyguardHide(true);
+                mStatusBar.dismissKeyguardThenExecute(() -> false /* dismissAction */,
+                        null /* cancelRunnable */, false /* afterKeyguardGone */);
+                return true;
             } else {
                 // abort gesture.
                 return false;
@@ -6398,6 +6404,30 @@
         public boolean isFalsingCheckNeeded() {
             return mStatusBarState == StatusBarState.KEYGUARD;
         }
+
+        @Override
+        public boolean isDragDownEnabledForView(ExpandableView view) {
+            if (isDragDownAnywhereEnabled()) {
+                return true;
+            }
+            if (mDynamicPrivacyController.isInLockedDownShade()) {
+                if (view == null) {
+                    // Dragging down is allowed in general
+                    return true;
+                }
+                if (view instanceof ExpandableNotificationRow) {
+                    // Only drag down on sensitive views, otherwise the ExpandHelper will take this
+                    return ((ExpandableNotificationRow) view).getEntry().isSensitive();
+                }
+            }
+            return false;
+        }
+
+        @Override
+        public boolean isDragDownAnywhereEnabled() {
+            return mStatusbarStateController.getState() == StatusBarState.KEYGUARD
+                    && !mKeyguardBypassController.getBypassEnabled();
+        }
     };
 
     public DragDownCallback getDragDownCallback() { return mDragDownCallback; }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/SectionHeaderView.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/SectionHeaderView.java
index cc1170f..b444fa5 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/SectionHeaderView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/SectionHeaderView.java
@@ -83,6 +83,11 @@
         bindContents();
     }
 
+    @Override
+    public boolean isTransparent() {
+        return true;
+    }
+
     /** Must be called whenever the UI mode changes (i.e. when we enter night mode). */
     void onUiModeChanged() {
         updateBackgroundColors();
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/StackScrollAlgorithm.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/StackScrollAlgorithm.java
index d9f8c88..ef80484 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/StackScrollAlgorithm.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/StackScrollAlgorithm.java
@@ -159,15 +159,14 @@
         float drawStart = !ambientState.isOnKeyguard() ? ambientState.getTopPadding()
                 + ambientState.getStackTranslation() + ambientState.getExpandAnimationTopChange()
                 : 0;
-        float previousNotificationEnd = 0;
-        float previousNotificationStart = 0;
+        float clipStart = 0;
         int childCount = algorithmState.visibleChildren.size();
+        boolean firstHeadsUp = true;
         for (int i = 0; i < childCount; i++) {
             ExpandableView child = algorithmState.visibleChildren.get(i);
             ExpandableViewState state = child.getViewState();
             if (!child.mustStayOnScreen() || state.headsUpIsVisible) {
-                previousNotificationEnd = Math.max(drawStart, previousNotificationEnd);
-                previousNotificationStart = Math.max(drawStart, previousNotificationStart);
+                clipStart = Math.max(drawStart, clipStart);
             }
             float newYTranslation = state.yTranslation;
             float newHeight = state.height;
@@ -175,20 +174,21 @@
             boolean isHeadsUp = (child instanceof ExpandableNotificationRow)
                     && ((ExpandableNotificationRow) child).isPinned();
             if (mClipNotificationScrollToTop
-                    && !state.inShelf && newYTranslation < previousNotificationEnd
-                    && (!isHeadsUp || ambientState.isShadeExpanded())) {
+                    && (!state.inShelf || (isHeadsUp && !firstHeadsUp))
+                    && newYTranslation < clipStart) {
                 // The previous view is overlapping on top, clip!
-                float overlapAmount = previousNotificationEnd - newYTranslation;
+                float overlapAmount = clipStart - newYTranslation;
                 state.clipTopAmount = (int) overlapAmount;
             } else {
                 state.clipTopAmount = 0;
             }
-
+            if (isHeadsUp) {
+                firstHeadsUp = false;
+            }
             if (!child.isTransparent()) {
                 // Only update the previous values if we are not transparent,
                 // otherwise we would clip to a transparent view.
-                previousNotificationEnd = newNotificationEnd;
-                previousNotificationStart = newYTranslation;
+                clipStart = Math.max(clipStart, isHeadsUp ? newYTranslation : newNotificationEnd);
             }
         }
     }
@@ -213,7 +213,6 @@
     private void updateDimmedActivatedHideSensitive(AmbientState ambientState,
             StackScrollAlgorithmState algorithmState) {
         boolean dimmed = ambientState.isDimmed();
-        boolean dark = ambientState.isFullyDark();
         boolean hideSensitive = ambientState.isHideSensitive();
         View activatedChild = ambientState.getActivatedChild();
         int childCount = algorithmState.visibleChildren.size();
@@ -221,7 +220,6 @@
             ExpandableView child = algorithmState.visibleChildren.get(i);
             ExpandableViewState childViewState = child.getViewState();
             childViewState.dimmed = dimmed;
-            childViewState.dark = dark;
             childViewState.hideSensitive = hideSensitive;
             boolean isActivatedChild = activatedChild == child;
             if (dimmed && isActivatedChild) {
@@ -255,7 +253,7 @@
         state.paddingMap.clear();
         int notGoneIndex = 0;
         ExpandableView lastView = null;
-        int firstHiddenIndex = ambientState.isDark()
+        int firstHiddenIndex = ambientState.isDozing()
                 ? (ambientState.hasPulsingNotifications() ? 1 : 0)
                 : childCount;
 
@@ -501,8 +499,7 @@
                 continue;
             }
             ExpandableNotificationRow row = (ExpandableNotificationRow) child;
-            if (!row.showingAmbientPulsing() || ambientState.isFullyDark()
-                    || (i == 0 && ambientState.isPulseExpanding())) {
+            if (!row.showingPulsing() || (i == 0 && ambientState.isPulseExpanding())) {
                 continue;
             }
             ExpandableViewState viewState = row.getViewState();
@@ -517,11 +514,11 @@
         for (int i = 0; i < childCount; i++) {
             View child = algorithmState.visibleChildren.get(i);
             if (!(child instanceof ExpandableNotificationRow)) {
-                break;
+                continue;
             }
             ExpandableNotificationRow row = (ExpandableNotificationRow) child;
             if (!row.isHeadsUp()) {
-                break;
+                continue;
             }
             ExpandableViewState childState = row.getViewState();
             if (topHeadsUpEntry == null && row.mustStayOnScreen() && !childState.headsUpIsVisible) {
@@ -531,7 +528,8 @@
             boolean isTopEntry = topHeadsUpEntry == row;
             float unmodifiedEndLocation = childState.yTranslation + childState.height;
             if (mIsExpanded) {
-                if (row.mustStayOnScreen() && !childState.headsUpIsVisible) {
+                if (row.mustStayOnScreen() && !childState.headsUpIsVisible
+                        && !row.showingPulsing()) {
                     // Ensure that the heads up is always visible even when scrolled off
                     clampHunToTop(ambientState, row, childState);
                     if (i == 0 && row.isAboveShelf()) {
@@ -548,12 +546,12 @@
                 ExpandableViewState topState =
                         topHeadsUpEntry == null ? null : topHeadsUpEntry.getViewState();
                 if (topState != null && !isTopEntry && (!mIsExpanded
-                        || unmodifiedEndLocation < topState.yTranslation + topState.height)) {
+                        || unmodifiedEndLocation > topState.yTranslation + topState.height)) {
                     // Ensure that a headsUp doesn't vertically extend further than the heads-up at
                     // the top most z-position
                     childState.height = row.getIntrinsicHeight();
-                    childState.yTranslation = topState.yTranslation + topState.height
-                            - childState.height;
+                    childState.yTranslation = Math.min(topState.yTranslation + topState.height
+                            - childState.height, childState.yTranslation);
                 }
 
                 // heads up notification show and this row is the top entry of heads up
@@ -668,7 +666,7 @@
             }
             childViewState.zTranslation = baseZ
                     + childrenOnTop * zDistanceBetweenElements;
-        } else if (i == 0 && child.isAboveShelf()) {
+        } else if (i == 0 && (child.isAboveShelf() || child.showingPulsing())) {
             // In case this is a new view that has never been measured before, we don't want to
             // elevate if we are currently expanded more then the notification
             int shelfHeight = ambientState.getShelf() == null ? 0 :
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/StackStateAnimator.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/StackStateAnimator.java
index a6f4ca5..0996ff2 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/StackStateAnimator.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/StackStateAnimator.java
@@ -28,6 +28,7 @@
 import com.android.systemui.R;
 import com.android.systemui.statusbar.NotificationShelf;
 import com.android.systemui.statusbar.StatusBarIconView;
+import com.android.systemui.statusbar.notification.collection.NotificationEntry;
 import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
 import com.android.systemui.statusbar.notification.row.ExpandableView;
 
@@ -174,8 +175,7 @@
                         || viewState.zTranslation != child.getTranslationZ()
                         || viewState.alpha != child.getAlpha()
                         || viewState.height != child.getActualHeight()
-                        || viewState.clipTopAmount != child.getClipTopAmount()
-                        || viewState.dark != child.isDark())) {
+                        || viewState.clipTopAmount != child.getClipTopAmount())) {
             mAnimationProperties.delay = mCurrentAdditionalDelay
                     + calculateChildAnimationDelay(viewState, animationStaggerCount);
         }
@@ -452,7 +452,11 @@
                     if (row.isDismissed()) {
                         needsAnimation = false;
                     }
-                    StatusBarIconView icon = row.getEntry().icon;
+                    NotificationEntry entry = row.getEntry();
+                    StatusBarIconView icon = entry.icon;
+                    if (entry.centeredIcon != null && entry.centeredIcon.getParent() != null) {
+                        icon = entry.centeredIcon;
+                    }
                     if (icon.getParent() != null) {
                         icon.getLocationOnScreen(mTmpLocation);
                         float iconPosition = mTmpLocation[0] - icon.getTranslationX()
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/BiometricUnlockController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/BiometricUnlockController.java
index eccd70b..41c6a7b 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/BiometricUnlockController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/BiometricUnlockController.java
@@ -16,6 +16,7 @@
 
 package com.android.systemui.statusbar.phone;
 
+import android.annotation.IntDef;
 import android.content.Context;
 import android.hardware.biometrics.BiometricSourceType;
 import android.metrics.LogMaker;
@@ -23,7 +24,6 @@
 import android.os.PowerManager;
 import android.os.SystemClock;
 import android.os.Trace;
-import android.provider.Settings;
 import android.util.Log;
 
 import com.android.internal.annotations.VisibleForTesting;
@@ -34,14 +34,14 @@
 import com.android.keyguard.KeyguardUpdateMonitor;
 import com.android.keyguard.KeyguardUpdateMonitorCallback;
 import com.android.systemui.Dependency;
-import com.android.systemui.R;
 import com.android.systemui.keyguard.KeyguardViewMediator;
 import com.android.systemui.keyguard.ScreenLifecycle;
 import com.android.systemui.keyguard.WakefulnessLifecycle;
 import com.android.systemui.statusbar.NotificationMediaManager;
-import com.android.systemui.tuner.TunerService;
 
 import java.io.PrintWriter;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
 
 /**
  * Controller which coordinates all the biometric unlocking actions with the UI.
@@ -53,6 +53,20 @@
     private static final long BIOMETRIC_WAKELOCK_TIMEOUT_MS = 15 * 1000;
     private static final String BIOMETRIC_WAKE_LOCK_NAME = "wake-and-unlock wakelock";
 
+    @IntDef(prefix = { "MODE_" }, value = {
+            MODE_NONE,
+            MODE_WAKE_AND_UNLOCK,
+            MODE_WAKE_AND_UNLOCK_PULSING,
+            MODE_SHOW_BOUNCER,
+            MODE_ONLY_WAKE,
+            MODE_UNLOCK_COLLAPSING,
+            MODE_UNLOCK_FADING,
+            MODE_DISMISS_BOUNCER,
+            MODE_WAKE_AND_UNLOCK_FROM_DREAM
+    })
+    @Retention(RetentionPolicy.SOURCE)
+    public @interface WakeAndUnlockMode {}
+
     /**
      * Mode in which we don't need to wake up the device when we authenticate.
      */
@@ -84,38 +98,33 @@
     /**
      * Mode in which fingerprint unlocks the device.
      */
-    public static final int MODE_UNLOCK = 5;
-
-    /**
-     * Mode in which fingerprint brings up the bouncer because fingerprint unlocking is currently
-     * not allowed.
-     */
-    public static final int MODE_DISMISS_BOUNCER = 6;
+    public static final int MODE_UNLOCK_COLLAPSING = 5;
 
     /**
      * Mode in which fingerprint wakes and unlocks the device from a dream.
      */
-    public static final int MODE_WAKE_AND_UNLOCK_FROM_DREAM = 7;
+    public static final int MODE_WAKE_AND_UNLOCK_FROM_DREAM = 6;
+
+    /**
+     * Faster mode of dismissing the lock screen when we cross fade to an app
+     * (used for keyguard bypass.)
+     */
+    public static final int MODE_UNLOCK_FADING = 7;
+
+    /**
+     * When bouncer is visible and will be dismissed.
+     */
+    public static final int MODE_DISMISS_BOUNCER = 8;
 
     /**
      * How much faster we collapse the lockscreen when authenticating with biometric.
      */
     private static final float BIOMETRIC_COLLAPSE_SPEEDUP_FACTOR = 1.1f;
 
-    /**
-     * If face unlock dismisses the lock screen or keeps user on keyguard by default on this device.
-     */
-    private final boolean mFaceDismissesKeyguardByDefault;
-
-    /**
-     * If face unlock dismisses the lock screen or keeps user on keyguard for the current user.
-     */
-    @VisibleForTesting
-    protected boolean mFaceDismissesKeyguard;
-
     private final NotificationMediaManager mMediaManager;
     private final PowerManager mPowerManager;
     private final Handler mHandler;
+    private final KeyguardBypassController mKeyguardBypassController;
     private PowerManager.WakeLock mWakeLock;
     private final KeyguardUpdateMonitor mUpdateMonitor;
     private final UnlockMethodCache mUnlockMethodCache;
@@ -134,16 +143,6 @@
     private boolean mHasScreenTurnedOnSinceAuthenticating;
     private boolean mFadedAwayAfterWakeAndUnlock;
 
-    private final TunerService.Tunable mFaceDismissedKeyguardTunable = new TunerService.Tunable() {
-        @Override
-        public void onTuningChanged(String key, String newValue) {
-            int defaultValue = mFaceDismissesKeyguardByDefault ? 1 : 0;
-            mFaceDismissesKeyguard = Settings.Secure.getIntForUser(mContext.getContentResolver(),
-                    Settings.Secure.FACE_UNLOCK_DISMISSES_KEYGUARD,
-                    defaultValue, KeyguardUpdateMonitor.getCurrentUser()) != 0;
-        }
-    };
-
     private final MetricsLogger mMetricsLogger = Dependency.get(MetricsLogger.class);
 
     public BiometricUnlockController(Context context,
@@ -153,12 +152,12 @@
             StatusBar statusBar,
             UnlockMethodCache unlockMethodCache, Handler handler,
             KeyguardUpdateMonitor keyguardUpdateMonitor,
-            TunerService tunerService) {
+            KeyguardBypassController keyguardBypassController) {
         this(context, dozeScrimController, keyguardViewMediator, scrimController, statusBar,
-                unlockMethodCache, handler, keyguardUpdateMonitor, tunerService,
+                unlockMethodCache, handler, keyguardUpdateMonitor,
                 context.getResources()
                         .getInteger(com.android.internal.R.integer.config_wakeUpDelayDoze),
-                context.getResources().getBoolean(R.bool.config_faceAuthDismissesKeyguard));
+                keyguardBypassController);
     }
 
     @VisibleForTesting
@@ -169,9 +168,8 @@
                                      StatusBar statusBar,
                                      UnlockMethodCache unlockMethodCache, Handler handler,
                                      KeyguardUpdateMonitor keyguardUpdateMonitor,
-                                     TunerService tunerService,
                                      int wakeUpDelay,
-                                     boolean faceDismissesKeyguard) {
+                                     KeyguardBypassController keyguardBypassController) {
         mContext = context;
         mPowerManager = context.getSystemService(PowerManager.class);
         mUpdateMonitor = keyguardUpdateMonitor;
@@ -187,9 +185,8 @@
         mUnlockMethodCache = unlockMethodCache;
         mHandler = handler;
         mWakeUpDelay = wakeUpDelay;
-        mFaceDismissesKeyguardByDefault = faceDismissesKeyguard;
-        tunerService.addTunable(mFaceDismissedKeyguardTunable,
-                Settings.Secure.FACE_UNLOCK_DISMISSES_KEYGUARD);
+        mKeyguardBypassController = keyguardBypassController;
+        mKeyguardBypassController.setUnlockController(this);
     }
 
     public void setStatusBarKeyguardViewManager(
@@ -261,11 +258,21 @@
         }
         mMetricsLogger.write(new LogMaker(MetricsEvent.BIOMETRIC_AUTH)
                 .setType(MetricsEvent.TYPE_SUCCESS).setSubtype(toSubtype(biometricSourceType)));
+        boolean unlockAllowed = mKeyguardBypassController.onBiometricAuthenticated(
+                biometricSourceType);
+        if (unlockAllowed) {
+            mKeyguardViewMediator.userActivity();
+            startWakeAndUnlock(biometricSourceType);
+        } else {
+            Log.d(TAG, "onBiometricAuthenticated aborted by bypass controller");
+        }
+    }
+
+    public void startWakeAndUnlock(BiometricSourceType biometricSourceType) {
         startWakeAndUnlock(calculateMode(biometricSourceType));
     }
 
-    public void startWakeAndUnlock(int mode) {
-        // TODO(b/62444020): remove when this bug is fixed
+    public void startWakeAndUnlock(@WakeAndUnlockMode int mode) {
         Log.v(TAG, "startWakeAndUnlock(" + mode + ")");
         boolean wasDeviceInteractive = mUpdateMonitor.isDeviceInteractive();
         mMode = mode;
@@ -297,19 +304,20 @@
             Trace.endSection();
         };
 
-        if (!delayWakeUp) {
+        if (!delayWakeUp && mMode != MODE_NONE) {
             wakeUp.run();
         }
         switch (mMode) {
             case MODE_DISMISS_BOUNCER:
-                Trace.beginSection("MODE_DISMISS");
+            case MODE_UNLOCK_FADING:
+                Trace.beginSection("MODE_DISMISS_BOUNCER or MODE_UNLOCK_FADING");
                 mStatusBarKeyguardViewManager.notifyKeyguardAuthenticated(
                         false /* strongAuth */);
                 Trace.endSection();
                 break;
-            case MODE_UNLOCK:
+            case MODE_UNLOCK_COLLAPSING:
             case MODE_SHOW_BOUNCER:
-                Trace.beginSection("MODE_UNLOCK or MODE_SHOW_BOUNCER");
+                Trace.beginSection("MODE_UNLOCK_COLLAPSING or MODE_SHOW_BOUNCER");
                 if (!wasDeviceInteractive) {
                     mPendingShowBouncer = true;
                 } else {
@@ -390,33 +398,38 @@
         return mMode;
     }
 
-    private int calculateMode(BiometricSourceType biometricSourceType) {
+    private @WakeAndUnlockMode int calculateMode(BiometricSourceType biometricSourceType) {
+        if (biometricSourceType == BiometricSourceType.FACE
+                || biometricSourceType == BiometricSourceType.IRIS) {
+            return calculateModeForPassiveAuth();
+        } else {
+            return calculateModeForFingerprint();
+        }
+    }
+
+    private @WakeAndUnlockMode int calculateModeForFingerprint() {
         boolean unlockingAllowed = mUpdateMonitor.isUnlockingWithBiometricAllowed();
         boolean deviceDreaming = mUpdateMonitor.isDreaming();
-        boolean faceStayingOnKeyguard = biometricSourceType == BiometricSourceType.FACE
-                && !mFaceDismissesKeyguard;
 
         if (!mUpdateMonitor.isDeviceInteractive()) {
             if (!mStatusBarKeyguardViewManager.isShowing()) {
                 return MODE_ONLY_WAKE;
             } else if (mDozeScrimController.isPulsing() && unlockingAllowed) {
-                return faceStayingOnKeyguard ? MODE_NONE : MODE_WAKE_AND_UNLOCK_PULSING;
+                return MODE_WAKE_AND_UNLOCK_PULSING;
             } else if (unlockingAllowed || !mUnlockMethodCache.isMethodSecure()) {
                 return MODE_WAKE_AND_UNLOCK;
             } else {
                 return MODE_SHOW_BOUNCER;
             }
         }
-        if (unlockingAllowed && deviceDreaming && !faceStayingOnKeyguard) {
+        if (unlockingAllowed && deviceDreaming) {
             return MODE_WAKE_AND_UNLOCK_FROM_DREAM;
         }
         if (mStatusBarKeyguardViewManager.isShowing()) {
-            if ((mStatusBarKeyguardViewManager.isBouncerShowing()
-                    || mStatusBarKeyguardViewManager.isBouncerPartiallyVisible())
-                    && unlockingAllowed) {
+            if (mStatusBarKeyguardViewManager.bouncerIsOrWillBeShowing() && unlockingAllowed) {
                 return MODE_DISMISS_BOUNCER;
             } else if (unlockingAllowed) {
-                return faceStayingOnKeyguard ? MODE_ONLY_WAKE : MODE_UNLOCK;
+                return MODE_UNLOCK_COLLAPSING;
             } else if (!mStatusBarKeyguardViewManager.isBouncerShowing()) {
                 return MODE_SHOW_BOUNCER;
             }
@@ -424,6 +437,51 @@
         return MODE_NONE;
     }
 
+    private @WakeAndUnlockMode int calculateModeForPassiveAuth() {
+        boolean unlockingAllowed = mUpdateMonitor.isUnlockingWithBiometricAllowed();
+        boolean deviceDreaming = mUpdateMonitor.isDreaming();
+        boolean bypass = mKeyguardBypassController.getBypassEnabled();
+
+        if (!mUpdateMonitor.isDeviceInteractive()) {
+            if (!mStatusBarKeyguardViewManager.isShowing()) {
+                return bypass ? MODE_WAKE_AND_UNLOCK : MODE_ONLY_WAKE;
+            } else if (!unlockingAllowed) {
+                return bypass ? MODE_SHOW_BOUNCER : MODE_NONE;
+            } else if (mDozeScrimController.isPulsing()) {
+                // Let's not wake-up to lock screen when not bypassing, otherwise the notification
+                // would move as the user tried to tap it.
+                return bypass ? MODE_WAKE_AND_UNLOCK_PULSING : MODE_NONE;
+            } else {
+                if (bypass) {
+                    // Wake-up fading out nicely
+                    return MODE_WAKE_AND_UNLOCK_PULSING;
+                } else {
+                    // We could theoretically return MODE_NONE, but this means that the device
+                    // would be not interactive, unlocked, and the user would not see the device
+                    // state.
+                    return MODE_ONLY_WAKE;
+                }
+            }
+        }
+        if (unlockingAllowed && deviceDreaming) {
+            return bypass ? MODE_WAKE_AND_UNLOCK_FROM_DREAM : MODE_ONLY_WAKE;
+        }
+        if (mStatusBarKeyguardViewManager.isShowing()) {
+            if (mStatusBarKeyguardViewManager.bouncerIsOrWillBeShowing() && unlockingAllowed) {
+                if (bypass && mKeyguardBypassController.canPlaySubtleWindowAnimations()) {
+                    return MODE_UNLOCK_FADING;
+                } else {
+                    return MODE_DISMISS_BOUNCER;
+                }
+            } else if (unlockingAllowed) {
+                return bypass ? MODE_UNLOCK_FADING : MODE_NONE;
+            } else {
+                return bypass ? MODE_SHOW_BOUNCER : MODE_NONE;
+            }
+        }
+        return MODE_NONE;
+    }
+
     @Override
     public void onBiometricAuthFailed(BiometricSourceType biometricSourceType) {
         mMetricsLogger.write(new LogMaker(MetricsEvent.BIOMETRIC_AUTH)
@@ -471,7 +529,8 @@
         mStatusBar.notifyBiometricAuthModeChanged();
     }
 
-    private final WakefulnessLifecycle.Observer mWakefulnessObserver =
+    @VisibleForTesting
+    final WakefulnessLifecycle.Observer mWakefulnessObserver =
             new WakefulnessLifecycle.Observer() {
         @Override
         public void onFinishedWakingUp() {
@@ -521,7 +580,14 @@
      * on or off.
      */
     public boolean isBiometricUnlock() {
-        return isWakeAndUnlock() || mMode == MODE_UNLOCK;
+        return isWakeAndUnlock() || mMode == MODE_UNLOCK_COLLAPSING || mMode == MODE_UNLOCK_FADING;
+    }
+
+    /**
+     * Successful authentication with fingerprint, face, or iris when the lockscreen fades away
+     */
+    public boolean isUnlockFading() {
+        return mMode == MODE_UNLOCK_FADING;
     }
 
     /**
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ButtonDispatcher.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ButtonDispatcher.java
index 539bc7b..fce1dcc 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ButtonDispatcher.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ButtonDispatcher.java
@@ -14,8 +14,7 @@
 
 package com.android.systemui.statusbar.phone;
 
-import static com.android.systemui.Interpolators.ALPHA_IN;
-import static com.android.systemui.Interpolators.ALPHA_OUT;
+import static com.android.systemui.Interpolators.LINEAR;
 
 import android.animation.Animator;
 import android.animation.AnimatorListenerAdapter;
@@ -23,6 +22,8 @@
 import android.view.View;
 import android.view.View.AccessibilityDelegate;
 
+import com.android.systemui.Dependency;
+import com.android.systemui.assist.AssistManager;
 import com.android.systemui.statusbar.policy.KeyButtonDrawable;
 
 import java.util.ArrayList;
@@ -32,12 +33,13 @@
  * multiples of the same nav bar icon appearing.
  */
 public class ButtonDispatcher {
-    private final static int FADE_DURATION_IN = 150;
-    private final static int FADE_DURATION_OUT = 100;
+    private static final int FADE_DURATION_IN = 150;
+    private static final int FADE_DURATION_OUT = 250;
 
     private final ArrayList<View> mViews = new ArrayList<>();
 
     private final int mId;
+    private final AssistManager mAssistManager;
 
     private View.OnClickListener mClickListener;
     private View.OnTouchListener mTouchListener;
@@ -55,7 +57,10 @@
     private AccessibilityDelegate mAccessibilityDelegate;
 
     private final ValueAnimator.AnimatorUpdateListener mAlphaListener = animation ->
-            setAlpha((float) animation.getAnimatedValue());
+            setAlpha(
+                    (float) animation.getAnimatedValue(),
+                    false /* animate */,
+                    false /* cancelAnimator */);
 
     private final AnimatorListenerAdapter mFadeListener = new AnimatorListenerAdapter() {
         @Override
@@ -67,6 +72,7 @@
 
     public ButtonDispatcher(int id) {
         mId = id;
+        mAssistManager = Dependency.get(AssistManager.class);
     }
 
     void clear() {
@@ -167,18 +173,32 @@
     }
 
     public void setAlpha(float alpha, boolean animate) {
-        setAlpha(alpha, animate, (getAlpha() < alpha) ? FADE_DURATION_IN : FADE_DURATION_OUT);
+        setAlpha(alpha, animate, true /* cancelAnimator */);
     }
 
     public void setAlpha(float alpha, boolean animate, long duration) {
+        setAlpha(alpha, animate, duration, true /* cancelAnimator */);
+    }
+
+    public void setAlpha(float alpha, boolean animate, boolean cancelAnimator) {
+        setAlpha(
+                alpha,
+                animate,
+                (getAlpha() < alpha) ? FADE_DURATION_IN : FADE_DURATION_OUT,
+                cancelAnimator);
+    }
+
+    public void setAlpha(float alpha, boolean animate, long duration, boolean cancelAnimator) {
+        if (mFadeAnimator != null && (cancelAnimator || animate)) {
+            mFadeAnimator.cancel();
+        }
         if (animate) {
-            if (mFadeAnimator != null) {
-                mFadeAnimator.cancel();
-            }
             setVisibility(View.VISIBLE);
             mFadeAnimator = ValueAnimator.ofFloat(getAlpha(), alpha);
+            mFadeAnimator.setStartDelay(
+                    mAssistManager.getAssistHandleShowAndGoRemainingDurationMs());
             mFadeAnimator.setDuration(duration);
-            mFadeAnimator.setInterpolator(getAlpha() < alpha ? ALPHA_IN : ALPHA_OUT);
+            mFadeAnimator.setInterpolator(LINEAR);
             mFadeAnimator.addListener(mFadeListener);
             mFadeAnimator.addUpdateListener(mAlphaListener);
             mFadeAnimator.start();
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/CollapsedStatusBarFragment.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/CollapsedStatusBarFragment.java
index 58f457e..d655b2f 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/CollapsedStatusBarFragment.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/CollapsedStatusBarFragment.java
@@ -35,6 +35,7 @@
 import com.android.systemui.SysUiServiceProvider;
 import com.android.systemui.plugins.statusbar.StatusBarStateController;
 import com.android.systemui.statusbar.CommandQueue;
+import com.android.systemui.statusbar.StatusBarState;
 import com.android.systemui.statusbar.phone.StatusBarIconController.DarkIconManager;
 import com.android.systemui.statusbar.policy.EncryptionHelper;
 import com.android.systemui.statusbar.policy.KeyguardMonitor;
@@ -201,20 +202,21 @@
     }
 
     protected int adjustDisableFlags(int state) {
+        boolean headsUpVisible = mStatusBarComponent.headsUpShouldBeVisible();
+        if (headsUpVisible) {
+            state |= DISABLE_CLOCK;
+        }
+
         if (!mKeyguardMonitor.isLaunchTransitionFadingAway()
                 && !mKeyguardMonitor.isKeyguardFadingAway()
-                && shouldHideNotificationIcons()) {
+                && shouldHideNotificationIcons()
+                && !(mStatusBarStateController.getState() == StatusBarState.KEYGUARD
+                        && headsUpVisible)) {
             state |= DISABLE_NOTIFICATION_ICONS;
             state |= DISABLE_SYSTEM_INFO;
             state |= DISABLE_CLOCK;
         }
 
-        // In landscape, the heads up show but shouldHideNotificationIcons() return false
-        // because the visual icon is in notification icon area rather than heads up's space.
-        // whether the notification icon show or not, clock should hide when heads up show.
-        if (mStatusBarComponent.isHeadsUpShouldBeVisible()) {
-            state |= DISABLE_CLOCK;
-        }
 
         if (mNetworkController != null && EncryptionHelper.IS_DATA_ENCRYPTED) {
             if (mNetworkController.hasEmergencyCryptKeeperText()) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeParameters.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeParameters.java
index a17e042..10b48e7 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeParameters.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeParameters.java
@@ -22,9 +22,7 @@
 import android.os.SystemProperties;
 import android.os.UserHandle;
 import android.provider.Settings;
-import android.text.TextUtils;
 import android.util.MathUtils;
-import android.util.SparseBooleanArray;
 
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.systemui.Dependency;
@@ -35,15 +33,17 @@
 
 import java.io.PrintWriter;
 
-public class DozeParameters implements TunerService.Tunable {
+/**
+ * Retrieve doze information
+ */
+public class DozeParameters implements TunerService.Tunable,
+        com.android.systemui.plugins.statusbar.DozeParameters {
     private static final int MAX_DURATION = 60 * 1000;
-    public static final String DOZE_SENSORS_WAKE_UP_FULLY = "doze_sensors_wake_up_fully";
     public static final boolean FORCE_NO_BLANKING =
             SystemProperties.getBoolean("debug.force_no_blanking", false);
     public static final boolean FORCE_BLANKING =
             SystemProperties.getBoolean("debug.force_blanking", false);
 
-    private static IntInOutMatcher sPickupSubtypePerformsProxMatcher;
     private static DozeParameters sInstance;
 
     private final Context mContext;
@@ -88,20 +88,6 @@
         pw.print("    getVibrateOnPickup(): "); pw.println(getVibrateOnPickup());
         pw.print("    getProxCheckBeforePulse(): "); pw.println(getProxCheckBeforePulse());
         pw.print("    getPickupVibrationThreshold(): "); pw.println(getPickupVibrationThreshold());
-        pw.print("    getPickupSubtypePerformsProxCheck(): ");pw.println(
-                dumpPickupSubtypePerformsProxCheck());
-    }
-
-    private String dumpPickupSubtypePerformsProxCheck() {
-        // Refresh sPickupSubtypePerformsProxMatcher
-        getPickupSubtypePerformsProxCheck(0);
-
-        if (sPickupSubtypePerformsProxMatcher == null) {
-            return "fallback: " + mContext.getResources().getBoolean(
-                    R.bool.doze_pickup_performs_proximity_check);
-        } else {
-            return "spec: " + sPickupSubtypePerformsProxMatcher.mSpec;
-        }
     }
 
     public boolean getDisplayStateSupported() {
@@ -221,21 +207,8 @@
         return SystemProperties.get(propName, mContext.getString(resId));
     }
 
-    public boolean getPickupSubtypePerformsProxCheck(int subType) {
-        String spec = getString("doze.pickup.proxcheck",
-                R.string.doze_pickup_subtype_performs_proximity_check);
-
-        if (TextUtils.isEmpty(spec)) {
-            // Fall back to non-subtype based property.
-            return mContext.getResources().getBoolean(R.bool.doze_pickup_performs_proximity_check);
-        }
-
-        if (sPickupSubtypePerformsProxMatcher == null
-                || !TextUtils.equals(spec, sPickupSubtypePerformsProxMatcher.mSpec)) {
-            sPickupSubtypePerformsProxMatcher = new IntInOutMatcher(spec);
-        }
-
-        return sPickupSubtypePerformsProxMatcher.isIn(subType);
+    public boolean getPickupPerformsProxCheck() {
+        return mContext.getResources().getBoolean(R.bool.doze_pickup_performs_proximity_check);
     }
 
     public int getPulseVisibleDurationExtended() {
@@ -254,81 +227,4 @@
     public AlwaysOnDisplayPolicy getPolicy() {
         return mAlwaysOnPolicy;
     }
-
-    /**
-     * Parses a spec of the form `1,2,3,!5,*`. The resulting object will match numbers that are
-     * listed, will not match numbers that are listed with a ! prefix, and will match / not match
-     * unlisted numbers depending on whether * or !* is present.
-     *
-     * *  -> match any numbers that are not explicitly listed
-     * !* -> don't match any numbers that are not explicitly listed
-     * 2  -> match 2
-     * !3 -> don't match 3
-     *
-     * It is illegal to specify:
-     * - an empty spec
-     * - a spec containing that are empty, or a lone !
-     * - a spec for anything other than numbers or *
-     * - multiple terms for the same number / multiple *s
-     */
-    public static class IntInOutMatcher {
-        private static final String WILDCARD = "*";
-        private static final char OUT_PREFIX = '!';
-
-        private final SparseBooleanArray mIsIn;
-        private final boolean mDefaultIsIn;
-        final String mSpec;
-
-        public IntInOutMatcher(String spec) {
-            if (TextUtils.isEmpty(spec)) {
-                throw new IllegalArgumentException("Spec must not be empty");
-            }
-
-            boolean defaultIsIn = false;
-            boolean foundWildcard = false;
-
-            mSpec = spec;
-            mIsIn = new SparseBooleanArray();
-
-            for (String itemPrefixed : spec.split(",", -1)) {
-                if (itemPrefixed.length() == 0) {
-                    throw new IllegalArgumentException(
-                            "Illegal spec, must not have zero-length items: `" + spec + "`");
-                }
-                boolean isIn = itemPrefixed.charAt(0) != OUT_PREFIX;
-                String item = isIn ? itemPrefixed : itemPrefixed.substring(1);
-
-                if (itemPrefixed.length() == 0) {
-                    throw new IllegalArgumentException(
-                            "Illegal spec, must not have zero-length items: `" + spec + "`");
-                }
-
-                if (WILDCARD.equals(item)) {
-                    if (foundWildcard) {
-                        throw new IllegalArgumentException("Illegal spec, `" + WILDCARD +
-                                "` must not appear multiple times in `" + spec + "`");
-                    }
-                    defaultIsIn = isIn;
-                    foundWildcard = true;
-                } else {
-                    int key = Integer.parseInt(item);
-                    if (mIsIn.indexOfKey(key) >= 0) {
-                        throw new IllegalArgumentException("Illegal spec, `" + key +
-                                "` must not appear multiple times in `" + spec + "`");
-                    }
-                    mIsIn.put(key, isIn);
-                }
-            }
-
-            if (!foundWildcard) {
-                throw new IllegalArgumentException("Illegal spec, must specify either * or !*");
-            }
-
-            mDefaultIsIn = defaultIsIn;
-        }
-
-        public boolean isIn(int value) {
-            return (mIsIn.get(value, mDefaultIsIn));
-        }
-    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeScrimController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeScrimController.java
index a243855..60e381a 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeScrimController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeScrimController.java
@@ -149,6 +149,14 @@
         mHandler.removeCallbacks(mPulseOut);
     }
 
+    /**
+     * When pulsing, cancel any timeouts that would take you out of the pulsing state.
+     */
+    public void cancelPendingPulseTimeout() {
+        mHandler.removeCallbacks(mPulseOut);
+        mHandler.removeCallbacks(mPulseOutExtended);
+    }
+
     private void cancelPulsing() {
         if (mPulseCallback != null) {
             if (DEBUG) Log.d(TAG, "Cancel pulsing");
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..3bef582 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/EdgeBackGestureHandler.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/EdgeBackGestureHandler.java
@@ -31,8 +31,10 @@
 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.util.StatsLog;
 import android.view.Gravity;
 import android.view.IPinnedStackController;
 import android.view.IPinnedStackListener;
@@ -66,7 +68,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,9 +106,13 @@
             new ISystemGestureExclusionListener.Stub() {
                 @Override
                 public void onSystemGestureExclusionChanged(int displayId,
-                        Region systemGestureExclusion) {
+                        Region systemGestureExclusion, Region unrestrictedOrNull) {
                     if (displayId == mDisplayId) {
-                        mMainExecutor.execute(() -> mExcludeRegion.set(systemGestureExclusion));
+                        mMainExecutor.execute(() -> {
+                            mExcludeRegion.set(systemGestureExclusion);
+                            mUnrestrictedExcludeRegion.set(unrestrictedOrNull != null
+                                    ? unrestrictedOrNull : systemGestureExclusion);
+                        });
                     }
                 }
             };
@@ -119,6 +126,8 @@
     private final Executor mMainExecutor;
 
     private final Region mExcludeRegion = new Region();
+    private final Region mUnrestrictedExcludeRegion = new Region();
+
     // The edge width where touch down is allowed
     private int mEdgeWidth;
     // The slop to distinguish between horizontal and vertical motion
@@ -137,6 +146,7 @@
     private final PointF mDownPoint = new PointF();
     private boolean mThresholdCrossed = false;
     private boolean mAllowGesture = false;
+    private boolean mInRejectedExclusion = false;
     private boolean mIsOnLeftEdge;
 
     private int mImeHeight = 0;
@@ -316,6 +326,12 @@
         if (isInExcludedRegion) {
             mOverviewProxyService.notifyBackAction(false /* completed */, -1, -1,
                     false /* isButton */, !mIsOnLeftEdge);
+            StatsLog.write(StatsLog.BACK_GESTURE_REPORTED_REPORTED,
+                    StatsLog.BACK_GESTURE__TYPE__INCOMPLETE_EXCLUDED, y,
+                    mIsOnLeftEdge ? StatsLog.BACK_GESTURE__X_LOCATION__LEFT :
+                            StatsLog.BACK_GESTURE__X_LOCATION__RIGHT);
+        } else {
+            mInRejectedExclusion = mUnrestrictedExcludeRegion.contains(x, y);
         }
         return !isInExcludedRegion;
     }
@@ -323,6 +339,7 @@
     private void cancelGesture(MotionEvent ev) {
         // Send action cancel to reset all the touch events
         mAllowGesture = false;
+        mInRejectedExclusion = false;
         MotionEvent cancelEv = MotionEvent.obtain(ev);
         cancelEv.setAction(MotionEvent.ACTION_CANCEL);
         mEdgePanel.handleTouch(cancelEv);
@@ -336,6 +353,7 @@
             // either the bouncer is showing or the notification panel is hidden
             int stateFlags = mOverviewProxyService.getSystemUiStateFlags();
             mIsOnLeftEdge = ev.getX() <= mEdgeWidth + mLeftInset;
+            mInRejectedExclusion = false;
             mAllowGesture = !QuickStepContract.isBackGestureDisabled(stateFlags)
                     && isWithinTouchRegion((int) ev.getX(), (int) ev.getY());
             if (mAllowGesture) {
@@ -390,6 +408,14 @@
                 }
                 mOverviewProxyService.notifyBackAction(performAction, (int) mDownPoint.x,
                         (int) mDownPoint.y, false /* isButton */, !mIsOnLeftEdge);
+                int backtype = performAction ? (mInRejectedExclusion
+                        ? StatsLog.BACK_GESTURE__TYPE__COMPLETED_REJECTED :
+                                StatsLog.BACK_GESTURE__TYPE__COMPLETED) :
+                                        StatsLog.BACK_GESTURE__TYPE__INCOMPLETE;
+                StatsLog.write(StatsLog.BACK_GESTURE_REPORTED_REPORTED, backtype,
+                        (int) mDownPoint.y, mIsOnLeftEdge
+                                ? StatsLog.BACK_GESTURE__X_LOCATION__LEFT :
+                                StatsLog.BACK_GESTURE__X_LOCATION__RIGHT);
             }
             if (isUp || action == MotionEvent.ACTION_CANCEL) {
                 mRegionSamplingHelper.stop();
@@ -461,7 +487,9 @@
         pw.println("EdgeBackGestureHandler:");
         pw.println("  mIsEnabled=" + mIsEnabled);
         pw.println("  mAllowGesture=" + mAllowGesture);
+        pw.println("  mInRejectedExclusion" + mInRejectedExclusion);
         pw.println("  mExcludeRegion=" + mExcludeRegion);
+        pw.println("  mUnrestrictedExcludeRegion=" + mUnrestrictedExcludeRegion);
         pw.println("  mImeHeight=" + mImeHeight);
         pw.println("  mIsAttached=" + mIsAttached);
         pw.println("  mEdgeWidth=" + mEdgeWidth);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpAppearanceController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpAppearanceController.java
index 66903fa..f53c4e8 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpAppearanceController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpAppearanceController.java
@@ -16,6 +16,8 @@
 
 package com.android.systemui.statusbar.phone;
 
+import static com.android.systemui.SysUiServiceProvider.getComponent;
+
 import android.graphics.Point;
 import android.graphics.Rect;
 import android.view.DisplayCutout;
@@ -27,11 +29,17 @@
 import com.android.systemui.Dependency;
 import com.android.systemui.R;
 import com.android.systemui.plugins.DarkIconDispatcher;
+import com.android.systemui.plugins.statusbar.StatusBarStateController;
+import com.android.systemui.statusbar.CommandQueue;
 import com.android.systemui.statusbar.CrossFadeHelper;
 import com.android.systemui.statusbar.HeadsUpStatusBarView;
+import com.android.systemui.statusbar.StatusBarState;
+import com.android.systemui.statusbar.SysuiStatusBarStateController;
+import com.android.systemui.statusbar.notification.NotificationWakeUpCoordinator;
 import com.android.systemui.statusbar.notification.collection.NotificationEntry;
 import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
 import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayout;
+import com.android.systemui.statusbar.policy.KeyguardMonitor;
 import com.android.systemui.statusbar.policy.OnHeadsUpChangedListener;
 
 import java.util.function.BiConsumer;
@@ -41,7 +49,7 @@
  * Controls the appearance of heads up notifications in the icon area and the header itself.
  */
 public class HeadsUpAppearanceController implements OnHeadsUpChangedListener,
-        DarkIconDispatcher.DarkReceiver {
+        DarkIconDispatcher.DarkReceiver, NotificationWakeUpCoordinator.WakeUpListener {
     public static final int CONTENT_FADE_DURATION = 110;
     public static final int CONTENT_FADE_DELAY = 100;
     private final NotificationIconAreaController mNotificationIconAreaController;
@@ -56,13 +64,17 @@
     private final Consumer<ExpandableNotificationRow>
             mSetTrackingHeadsUp = this::setTrackingHeadsUp;
     private final Runnable mUpdatePanelTranslation = this::updatePanelTranslation;
-    private final BiConsumer<Float, Float> mSetExpandedHeight = this::setExpandedHeight;
+    private final BiConsumer<Float, Float> mSetExpandedHeight = this::setAppearFraction;
+    private final KeyguardBypassController mBypassController;
+    private final StatusBarStateController mStatusBarStateController;
+    private final CommandQueue mCommandQueue;
+    private final NotificationWakeUpCoordinator mWakeUpCoordinator;
     @VisibleForTesting
     float mExpandedHeight;
     @VisibleForTesting
     boolean mIsExpanded;
     @VisibleForTesting
-    float mExpandFraction;
+    float mAppearFraction;
     private ExpandableNotificationRow mTrackedChild;
     private boolean mShown;
     private final View.OnLayoutChangeListener mStackScrollLayoutChangeListener =
@@ -77,13 +89,18 @@
             };
     private boolean mAnimationsEnabled = true;
     Point mPoint;
+    private KeyguardMonitor mKeyguardMonitor;
 
 
     public HeadsUpAppearanceController(
             NotificationIconAreaController notificationIconAreaController,
             HeadsUpManagerPhone headsUpManager,
-            View statusbarView) {
-        this(notificationIconAreaController, headsUpManager,
+            View statusbarView,
+            SysuiStatusBarStateController statusBarStateController,
+            KeyguardBypassController keyguardBypassController,
+            NotificationWakeUpCoordinator wakeUpCoordinator) {
+        this(notificationIconAreaController, headsUpManager, statusBarStateController,
+                keyguardBypassController, wakeUpCoordinator,
                 statusbarView.findViewById(R.id.heads_up_status_bar_view),
                 statusbarView.findViewById(R.id.notification_stack_scroller),
                 statusbarView.findViewById(R.id.notification_panel),
@@ -96,6 +113,9 @@
     public HeadsUpAppearanceController(
             NotificationIconAreaController notificationIconAreaController,
             HeadsUpManagerPhone headsUpManager,
+            StatusBarStateController stateController,
+            KeyguardBypassController bypassController,
+            NotificationWakeUpCoordinator wakeUpCoordinator,
             HeadsUpStatusBarView headsUpStatusBarView,
             NotificationStackScrollLayout stackScroller,
             NotificationPanelView panelView,
@@ -114,7 +134,7 @@
         panelView.addTrackingHeadsUpListener(mSetTrackingHeadsUp);
         panelView.addVerticalTranslationListener(mUpdatePanelTranslation);
         panelView.setHeadsUpAppearanceController(this);
-        mStackScroller.addOnExpandedHeightListener(mSetExpandedHeight);
+        mStackScroller.addOnExpandedHeightChangedListener(mSetExpandedHeight);
         mStackScroller.addOnLayoutChangeListener(mStackScrollLayoutChangeListener);
         mStackScroller.setHeadsUpAppearanceController(this);
         mClockView = clockView;
@@ -135,16 +155,23 @@
                 mHeadsUpStatusBarView.removeOnLayoutChangeListener(this);
             }
         });
+        mBypassController = bypassController;
+        mStatusBarStateController = stateController;
+        mWakeUpCoordinator = wakeUpCoordinator;
+        wakeUpCoordinator.addListener(this);
+        mCommandQueue = getComponent(headsUpStatusBarView.getContext(), CommandQueue.class);
+        mKeyguardMonitor = Dependency.get(KeyguardMonitor.class);
     }
 
 
     public void destroy() {
         mHeadsUpManager.removeListener(this);
         mHeadsUpStatusBarView.setOnDrawingRectChangedListener(null);
+        mWakeUpCoordinator.removeListener(this);
         mPanelView.removeTrackingHeadsUpListener(mSetTrackingHeadsUp);
         mPanelView.removeVerticalTranslationListener(mUpdatePanelTranslation);
         mPanelView.setHeadsUpAppearanceController(null);
-        mStackScroller.removeOnExpandedHeightListener(mSetExpandedHeight);
+        mStackScroller.removeOnExpandedHeightChangedListener(mSetExpandedHeight);
         mStackScroller.removeOnLayoutChangeListener(mStackScrollLayoutChangeListener);
         mDarkIconDispatcher.removeDarkReceiver(this);
     }
@@ -219,7 +246,7 @@
 
     private void updateTopEntry() {
         NotificationEntry newEntry = null;
-        if (!mIsExpanded && mHeadsUpManager.hasPinnedHeadsUp()) {
+        if (shouldBeVisible()) {
             newEntry = mHeadsUpManager.getTopEntry();
         }
         NotificationEntry previousEntry = mHeadsUpStatusBarView.getShowingEntry();
@@ -269,6 +296,11 @@
                     updateParentClipping(true /* shouldClip */);
                 });
             }
+            // Show the status bar icons when the view gets shown / hidden
+            if (mStatusBarStateController.getState() != StatusBarState.SHADE) {
+                mCommandQueue.recomputeDisableFlags(
+                        mHeadsUpStatusBarView.getContext().getDisplayId(), false);
+            }
         }
     }
 
@@ -342,7 +374,15 @@
      * @return if the heads up status bar view should be shown
      */
     public boolean shouldBeVisible() {
-        return !mIsExpanded && mHeadsUpManager.hasPinnedHeadsUp();
+        boolean notificationsShown = !mWakeUpCoordinator.getNotificationsFullyHidden();
+        boolean canShow = !mIsExpanded && notificationsShown;
+        if (mBypassController.getBypassEnabled() &&
+                (mStatusBarStateController.getState() == StatusBarState.KEYGUARD
+                        || mKeyguardMonitor.isKeyguardGoingAway())
+                && notificationsShown) {
+            canShow = true;
+        }
+        return canShow && mHeadsUpManager.hasPinnedHeadsUp();
     }
 
     @Override
@@ -351,12 +391,15 @@
         updateHeader(entry);
     }
 
-    public void setExpandedHeight(float expandedHeight, float appearFraction) {
-        boolean changedHeight = expandedHeight != mExpandedHeight;
+    public void setAppearFraction(float expandedHeight, float appearFraction) {
+        boolean changed = expandedHeight != mExpandedHeight;
         mExpandedHeight = expandedHeight;
-        mExpandFraction = appearFraction;
+        mAppearFraction = appearFraction;
         boolean isExpanded = expandedHeight > 0;
-        if (changedHeight) {
+        // We only notify if the expandedHeight changed and not on the appearFraction, since
+        // otherwise we may run into an infinite loop where the panel and this are constantly
+        // updating themselves over just a small fraction
+        if (changed) {
             updateHeadsUpHeaders();
         }
         if (isExpanded != mIsExpanded) {
@@ -389,8 +432,9 @@
     public void updateHeader(NotificationEntry entry) {
         ExpandableNotificationRow row = entry.getRow();
         float headerVisibleAmount = 1.0f;
-        if (row.isPinned() || row.isHeadsUpAnimatingAway() || row == mTrackedChild) {
-            headerVisibleAmount = mExpandFraction;
+        if (row.isPinned() || row.isHeadsUpAnimatingAway() || row == mTrackedChild
+                || row.showingPulsing()) {
+            headerVisibleAmount = mAppearFraction;
         }
         row.setHeaderVisibleAmount(headerVisibleAmount);
     }
@@ -400,8 +444,7 @@
         mHeadsUpStatusBarView.onDarkChanged(area, darkIntensity, tint);
     }
 
-    public void setPublicMode(boolean publicMode) {
-        mHeadsUpStatusBarView.setPublicMode(publicMode);
+    public void onStateChanged() {
         updateTopEntry();
     }
 
@@ -410,7 +453,12 @@
             mTrackedChild = oldController.mTrackedChild;
             mExpandedHeight = oldController.mExpandedHeight;
             mIsExpanded = oldController.mIsExpanded;
-            mExpandFraction = oldController.mExpandFraction;
+            mAppearFraction = oldController.mAppearFraction;
         }
     }
+
+    @Override
+    public void onFullyHiddenChanged(boolean isFullyHidden) {
+        updateTopEntry();
+    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpManagerPhone.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpManagerPhone.java
index 595c1ac..a7e7f08 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpManagerPhone.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpManagerPhone.java
@@ -32,7 +32,7 @@
 
 import androidx.collection.ArraySet;
 
-import com.android.systemui.Dependency;
+import com.android.internal.annotations.VisibleForTesting;
 import com.android.systemui.Dumpable;
 import com.android.systemui.R;
 import com.android.systemui.ScreenDecorations;
@@ -51,18 +51,27 @@
 import java.util.HashSet;
 import java.util.Stack;
 
+import javax.inject.Inject;
+import javax.inject.Singleton;
+
 /**
  * A implementation of HeadsUpManager for phone and car.
  */
+@Singleton
 public class HeadsUpManagerPhone extends HeadsUpManager implements Dumpable,
         VisualStabilityManager.Callback, OnHeadsUpChangedListener,
         ConfigurationController.ConfigurationListener, StateListener {
     private static final String TAG = "HeadsUpManagerPhone";
 
-    private final View mStatusBarWindowView;
-    private final NotificationGroupManager mGroupManager;
-    private final VisualStabilityManager mVisualStabilityManager;
-    private final StatusBarTouchableRegionManager mStatusBarTouchableRegionManager;
+    @VisibleForTesting
+    final int mExtensionTime;
+    private final StatusBarStateController mStatusBarStateController;
+    private final KeyguardBypassController mBypassController;
+    private final int mAutoHeadsUpNotificationDecay;
+    private View mStatusBarWindowView;
+    private NotificationGroupManager mGroupManager;
+    private VisualStabilityManager mVisualStabilityManager;
+    private StatusBarTouchableRegionManager mStatusBarTouchableRegionManager;
     private boolean mReleaseOnExpandFinish;
 
     private int mStatusBarHeight;
@@ -71,6 +80,7 @@
     private boolean mTrackingHeadsUp;
     private HashSet<String> mSwipedOutKeys = new HashSet<>();
     private HashSet<NotificationEntry> mEntriesToRemoveAfterExpand = new HashSet<>();
+    private HashSet<String> mKeysToRemoveWhenLeavingKeyguard = new HashSet<>();
     private ArraySet<NotificationEntry> mEntriesToRemoveWhenReorderingAllowed
             = new ArraySet<>();
     private boolean mIsExpanded;
@@ -102,21 +112,33 @@
     ///////////////////////////////////////////////////////////////////////////////////////////////
     //  Constructor:
 
+    @Inject
     public HeadsUpManagerPhone(@NonNull final Context context,
-                               @NonNull View statusBarWindowView,
-                               @NonNull NotificationGroupManager groupManager,
-                               @NonNull StatusBar bar,
-                               @NonNull VisualStabilityManager visualStabilityManager) {
+            StatusBarStateController statusBarStateController,
+            KeyguardBypassController bypassController) {
         super(context);
+        Resources resources = mContext.getResources();
+        mExtensionTime = resources.getInteger(R.integer.ambient_notification_extension_time);
+        mAutoHeadsUpNotificationDecay = resources.getInteger(
+                R.integer.auto_heads_up_notification_decay);
+        mStatusBarStateController = statusBarStateController;
+        mStatusBarStateController.addCallback(this);
+        mBypassController = bypassController;
 
+        initResources();
+    }
+
+
+    public void setUp(@NonNull View statusBarWindowView,
+            @NonNull NotificationGroupManager groupManager,
+            @NonNull StatusBar bar,
+            @NonNull VisualStabilityManager visualStabilityManager) {
         mStatusBarWindowView = statusBarWindowView;
-        mStatusBarTouchableRegionManager = new StatusBarTouchableRegionManager(context, this, bar,
+        mStatusBarTouchableRegionManager = new StatusBarTouchableRegionManager(mContext, this, bar,
                 statusBarWindowView);
         mGroupManager = groupManager;
         mVisualStabilityManager = visualStabilityManager;
 
-        initResources();
-
         addListener(new OnHeadsUpChangedListener() {
             @Override
             public void onHeadsUpPinnedModeChanged(boolean hasPinnedNotification) {
@@ -126,7 +148,6 @@
                 mStatusBarTouchableRegionManager.updateTouchableRegion();
             }
         });
-        Dependency.get(StatusBarStateController.class).addCallback(this);
     }
 
     public void setAnimationStateHandler(AnimationStateHandler handler) {
@@ -210,7 +231,36 @@
 
     @Override
     public void onStateChanged(int newState) {
+        boolean wasKeyguard = mStatusBarState == StatusBarState.KEYGUARD;
+        boolean isKeyguard = newState == StatusBarState.KEYGUARD;
         mStatusBarState = newState;
+        if (wasKeyguard && !isKeyguard && mKeysToRemoveWhenLeavingKeyguard.size() != 0) {
+            String[] keys = mKeysToRemoveWhenLeavingKeyguard.toArray(new String[0]);
+            for (String key : keys) {
+                removeAlertEntry(key);
+            }
+            mKeysToRemoveWhenLeavingKeyguard.clear();
+        }
+    }
+
+    @Override
+    public void onDozingChanged(boolean isDozing) {
+        if (!isDozing) {
+            // Let's make sure all huns we got while dozing time out within the normal timeout
+            // duration. Otherwise they could get stuck for a very long time
+            for (AlertEntry entry : mAlertEntries.values()) {
+                entry.updateEntry(true /* updatePostTime */);
+            }
+        }
+    }
+
+    @Override
+    public boolean isEntryAutoHeadsUpped(String key) {
+        HeadsUpEntryPhone headsUpEntryPhone = getHeadsUpEntryPhone(key);
+        if (headsUpEntryPhone == null) {
+            return false;
+        }
+        return headsUpEntryPhone.isAutoHeadsUp();
     }
 
     /**
@@ -262,6 +312,18 @@
         }
     }
 
+    /**
+     * Extends the lifetime of the currently showing pulsing notification so that the pulse lasts
+     * longer.
+     */
+    public void extendHeadsUp() {
+        HeadsUpEntryPhone topEntry = getTopHeadsUpEntryPhone();
+        if (topEntry == null) {
+            return;
+        }
+        topEntry.extendPulse();
+    }
+
     ///////////////////////////////////////////////////////////////////////////////////////////////
     //  HeadsUpManager public methods overrides:
 
@@ -380,14 +442,18 @@
 
     @Override
     protected void onAlertEntryRemoved(AlertEntry alertEntry) {
+        mKeysToRemoveWhenLeavingKeyguard.remove(alertEntry.mEntry.key);
         super.onAlertEntryRemoved(alertEntry);
         mEntryPool.release((HeadsUpEntryPhone) alertEntry);
     }
 
     @Override
     protected boolean shouldHeadsUpBecomePinned(NotificationEntry entry) {
-        return mStatusBarState != StatusBarState.KEYGUARD && !mIsExpanded
-                || super.shouldHeadsUpBecomePinned(entry);
+        boolean pin = mStatusBarState == StatusBarState.SHADE && !mIsExpanded;
+        if (mBypassController.getBypassEnabled()) {
+            pin |= mStatusBarState == StatusBarState.KEYGUARD;
+        }
+        return pin || super.shouldHeadsUpBecomePinned(entry);
     }
 
     @Override
@@ -433,6 +499,17 @@
 
         private boolean mMenuShownPinned;
 
+        /**
+         * If the time this entry has been on was extended
+         */
+        private boolean extended;
+
+        /**
+         * Was this entry received while on keyguard
+         */
+        private boolean mIsAutoHeadsUp;
+
+
         @Override
         protected boolean isSticky() {
             return super.isSticky() || mMenuShownPinned;
@@ -440,14 +517,19 @@
 
         public void setEntry(@NonNull final NotificationEntry entry) {
             Runnable removeHeadsUpRunnable = () -> {
-                if (!mVisualStabilityManager.isReorderingAllowed()) {
+                if (!mVisualStabilityManager.isReorderingAllowed()
+                        // We don't want to allow reordering while pulsing, but headsup need to
+                        // time out anyway
+                        && !entry.showingPulsing()) {
                     mEntriesToRemoveWhenReorderingAllowed.add(entry);
                     mVisualStabilityManager.addReorderingAllowedCallback(
                             HeadsUpManagerPhone.this);
-                } else if (!mTrackingHeadsUp) {
-                    removeAlertEntry(entry.key);
-                } else {
+                } else if (mTrackingHeadsUp) {
                     mEntriesToRemoveAfterExpand.add(entry);
+                } else if (mIsAutoHeadsUp && mStatusBarState == StatusBarState.KEYGUARD) {
+                    mKeysToRemoveWhenLeavingKeyguard.add(entry.key);
+                } else {
+                    removeAlertEntry(entry.key);
                 }
             };
 
@@ -456,6 +538,7 @@
 
         @Override
         public void updateEntry(boolean updatePostTime) {
+            mIsAutoHeadsUp = mEntry.isAutoHeadsUp();
             super.updateEntry(updatePostTime);
 
             if (mEntriesToRemoveAfterExpand.contains(mEntry)) {
@@ -464,6 +547,7 @@
             if (mEntriesToRemoveWhenReorderingAllowed.contains(mEntry)) {
                 mEntriesToRemoveWhenReorderingAllowed.remove(mEntry);
             }
+            mKeysToRemoveWhenLeavingKeyguard.remove(mEntry.key);
         }
 
         @Override
@@ -497,6 +581,45 @@
         public void reset() {
             super.reset();
             mMenuShownPinned = false;
+            extended = false;
+            mIsAutoHeadsUp = false;
+        }
+
+        private void extendPulse() {
+            if (!extended) {
+                extended = true;
+                updateEntry(false);
+            }
+        }
+
+        @Override
+        public int compareTo(AlertEntry alertEntry) {
+            HeadsUpEntryPhone headsUpEntry = (HeadsUpEntryPhone) alertEntry;
+            boolean autoShown = isAutoHeadsUp();
+            boolean otherAutoShown = headsUpEntry.isAutoHeadsUp();
+            if (autoShown && !otherAutoShown) {
+                return 1;
+            } else if (!autoShown && otherAutoShown) {
+                return -1;
+            }
+            return super.compareTo(alertEntry);
+        }
+
+        @Override
+        protected long calculateFinishTime() {
+            return mPostTime + getDecayDuration() + (extended ? mExtensionTime : 0);
+        }
+
+        private int getDecayDuration() {
+            if (isAutoHeadsUp()) {
+                return getRecommendedHeadsUpTimeoutMs(mAutoHeadsUpNotificationDecay);
+            } else {
+                return getRecommendedHeadsUpTimeoutMs(mAutoDismissNotificationDecay);
+            }
+        }
+
+        private boolean isAutoHeadsUp() {
+            return mIsAutoHeadsUp;
         }
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBouncer.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBouncer.java
index 0b994ff..dc9b373 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBouncer.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBouncer.java
@@ -54,7 +54,7 @@
 public class KeyguardBouncer {
 
     private static final String TAG = "KeyguardBouncer";
-    static final long BOUNCER_FACE_DELAY = 800;
+    static final long BOUNCER_FACE_DELAY = 1200;
     static final float ALPHA_EXPANSION_THRESHOLD = 0.95f;
     static final float EXPANSION_HIDDEN = 1f;
     static final float EXPANSION_VISIBLE = 0f;
@@ -68,6 +68,7 @@
     private final Handler mHandler;
     private final BouncerExpansionCallback mExpansionCallback;
     private final KeyguardUpdateMonitor mKeyguardUpdateMonitor;
+    private final UnlockMethodCache mUnlockMethodCache;
     private final KeyguardUpdateMonitorCallback mUpdateMonitorCallback =
             new KeyguardUpdateMonitorCallback() {
                 @Override
@@ -76,6 +77,7 @@
                 }
             };
     private final Runnable mRemoveViewRunnable = this::removeView;
+    private final KeyguardBypassController mKeyguardBypassController;
     protected KeyguardHostView mKeyguardView;
     private final Runnable mResetRunnable = ()-> {
         if (mKeyguardView != null) {
@@ -95,8 +97,9 @@
     public KeyguardBouncer(Context context, ViewMediatorCallback callback,
             LockPatternUtils lockPatternUtils, ViewGroup container,
             DismissCallbackRegistry dismissCallbackRegistry, FalsingManager falsingManager,
-            BouncerExpansionCallback expansionCallback,
-            KeyguardUpdateMonitor keyguardUpdateMonitor, Handler handler) {
+            BouncerExpansionCallback expansionCallback, UnlockMethodCache unlockMethodCache,
+            KeyguardUpdateMonitor keyguardUpdateMonitor,
+            KeyguardBypassController keyguardBypassController, Handler handler) {
         mContext = context;
         mCallback = callback;
         mLockPatternUtils = lockPatternUtils;
@@ -106,7 +109,9 @@
         mDismissCallbackRegistry = dismissCallbackRegistry;
         mExpansionCallback = expansionCallback;
         mHandler = handler;
+        mUnlockMethodCache = unlockMethodCache;
         mKeyguardUpdateMonitor.registerCallback(mUpdateMonitorCallback);
+        mKeyguardBypassController = keyguardBypassController;
     }
 
     public void show(boolean resetSecuritySelection) {
@@ -168,7 +173,9 @@
 
         // Split up the work over multiple frames.
         DejankUtils.removeCallbacks(mResetRunnable);
-        if (mKeyguardUpdateMonitor.isFaceDetectionRunning()) {
+        if (mUnlockMethodCache.isFaceAuthEnabled() && !needsFullscreenBouncer()
+                && !mKeyguardUpdateMonitor.userNeedsStrongAuth()
+                && !mKeyguardBypassController.getBypassEnabled()) {
             mHandler.postDelayed(mShowRunnable, BOUNCER_FACE_DELAY);
         } else {
             DejankUtils.postAfterTraversal(mShowRunnable);
@@ -204,14 +211,12 @@
      * @see #onFullyShown()
      */
     private void onFullyHidden() {
-        if (!mShowingSoon) {
-            cancelShowRunnable();
-            if (mRoot != null) {
-                mRoot.setVisibility(View.INVISIBLE);
-            }
-            mFalsingManager.onBouncerHidden();
-            DejankUtils.postAfterTraversal(mResetRunnable);
+        cancelShowRunnable();
+        if (mRoot != null) {
+            mRoot.setVisibility(View.INVISIBLE);
         }
+        mFalsingManager.onBouncerHidden();
+        DejankUtils.postAfterTraversal(mResetRunnable);
     }
 
     private final Runnable mShowRunnable = new Runnable() {
@@ -342,9 +347,11 @@
                 && mExpansion == EXPANSION_VISIBLE && !isAnimatingAway();
     }
 
-    public boolean isPartiallyVisible() {
-        return (mShowingSoon || (mRoot != null && mRoot.getVisibility() == View.VISIBLE))
-                && mExpansion != EXPANSION_HIDDEN && !isAnimatingAway();
+    /**
+     * {@link #show(boolean)} was called but we're not showing yet, or being dragged.
+     */
+    public boolean inTransit() {
+        return mShowingSoon || mExpansion != EXPANSION_HIDDEN && mExpansion != EXPANSION_VISIBLE;
     }
 
     /**
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBypassController.kt b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBypassController.kt
new file mode 100644
index 0000000..832ea9e
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBypassController.kt
@@ -0,0 +1,171 @@
+/*
+ * 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.systemui.statusbar.phone
+
+import android.content.Context
+import android.content.pm.PackageManager
+import android.hardware.biometrics.BiometricSourceType
+import android.provider.Settings
+import com.android.systemui.plugins.statusbar.StatusBarStateController
+import com.android.systemui.statusbar.NotificationLockscreenUserManager
+import com.android.systemui.statusbar.StatusBarState
+import com.android.systemui.tuner.TunerService
+import java.io.PrintWriter
+import javax.inject.Inject
+import javax.inject.Singleton
+
+@Singleton
+class KeyguardBypassController {
+
+    private val unlockMethodCache: UnlockMethodCache
+    private val statusBarStateController: StatusBarStateController
+    private var hasFaceFeature: Boolean
+
+    /**
+     * The pending unlock type which is set if the bypass was blocked when it happened.
+     */
+    private var pendingUnlockType: BiometricSourceType? = null
+
+    lateinit var unlockController: BiometricUnlockController
+    var isPulseExpanding = false
+
+    /**
+     * If face unlock dismisses the lock screen or keeps user on keyguard for the current user.
+     */
+    var bypassEnabled: Boolean = false
+        get() = field && unlockMethodCache.isFaceAuthEnabled
+        private set
+
+    var bouncerShowing: Boolean = false
+    var launchingAffordance: Boolean = false
+    var qSExpanded = false
+        set(value) {
+            val changed = field != value
+            field = value
+            if (changed && !value) {
+                maybePerformPendingUnlock()
+            }
+        }
+
+    @Inject
+    constructor(
+        context: Context,
+        tunerService: TunerService,
+        statusBarStateController: StatusBarStateController,
+        lockscreenUserManager: NotificationLockscreenUserManager
+    ) {
+        unlockMethodCache = UnlockMethodCache.getInstance(context)
+        this.statusBarStateController = statusBarStateController
+
+        hasFaceFeature = context.getPackageManager().hasSystemFeature(PackageManager.FEATURE_FACE)
+        if (!hasFaceFeature) {
+            return
+        }
+
+        statusBarStateController.addCallback(object : StatusBarStateController.StateListener {
+            override fun onStateChanged(newState: Int) {
+                if (newState != StatusBarState.KEYGUARD) {
+                    pendingUnlockType = null
+                }
+            }
+        })
+
+        val dismissByDefault = if (context.resources.getBoolean(
+                        com.android.internal.R.bool.config_faceAuthDismissesKeyguard)) 1 else 0
+        tunerService.addTunable(object : TunerService.Tunable {
+            override fun onTuningChanged(key: String?, newValue: String?) {
+                bypassEnabled = tunerService.getValue(key, dismissByDefault) != 0
+            }
+        }, Settings.Secure.FACE_UNLOCK_DISMISSES_KEYGUARD)
+        lockscreenUserManager.addUserChangedListener { pendingUnlockType = null }
+    }
+
+    /**
+     * Notify that the biometric unlock has happened.
+     *
+     * @return false if we can not wake and unlock right now
+     */
+    fun onBiometricAuthenticated(biometricSourceType: BiometricSourceType): Boolean {
+        if (bypassEnabled) {
+            val can = canBypass()
+            if (!can && (isPulseExpanding || qSExpanded)) {
+                pendingUnlockType = biometricSourceType
+            }
+            return can
+        }
+        return true
+    }
+
+    fun maybePerformPendingUnlock() {
+        if (pendingUnlockType != null) {
+            if (onBiometricAuthenticated(pendingUnlockType!!)) {
+                unlockController.startWakeAndUnlock(pendingUnlockType)
+                pendingUnlockType = null
+            }
+        }
+    }
+
+    /**
+     * If keyguard can be dismissed because of bypass.
+     */
+    fun canBypass(): Boolean {
+        if (bypassEnabled) {
+            return when {
+                bouncerShowing -> true
+                statusBarStateController.state != StatusBarState.KEYGUARD -> false
+                launchingAffordance -> false
+                isPulseExpanding || qSExpanded -> false
+                else -> true
+            }
+        }
+        return false
+    }
+
+    /**
+     * If shorter animations should be played when unlocking.
+     */
+    fun canPlaySubtleWindowAnimations(): Boolean {
+        if (bypassEnabled) {
+            return when {
+                statusBarStateController.state != StatusBarState.KEYGUARD -> false
+                qSExpanded -> false
+                else -> true
+            }
+        }
+        return false
+    }
+
+    fun onStartedGoingToSleep() {
+        pendingUnlockType = null
+    }
+
+    fun dump(pw: PrintWriter) {
+        pw.println("KeyguardBypassController:")
+        pw.print("  pendingUnlockType: "); pw.println(pendingUnlockType)
+        pw.print("  bypassEnabled: "); pw.println(bypassEnabled)
+        pw.print("  canBypass: "); pw.println(canBypass())
+        pw.print("  bouncerShowing: "); pw.println(bouncerShowing)
+        pw.print("  isPulseExpanding: "); pw.println(isPulseExpanding)
+        pw.print("  launchingAffordance: "); pw.println(launchingAffordance)
+        pw.print("  qSExpanded: "); pw.println(qSExpanded)
+        pw.print("  hasFaceFeature: "); pw.println(hasFaceFeature)
+    }
+
+    companion object {
+        const val BYPASS_PANEL_FADE_DURATION = 67
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardClockPositionAlgorithm.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardClockPositionAlgorithm.java
index bc2d00f5..179375e 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardClockPositionAlgorithm.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardClockPositionAlgorithm.java
@@ -112,6 +112,17 @@
     private float mEmptyDragAmount;
 
     /**
+     * Setting if bypass is enabled. If true the clock should always be positioned like it's dark
+     * and other minor adjustments.
+     */
+    private boolean mBypassEnabled;
+
+    /**
+     * The stackscroller padding when unlocked
+     */
+    private int mUnlockedStackScrollerPadding;
+
+    /**
      * Refreshes the dimension values.
      */
     public void loadDimens(Resources res) {
@@ -132,7 +143,8 @@
 
     public void setup(int minTopMargin, int maxShadeBottom, int notificationStackHeight,
             float panelExpansion, int parentHeight, int keyguardStatusHeight, int clockPreferredY,
-            boolean hasCustomClock, boolean hasVisibleNotifs, float dark, float emptyDragAmount) {
+            boolean hasCustomClock, boolean hasVisibleNotifs, float dark, float emptyDragAmount,
+            boolean bypassEnabled, int unlockedStackScrollerPadding) {
         mMinTopMargin = minTopMargin + mContainerTopPadding;
         mMaxShadeBottom = maxShadeBottom;
         mNotificationStackHeight = notificationStackHeight;
@@ -144,18 +156,24 @@
         mHasVisibleNotifs = hasVisibleNotifs;
         mDarkAmount = dark;
         mEmptyDragAmount = emptyDragAmount;
+        mBypassEnabled = bypassEnabled;
+        mUnlockedStackScrollerPadding = unlockedStackScrollerPadding;
     }
 
     public void run(Result result) {
-        final int y = getClockY();
+        final int y = getClockY(mPanelExpansion);
         result.clockY = y;
         result.clockAlpha = getClockAlpha(y);
-        result.stackScrollerPadding = y + mKeyguardStatusHeight;
+        result.stackScrollerPadding = mBypassEnabled ? mUnlockedStackScrollerPadding
+                : y + mKeyguardStatusHeight;
+        result.stackScrollerPaddingExpanded = mBypassEnabled ? mUnlockedStackScrollerPadding
+                : getClockY(1.0f) + mKeyguardStatusHeight;
         result.clockX = (int) interpolate(0, burnInPreventionOffsetX(), mDarkAmount);
     }
 
     public float getMinStackScrollerPadding() {
-        return mMinTopMargin + mKeyguardStatusHeight + mClockNotificationsMargin;
+        return mBypassEnabled ? mUnlockedStackScrollerPadding
+                : mMinTopMargin + mKeyguardStatusHeight + mClockNotificationsMargin;
     }
 
     private int getMaxClockY() {
@@ -167,7 +185,7 @@
     }
 
     private int getExpandedPreferredClockY() {
-        return (mHasCustomClock && !mHasVisibleNotifs) ? getPreferredClockY()
+        return (mHasCustomClock && (!mHasVisibleNotifs || mBypassEnabled)) ? getPreferredClockY()
                 : getExpandedClockPosition();
     }
 
@@ -195,7 +213,7 @@
         return (int) y;
     }
 
-    private int getClockY() {
+    private int getClockY(float panelExpansion) {
         // Dark: Align the bottom edge of the clock at about half of the screen:
         float clockYDark = (mHasCustomClock ? getPreferredClockY() : getMaxClockY())
                 + burnInPreventionOffsetY();
@@ -205,11 +223,12 @@
         float clockYBouncer = -mKeyguardStatusHeight;
 
         // Move clock up while collapsing the shade
-        float shadeExpansion = Interpolators.FAST_OUT_LINEAR_IN.getInterpolation(mPanelExpansion);
+        float shadeExpansion = Interpolators.FAST_OUT_LINEAR_IN.getInterpolation(panelExpansion);
         float clockY = MathUtils.lerp(clockYBouncer, clockYRegular, shadeExpansion);
         clockYDark = MathUtils.lerp(clockYBouncer, clockYDark, shadeExpansion);
 
-        return (int) (MathUtils.lerp(clockY, clockYDark, mDarkAmount) + mEmptyDragAmount);
+        float darkAmount = mBypassEnabled && !mHasCustomClock ? 1.0f : mDarkAmount;
+        return (int) (MathUtils.lerp(clockY, clockYDark, darkAmount) + mEmptyDragAmount);
     }
 
     /**
@@ -257,5 +276,10 @@
          * The top padding of the stack scroller, in pixels.
          */
         public int stackScrollerPadding;
+
+        /**
+         * The top padding of the stack scroller, in pixels when fully expanded.
+         */
+        public int stackScrollerPaddingExpanded;
     }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardDismissHandler.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardDismissHandler.java
index 6111178..b11329a 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardDismissHandler.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardDismissHandler.java
@@ -24,6 +24,7 @@
     /**
      * Executes an action that requres the screen to be unlocked, showing the keyguard if
      * necessary. Does not close the notification shade (in case it was open).
+     * @param requiresShadeOpen does the shade need to be forced open when hiding the keyguard?
      */
-    void executeWhenUnlocked(OnDismissAction action);
+    void executeWhenUnlocked(OnDismissAction action, boolean requiresShadeOpen);
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardDismissUtil.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardDismissUtil.java
index e541e14..834d2a5 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardDismissUtil.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardDismissUtil.java
@@ -37,7 +37,7 @@
     public KeyguardDismissUtil() {
     }
 
-    /** Sets the actual {@link DismissHandler} implementation. */
+    /** Sets the actual {@link KeyguardDismissHandler} implementation. */
     public void setDismissHandler(KeyguardDismissHandler dismissHandler) {
         mDismissHandler = dismissHandler;
     }
@@ -46,15 +46,17 @@
      * Executes an action that requires the screen to be unlocked.
      *
      * <p>Must be called after {@link #setDismissHandler}.
+     *
+     * @param requiresShadeOpen does the shade need to be forced open when hiding the keyguard?
      */
     @Override
-    public void executeWhenUnlocked(OnDismissAction action) {
+    public void executeWhenUnlocked(OnDismissAction action, boolean requiresShadeOpen) {
         KeyguardDismissHandler dismissHandler = mDismissHandler;
         if (dismissHandler == null) {
             Log.wtf(TAG, "KeyguardDismissHandler not set.");
             action.onDismiss();
             return;
         }
-        dismissHandler.executeWhenUnlocked(action);
+        dismissHandler.executeWhenUnlocked(action, requiresShadeOpen);
     }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardLiftController.kt b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardLiftController.kt
new file mode 100644
index 0000000..f4635d1
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardLiftController.kt
@@ -0,0 +1,84 @@
+/*
+ * 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.systemui.statusbar.phone
+
+import android.content.Context
+import android.hardware.Sensor
+import android.hardware.TriggerEvent
+import android.hardware.TriggerEventListener
+import com.android.keyguard.KeyguardUpdateMonitor
+import com.android.keyguard.KeyguardUpdateMonitorCallback
+import com.android.systemui.plugins.statusbar.StatusBarStateController
+import com.android.systemui.util.Assert
+import com.android.systemui.util.AsyncSensorManager
+
+class KeyguardLiftController constructor(
+    context: Context,
+    private val statusBarStateController: StatusBarStateController,
+    private val asyncSensorManager: AsyncSensorManager
+) : StatusBarStateController.StateListener, KeyguardUpdateMonitorCallback() {
+
+    private val keyguardUpdateMonitor = KeyguardUpdateMonitor.getInstance(context)
+    private val pickupSensor = asyncSensorManager.getDefaultSensor(Sensor.TYPE_PICK_UP_GESTURE)
+    private var isListening = false
+    private var bouncerVisible = false
+
+    init {
+        statusBarStateController.addCallback(this)
+        keyguardUpdateMonitor.registerCallback(this)
+        updateListeningState()
+    }
+
+    private val listener: TriggerEventListener = object : TriggerEventListener() {
+        override fun onTrigger(event: TriggerEvent?) {
+            Assert.isMainThread()
+            // Not listening anymore since trigger events unregister themselves
+            isListening = false
+            updateListeningState()
+            keyguardUpdateMonitor.requestFaceAuth()
+        }
+    }
+
+    override fun onDozingChanged(isDozing: Boolean) {
+        updateListeningState()
+    }
+
+    override fun onKeyguardBouncerChanged(bouncer: Boolean) {
+        bouncerVisible = bouncer
+        updateListeningState()
+    }
+
+    override fun onKeyguardVisibilityChanged(showing: Boolean) {
+        updateListeningState()
+    }
+
+    private fun updateListeningState() {
+        val onKeyguard = keyguardUpdateMonitor.isKeyguardVisible &&
+                !statusBarStateController.isDozing
+
+        val shouldListen = onKeyguard || bouncerVisible
+        if (shouldListen != isListening) {
+            isListening = shouldListen
+
+            if (shouldListen) {
+                asyncSensorManager.requestTriggerSensor(listener, pickupSensor)
+            } else {
+                asyncSensorManager.cancelTriggerSensor(listener, pickupSensor)
+            }
+        }
+    }
+}
\ No newline at end of file
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/LockIcon.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/LockIcon.java
index 3d0c9e8..06a2225 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/LockIcon.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/LockIcon.java
@@ -16,9 +16,9 @@
 
 package com.android.systemui.statusbar.phone;
 
-import static com.android.systemui.Dependency.MAIN_HANDLER_NAME;
 import static com.android.systemui.util.InjectionInflationController.VIEW_CONTEXT;
 
+import android.annotation.IntDef;
 import android.content.Context;
 import android.content.res.ColorStateList;
 import android.content.res.Configuration;
@@ -28,10 +28,12 @@
 import android.graphics.drawable.AnimatedVectorDrawable;
 import android.graphics.drawable.Drawable;
 import android.hardware.biometrics.BiometricSourceType;
-import android.os.Handler;
 import android.os.Trace;
+import android.provider.Settings;
+import android.text.TextUtils;
 import android.util.AttributeSet;
 import android.view.ViewGroup;
+import android.view.ViewTreeObserver;
 import android.view.accessibility.AccessibilityNodeInfo;
 
 import androidx.annotation.Nullable;
@@ -40,16 +42,23 @@
 import com.android.internal.telephony.IccCardConstants;
 import com.android.keyguard.KeyguardUpdateMonitor;
 import com.android.keyguard.KeyguardUpdateMonitorCallback;
+import com.android.systemui.Interpolators;
 import com.android.systemui.R;
 import com.android.systemui.dock.DockManager;
 import com.android.systemui.plugins.statusbar.StatusBarStateController;
 import com.android.systemui.statusbar.KeyguardAffordanceView;
+import com.android.systemui.statusbar.StatusBarState;
+import com.android.systemui.statusbar.notification.NotificationWakeUpCoordinator;
 import com.android.systemui.statusbar.phone.ScrimController.ScrimVisibility;
 import com.android.systemui.statusbar.policy.AccessibilityController;
 import com.android.systemui.statusbar.policy.ConfigurationController;
 import com.android.systemui.statusbar.policy.KeyguardMonitor;
+import com.android.systemui.statusbar.policy.OnHeadsUpChangedListener;
 import com.android.systemui.statusbar.policy.UserInfoController.OnUserInfoChangedListener;
 
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
 import javax.inject.Inject;
 import javax.inject.Named;
 
@@ -58,7 +67,9 @@
  */
 public class LockIcon extends KeyguardAffordanceView implements OnUserInfoChangedListener,
         StatusBarStateController.StateListener, ConfigurationController.ConfigurationListener,
-        UnlockMethodCache.OnUnlockMethodChangedListener {
+        UnlockMethodCache.OnUnlockMethodChangedListener,
+        NotificationWakeUpCoordinator.WakeUpListener, ViewTreeObserver.OnPreDrawListener,
+        OnHeadsUpChangedListener {
 
     private static final int STATE_LOCKED = 0;
     private static final int STATE_LOCK_OPEN = 1;
@@ -70,35 +81,53 @@
     private final KeyguardUpdateMonitor mKeyguardUpdateMonitor;
     private final AccessibilityController mAccessibilityController;
     private final DockManager mDockManager;
-    private final Handler mMainHandler;
     private final KeyguardMonitor mKeyguardMonitor;
+    private final KeyguardBypassController mBypassController;
+    private final NotificationWakeUpCoordinator mWakeUpCoordinator;
+    private final HeadsUpManagerPhone mHeadsUpManager;
 
     private int mLastState = 0;
+    private boolean mForceUpdate;
     private boolean mTransientBiometricsError;
     private boolean mIsFaceUnlockState;
     private boolean mSimLocked;
     private int mDensity;
     private boolean mPulsing;
     private boolean mDozing;
-    private boolean mBouncerVisible;
     private boolean mDocked;
-    private boolean mLastDozing;
-    private boolean mLastPulsing;
-    private boolean mLastBouncerVisible;
+    private boolean mBlockUpdates;
     private int mIconColor;
     private float mDozeAmount;
-    private int mIconRes;
-    private boolean mWasPulsingOnThisFrame;
+    private boolean mBouncerShowingScrimmed;
     private boolean mWakeAndUnlockRunning;
     private boolean mKeyguardShowing;
     private boolean mShowingLaunchAffordance;
+    private boolean mKeyguardJustShown;
+    private boolean mUpdatePending;
 
     private final KeyguardMonitor.Callback mKeyguardMonitorCallback =
             new KeyguardMonitor.Callback() {
                 @Override
                 public void onKeyguardShowingChanged() {
+                    boolean force = false;
+                    boolean wasShowing = mKeyguardShowing;
                     mKeyguardShowing = mKeyguardMonitor.isShowing();
-                    update(false /* force */);
+                    if (!wasShowing && mKeyguardShowing && mBlockUpdates) {
+                        mBlockUpdates = false;
+                        force = true;
+                    }
+                    if (!wasShowing && mKeyguardShowing) {
+                        mKeyguardJustShown = true;
+                    }
+                    update(force);
+                }
+
+                @Override
+                public void onKeyguardFadingAwayChanged() {
+                    if (!mKeyguardMonitor.isKeyguardFadingAway() && mBlockUpdates) {
+                        mBlockUpdates = false;
+                        update(true /* force */);
+                    }
                 }
             };
     private final DockManager.DockEventListener mDockEventListener =
@@ -109,7 +138,7 @@
                             || event == DockManager.STATE_DOCKED_HIDE;
                     if (docked != mDocked) {
                         mDocked = docked;
-                        update(true /* force */);
+                        update();
                     }
         }
     };
@@ -119,9 +148,8 @@
                 @Override
                 public void onSimStateChanged(int subId, int slotId,
                         IccCardConstants.State simState) {
-                    boolean oldSimLocked = mSimLocked;
                     mSimLocked = mKeyguardUpdateMonitor.isSimPinSecure();
-                    update(oldSimLocked != mSimLocked);
+                    update();
                 }
 
                 @Override
@@ -146,9 +174,11 @@
             StatusBarStateController statusBarStateController,
             ConfigurationController configurationController,
             AccessibilityController accessibilityController,
+            KeyguardBypassController bypassController,
+            NotificationWakeUpCoordinator wakeUpCoordinator,
             KeyguardMonitor keyguardMonitor,
             @Nullable DockManager dockManager,
-            @Named(MAIN_HANDLER_NAME) Handler mainHandler) {
+            HeadsUpManagerPhone headsUpManager) {
         super(context, attrs);
         mContext = context;
         mUnlockMethodCache = UnlockMethodCache.getInstance(context);
@@ -156,9 +186,11 @@
         mAccessibilityController = accessibilityController;
         mConfigurationController = configurationController;
         mStatusBarStateController = statusBarStateController;
+        mBypassController = bypassController;
+        mWakeUpCoordinator = wakeUpCoordinator;
         mKeyguardMonitor = keyguardMonitor;
         mDockManager = dockManager;
-        mMainHandler = mainHandler;
+        mHeadsUpManager = headsUpManager;
     }
 
     @Override
@@ -169,11 +201,13 @@
         mKeyguardMonitor.addCallback(mKeyguardMonitorCallback);
         mKeyguardUpdateMonitor.registerCallback(mUpdateMonitorCallback);
         mUnlockMethodCache.addListener(this);
+        mWakeUpCoordinator.addListener(this);
         mSimLocked = mKeyguardUpdateMonitor.isSimPinSecure();
         if (mDockManager != null) {
             mDockManager.addListener(mDockEventListener);
         }
         onThemeChanged();
+        update();
     }
 
     @Override
@@ -183,6 +217,7 @@
         mConfigurationController.removeCallback(this);
         mKeyguardUpdateMonitor.removeCallback(mUpdateMonitorCallback);
         mKeyguardMonitor.removeCallback(mKeyguardMonitorCallback);
+        mWakeUpCoordinator.removeListener(this);
         mUnlockMethodCache.removeListener(this);
         if (mDockManager != null) {
             mDockManager.removeListener(mDockEventListener);
@@ -226,59 +261,111 @@
     }
 
     public void update(boolean force) {
-        int state = getState();
-        mIsFaceUnlockState = state == STATE_SCANNING_FACE;
-        if (state != mLastState || mLastDozing != mDozing || mLastPulsing != mPulsing
-                || mLastBouncerVisible != mBouncerVisible || force) {
-            int iconAnimRes = getAnimationResForTransition(mLastState, state, mLastPulsing,
-                    mPulsing, mLastDozing, mDozing, mBouncerVisible);
-            boolean isAnim = iconAnimRes != -1;
-
-            int iconRes = isAnim ? iconAnimRes : getIconForState(state);
-            if (iconRes != mIconRes) {
-                mIconRes = iconRes;
-
-                Drawable icon = mContext.getDrawable(iconRes);
-                final AnimatedVectorDrawable animation = icon instanceof AnimatedVectorDrawable
-                        ? (AnimatedVectorDrawable) icon
-                        : null;
-                setImageDrawable(icon, false);
-                if (mIsFaceUnlockState) {
-                    announceForAccessibility(getContext().getString(
-                            R.string.accessibility_scanning_face));
-                }
-
-                if (animation != null && isAnim) {
-                    animation.forceAnimationOnUI();
-                    animation.clearAnimationCallbacks();
-                    animation.registerAnimationCallback(new Animatable2.AnimationCallback() {
-                        @Override
-                        public void onAnimationEnd(Drawable drawable) {
-                            if (getDrawable() == animation && state == getState()
-                                    && doesAnimationLoop(iconAnimRes)) {
-                                animation.start();
-                            } else {
-                                Trace.endAsyncSection("LockIcon#Animation", state);
-                            }
-                        }
-                    });
-                    Trace.beginAsyncSection("LockIcon#Animation", state);
-                    animation.start();
-                }
-            }
-            updateDarkTint();
-
-            mLastState = state;
-            mLastDozing = mDozing;
-            mLastPulsing = mPulsing;
-            mLastBouncerVisible = mBouncerVisible;
+        if (force) {
+            mForceUpdate = true;
         }
+        if (!mUpdatePending) {
+            mUpdatePending = true;
+            getViewTreeObserver().addOnPreDrawListener(this);
+        }
+    }
 
+    @Override
+    public boolean onPreDraw() {
+        mUpdatePending = false;
+        getViewTreeObserver().removeOnPreDrawListener(this);
+
+        int state = getState();
+        int lastState = mLastState;
+        boolean keyguardJustShown = mKeyguardJustShown;
+        mIsFaceUnlockState = state == STATE_SCANNING_FACE;
+        mLastState = state;
+        mKeyguardJustShown = false;
+
+        boolean shouldUpdate = lastState != state || mForceUpdate;
+        if (mBlockUpdates && canBlockUpdates()) {
+            shouldUpdate = false;
+        }
+        if (shouldUpdate) {
+            mForceUpdate = false;
+            @LockAnimIndex final int lockAnimIndex = getAnimationIndexForTransition(lastState,
+                    state, mPulsing, mDozing, keyguardJustShown);
+            boolean isAnim = lockAnimIndex != -1;
+            int iconRes = isAnim ? getThemedAnimationResId(lockAnimIndex) : getIconForState(state);
+
+            Drawable icon = mContext.getDrawable(iconRes);
+            final AnimatedVectorDrawable animation = icon instanceof AnimatedVectorDrawable
+                    ? (AnimatedVectorDrawable) icon
+                    : null;
+            setImageDrawable(icon, false);
+            if (mIsFaceUnlockState) {
+                announceForAccessibility(getContext().getString(
+                        R.string.accessibility_scanning_face));
+            }
+
+            if (animation != null && isAnim) {
+                animation.forceAnimationOnUI();
+                animation.clearAnimationCallbacks();
+                animation.registerAnimationCallback(new Animatable2.AnimationCallback() {
+                    @Override
+                    public void onAnimationEnd(Drawable drawable) {
+                        if (getDrawable() == animation && state == getState()
+                                && doesAnimationLoop(lockAnimIndex)) {
+                            animation.start();
+                        } else {
+                            Trace.endAsyncSection("LockIcon#Animation", state);
+                        }
+                    }
+                });
+                Trace.beginAsyncSection("LockIcon#Animation", state);
+                animation.start();
+            }
+        }
+        updateDarkTint();
+
+        updateIconVisibility();
+        updateClickability();
+
+        return true;
+    }
+
+    /**
+     * Update the icon visibility
+     * @return true if the visibility changed
+     */
+    private boolean updateIconVisibility() {
         boolean onAodNotPulsingOrDocked = mDozing && (!mPulsing || mDocked);
         boolean invisible = onAodNotPulsingOrDocked || mWakeAndUnlockRunning
                 || mShowingLaunchAffordance;
-        setVisibility(invisible ? INVISIBLE : VISIBLE);
-        updateClickability();
+        if (mBypassController.getBypassEnabled() && !mBouncerShowingScrimmed) {
+            if ((mHeadsUpManager.isHeadsUpGoingAway() || mHeadsUpManager.hasPinnedHeadsUp()
+                    || mStatusBarStateController.getState() == StatusBarState.KEYGUARD)
+                    && !mWakeUpCoordinator.getNotificationsFullyHidden()) {
+                invisible = true;
+            }
+        }
+        boolean wasInvisible = getVisibility() == INVISIBLE;
+        if (invisible != wasInvisible) {
+            setVisibility(invisible ? INVISIBLE : VISIBLE);
+            animate().cancel();
+            if (!invisible) {
+                setScaleX(0);
+                setScaleY(0);
+                animate()
+                        .setInterpolator(Interpolators.LINEAR_OUT_SLOW_IN)
+                        .scaleX(1)
+                        .scaleY(1)
+                        .withLayer()
+                        .setDuration(233)
+                        .start();
+            }
+            return true;
+        }
+        return false;
+    }
+
+    private boolean canBlockUpdates() {
+        return mKeyguardShowing || mKeyguardMonitor.isKeyguardFadingAway();
     }
 
     private void updateClickability() {
@@ -335,46 +422,100 @@
         return iconRes;
     }
 
-    private boolean doesAnimationLoop(int resourceId) {
-        return resourceId == com.android.internal.R.anim.lock_scanning;
+    private boolean doesAnimationLoop(@LockAnimIndex int lockAnimIndex) {
+        return lockAnimIndex == SCANNING;
     }
 
-    private int getAnimationResForTransition(int oldState, int newState,
-            boolean wasPulsing, boolean pulsing, boolean wasDozing, boolean dozing,
-            boolean bouncerVisible) {
+    private static int getAnimationIndexForTransition(int oldState, int newState, boolean pulsing,
+            boolean dozing, boolean keyguardJustShown) {
 
         // Never animate when screen is off
-        if (dozing && !pulsing && !mWasPulsingOnThisFrame) {
+        if (dozing && !pulsing) {
             return -1;
         }
 
-        boolean isError = oldState != STATE_BIOMETRICS_ERROR && newState == STATE_BIOMETRICS_ERROR;
-        boolean justUnlocked = oldState != STATE_LOCK_OPEN && newState == STATE_LOCK_OPEN;
-        boolean justLocked = oldState == STATE_LOCK_OPEN && newState == STATE_LOCKED;
-        boolean nowPulsing = !wasPulsing && pulsing;
-        boolean turningOn = wasDozing && !dozing && !mWasPulsingOnThisFrame;
-
-        if (isError) {
-            return com.android.internal.R.anim.lock_to_error;
-        } else if (justUnlocked) {
-            return com.android.internal.R.anim.lock_unlock;
-        } else if (justLocked) {
-            return com.android.internal.R.anim.lock_lock;
-        } else if (newState == STATE_SCANNING_FACE && bouncerVisible) {
-            return com.android.internal.R.anim.lock_scanning;
-        } else if ((nowPulsing || turningOn) && newState != STATE_LOCK_OPEN) {
-            return com.android.internal.R.anim.lock_in;
+        if (newState == STATE_BIOMETRICS_ERROR) {
+            return ERROR;
+        } else if (oldState != STATE_LOCK_OPEN && newState == STATE_LOCK_OPEN) {
+            return UNLOCK;
+        } else if (oldState == STATE_LOCK_OPEN && newState == STATE_LOCKED && !keyguardJustShown) {
+            return LOCK;
+        } else if (newState == STATE_SCANNING_FACE) {
+            return SCANNING;
         }
         return -1;
     }
 
+    @Override
+    public void onFullyHiddenChanged(boolean isFullyHidden) {
+        if (mBypassController.getBypassEnabled()) {
+            boolean changed = updateIconVisibility();
+            if (changed) {
+                update();
+            }
+        }
+    }
+
+    public void setBouncerShowingScrimmed(boolean bouncerShowing) {
+        mBouncerShowingScrimmed = bouncerShowing;
+        if (mBypassController.getBypassEnabled()) {
+            update();
+        }
+    }
+
+    @Retention(RetentionPolicy.SOURCE)
+    @IntDef({ERROR, UNLOCK, LOCK, SCANNING})
+    @interface LockAnimIndex {}
+    private static final int ERROR = 0, UNLOCK = 1, LOCK = 2, SCANNING = 3;
+    private static final int[][] LOCK_ANIM_RES_IDS = new int[][] {
+            {
+                    R.anim.lock_to_error,
+                    R.anim.lock_unlock,
+                    R.anim.lock_lock,
+                    R.anim.lock_scanning
+            },
+            {
+                    R.anim.lock_to_error_circular,
+                    R.anim.lock_unlock_circular,
+                    R.anim.lock_lock_circular,
+                    R.anim.lock_scanning_circular
+            },
+            {
+                    R.anim.lock_to_error_filled,
+                    R.anim.lock_unlock_filled,
+                    R.anim.lock_lock_filled,
+                    R.anim.lock_scanning_filled
+            },
+            {
+                    R.anim.lock_to_error_rounded,
+                    R.anim.lock_unlock_rounded,
+                    R.anim.lock_lock_rounded,
+                    R.anim.lock_scanning_rounded
+            },
+    };
+
+    private int getThemedAnimationResId(@LockAnimIndex int lockAnimIndex) {
+        final String setting = TextUtils.emptyIfNull(
+                Settings.Secure.getString(getContext().getContentResolver(),
+                Settings.Secure.THEME_CUSTOMIZATION_OVERLAY_PACKAGES));
+        if (setting.contains("com.android.theme.icon_pack.circular.android")) {
+            return LOCK_ANIM_RES_IDS[1][lockAnimIndex];
+        } else if (setting.contains("com.android.theme.icon_pack.filled.android")) {
+            return LOCK_ANIM_RES_IDS[2][lockAnimIndex];
+        } else if (setting.contains("com.android.theme.icon_pack.rounded.android")) {
+            return LOCK_ANIM_RES_IDS[3][lockAnimIndex];
+        }
+        return LOCK_ANIM_RES_IDS[0][lockAnimIndex];
+    }
+
     private int getState() {
         KeyguardUpdateMonitor updateMonitor = KeyguardUpdateMonitor.getInstance(mContext);
-        if (mTransientBiometricsError) {
-            return STATE_BIOMETRICS_ERROR;
-        } else if ((mUnlockMethodCache.canSkipBouncer() || !mKeyguardShowing) && !mSimLocked) {
+        if ((mUnlockMethodCache.canSkipBouncer() || !mKeyguardShowing
+                || mKeyguardMonitor.isKeyguardGoingAway()) && !mSimLocked) {
             return STATE_LOCK_OPEN;
-        } else if (updateMonitor.isFaceDetectionRunning()) {
+        } else if (mTransientBiometricsError) {
+            return STATE_BIOMETRICS_ERROR;
+        } else if (updateMonitor.isFaceDetectionRunning() && !mPulsing) {
             return STATE_SCANNING_FACE;
         } else {
             return STATE_LOCKED;
@@ -393,12 +534,6 @@
      */
     public void setPulsing(boolean pulsing) {
         mPulsing = pulsing;
-        if (!mPulsing) {
-            mWasPulsingOnThisFrame = true;
-            mMainHandler.post(() -> {
-                mWasPulsingOnThisFrame = false;
-            });
-        }
         update();
     }
 
@@ -416,17 +551,6 @@
         setImageTintList(ColorStateList.valueOf(color));
     }
 
-    /**
-     * If bouncer is visible or not.
-     */
-    public void setBouncerVisible(boolean bouncerVisible) {
-        if (mBouncerVisible == bouncerVisible) {
-            return;
-        }
-        mBouncerVisible = bouncerVisible;
-        update();
-    }
-
     @Override
     public void onDensityOrFontScaleChanged() {
         ViewGroup.LayoutParams lp = getLayoutParams();
@@ -453,11 +577,17 @@
     /**
      * We need to hide the lock whenever there's a fingerprint unlock, otherwise you'll see the
      * icon on top of the black front scrim.
+     * @param wakeAndUnlock are we wake and unlocking
+     * @param isUnlock are we currently unlocking
      */
-    public void onBiometricAuthModeChanged(boolean wakeAndUnlock) {
+    public void onBiometricAuthModeChanged(boolean wakeAndUnlock, boolean isUnlock) {
         if (wakeAndUnlock) {
             mWakeAndUnlockRunning = true;
         }
+        if (isUnlock && mBypassController.getBypassEnabled() && canBlockUpdates()) {
+            // We don't want the icon to change while we are unlocking
+            mBlockUpdates = true;
+        }
         update();
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/MultiUserSwitch.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/MultiUserSwitch.java
index c0a1b12..1d4d0bd 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/MultiUserSwitch.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/MultiUserSwitch.java
@@ -103,10 +103,11 @@
         final boolean userSwitcherEnabled = Settings.Global.getInt(mContext.getContentResolver(),
                 Settings.Global.USER_SWITCHER_ENABLED, 0) != 0;
 
-        if (!UserManager.supportsMultipleUsers()
-                || mUserManager.hasUserRestriction(UserManager.DISALLOW_USER_SWITCH)
+        // TODO(b/138661450) Move IPC calls to background
+        if (!userSwitcherEnabled
+                || !UserManager.supportsMultipleUsers()
                 || UserManager.isDeviceInDemoMode(mContext)
-                || !userSwitcherEnabled) {
+                || mUserManager.hasUserRestriction(UserManager.DISALLOW_USER_SWITCH)) {
             return false;
         }
 
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 776cd4d..f689a3e 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java
@@ -21,7 +21,9 @@
 import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_HOME_DISABLED;
 import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_NOTIFICATION_PANEL_EXPANDED;
 import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_OVERVIEW_DISABLED;
+import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_QUICK_SETTINGS_EXPANDED;
 import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_SCREEN_PINNING;
+import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_SEARCH_DISABLED;
 import static com.android.systemui.shared.system.QuickStepContract.isGesturalMode;
 import static com.android.systemui.statusbar.phone.BarTransitions.MODE_OPAQUE;
 
@@ -321,7 +323,7 @@
 
     public void setComponents(NotificationPanelView panel, AssistManager assistManager) {
         mPanelView = panel;
-        updateSystemUiStateFlags();
+        updatePanelSystemUiStateFlags();
     }
 
     @Override
@@ -585,7 +587,7 @@
         updateNavButtonIcons();
         updateSlippery();
         setUpSwipeUpOnboarding(isQuickStepSwipeUpEnabled());
-        updateSystemUiStateFlags();
+        updateDisabledSystemUiStateFlags();
     }
 
     public void updateNavButtonIcons() {
@@ -617,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));
 
@@ -627,7 +633,7 @@
         if (mOverviewProxyService.isEnabled()) {
             // Force disable recents when not in legacy mode
             disableRecent |= !QuickStepContract.isLegacyMode(mNavBarMode);
-            if (pinningActive) {
+            if (pinningActive && !QuickStepContract.isGesturalMode(mNavBarMode)) {
                 disableBack = disableHome = false;
             }
         } else if (pinningActive) {
@@ -647,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
@@ -706,12 +713,12 @@
         }
     }
 
-    public void onPanelExpandedChange() {
+    public void onStatusBarPanelStateChanged() {
         updateSlippery();
-        updateSystemUiStateFlags();
+        updatePanelSystemUiStateFlags();
     }
 
-    public void updateSystemUiStateFlags() {
+    public void updateDisabledSystemUiStateFlags() {
         int displayId = mContext.getDisplayId();
         mOverviewProxyService.setSystemUiStateFlag(SYSUI_STATE_SCREEN_PINNING,
                 ActivityManagerWrapper.getInstance().isScreenPinningActive(), displayId);
@@ -719,9 +726,17 @@
                 (mDisabledFlags & View.STATUS_BAR_DISABLE_RECENT) != 0, displayId);
         mOverviewProxyService.setSystemUiStateFlag(SYSUI_STATE_HOME_DISABLED,
                 (mDisabledFlags & View.STATUS_BAR_DISABLE_HOME) != 0, displayId);
+        mOverviewProxyService.setSystemUiStateFlag(SYSUI_STATE_SEARCH_DISABLED,
+                (mDisabledFlags & View.STATUS_BAR_DISABLE_SEARCH) != 0, displayId);
+    }
+
+    public void updatePanelSystemUiStateFlags() {
+        int displayId = mContext.getDisplayId();
         if (mPanelView != null) {
             mOverviewProxyService.setSystemUiStateFlag(SYSUI_STATE_NOTIFICATION_PANEL_EXPANDED,
                     mPanelView.isFullyExpanded() && !mPanelView.isInSettings(), displayId);
+            mOverviewProxyService.setSystemUiStateFlag(SYSUI_STATE_QUICK_SETTINGS_EXPANDED,
+                    mPanelView.isInSettings(), displayId);
         }
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationHandle.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationHandle.java
index 0fe1294..4f7af580 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationHandle.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationHandle.java
@@ -53,8 +53,8 @@
         final int dualToneLightTheme = Utils.getThemeAttr(context, R.attr.lightIconTheme);
         Context lightContext = new ContextThemeWrapper(context, dualToneLightTheme);
         Context darkContext = new ContextThemeWrapper(context, dualToneDarkTheme);
-        mLightColor = Utils.getColorAttrDefaultColor(lightContext, R.attr.singleToneColor);
-        mDarkColor = Utils.getColorAttrDefaultColor(darkContext, R.attr.singleToneColor);
+        mLightColor = Utils.getColorAttrDefaultColor(lightContext, R.attr.homeHandleColor);
+        mDarkColor = Utils.getColorAttrDefaultColor(darkContext, R.attr.homeHandleColor);
         mPaint.setAntiAlias(true);
         setFocusable(false);
     }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationModeController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationModeController.java
index 4d7cf27..1df9411 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationModeController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationModeController.java
@@ -16,42 +16,46 @@
 
 package com.android.systemui.statusbar.phone;
 
+import static android.app.Activity.RESULT_CANCELED;
+import static android.app.Activity.RESULT_OK;
+import static android.app.admin.DevicePolicyManager.STATE_USER_UNMANAGED;
 import static android.content.Intent.ACTION_OVERLAY_CHANGED;
 import static android.content.Intent.ACTION_PREFERRED_ACTIVITY_CHANGED;
+import static android.content.pm.PackageManager.FEATURE_DEVICE_ADMIN;
 import static android.os.UserHandle.USER_CURRENT;
 import static android.view.WindowManagerPolicyConstants.NAV_BAR_MODE_3BUTTON;
 import static android.view.WindowManagerPolicyConstants.NAV_BAR_MODE_3BUTTON_OVERLAY;
 import static android.view.WindowManagerPolicyConstants.NAV_BAR_MODE_GESTURAL;
 import static android.view.WindowManagerPolicyConstants.NAV_BAR_MODE_GESTURAL_OVERLAY;
 
-import android.app.Notification;
-import android.app.NotificationManager;
+import static com.android.systemui.shared.system.QuickStepContract.ACTION_ENABLE_GESTURE_NAV;
+import static com.android.systemui.shared.system.QuickStepContract.ACTION_ENABLE_GESTURE_NAV_RESULT;
+import static com.android.systemui.shared.system.QuickStepContract.EXTRA_RESULT_INTENT;
+
 import android.app.PendingIntent;
+import android.app.admin.DevicePolicyManager;
 import android.content.BroadcastReceiver;
 import android.content.ComponentName;
 import android.content.Context;
 import android.content.Intent;
 import android.content.IntentFilter;
 import android.content.om.IOverlayManager;
-import android.content.pm.ApplicationInfo;
 import android.content.pm.PackageManager;
 import android.content.res.ApkAssets;
 import android.os.PatternMatcher;
 import android.os.RemoteException;
 import android.os.ServiceManager;
 import android.os.UserHandle;
+import android.os.UserManager;
 import android.provider.Settings;
 import android.provider.Settings.Secure;
-import android.text.TextUtils;
 import android.util.Log;
 import android.util.SparseBooleanArray;
 
 import com.android.systemui.Dumpable;
-import com.android.systemui.R;
 import com.android.systemui.UiOffloadThread;
 import com.android.systemui.shared.system.ActivityManagerWrapper;
 import com.android.systemui.statusbar.policy.DeviceProvisionedController;
-import com.android.systemui.util.NotificationChannels;
 
 import java.io.FileDescriptor;
 import java.io.PrintWriter;
@@ -70,11 +74,6 @@
     private static final String TAG = NavigationModeController.class.getSimpleName();
     private static final boolean DEBUG = false;
 
-    private static final int SYSTEM_APP_MASK =
-            ApplicationInfo.FLAG_SYSTEM | ApplicationInfo.FLAG_UPDATED_SYSTEM_APP;
-    static final String SHARED_PREFERENCES_NAME = "navigation_mode_controller_preferences";
-    static final String PREFS_SWITCHED_FROM_GESTURE_NAV_KEY = "switched_from_gesture_nav";
-
     public interface ModeChangedListener {
         void onNavigationModeChanged(int mode);
     }
@@ -90,8 +89,6 @@
     private int mMode = NAV_BAR_MODE_3BUTTON;
     private ArrayList<ModeChangedListener> mListeners = new ArrayList<>();
 
-    private String mLastDefaultLauncher;
-
     private BroadcastReceiver mReceiver = new BroadcastReceiver() {
         @Override
         public void onReceive(Context context, Intent intent) {
@@ -102,18 +99,6 @@
                     }
                     updateCurrentInteractionMode(true /* notify */);
                     break;
-                case ACTION_PREFERRED_ACTIVITY_CHANGED:
-                    if (DEBUG) {
-                        Log.d(TAG, "ACTION_PREFERRED_ACTIVITY_CHANGED");
-                    }
-                    final String launcher = getDefaultLauncherPackageName(mCurrentUserContext);
-                    // Check if it is a default launcher change
-                    if (!TextUtils.equals(mLastDefaultLauncher, launcher)) {
-                        switchFromGestureNavModeIfNotSupportedByDefaultLauncher();
-                        showNotificationIfDefaultLauncherSupportsGestureNav();
-                        mLastDefaultLauncher = launcher;
-                    }
-                    break;
             }
         }
     };
@@ -149,7 +134,6 @@
 
                     // Update the nav mode for the current user
                     updateCurrentInteractionMode(true /* notify */);
-                    switchFromGestureNavModeIfNotSupportedByDefaultLauncher();
 
                     // When switching users, defer enabling the gestural nav overlay until the user
                     // is all set up
@@ -157,6 +141,8 @@
                 }
             };
 
+    private BroadcastReceiver mEnableGestureNavReceiver;
+
     @Inject
     public NavigationModeController(Context context,
             DeviceProvisionedController deviceProvisionedController,
@@ -177,16 +163,81 @@
         IntentFilter preferredActivityFilter = new IntentFilter(ACTION_PREFERRED_ACTIVITY_CHANGED);
         mContext.registerReceiverAsUser(mReceiver, UserHandle.ALL, preferredActivityFilter, null,
                 null);
-        // We are only interested in launcher changes, so keeping track of the current default.
-        mLastDefaultLauncher = getDefaultLauncherPackageName(mContext);
 
         updateCurrentInteractionMode(false /* notify */);
-        switchFromGestureNavModeIfNotSupportedByDefaultLauncher();
 
         // Check if we need to defer enabling gestural nav
         deferGesturalNavOverlayIfNecessary();
     }
 
+    private void removeEnableGestureNavListener() {
+        if (mEnableGestureNavReceiver != null) {
+            if (DEBUG) {
+                Log.d(TAG, "mEnableGestureNavReceiver unregistered");
+            }
+            mContext.unregisterReceiver(mEnableGestureNavReceiver);
+            mEnableGestureNavReceiver = null;
+        }
+    }
+
+    private boolean setGestureModeOverlayForMainLauncher() {
+        removeEnableGestureNavListener();
+        if (getCurrentInteractionMode(mCurrentUserContext) == NAV_BAR_MODE_GESTURAL) {
+            // Already in gesture mode
+            return true;
+        }
+
+        Log.d(TAG, "Switching system navigation to full-gesture mode:"
+                + " contextUser="
+                + mCurrentUserContext.getUserId());
+
+        setModeOverlay(NAV_BAR_MODE_GESTURAL_OVERLAY, USER_CURRENT);
+        return true;
+    }
+
+    private boolean enableGestureNav(Intent intent) {
+        if (!(intent.getParcelableExtra(EXTRA_RESULT_INTENT) instanceof PendingIntent)) {
+            Log.e(TAG, "No callback pending intent was attached");
+            return false;
+        }
+
+        PendingIntent callback = intent.getParcelableExtra(EXTRA_RESULT_INTENT);
+        Intent callbackIntent = callback.getIntent();
+        if (callbackIntent == null
+                || !ACTION_ENABLE_GESTURE_NAV_RESULT.equals(callbackIntent.getAction())) {
+            Log.e(TAG, "Invalid callback intent");
+            return false;
+        }
+        String callerPackage = callback.getCreatorPackage();
+        UserHandle callerUser = callback.getCreatorUserHandle();
+
+        DevicePolicyManager dpm = mCurrentUserContext.getSystemService(DevicePolicyManager.class);
+        ComponentName ownerComponent = dpm.getDeviceOwnerComponentOnCallingUser();
+
+        if (ownerComponent != null) {
+            // Verify that the caller is the owner component
+            if (!ownerComponent.getPackageName().equals(callerPackage)
+                    || !mCurrentUserContext.getUser().equals(callerUser)) {
+                Log.e(TAG, "Callback must be from the device owner");
+                return false;
+            }
+        } else {
+            UserHandle callerParent = mCurrentUserContext.getSystemService(UserManager.class)
+                    .getProfileParent(callerUser);
+            if (callerParent == null || !callerParent.equals(mCurrentUserContext.getUser())) {
+                Log.e(TAG, "Callback must be from a managed user");
+                return false;
+            }
+            ComponentName profileOwner = dpm.getProfileOwnerAsUser(callerUser);
+            if (profileOwner == null || !profileOwner.getPackageName().equals(callerPackage)) {
+                Log.e(TAG, "Callback must be from the profile owner");
+                return false;
+            }
+        }
+
+        return setGestureModeOverlayForMainLauncher();
+    }
+
     public void updateCurrentInteractionMode(boolean notify) {
         mCurrentUserContext = getCurrentUserContext();
         int mode = getCurrentInteractionMode(mCurrentUserContext);
@@ -245,6 +296,10 @@
         }
     }
 
+    private boolean supportsDeviceAdmin() {
+        return mContext.getPackageManager().hasSystemFeature(FEATURE_DEVICE_ADMIN);
+    }
+
     private void deferGesturalNavOverlayIfNecessary() {
         final int userId = mDeviceProvisionedController.getCurrentUser();
         mRestoreGesturalNavBarMode.put(userId, false);
@@ -255,6 +310,7 @@
                 Log.d(TAG, "deferGesturalNavOverlayIfNecessary: device is provisioned and user is "
                         + "setup");
             }
+            removeEnableGestureNavListener();
             return;
         }
 
@@ -270,6 +326,7 @@
                 Log.d(TAG, "deferGesturalNavOverlayIfNecessary: no default gestural overlay, "
                         + "default=" + defaultOverlays);
             }
+            removeEnableGestureNavListener();
             return;
         }
 
@@ -277,6 +334,24 @@
         // provisioned
         setModeOverlay(NAV_BAR_MODE_3BUTTON_OVERLAY, USER_CURRENT);
         mRestoreGesturalNavBarMode.put(userId, true);
+
+        if (supportsDeviceAdmin() && mEnableGestureNavReceiver == null) {
+            mEnableGestureNavReceiver = new BroadcastReceiver() {
+                @Override
+                public void onReceive(Context context, Intent intent) {
+                    if (DEBUG) {
+                        Log.d(TAG, "ACTION_ENABLE_GESTURE_NAV");
+                    }
+                    setResultCode(enableGestureNav(intent) ? RESULT_OK : RESULT_CANCELED);
+                }
+            };
+            // Register for all users so that we can get managed users as well
+            mContext.registerReceiverAsUser(mEnableGestureNavReceiver, UserHandle.ALL,
+                    new IntentFilter(ACTION_ENABLE_GESTURE_NAV), null, null);
+            if (DEBUG) {
+                Log.d(TAG, "mEnableGestureNavReceiver registered");
+            }
+        }
         if (DEBUG) {
             Log.d(TAG, "deferGesturalNavOverlayIfNecessary: setting to 3 button mode");
         }
@@ -290,7 +365,15 @@
         final int userId = mDeviceProvisionedController.getCurrentUser();
         if (mRestoreGesturalNavBarMode.get(userId)) {
             // Restore the gestural state if necessary
-            setModeOverlay(NAV_BAR_MODE_GESTURAL_OVERLAY, USER_CURRENT);
+            if (!supportsDeviceAdmin()
+                    || mCurrentUserContext.getSystemService(DevicePolicyManager.class)
+                    .getUserProvisioningState() == STATE_USER_UNMANAGED) {
+                setGestureModeOverlayForMainLauncher();
+            } else {
+                if (DEBUG) {
+                    Log.d(TAG, "Not restoring to gesture nav for managed user");
+                }
+            }
             mRestoreGesturalNavBarMode.put(userId, false);
         }
     }
@@ -309,100 +392,6 @@
         });
     }
 
-    private void switchFromGestureNavModeIfNotSupportedByDefaultLauncher() {
-        if (getCurrentInteractionMode(mCurrentUserContext) != NAV_BAR_MODE_GESTURAL) {
-            return;
-        }
-        final Boolean supported = isGestureNavSupportedByDefaultLauncher(mCurrentUserContext);
-        if (supported == null || supported) {
-            return;
-        }
-
-        Log.d(TAG, "Switching system navigation to 3-button mode:"
-                + " defaultLauncher=" + getDefaultLauncherPackageName(mCurrentUserContext)
-                + " contextUser=" + mCurrentUserContext.getUserId());
-
-        setModeOverlay(NAV_BAR_MODE_3BUTTON_OVERLAY, USER_CURRENT);
-        showNotification(mCurrentUserContext, R.string.notification_content_system_nav_changed);
-        mCurrentUserContext.getSharedPreferences(SHARED_PREFERENCES_NAME, Context.MODE_PRIVATE)
-                .edit().putBoolean(PREFS_SWITCHED_FROM_GESTURE_NAV_KEY, true).apply();
-    }
-
-    private void showNotificationIfDefaultLauncherSupportsGestureNav() {
-        boolean previouslySwitchedFromGestureNav = mCurrentUserContext
-                .getSharedPreferences(SHARED_PREFERENCES_NAME, Context.MODE_PRIVATE)
-                .getBoolean(PREFS_SWITCHED_FROM_GESTURE_NAV_KEY, false);
-        if (!previouslySwitchedFromGestureNav) {
-            return;
-        }
-        if (getCurrentInteractionMode(mCurrentUserContext) == NAV_BAR_MODE_GESTURAL) {
-            return;
-        }
-        final Boolean supported = isGestureNavSupportedByDefaultLauncher(mCurrentUserContext);
-        if (supported == null || !supported) {
-            return;
-        }
-
-        showNotification(mCurrentUserContext, R.string.notification_content_gesture_nav_available);
-        mCurrentUserContext.getSharedPreferences(SHARED_PREFERENCES_NAME, Context.MODE_PRIVATE)
-                .edit().putBoolean(PREFS_SWITCHED_FROM_GESTURE_NAV_KEY, false).apply();
-    }
-
-    /**
-     * Returns null if there is no default launcher set for the current user. Returns true if the
-     * current default launcher supports Gesture Navigation. Returns false otherwise.
-     */
-    private Boolean isGestureNavSupportedByDefaultLauncher(Context context) {
-        final String defaultLauncherPackageName = getDefaultLauncherPackageName(context);
-        if (DEBUG) {
-            Log.d(TAG, "isGestureNavSupportedByDefaultLauncher:"
-                    + " defaultLauncher=" + defaultLauncherPackageName
-                    + " contextUser=" + context.getUserId());
-        }
-        if (defaultLauncherPackageName == null) {
-            return null;
-        }
-        if (isSystemApp(context, defaultLauncherPackageName)) {
-            return true;
-        }
-        return false;
-    }
-
-    private String getDefaultLauncherPackageName(Context context) {
-        final ComponentName cn = context.getPackageManager().getHomeActivities(new ArrayList<>());
-        if (cn == null) {
-            return null;
-        }
-        return cn.getPackageName();
-    }
-
-    /** Returns true if the app for the given package name is a system app for this device */
-    private boolean isSystemApp(Context context, String packageName) {
-        try {
-            ApplicationInfo ai = context.getPackageManager().getApplicationInfo(packageName,
-                    PackageManager.GET_META_DATA);
-            return ai != null && ((ai.flags & SYSTEM_APP_MASK) != 0);
-        } catch (PackageManager.NameNotFoundException e) {
-            return false;
-        }
-    }
-
-    private void showNotification(Context context, int resId) {
-        final CharSequence message = context.getResources().getString(resId);
-        if (DEBUG) {
-            Log.d(TAG, "showNotification: message=" + message);
-        }
-
-        final Notification.Builder builder =
-                new Notification.Builder(mContext, NotificationChannels.ALERTS)
-                        .setContentText(message)
-                        .setStyle(new Notification.BigTextStyle())
-                        .setSmallIcon(R.drawable.ic_info)
-                        .setAutoCancel(true)
-                        .setContentIntent(PendingIntent.getActivity(context, 0, new Intent(), 0));
-        context.getSystemService(NotificationManager.class).notify(TAG, 0, builder.build());
-    }
-
     @Override
     public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
         pw.println("NavigationModeController:");
@@ -415,12 +404,6 @@
         }
         pw.println("  defaultOverlays=" + defaultOverlays);
         dumpAssetPaths(mCurrentUserContext);
-
-        pw.println("  defaultLauncher=" + mLastDefaultLauncher);
-        boolean previouslySwitchedFromGestureNav = mCurrentUserContext
-                .getSharedPreferences(SHARED_PREFERENCES_NAME, Context.MODE_PRIVATE)
-                .getBoolean(PREFS_SWITCHED_FROM_GESTURE_NAV_KEY, false);
-        pw.println("  previouslySwitchedFromGestureNav=" + previouslySwitchedFromGestureNav);
     }
 
     private void dumpAssetPaths(Context context) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationGroupAlertTransferHelper.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationGroupAlertTransferHelper.java
index 4dbd854..4d69f77e 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationGroupAlertTransferHelper.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationGroupAlertTransferHelper.java
@@ -28,8 +28,6 @@
 import com.android.systemui.plugins.statusbar.StatusBarStateController;
 import com.android.systemui.plugins.statusbar.StatusBarStateController.StateListener;
 import com.android.systemui.statusbar.AlertingNotificationManager;
-import com.android.systemui.statusbar.AmbientPulseManager;
-import com.android.systemui.statusbar.AmbientPulseManager.OnAmbientChangedListener;
 import com.android.systemui.statusbar.InflationTask;
 import com.android.systemui.statusbar.notification.NotificationEntryListener;
 import com.android.systemui.statusbar.notification.NotificationEntryManager;
@@ -48,13 +46,13 @@
 import javax.inject.Singleton;
 
 /**
- * A helper class dealing with the alert interactions between {@link NotificationGroupManager},
- * {@link HeadsUpManager}, {@link AmbientPulseManager}. In particular, this class deals with keeping
+ * A helper class dealing with the alert interactions between {@link NotificationGroupManager} and
+ * {@link HeadsUpManager}. In particular, this class deals with keeping
  * the correct notification in a group alerting based off the group suppression.
  */
 @Singleton
 public class NotificationGroupAlertTransferHelper implements OnHeadsUpChangedListener,
-        OnAmbientChangedListener, StateListener {
+        StateListener {
 
     private static final long ALERT_TRANSFER_TIMEOUT = 300;
 
@@ -70,8 +68,6 @@
     private final ArrayMap<String, PendingAlertInfo> mPendingAlerts = new ArrayMap<>();
 
     private HeadsUpManager mHeadsUpManager;
-    private final AmbientPulseManager mAmbientPulseManager =
-            Dependency.get(AmbientPulseManager.class);
     private final NotificationGroupManager mGroupManager =
             Dependency.get(NotificationGroupManager.class);
 
@@ -144,10 +140,9 @@
 
         @Override
         public void onGroupSuppressionChanged(NotificationGroup group, boolean suppressed) {
-            AlertingNotificationManager alertManager = getActiveAlertManager();
             if (suppressed) {
-                if (alertManager.isAlerting(group.summary.key)) {
-                    handleSuppressedSummaryAlerted(group.summary, alertManager);
+                if (mHeadsUpManager.isAlerting(group.summary.key)) {
+                    handleSuppressedSummaryAlerted(group.summary, mHeadsUpManager);
                 }
             } else {
                 // Group summary can be null if we are no longer suppressed because the summary was
@@ -160,8 +155,8 @@
                 // Group is no longer suppressed. We should check if we need to transfer the alert
                 // back to the summary now that it's no longer suppressed.
                 if (groupAlertEntry.mAlertSummaryOnNextAddition) {
-                    if (!alertManager.isAlerting(group.summary.key)) {
-                        alertNotificationWhenPossible(group.summary, alertManager);
+                    if (!mHeadsUpManager.isAlerting(group.summary.key)) {
+                        alertNotificationWhenPossible(group.summary, mHeadsUpManager);
                     }
                     groupAlertEntry.mAlertSummaryOnNextAddition = false;
                 } else {
@@ -172,11 +167,6 @@
     };
 
     @Override
-    public void onAmbientStateChanged(NotificationEntry entry, boolean isAmbient) {
-        onAlertStateChanged(entry, isAmbient, mAmbientPulseManager);
-    }
-
-    @Override
     public void onHeadsUpStateChanged(NotificationEntry entry, boolean isHeadsUp) {
         onAlertStateChanged(entry, isHeadsUp, mHeadsUpManager);
     }
@@ -208,11 +198,10 @@
             PendingAlertInfo alertInfo = mPendingAlerts.remove(entry.key);
             if (alertInfo != null) {
                 if (alertInfo.isStillValid()) {
-                    alertNotificationWhenPossible(entry, getActiveAlertManager());
+                    alertNotificationWhenPossible(entry, mHeadsUpManager);
                 } else {
                     // The transfer is no longer valid. Free the content.
-                    entry.getRow().freeContentViewWhenSafe(
-                            alertInfo.mAlertManager.getContentFlag());
+                    entry.getRow().freeContentViewWhenSafe(mHeadsUpManager.getContentFlag());
                 }
             }
         }
@@ -354,7 +343,6 @@
         if (SystemClock.elapsedRealtime() - groupAlertEntry.mLastAlertTransferTime
                 < ALERT_TRANSFER_TIMEOUT) {
             NotificationEntry summary = groupAlertEntry.mGroup.summary;
-            AlertingNotificationManager alertManager = getActiveAlertManager();
 
             if (!onlySummaryAlerts(summary)) {
                 return;
@@ -369,9 +357,9 @@
             boolean releasedChild = false;
             for (int i = 0; i < children.size(); i++) {
                 NotificationEntry entry = children.get(i);
-                if (onlySummaryAlerts(entry) && alertManager.isAlerting(entry.key)) {
+                if (onlySummaryAlerts(entry) && mHeadsUpManager.isAlerting(entry.key)) {
                     releasedChild = true;
-                    alertManager.removeNotification(entry.key, true /* releaseImmediately */);
+                    mHeadsUpManager.removeNotification(entry.key, true /* releaseImmediately */);
                 }
                 if (mPendingAlerts.containsKey(entry.key)) {
                     // This is the child that would've been removed if it was inflated.
@@ -379,10 +367,10 @@
                     mPendingAlerts.get(entry.key).mAbortOnInflation = true;
                 }
             }
-            if (releasedChild && !alertManager.isAlerting(summary.key)) {
+            if (releasedChild && !mHeadsUpManager.isAlerting(summary.key)) {
                 boolean notifyImmediately = (numChildren - numPendingChildren) > 1;
                 if (notifyImmediately) {
-                    alertNotificationWhenPossible(summary, alertManager);
+                    alertNotificationWhenPossible(summary, mHeadsUpManager);
                 } else {
                     // Should wait until the pending child inflates before alerting.
                     groupAlertEntry.mAlertSummaryOnNextAddition = true;
@@ -403,7 +391,7 @@
             @NonNull AlertingNotificationManager alertManager) {
         @InflationFlag int contentFlag = alertManager.getContentFlag();
         if (!entry.getRow().isInflationFlagSet(contentFlag)) {
-            mPendingAlerts.put(entry.key, new PendingAlertInfo(entry, alertManager));
+            mPendingAlerts.put(entry.key, new PendingAlertInfo(entry));
             entry.getRow().updateInflationFlag(contentFlag, true /* shouldInflate */);
             entry.getRow().inflateViews();
             return;
@@ -415,10 +403,6 @@
         }
     }
 
-    private AlertingNotificationManager getActiveAlertManager() {
-        return mIsDozing ? mAmbientPulseManager : mHeadsUpManager;
-    }
-
     private boolean onlySummaryAlerts(NotificationEntry entry) {
         return entry.notification.getNotification().getGroupAlertBehavior()
                 == Notification.GROUP_ALERT_SUMMARY;
@@ -429,10 +413,6 @@
      * inflation completes.
      */
     private class PendingAlertInfo {
-        /**
-         * The alert manager when the transfer is initiated.
-         */
-        final AlertingNotificationManager mAlertManager;
 
         /**
          * The original notification when the transfer is initiated. This is used to determine if
@@ -450,10 +430,9 @@
          */
         boolean mAbortOnInflation;
 
-        PendingAlertInfo(NotificationEntry entry, AlertingNotificationManager alertManager) {
+        PendingAlertInfo(NotificationEntry entry) {
             mOriginalNotification = entry.notification;
             mEntry = entry;
-            mAlertManager = alertManager;
         }
 
         /**
@@ -466,10 +445,6 @@
                 // Notification is aborted due to the transfer being explicitly cancelled
                 return false;
             }
-            if (mAlertManager != getActiveAlertManager()) {
-                // Alert manager has changed
-                return false;
-            }
             if (mEntry.notification.getGroupKey() != mOriginalNotification.getGroupKey()) {
                 // Groups have changed
                 return false;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationGroupManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationGroupManager.java
index cc8af3b..0bbfbef 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationGroupManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationGroupManager.java
@@ -24,8 +24,6 @@
 import com.android.systemui.Dependency;
 import com.android.systemui.plugins.statusbar.StatusBarStateController;
 import com.android.systemui.plugins.statusbar.StatusBarStateController.StateListener;
-import com.android.systemui.statusbar.AmbientPulseManager;
-import com.android.systemui.statusbar.AmbientPulseManager.OnAmbientChangedListener;
 import com.android.systemui.statusbar.StatusBarState;
 import com.android.systemui.statusbar.notification.collection.NotificationEntry;
 import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
@@ -46,8 +44,7 @@
  * A class to handle notifications and their corresponding groups.
  */
 @Singleton
-public class NotificationGroupManager implements OnHeadsUpChangedListener,
-        OnAmbientChangedListener, StateListener {
+public class NotificationGroupManager implements OnHeadsUpChangedListener, StateListener {
 
     private static final String TAG = "NotificationGroupManager";
     private final HashMap<String, NotificationGroup> mGroupMap = new HashMap<>();
@@ -55,12 +52,11 @@
     private int mBarState = -1;
     private HashMap<String, StatusBarNotification> mIsolatedEntries = new HashMap<>();
     private HeadsUpManager mHeadsUpManager;
-    private AmbientPulseManager mAmbientPulseManager = Dependency.get(AmbientPulseManager.class);
     private boolean mIsUpdatingUnchangedGroup;
 
     @Inject
-    public NotificationGroupManager() {
-        Dependency.get(StatusBarStateController.class).addCallback(this);
+    public NotificationGroupManager(StatusBarStateController statusBarStateController) {
+        statusBarStateController.addCallback(this);
     }
 
     /**
@@ -439,23 +435,6 @@
     }
 
     @Override
-    public void onHeadsUpPinnedModeChanged(boolean inPinnedMode) {
-    }
-
-    @Override
-    public void onHeadsUpPinned(NotificationEntry entry) {
-    }
-
-    @Override
-    public void onHeadsUpUnPinned(NotificationEntry entry) {
-    }
-
-    @Override
-    public void onAmbientStateChanged(NotificationEntry entry, boolean isAmbient) {
-        onAlertStateChanged(entry, isAmbient);
-    }
-
-    @Override
     public void onHeadsUpStateChanged(NotificationEntry entry, boolean isHeadsUp) {
         onAlertStateChanged(entry, isHeadsUp);
     }
@@ -485,7 +464,7 @@
         if (!sbn.isGroup() || sbn.getNotification().isGroupSummary()) {
             return false;
         }
-        if (!mHeadsUpManager.isAlerting(entry.key) && !mAmbientPulseManager.isAlerting(entry.key)) {
+        if (!mHeadsUpManager.isAlerting(entry.key)) {
             return false;
         }
         return (sbn.getNotification().fullScreenIntent != null
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconAreaController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconAreaController.java
index f52beca..ba34069 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconAreaController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconAreaController.java
@@ -12,21 +12,23 @@
 import androidx.annotation.NonNull;
 import androidx.collection.ArrayMap;
 
-import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.statusbar.StatusBarIcon;
 import com.android.internal.util.ContrastColorUtil;
+import com.android.settingslib.Utils;
 import com.android.systemui.Dependency;
+import com.android.systemui.Interpolators;
 import com.android.systemui.R;
 import com.android.systemui.plugins.DarkIconDispatcher;
 import com.android.systemui.plugins.DarkIconDispatcher.DarkReceiver;
 import com.android.systemui.plugins.statusbar.StatusBarStateController;
-import com.android.systemui.statusbar.NotificationListener;
+import com.android.systemui.statusbar.CrossFadeHelper;
 import com.android.systemui.statusbar.NotificationMediaManager;
 import com.android.systemui.statusbar.NotificationShelf;
 import com.android.systemui.statusbar.StatusBarIconView;
 import com.android.systemui.statusbar.StatusBarState;
 import com.android.systemui.statusbar.notification.NotificationEntryManager;
 import com.android.systemui.statusbar.notification.NotificationUtils;
+import com.android.systemui.statusbar.notification.NotificationWakeUpCoordinator;
 import com.android.systemui.statusbar.notification.collection.NotificationEntry;
 import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
 
@@ -39,15 +41,20 @@
  * normally reserved for notifications.
  */
 public class NotificationIconAreaController implements DarkReceiver,
-        StatusBarStateController.StateListener {
+        StatusBarStateController.StateListener,
+        NotificationWakeUpCoordinator.WakeUpListener {
 
     public static final String HIGH_PRIORITY = "high_priority";
+    private static final long AOD_ICONS_APPEAR_DURATION = 200;
 
     private final ContrastColorUtil mContrastColorUtil;
     private final NotificationEntryManager mEntryManager;
     private final Runnable mUpdateStatusBarIcons = this::updateStatusBarIcons;
     private final StatusBarStateController mStatusBarStateController;
     private final NotificationMediaManager mMediaManager;
+    private final NotificationWakeUpCoordinator mWakeUpCoordinator;
+    private final KeyguardBypassController mBypassController;
+    private final DozeParameters mDozeParameters;
 
     private int mIconSize;
     private int mIconHPadding;
@@ -60,20 +67,23 @@
     private NotificationIconContainer mShelfIcons;
     protected View mCenteredIconArea;
     private NotificationIconContainer mCenteredIcon;
+    private NotificationIconContainer mAodIcons;
     private StatusBarIconView mCenteredIconView;
     private final Rect mTintArea = new Rect();
     private ViewGroup mNotificationScrollLayout;
     private Context mContext;
-    private boolean mFullyDark;
-    private boolean mAnimationsEnabled;
+    private int mAodIconAppearTranslation;
 
-    /**
-     * Ratio representing being awake or in ambient mode, where 1 is dark and 0 awake.
-     */
-    private float mDarkAmount;
+    private boolean mAnimationsEnabled;
+    private int mAodIconTint;
+    private boolean mFullyHidden;
+    private boolean mAodIconsVisible;
+    private boolean mIsPulsing;
 
     public NotificationIconAreaController(Context context, StatusBar statusBar,
             StatusBarStateController statusBarStateController,
+            NotificationWakeUpCoordinator wakeUpCoordinator,
+            KeyguardBypassController keyguardBypassController,
             NotificationMediaManager notificationMediaManager) {
         mStatusBar = statusBar;
         mContrastColorUtil = ContrastColorUtil.getInstance(context);
@@ -82,8 +92,13 @@
         mStatusBarStateController = statusBarStateController;
         mStatusBarStateController.addCallback(this);
         mMediaManager = notificationMediaManager;
+        mDozeParameters = DozeParameters.getInstance(mContext);
+        mWakeUpCoordinator = wakeUpCoordinator;
+        wakeUpCoordinator.addListener(this);
+        mBypassController = keyguardBypassController;
 
         initializeNotificationAreaViews(context);
+        reloadAodColor();
     }
 
     protected View inflateIconArea(LayoutInflater inflater) {
@@ -104,6 +119,24 @@
 
         mCenteredIconArea = layoutInflater.inflate(R.layout.center_icon_area, null);
         mCenteredIcon = mCenteredIconArea.findViewById(R.id.centeredIcon);
+
+        initAodIcons();
+    }
+
+    public void initAodIcons() {
+        boolean changed = mAodIcons != null;
+        if (changed) {
+            mAodIcons.setAnimationsEnabled(false);
+            mAodIcons.removeAllViews();
+        }
+        mAodIcons = mStatusBar.getStatusBarWindow().findViewById(
+                R.id.clock_notification_icon_container);
+        mAodIcons.setOnLockScreen(true);
+        updateAodIconsVisibility(false /* animate */);
+        updateAnimations();
+        if (changed) {
+            updateAodNotificationIcons();
+        }
     }
 
     public void setupShelf(NotificationShelf shelf) {
@@ -126,6 +159,10 @@
             View child = mCenteredIcon.getChildAt(i);
             child.setLayoutParams(params);
         }
+        for (int i = 0; i < mAodIcons.getChildCount(); i++) {
+            View child = mAodIcons.getChildAt(i);
+            child.setLayoutParams(params);
+        }
     }
 
     @NonNull
@@ -138,6 +175,8 @@
         Resources res = context.getResources();
         mIconSize = res.getDimensionPixelSize(com.android.internal.R.dimen.status_bar_icon_size);
         mIconHPadding = res.getDimensionPixelSize(R.dimen.status_bar_icon_padding);
+        mAodIconAppearTranslation = res.getDimensionPixelSize(
+                R.dimen.shelf_appear_translation);
     }
 
     /**
@@ -192,12 +231,17 @@
     }
 
     protected boolean shouldShowNotificationIcon(NotificationEntry entry,
-            boolean showAmbient, boolean showLowPriority, boolean hideDismissed,
-            boolean hideRepliedMessages, boolean hideCurrentMedia, boolean hideCenteredIcon) {
+            boolean showAmbient, boolean hideDismissed,
+            boolean hideRepliedMessages, boolean hideCurrentMedia, boolean hideCenteredIcon,
+            boolean hidePulsing, boolean onlyShowCenteredIcon) {
 
-        final boolean isCenteredNotificationIcon = entry.centeredIcon != null
+        final boolean isCenteredNotificationIcon = mCenteredIconView != null
+                && entry.centeredIcon != null
                 && Objects.equals(entry.centeredIcon, mCenteredIconView);
-        if (hideCenteredIcon == isCenteredNotificationIcon) {
+        if (onlyShowCenteredIcon) {
+            return isCenteredNotificationIcon;
+        }
+        if (hideCenteredIcon && isCenteredNotificationIcon && !entry.isRowHeadsUp()) {
             return false;
         }
         if (mEntryManager.getNotificationData().isAmbient(entry.key) && !showAmbient) {
@@ -206,9 +250,6 @@
         if (hideCurrentMedia && entry.key.equals(mMediaManager.getMediaNotificationKey())) {
             return false;
         }
-        if (!showLowPriority && !entry.isHighPriority()) {
-            return false;
-        }
         if (!entry.isTopLevelChild()) {
             return false;
         }
@@ -222,7 +263,12 @@
             return false;
         }
         // showAmbient == show in shade but not shelf
-        if ((!showAmbient || mFullyDark) && entry.shouldSuppressStatusBar()) {
+        if (!showAmbient && entry.shouldSuppressStatusBar()) {
+            return false;
+        }
+        if (hidePulsing && entry.showingPulsing()
+                && (!mWakeUpCoordinator.getNotificationsFullyHidden()
+                        || !entry.isPulseSuppressed())) {
             return false;
         }
         return true;
@@ -235,6 +281,7 @@
         updateStatusBarIcons();
         updateShelfIcons();
         updateCenterIcon();
+        updateAodNotificationIcons();
 
         applyNotificationIconsTint();
     }
@@ -242,50 +289,45 @@
     private void updateShelfIcons() {
         updateIconsForLayout(entry -> entry.expandedIcon, mShelfIcons,
                 true /* showAmbient */,
-                true /* showLowPriority */,
                 false /* hideDismissed */,
-                mFullyDark /* hideRepliedMessages */,
-                mFullyDark /* hideCurrentMedia */,
-                true /* hide centered icon */);
+                false /* hideRepliedMessages */,
+                false /* hideCurrentMedia */,
+                false /* hide centered icon */,
+                false /* hidePulsing */,
+                false /* onlyShowCenteredIcon */);
     }
 
     public void updateStatusBarIcons() {
         updateIconsForLayout(entry -> entry.icon, mNotificationIcons,
                 false /* showAmbient */,
-                true /* showLowPriority */,
                 true /* hideDismissed */,
                 true /* hideRepliedMessages */,
                 false /* hideCurrentMedia */,
-                true /* hide centered icon */);
+                true /* hide centered icon */,
+                false /* hidePulsing */,
+                false /* onlyShowCenteredIcon */);
     }
 
     private void updateCenterIcon() {
         updateIconsForLayout(entry -> entry.centeredIcon, mCenteredIcon,
                 false /* showAmbient */,
-                true /* showLowPriority */,
                 false /* hideDismissed */,
                 false /* hideRepliedMessages */,
-                mFullyDark /* hideCurrentMedia */,
-                false /* hide centered icon */);
+                false /* hideCurrentMedia */,
+                false /* hide centered icon */,
+                false /* hidePulsing */,
+                true/* onlyShowCenteredIcon */);
     }
 
-    /**
-     * If icons of the status bar should animate when they are added or removed.
-     */
-    public void setAnimationsEnabled(boolean enabled) {
-        mAnimationsEnabled = enabled;
-        updateAnimations();
-    }
-
-    @Override
-    public void onStateChanged(int newState) {
-        updateAnimations();
-    }
-
-    private void updateAnimations() {
-        boolean inShade = mStatusBarStateController.getState() == StatusBarState.SHADE;
-        mCenteredIcon.setAnimationsEnabled(mAnimationsEnabled && inShade);
-        mNotificationIcons.setAnimationsEnabled(mAnimationsEnabled && inShade);
+    public void updateAodNotificationIcons() {
+        updateIconsForLayout(entry -> entry.aodIcon, mAodIcons,
+                false /* showAmbient */,
+                true /* hideDismissed */,
+                true /* hideRepliedMessages */,
+                true /* hideCurrentMedia */,
+                true /* hide centered icon */,
+                mBypassController.getBypassEnabled() /* hidePulsing */,
+                false /* onlyShowCenteredIcon */);
     }
 
     /**
@@ -296,11 +338,12 @@
      * @param showAmbient should ambient notification icons be shown
      * @param hideDismissed should dismissed icons be hidden
      * @param hideRepliedMessages should messages that have been replied to be hidden
+     * @param hidePulsing should pulsing notifications be hidden
      */
     private void updateIconsForLayout(Function<NotificationEntry, StatusBarIconView> function,
-            NotificationIconContainer hostLayout, boolean showAmbient, boolean showLowPriority,
+            NotificationIconContainer hostLayout, boolean showAmbient,
             boolean hideDismissed, boolean hideRepliedMessages, boolean hideCurrentMedia,
-            boolean hideCenteredIcon) {
+            boolean hideCenteredIcon, boolean hidePulsing, boolean onlyShowCenteredIcon) {
         ArrayList<StatusBarIconView> toShow = new ArrayList<>(
                 mNotificationScrollLayout.getChildCount());
 
@@ -309,8 +352,9 @@
             View view = mNotificationScrollLayout.getChildAt(i);
             if (view instanceof ExpandableNotificationRow) {
                 NotificationEntry ent = ((ExpandableNotificationRow) view).getEntry();
-                if (shouldShowNotificationIcon(ent, showAmbient, showLowPriority, hideDismissed,
-                        hideRepliedMessages, hideCurrentMedia, hideCenteredIcon)) {
+                if (shouldShowNotificationIcon(ent, showAmbient, hideDismissed,
+                        hideRepliedMessages, hideCurrentMedia, hideCenteredIcon, hidePulsing,
+                        onlyShowCenteredIcon)) {
                     StatusBarIconView iconView = function.apply(ent);
                     if (iconView != null) {
                         toShow.add(iconView);
@@ -424,6 +468,8 @@
                 iv.executeOnLayout(() -> updateTintForIcon(iv, mCenteredIconTint));
             }
         }
+
+        updateAodIconColors();
     }
 
     private void updateTintForIcon(StatusBarIconView v, int tint) {
@@ -437,12 +483,6 @@
         v.setDecorColor(tint);
     }
 
-    public void setDark(boolean dark) {
-        mNotificationIcons.setDark(dark, false, 0);
-        mShelfIcons.setDark(dark, false, 0);
-        mCenteredIcon.setDark(dark, false, 0);
-    }
-
     /**
      * Shows the icon view given in the center.
      */
@@ -463,12 +503,119 @@
     }
 
     @Override
-    public void onDozeAmountChanged(float linear, float eased) {
-        mDarkAmount = linear;
-        boolean fullyDark = mDarkAmount == 1f;
-        if (mFullyDark != fullyDark) {
-            mFullyDark = fullyDark;
-            updateShelfIcons();
+    public void onDozingChanged(boolean isDozing) {
+        boolean animate = mDozeParameters.getAlwaysOn()
+                && !mDozeParameters.getDisplayNeedsBlanking();
+        mAodIcons.setDozing(isDozing, animate, 0);
+    }
+
+    public void setAnimationsEnabled(boolean enabled) {
+        mAnimationsEnabled = enabled;
+        updateAnimations();
+    }
+
+    @Override
+    public void onStateChanged(int newState) {
+        updateAodIconsVisibility(false /* animate */);
+        updateAnimations();
+    }
+
+    private void updateAnimations() {
+        boolean inShade = mStatusBarStateController.getState() == StatusBarState.SHADE;
+        mAodIcons.setAnimationsEnabled(mAnimationsEnabled && !inShade);
+        mCenteredIcon.setAnimationsEnabled(mAnimationsEnabled && inShade);
+        mNotificationIcons.setAnimationsEnabled(mAnimationsEnabled && inShade);
+    }
+
+    public void onThemeChanged() {
+        reloadAodColor();
+        updateAodIconColors();
+    }
+
+    public void appearAodIcons() {
+        DozeParameters dozeParameters = DozeParameters.getInstance(mContext);
+        if (dozeParameters.shouldControlScreenOff()) {
+            mAodIcons.setTranslationY(-mAodIconAppearTranslation);
+            mAodIcons.setAlpha(0);
+            mAodIcons.animate()
+                    .setInterpolator(Interpolators.DECELERATE_QUINT)
+                    .translationY(0)
+                    .setDuration(AOD_ICONS_APPEAR_DURATION)
+                    .start();
+            mAodIcons.animate()
+                    .alpha(1)
+                    .setInterpolator(Interpolators.LINEAR)
+                    .setDuration(AOD_ICONS_APPEAR_DURATION)
+                    .start();
+        }
+    }
+
+    private void reloadAodColor() {
+        mAodIconTint = Utils.getColorAttrDefaultColor(mContext,
+                R.attr.wallpaperTextColor);
+    }
+    private void updateAodIconColors() {
+        for (int i = 0; i < mAodIcons.getChildCount(); i++) {
+            final StatusBarIconView iv = (StatusBarIconView) mAodIcons.getChildAt(i);
+            if (iv.getWidth() != 0) {
+                updateTintForIcon(iv, mAodIconTint);
+            } else {
+                iv.executeOnLayout(() -> updateTintForIcon(iv, mAodIconTint));
+            }
+        }
+    }
+
+    @Override
+    public void onFullyHiddenChanged(boolean fullyHidden) {
+        boolean animate = true;
+        if (!mBypassController.getBypassEnabled()) {
+            animate = mDozeParameters.getAlwaysOn() && !mDozeParameters.getDisplayNeedsBlanking();
+            // We only want the appear animations to happen when the notifications get fully hidden,
+            // since otherwise the unhide animation overlaps
+            animate &= fullyHidden;
+        }
+        updateAodIconsVisibility(animate);
+        updateAodNotificationIcons();
+    }
+
+    @Override
+    public void onPulseExpansionChanged(boolean expandingChanged) {
+        if (expandingChanged) {
+            updateAodIconsVisibility(true /* animate */);
+        }
+    }
+
+    private void updateAodIconsVisibility(boolean animate) {
+        boolean visible = mBypassController.getBypassEnabled()
+                || mWakeUpCoordinator.getNotificationsFullyHidden();
+        if (mStatusBarStateController.getState() != StatusBarState.KEYGUARD) {
+            visible = false;
+        }
+        if (visible && mWakeUpCoordinator.isPulseExpanding()) {
+            visible = false;
+        }
+        if (mAodIconsVisible != visible) {
+            mAodIconsVisible = visible;
+            mAodIcons.animate().cancel();
+            if (animate) {
+                boolean wasFullyInvisible = mAodIcons.getVisibility() != View.VISIBLE;
+                if (mAodIconsVisible) {
+                    if (wasFullyInvisible) {
+                        // No fading here, let's just appear the icons instead!
+                        mAodIcons.setVisibility(View.VISIBLE);
+                        mAodIcons.setAlpha(1.0f);
+                        appearAodIcons();
+                    } else {
+                        // We were fading out, let's fade in instead
+                        CrossFadeHelper.fadeIn(mAodIcons);
+                    }
+                } else {
+                    CrossFadeHelper.fadeOut(mAodIcons);
+                }
+            } else {
+                mAodIcons.setAlpha(1.0f);
+                mAodIcons.setVisibility(visible ? View.VISIBLE : View.INVISIBLE);
+            }
         }
     }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconContainer.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconContainer.java
index e20a23e..a53ce9b 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconContainer.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconContainer.java
@@ -128,7 +128,7 @@
         }
     }.setDuration(CONTENT_FADE_DURATION);
 
-    private static final int MAX_VISIBLE_ICONS_WHEN_DARK = 5;
+    private static final int MAX_VISIBLE_ICONS_ON_LOCK = 5;
     public static final int MAX_STATIC_ICONS = 4;
     private static final int MAX_DOTS = 1;
 
@@ -141,7 +141,8 @@
     private int mActualLayoutWidth = NO_VALUE;
     private float mActualPaddingEnd = NO_VALUE;
     private float mActualPaddingStart = NO_VALUE;
-    private boolean mDark;
+    private boolean mDozing;
+    private boolean mOnLockScreen;
     private boolean mChangingViewPositions;
     private int mAddAnimationStartIndex = -1;
     private int mCannedAnimationStartIndex = -1;
@@ -288,7 +289,7 @@
             }
         }
         if (child instanceof StatusBarIconView) {
-            ((StatusBarIconView) child).setDark(mDark, false, 0);
+            ((StatusBarIconView) child).setDozing(mDozing, false, 0);
         }
     }
 
@@ -319,7 +320,7 @@
         if (child instanceof StatusBarIconView) {
             boolean isReplacingIcon = isReplacingIcon(child);
             final StatusBarIconView icon = (StatusBarIconView) child;
-            if (mAnimationsEnabled && icon.getVisibleState() != StatusBarIconView.STATE_HIDDEN
+            if (areAnimationsEnabled(icon) && icon.getVisibleState() != StatusBarIconView.STATE_HIDDEN
                     && child.getVisibility() == VISIBLE && isReplacingIcon) {
                 int animationStartIndex = findFirstViewIndexAfter(icon.getTranslationX());
                 if (mAddAnimationStartIndex < 0) {
@@ -330,7 +331,7 @@
             }
             if (!mChangingViewPositions) {
                 mIconStates.remove(child);
-                if (mAnimationsEnabled && !isReplacingIcon) {
+                if (areAnimationsEnabled(icon) && !isReplacingIcon) {
                     addTransientView(icon, 0);
                     boolean isIsolatedIcon = child == mIsolatedIcon;
                     icon.setVisibleState(StatusBarIconView.STATE_HIDDEN, true /* animate */,
@@ -341,6 +342,10 @@
         }
     }
 
+    private boolean areAnimationsEnabled(StatusBarIconView icon) {
+        return mAnimationsEnabled || icon == mIsolatedIcon;
+    }
+
     /**
      * Finds the first view with a translation bigger then a given value
      */
@@ -373,7 +378,7 @@
         float translationX = getActualPaddingStart();
         int firstOverflowIndex = -1;
         int childCount = getChildCount();
-        int maxVisibleIcons = mDark ? MAX_VISIBLE_ICONS_WHEN_DARK :
+        int maxVisibleIcons = mOnLockScreen ? MAX_VISIBLE_ICONS_ON_LOCK :
                 mIsStaticLayout ? MAX_STATIC_ICONS : childCount;
         float layoutEnd = getLayoutEnd();
         float overflowStart = getMaxOverflowStart();
@@ -390,8 +395,8 @@
             boolean forceOverflow = mSpeedBumpIndex != -1 && i >= mSpeedBumpIndex
                     && iconState.iconAppearAmount > 0.0f || i >= maxVisibleIcons;
             boolean noOverflowAfter = i == childCount - 1;
-            float drawingScale = mDark && view instanceof StatusBarIconView
-                    ? ((StatusBarIconView) view).getIconScaleFullyDark()
+            float drawingScale = mOnLockScreen && view instanceof StatusBarIconView
+                    ? ((StatusBarIconView) view).getIconScaleIncreased()
                     : 1f;
             if (mOpenedAmount != 0.0f) {
                 noOverflowAfter = noOverflowAfter && !hasAmbient && !forceOverflow;
@@ -438,7 +443,7 @@
             mFirstVisibleIconState = mIconStates.get(getChildAt(0));
         }
 
-        boolean center = mDark;
+        boolean center = mOnLockScreen;
         if (center && translationX < getLayoutEnd()) {
             float initialTranslation =
                     mFirstVisibleIconState == null ? 0 : mFirstVisibleIconState.xTranslation;
@@ -558,13 +563,13 @@
         mChangingViewPositions = changingViewPositions;
     }
 
-    public void setDark(boolean dark, boolean fade, long delay) {
-        mDark = dark;
+    public void setDozing(boolean dozing, boolean fade, long delay) {
+        mDozing = dozing;
         mDisallowNextAnimation |= !fade;
         for (int i = 0; i < getChildCount(); i++) {
             View view = getChildAt(i);
             if (view instanceof StatusBarIconView) {
-                ((StatusBarIconView) view).setDark(dark, fade, delay);
+                ((StatusBarIconView) view).setDozing(dozing, fade, delay);
             }
         }
     }
@@ -668,6 +673,10 @@
         }
     }
 
+    public void setOnLockScreen(boolean onLockScreen) {
+        mOnLockScreen = onLockScreen;
+    }
+
     public class IconState extends ViewState {
         public static final int NO_VALUE = NotificationIconContainer.NO_VALUE;
         public float iconAppearAmount = 1.0f;
@@ -690,7 +699,7 @@
                 StatusBarIconView icon = (StatusBarIconView) view;
                 boolean animate = false;
                 AnimationProperties animationProperties = null;
-                boolean animationsAllowed = mAnimationsEnabled && !mDisallowNextAnimation
+                boolean animationsAllowed = areAnimationsEnabled(icon) && !mDisallowNextAnimation
                         && !noAnimations;
                 if (animationsAllowed) {
                     if (justAdded || justReplaced) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
index bc205d6..a0847b6 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
@@ -40,6 +40,7 @@
 import android.graphics.Rect;
 import android.graphics.Region;
 import android.os.PowerManager;
+import android.os.SystemClock;
 import android.util.AttributeSet;
 import android.util.Log;
 import android.util.MathUtils;
@@ -57,6 +58,7 @@
 import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
 import com.android.keyguard.KeyguardClockSwitch;
 import com.android.keyguard.KeyguardStatusView;
+import com.android.keyguard.KeyguardUpdateMonitor;
 import com.android.systemui.DejankUtils;
 import com.android.systemui.Dependency;
 import com.android.systemui.Interpolators;
@@ -114,7 +116,8 @@
         KeyguardAffordanceHelper.Callback, NotificationStackScrollLayout.OnEmptySpaceClickListener,
         OnHeadsUpChangedListener, QS.HeightListener, ZenModeController.Callback,
         ConfigurationController.ConfigurationListener, StateListener,
-        PulseExpansionHandler.ExpansionCallback, DynamicPrivacyController.Listener {
+        PulseExpansionHandler.ExpansionCallback, DynamicPrivacyController.Listener,
+        NotificationWakeUpCoordinator.WakeUpListener {
 
     private static final boolean DEBUG = false;
 
@@ -138,6 +141,12 @@
     private static final int CAP_HEIGHT = 1456;
     private static final int FONT_HEIGHT = 2163;
 
+    /**
+     * Maximum time before which we will expand the panel even for slow motions when getting a
+     * touch passed over from launcher.
+     */
+    private static final int MAX_TIME_TO_OPEN_WHEN_FLINGING_FROM_LAUNCHER = 300;
+
     static final String COUNTER_PANEL_OPEN = "panel_open";
     static final String COUNTER_PANEL_OPEN_QS = "panel_open_qs";
     private static final String COUNTER_PANEL_OPEN_PEEK = "panel_open_peek";
@@ -147,12 +156,23 @@
 
     private static final AnimationProperties CLOCK_ANIMATION_PROPERTIES = new AnimationProperties()
             .setDuration(StackStateAnimator.ANIMATION_DURATION_STANDARD);
+    private static final AnimatableProperty KEYGUARD_HEADS_UP_SHOWING_AMOUNT
+            = AnimatableProperty.from("KEYGUARD_HEADS_UP_SHOWING_AMOUNT",
+            NotificationPanelView::setKeyguardHeadsUpShowingAmount,
+            NotificationPanelView::getKeyguardHeadsUpShowingAmount,
+            R.id.keyguard_hun_animator_tag,
+            R.id.keyguard_hun_animator_end_tag,
+            R.id.keyguard_hun_animator_start_tag);
+    private static final AnimationProperties KEYGUARD_HUN_PROPERTIES =
+            new AnimationProperties().setDuration(StackStateAnimator.ANIMATION_DURATION_STANDARD);
 
     private final InjectionInflationController mInjectionInflationController;
     private final PowerManager mPowerManager;
     private final AccessibilityManager mAccessibilityManager;
     private final NotificationWakeUpCoordinator mWakeUpCoordinator;
     private final PulseExpansionHandler mPulseExpansionHandler;
+    private final KeyguardBypassController mKeyguardBypassController;
+    private final KeyguardUpdateMonitor mUpdateMonitor;
 
     @VisibleForTesting
     protected KeyguardAffordanceHelper mAffordanceHelper;
@@ -213,6 +233,8 @@
     private int mNotificationsHeaderCollideDistance;
     private int mUnlockMoveDistance;
     private float mEmptyDragAmount;
+    private float mDownX;
+    private float mDownY;
 
     private final KeyguardClockPositionAlgorithm mClockPositionAlgorithm =
             new KeyguardClockPositionAlgorithm();
@@ -277,6 +299,12 @@
     private boolean mBlockingExpansionForCurrentTouch;
 
     /**
+     * Following variables maintain state of events when input focus transfer may occur.
+     */
+    private boolean mExpectingSynthesizedDown; // expecting to see synthesized DOWN event
+    private boolean mLastEventSynthesizedDown; // last event was synthesized DOWN event
+
+    /**
      * Current dark amount that follows regular interpolation curve of animation.
      */
     private float mInterpolatedDarkAmount;
@@ -347,13 +375,23 @@
     private int mThemeResId;
     private KeyguardIndicationController mKeyguardIndicationController;
     private Consumer<Boolean> mAffordanceLaunchListener;
+    private int mShelfHeight;
+    private Runnable mOnReinflationListener;
+    private int mDarkIconSize;
+    private int mHeadsUpInset;
+    private boolean mHeadsUpPinnedMode;
+    private float mKeyguardHeadsUpShowingAmount = 0.0f;
+    private boolean mShowingKeyguardHeadsUp;
+    private boolean mAllowExpandForSmallExpansion;
+    private Runnable mExpandAfterLayoutRunnable;
 
     @Inject
     public NotificationPanelView(@Named(VIEW_CONTEXT) Context context, AttributeSet attrs,
             InjectionInflationController injectionInflationController,
             NotificationWakeUpCoordinator coordinator,
             PulseExpansionHandler pulseExpansionHandler,
-            DynamicPrivacyController dynamicPrivacyController) {
+            DynamicPrivacyController dynamicPrivacyController,
+            KeyguardBypassController bypassController) {
         super(context, attrs);
         setWillNotDraw(!DEBUG);
         mInjectionInflationController = injectionInflationController;
@@ -367,7 +405,14 @@
         mCommandQueue = getComponent(context, CommandQueue.class);
         mDisplayId = context.getDisplayId();
         mPulseExpansionHandler = pulseExpansionHandler;
+        pulseExpansionHandler.setPulseExpandAbortListener(() -> {
+            if (mQs != null) {
+                mQs.animateHeaderSlidingOut();
+            }
+        });
         mThemeResId = context.getThemeResId();
+        mKeyguardBypassController = bypassController;
+        mUpdateMonitor = KeyguardUpdateMonitor.getInstance(mContext);
         dynamicPrivacyController.addListener(this);
 
         mBottomAreaShadeAlphaAnimator = ValueAnimator.ofFloat(1f, 0);
@@ -416,6 +461,21 @@
         mWakeUpCoordinator.setStackScroller(mNotificationStackScroller);
         mQsFrame = findViewById(R.id.qs_frame);
         mPulseExpansionHandler.setUp(mNotificationStackScroller, this, mShadeController);
+        mWakeUpCoordinator.addListener(new NotificationWakeUpCoordinator.WakeUpListener() {
+            @Override
+            public void onFullyHiddenChanged(boolean isFullyHidden) {
+                updateKeyguardStatusBarForHeadsUp();
+            }
+
+            @Override
+            public void onPulseExpansionChanged(boolean expandingChanged) {
+                if (mKeyguardBypassController.getBypassEnabled()) {
+                    // Position the notifications while dragging down while pulsing
+                    requestScrollerTopPaddingUpdate(false /* animate */);
+                    updateQSPulseExpansion();
+                }
+            }
+        });
     }
 
     @Override
@@ -460,6 +520,13 @@
                 R.dimen.keyguard_indication_bottom_padding);
         mQsNotificationTopPadding = getResources().getDimensionPixelSize(
                 R.dimen.qs_notification_padding);
+        mShelfHeight = getResources().getDimensionPixelSize(R.dimen.notification_shelf_height);
+        mDarkIconSize = getResources().getDimensionPixelSize(
+                R.dimen.status_bar_icon_drawing_size_dark);
+        int statusbarHeight = getResources().getDimensionPixelSize(
+                com.android.internal.R.dimen.status_bar_height);
+        mHeadsUpInset = statusbarHeight + getResources().getDimensionPixelSize(
+                R.dimen.heads_up_status_bar_padding);
     }
 
     /**
@@ -552,6 +619,9 @@
 
         setKeyguardStatusViewVisibility(mBarState, false, false);
         setKeyguardBottomAreaVisibility(mBarState, false);
+        if (mOnReinflationListener != null) {
+            mOnReinflationListener.run();
+        }
     }
 
     private void initBottomArea() {
@@ -610,6 +680,10 @@
         }
         updateMaxHeadsUpTranslation();
         updateGestureExclusionRect();
+        if (mExpandAfterLayoutRunnable != null) {
+            mExpandAfterLayoutRunnable.run();
+            mExpandAfterLayoutRunnable = null;
+        }
     }
 
     private void updateGestureExclusionRect() {
@@ -671,24 +745,30 @@
         boolean animateClock = animate || mAnimateNextPositionUpdate;
         int stackScrollerPadding;
         if (mBarState != StatusBarState.KEYGUARD) {
-            stackScrollerPadding = (mQs != null ? mQs.getHeader().getHeight() : 0) + mQsPeekHeight
-                    + mQsNotificationTopPadding;
+            stackScrollerPadding = getUnlockedStackScrollerPadding();
         } else {
             int totalHeight = getHeight();
             int bottomPadding = Math.max(mIndicationBottomPadding, mAmbientIndicationBottomPadding);
             int clockPreferredY = mKeyguardStatusView.getClockPreferredY(totalHeight);
+            boolean bypassEnabled = mKeyguardBypassController.getBypassEnabled();
+            final boolean hasVisibleNotifications =
+                    !bypassEnabled && mNotificationStackScroller.getVisibleNotificationCount() != 0;
+            mKeyguardStatusView.setHasVisibleNotifications(hasVisibleNotifications);
             mClockPositionAlgorithm.setup(
                     mStatusBarMinHeight,
                     totalHeight - bottomPadding,
                     mNotificationStackScroller.getIntrinsicContentHeight(),
                     getExpandedFraction(),
                     totalHeight,
-                    mKeyguardStatusView.getHeight(),
+                    (int) (mKeyguardStatusView.getHeight()
+                            - mShelfHeight / 2.0f - mDarkIconSize / 2.0f),
                     clockPreferredY,
                     hasCustomClock(),
-                    mNotificationStackScroller.getVisibleNotificationCount() != 0,
+                    hasVisibleNotifications,
                     mInterpolatedDarkAmount,
-                    mEmptyDragAmount);
+                    mEmptyDragAmount,
+                    bypassEnabled,
+                    getUnlockedStackScrollerPadding());
             mClockPositionAlgorithm.run(mClockPositionResult);
             PropertyAnimator.setProperty(mKeyguardStatusView, AnimatableProperty.X,
                     mClockPositionResult.clockX, CLOCK_ANIMATION_PROPERTIES, animateClock);
@@ -696,10 +776,9 @@
                     mClockPositionResult.clockY, CLOCK_ANIMATION_PROPERTIES, animateClock);
             updateNotificationTranslucency();
             updateClock();
-            stackScrollerPadding = mClockPositionResult.stackScrollerPadding;
+            stackScrollerPadding = mClockPositionResult.stackScrollerPaddingExpanded;
         }
         mNotificationStackScroller.setIntrinsicPadding(stackScrollerPadding);
-        mNotificationStackScroller.setAntiBurnInOffsetX(mClockPositionResult.clockX);
         mKeyguardBottomArea.setAntiBurnInOffsetX(mClockPositionResult.clockX);
 
         mStackScrollerMeasuringPass++;
@@ -709,6 +788,14 @@
     }
 
     /**
+     * @return the padding of the stackscroller when unlocked
+     */
+    private int getUnlockedStackScrollerPadding() {
+        return (mQs != null ? mQs.getHeader().getHeight() : 0) + mQsPeekHeight
+                + mQsNotificationTopPadding;
+    }
+
+    /**
      * @param maximum the maximum to return at most
      * @return the maximum keyguard notifications that can fit on the screen
      */
@@ -868,7 +955,7 @@
     protected void flingToHeight(float vel, boolean expand, float target,
             float collapseSpeedUpFactor, boolean expandBecauseOfFalsing) {
         mHeadsUpTouchHelper.notifyFling(!expand);
-        setClosingWithAlphaFadeout(!expand && getFadeoutAlpha() == 1.0f);
+        setClosingWithAlphaFadeout(!expand && !isOnKeyguard() && getFadeoutAlpha() == 1.0f);
         super.flingToHeight(vel, expand, target, collapseSpeedUpFactor, expandBecauseOfFalsing);
     }
 
@@ -889,7 +976,8 @@
             MetricsLogger.count(mContext, COUNTER_PANEL_OPEN_PEEK, 1);
             return true;
         }
-        if (mPulseExpansionHandler.onInterceptTouchEvent(event)) {
+        if (!shouldQuickSettingsIntercept(mDownX, mDownY, 0)
+                && mPulseExpansionHandler.onInterceptTouchEvent(event)) {
             return true;
         }
 
@@ -990,8 +1078,21 @@
             mOnlyAffordanceInThisMotion = false;
             mQsTouchAboveFalsingThreshold = mQsFullyExpanded;
             mDozingOnDown = isDozing();
+            mDownX = event.getX();
+            mDownY = event.getY();
             mCollapsedOnDown = isFullyCollapsed();
             mListenForHeadsUp = mCollapsedOnDown && mHeadsUpManager.hasPinnedHeadsUp();
+            mAllowExpandForSmallExpansion = mExpectingSynthesizedDown;
+            mTouchSlopExceededBeforeDown = mExpectingSynthesizedDown;
+            if (mExpectingSynthesizedDown) {
+                mLastEventSynthesizedDown = true;
+            } else {
+                // down but not synthesized motion event.
+                mLastEventSynthesizedDown = false;
+            }
+        } else {
+            // not down event at all.
+            mLastEventSynthesizedDown = false;
         }
     }
 
@@ -1041,6 +1142,20 @@
     }
 
     @Override
+    protected boolean shouldExpandWhenNotFlinging() {
+        if (super.shouldExpandWhenNotFlinging()) {
+            return true;
+        }
+        if (mAllowExpandForSmallExpansion) {
+            // When we get a touch that came over from launcher, the velocity isn't always correct
+            // Let's err on expanding if the gesture has been reasonably slow
+            long timeSinceDown = SystemClock.uptimeMillis() - mDownTime;
+            return timeSinceDown <= MAX_TIME_TO_OPEN_WHEN_FLINGING_FROM_LAUNCHER;
+        }
+        return false;
+    }
+
+    @Override
     protected float getOpeningHeight() {
         return mNotificationStackScroller.getOpeningHeight();
     }
@@ -1057,13 +1172,20 @@
             return false;
         }
 
-        initDownStates(event);
         // Make sure the next touch won't the blocked after the current ends.
         if (event.getAction() == MotionEvent.ACTION_UP
                 || event.getAction() == MotionEvent.ACTION_CANCEL) {
             mBlockingExpansionForCurrentTouch = false;
         }
-        if (!mIsExpanding && mPulseExpansionHandler.onTouchEvent(event)) {
+        // When touch focus transfer happens, ACTION_DOWN->ACTION_UP may happen immediately
+        // without any ACTION_MOVE event.
+        // In such case, simply expand the panel instead of being stuck at the bottom bar.
+        if (mLastEventSynthesizedDown && event.getAction() == MotionEvent.ACTION_UP) {
+            expand(true /* animate */);
+        }
+        initDownStates(event);
+        if (!mIsExpanding && !shouldQuickSettingsIntercept(mDownX, mDownY, 0)
+                && mPulseExpansionHandler.onTouchEvent(event)) {
             // We're expanding all the other ones shouldn't get this anymore
             return true;
         }
@@ -1180,6 +1302,49 @@
         }
     }
 
+    /**
+     * Input focus transfer is about to happen.
+     */
+    public void startWaitingForOpenPanelGesture() {
+        if (!isFullyCollapsed()) {
+            return;
+        }
+        mExpectingSynthesizedDown = true;
+        onTrackingStarted();
+        updatePanelExpanded();
+    }
+
+    /**
+     * Called when this view is no longer waiting for input focus transfer.
+     *
+     * There are two scenarios behind this function call. First, input focus transfer
+     * has successfully happened and this view already received synthetic DOWN event.
+     * (mExpectingSynthesizedDown == false). Do nothing.
+     *
+     * Second, before input focus transfer finished, user may have lifted finger
+     * in previous window and this window never received synthetic DOWN event.
+     * (mExpectingSynthesizedDown == true).
+     * In this case, we use the velocity to trigger fling event.
+     *
+     * @param velocity unit is in px / millis
+     */
+    public void stopWaitingForOpenPanelGesture(final float velocity) {
+        if (mExpectingSynthesizedDown) {
+            mExpectingSynthesizedDown = false;
+            maybeVibrateOnOpening();
+            Runnable runnable = () -> fling(velocity > 1f ? 1000f * velocity : 0,
+                    true /* expand */);
+            if (mStatusBar.getStatusBarWindow().getHeight()
+                    != mStatusBar.getStatusBarHeight()) {
+                // The panel is already expanded to its full size, let's expand directly
+                runnable.run();
+            } else {
+                mExpandAfterLayoutRunnable = runnable;
+            }
+            onTrackingStopped(false);
+        }
+    }
+
     @Override
     protected boolean flingExpands(float vel, float vectorVel, float x, float y) {
         boolean expands = super.flingExpands(vel, vectorVel, x, y);
@@ -1192,8 +1357,12 @@
     }
 
     @Override
-    protected boolean hasConflictingGestures() {
-        return mBarState != StatusBarState.SHADE;
+    protected boolean shouldGestureWaitForTouchSlop() {
+        if (mExpectingSynthesizedDown) {
+            mExpectingSynthesizedDown = false;
+            return false;
+        }
+        return isFullyCollapsed() || mBarState != StatusBarState.SHADE;
     }
 
     @Override
@@ -1334,6 +1503,8 @@
             mFalsingManager.setQsExpanded(expanded);
             mStatusBar.setQsExpanded(expanded);
             mNotificationContainerParent.setQsExpanded(expanded);
+            mPulseExpansionHandler.setQsExpanded(expanded);
+            mKeyguardBypassController.setQSExpanded(expanded);
         }
     }
 
@@ -1348,9 +1519,6 @@
 
         mBarState = statusBarState;
         mKeyguardShowing = keyguardShowing;
-        if (mQs != null) {
-            mQs.setKeyguardShowing(mKeyguardShowing);
-        }
 
         if (oldState == StatusBarState.KEYGUARD
                 && (goingToFullShade || statusBarState == StatusBarState.SHADE_LOCKED)) {
@@ -1361,6 +1529,7 @@
         } else if (oldState == StatusBarState.SHADE_LOCKED
                 && statusBarState == StatusBarState.KEYGUARD) {
             animateKeyguardStatusBarIn(StackStateAnimator.ANIMATION_DURATION_STANDARD);
+            mNotificationStackScroller.resetScrollPosition();
             // Only animate header if the header is visible. If not, it will partially animate out
             // the top of QS
             if (!mQsExpanded) {
@@ -1375,10 +1544,13 @@
                 }
             }
         }
+        updateKeyguardStatusBarForHeadsUp();
         if (keyguardShowing) {
             updateDozingVisibilities(false /* animate */);
         }
-
+        // THe update needs to happen after the headerSlide in above, otherwise the translation
+        // would reset
+        updateQSPulseExpansion();
         maybeAnimateBottomAreaAlpha();
         resetHorizontalPanelPosition();
         updateQsState();
@@ -1431,9 +1603,15 @@
         anim.setStartDelay(mKeyguardMonitor.isKeyguardFadingAway()
                 ? mKeyguardMonitor.getKeyguardFadingAwayDelay()
                 : 0);
-        anim.setDuration(mKeyguardMonitor.isKeyguardFadingAway()
-                ? mKeyguardMonitor.getKeyguardFadingAwayDuration() / 2
-                : StackStateAnimator.ANIMATION_DURATION_STANDARD);
+
+        long duration;
+        if (mKeyguardMonitor.isKeyguardFadingAway()) {
+            duration = mKeyguardMonitor.getShortenedFadingAwayDuration();
+        } else {
+            duration = StackStateAnimator.ANIMATION_DURATION_STANDARD;
+        }
+        anim.setDuration(duration);
+
         anim.setInterpolator(Interpolators.LINEAR_OUT_SLOW_IN);
         anim.addListener(new AnimatorListenerAdapter() {
             @Override
@@ -1476,7 +1654,7 @@
             mKeyguardBottomArea.animate()
                     .alpha(0f)
                     .setStartDelay(mKeyguardMonitor.getKeyguardFadingAwayDelay())
-                    .setDuration(mKeyguardMonitor.getKeyguardFadingAwayDuration() / 2)
+                    .setDuration(mKeyguardMonitor.getShortenedFadingAwayDuration())
                     .setInterpolator(Interpolators.ALPHA_OUT)
                     .withEndAction(mAnimateKeyguardBottomAreaInvisibleEndRunnable)
                     .start();
@@ -1505,7 +1683,7 @@
             if (keyguardFadingAway) {
                 mKeyguardStatusView.animate()
                         .setStartDelay(mKeyguardMonitor.getKeyguardFadingAwayDelay())
-                        .setDuration(mKeyguardMonitor.getKeyguardFadingAwayDuration() / 2)
+                        .setDuration(mKeyguardMonitor.getShortenedFadingAwayDuration())
                         .start();
             }
         } else if (mBarState == StatusBarState.SHADE_LOCKED
@@ -1588,8 +1766,8 @@
             mStatusBar.executeRunnableDismissingKeyguard(null, null /* cancelAction */,
                     false /* dismissShade */, true /* afterKeyguardGone */, false /* deferred */);
         }
-        if (mExpansionListener != null) {
-            mExpansionListener.onQsExpansionChanged(mQsMaxExpansionHeight != 0
+        for (int i = 0; i < mExpansionListeners.size(); i++) {
+            mExpansionListeners.get(i).onQsExpansionChanged(mQsMaxExpansionHeight != 0
                     ? mQsExpansionHeight / mQsMaxExpansionHeight : 0);
         }
         if (DEBUG) {
@@ -1627,7 +1805,7 @@
             // padding on Keyguard, maxQsPadding denotes the top padding from the quick settings
             // panel. We need to take the maximum and linearly interpolate with the panel expansion
             // for a nice motion.
-            int maxNotificationPadding = mClockPositionResult.stackScrollerPadding;
+            int maxNotificationPadding = getKeyguardNotificationStaticPadding();
             int maxQsPadding = mQsMaxExpansionHeight + mQsNotificationTopPadding;
             int max = mBarState == StatusBarState.KEYGUARD
                     ? Math.max(maxNotificationPadding, maxQsPadding)
@@ -1635,11 +1813,12 @@
             return (int) MathUtils.lerp((float) mQsMinExpansionHeight, (float) max,
                     getExpandedFraction());
         } else if (mQsSizeChangeAnimator != null) {
-            return (int) mQsSizeChangeAnimator.getAnimatedValue();
+            return Math.max((int) mQsSizeChangeAnimator.getAnimatedValue(),
+                    getKeyguardNotificationStaticPadding());
         } else if (mKeyguardShowing) {
             // We can only do the smoother transition on Keyguard when we also are not collapsing
             // from a scrolled quick settings.
-            return MathUtils.lerp((float) mNotificationStackScroller.getIntrinsicPadding(),
+            return MathUtils.lerp((float) getKeyguardNotificationStaticPadding(),
                     (float) (mQsMaxExpansionHeight + mQsNotificationTopPadding),
                     getQsExpansionFraction());
         } else {
@@ -1647,10 +1826,43 @@
         }
     }
 
+    /**
+     * @return the topPadding of notifications when on keyguard not respecting quick settings
+     *         expansion
+     */
+    private int getKeyguardNotificationStaticPadding() {
+        if (!mKeyguardShowing) {
+            return 0;
+        }
+        if (!mKeyguardBypassController.getBypassEnabled()) {
+            return mClockPositionResult.stackScrollerPadding;
+        }
+        int collapsedPosition = mHeadsUpInset;
+        if (!mNotificationStackScroller.isPulseExpanding()) {
+            return collapsedPosition;
+        } else {
+            int expandedPosition = mClockPositionResult.stackScrollerPadding;
+            return (int) MathUtils.lerp(collapsedPosition, expandedPosition,
+                    mNotificationStackScroller.calculateAppearFractionBypass());
+        }
+    }
+
+
     protected void requestScrollerTopPaddingUpdate(boolean animate) {
-        mNotificationStackScroller.updateTopPadding(calculateQsTopPadding(),
-                animate, mKeyguardShowing
-                        && (mQsExpandImmediate || mIsExpanding && mQsExpandedWhenExpandingStarted));
+        mNotificationStackScroller.updateTopPadding(calculateQsTopPadding(), animate);
+        if (mKeyguardShowing && mKeyguardBypassController.getBypassEnabled()) {
+            // update the position of the header
+            updateQsExpansion();
+        }
+    }
+
+
+    private void updateQSPulseExpansion() {
+        if (mQs != null) {
+            mQs.setShowCollapsedOnKeyguard(mKeyguardShowing
+                    && mKeyguardBypassController.getBypassEnabled()
+                    && mNotificationStackScroller.isPulseExpanding());
+        }
     }
 
     private void trackMovement(MotionEvent event) {
@@ -1755,7 +1967,8 @@
      * @return Whether we should intercept a gesture to open Quick Settings.
      */
     private boolean shouldQuickSettingsIntercept(float x, float y, float yDiff) {
-        if (!mQsExpansionEnabled || mCollapsedOnDown) {
+        if (!mQsExpansionEnabled || mCollapsedOnDown
+                || (mKeyguardShowing && mKeyguardBypassController.getBypassEnabled())) {
             return false;
         }
         View header = mKeyguardShowing || mQs == null ? mKeyguardStatusBar : mQs.getHeader();
@@ -1781,8 +1994,16 @@
 
     @Override
     protected int getMaxPanelHeight() {
+        if (mKeyguardBypassController.getBypassEnabled() && mBarState == StatusBarState.KEYGUARD) {
+            return getMaxPanelHeightBypass();
+        } else {
+            return getMaxPanelHeightNonBypass();
+        }
+    }
+
+    private int getMaxPanelHeightNonBypass() {
         int min = mStatusBarMinHeight;
-        if (mBarState != StatusBarState.KEYGUARD
+        if (!(mBarState == StatusBarState.KEYGUARD)
                 && mNotificationStackScroller.getNotGoneChildCount() == 0) {
             int minHeight = (int) (mQsMinExpansionHeight + getOverExpansionAmount());
             min = Math.max(min, minHeight);
@@ -1798,6 +2019,15 @@
         return maxHeight;
     }
 
+    private int getMaxPanelHeightBypass() {
+        int position = mClockPositionAlgorithm.getExpandedClockPosition()
+                + mKeyguardStatusView.getHeight();
+        if (mNotificationStackScroller.getVisibleNotificationCount() != 0) {
+            position += mShelfHeight / 2.0f + mDarkIconSize / 2.0f;
+        }
+        return position;
+    }
+
     public boolean isInSettings() {
         return mQsExpanded;
     }
@@ -1849,7 +2079,7 @@
     }
 
     private void updatePanelExpanded() {
-        boolean isExpanded = !isFullyCollapsed();
+        boolean isExpanded = !isFullyCollapsed() || mExpectingSynthesizedDown;
         if (mPanelExpanded != isExpanded) {
             mHeadsUpManager.setIsPanelExpanded(isExpanded);
             mStatusBar.setPanelExpanded(isExpanded);
@@ -1912,15 +2142,19 @@
                 !mHeadsUpManager.hasPinnedHeadsUp()) {
             alpha = getFadeoutAlpha();
         }
-        if (mBarState == StatusBarState.KEYGUARD && !mHintAnimationRunning) {
+        if (mBarState == StatusBarState.KEYGUARD && !mHintAnimationRunning
+                && !mKeyguardBypassController.getBypassEnabled()) {
             alpha *= mClockPositionResult.clockAlpha;
         }
         mNotificationStackScroller.setAlpha(alpha);
     }
 
     private float getFadeoutAlpha() {
-        float alpha = (getNotificationsTopY() + mNotificationStackScroller.getFirstItemMinHeight())
-                / mQsMinExpansionHeight;
+        float alpha;
+        if (mQsMinExpansionHeight == 0) {
+            return 1.0f;
+        }
+        alpha = getExpandedHeight() / mQsMinExpansionHeight;
         alpha = Math.max(0, Math.min(alpha, 1));
         alpha = (float) Math.pow(alpha, 0.75);
         return alpha;
@@ -1947,11 +2181,25 @@
     }
 
     protected float getHeaderTranslation() {
-        if (mBarState == StatusBarState.KEYGUARD) {
-            return 0;
+        if (mBarState == StatusBarState.KEYGUARD && !mKeyguardBypassController.getBypassEnabled()) {
+            return -mQs.getQsMinExpansionHeight();
         }
-        float translation = MathUtils.lerp(-mQsMinExpansionHeight, 0,
-                Math.min(1.0f, mNotificationStackScroller.getAppearFraction(mExpandedHeight)))
+        float appearAmount = mNotificationStackScroller.calculateAppearFraction(mExpandedHeight);
+        float startHeight = -mQsExpansionHeight;
+        if (mKeyguardBypassController.getBypassEnabled() && isOnKeyguard()
+                && mNotificationStackScroller.isPulseExpanding()) {
+            if (!mPulseExpansionHandler.isExpanding()
+                    && !mPulseExpansionHandler.getLeavingLockscreen()) {
+                // If we aborted the expansion we need to make sure the header doesn't reappear
+                // again after the header has animated away
+                appearAmount = 0;
+            } else {
+                appearAmount = mNotificationStackScroller.calculateAppearFractionBypass();
+            }
+            startHeight = -mQs.getQsMinExpansionHeight();
+        }
+        float translation = MathUtils.lerp(startHeight, 0,
+                Math.min(1.0f, appearAmount))
                 + mExpandOffset;
         return Math.min(0, translation);
     }
@@ -1964,18 +2212,18 @@
         float alpha;
         if (mBarState == StatusBarState.KEYGUARD) {
 
-            // When on Keyguard, we hide the header as soon as the top card of the notification
-            // stack scroller is close enough (collision distance) to the bottom of the header.
-            alpha = getNotificationsTopY()
+            // When on Keyguard, we hide the header as soon as we expanded close enough to the
+            // header
+            alpha = getExpandedHeight()
                     /
                     (mKeyguardStatusBar.getHeight() + mNotificationsHeaderCollideDistance);
         } else {
 
             // In SHADE_LOCKED, the top card is already really close to the header. Hide it as
             // soon as we start translating the stack.
-            alpha = getNotificationsTopY() / mKeyguardStatusBar.getHeight();
+            alpha = getExpandedHeight() / mKeyguardStatusBar.getHeight();
         }
-        alpha = MathUtils.constrain(alpha, 0, 1);
+        alpha = MathUtils.saturate(alpha);
         alpha = (float) Math.pow(alpha, 0.75);
         return alpha;
     }
@@ -1987,6 +2235,7 @@
         float alphaQsExpansion = 1 - Math.min(1, getQsExpansionFraction() * 2);
         float newAlpha = Math.min(getKeyguardContentsAlpha(), alphaQsExpansion)
                 * mKeyguardStatusBarAnimateAlpha;
+        newAlpha *= 1.0f - mKeyguardHeadsUpShowingAmount;
         mKeyguardStatusBar.setAlpha(newAlpha);
         mKeyguardStatusBar.setVisibility(newAlpha != 0f && !mDozing ? VISIBLE : INVISIBLE);
     }
@@ -2026,13 +2275,6 @@
         mBigClockContainer.setAlpha(alpha);
     }
 
-    private float getNotificationsTopY() {
-        if (mNotificationStackScroller.getNotGoneChildCount() == 0) {
-            return getExpandedHeight();
-        }
-        return mNotificationStackScroller.getNotificationsTopY();
-    }
-
     @Override
     protected void onExpandingStarted() {
         super.onExpandingStarted();
@@ -2519,10 +2761,14 @@
         switch (mBarState) {
             case StatusBarState.KEYGUARD:
                 if (!mDozingOnDown) {
-                    mLockscreenGestureLogger.write(
-                            MetricsEvent.ACTION_LS_HINT,
-                            0 /* lengthDp - N/A */, 0 /* velocityDp - N/A */);
-                    startUnlockHintAnimation();
+                    if (mKeyguardBypassController.getBypassEnabled()) {
+                        mUpdateMonitor.requestFaceAuth();
+                    } else {
+                        mLockscreenGestureLogger.write(
+                                MetricsEvent.ACTION_LS_HINT,
+                                0 /* lengthDp - N/A */, 0 /* velocityDp - N/A */);
+                        startUnlockHintAnimation();
+                    }
                 }
                 return true;
             case StatusBarState.SHADE_LOCKED:
@@ -2615,16 +2861,51 @@
                     mHeadsUpExistenceChangedRunnable);
         }
         updateGestureExclusionRect();
+        mHeadsUpPinnedMode = inPinnedMode;
+        updateHeadsUpVisibility();
+        updateKeyguardStatusBarForHeadsUp();
+    }
+
+    private void updateKeyguardStatusBarForHeadsUp() {
+        boolean showingKeyguardHeadsUp = mKeyguardShowing
+                && mHeadsUpAppearanceController.shouldBeVisible();
+        if (mShowingKeyguardHeadsUp != showingKeyguardHeadsUp) {
+            mShowingKeyguardHeadsUp = showingKeyguardHeadsUp;
+            if (mKeyguardShowing) {
+                PropertyAnimator.setProperty(this, KEYGUARD_HEADS_UP_SHOWING_AMOUNT,
+                        showingKeyguardHeadsUp ? 1.0f : 0.0f, KEYGUARD_HUN_PROPERTIES,
+                        true /* animate */);
+            } else {
+                PropertyAnimator.applyImmediately(this, KEYGUARD_HEADS_UP_SHOWING_AMOUNT, 0.0f);
+            }
+        }
+    }
+
+    private void setKeyguardHeadsUpShowingAmount(float amount) {
+        mKeyguardHeadsUpShowingAmount = amount;
+        updateHeaderKeyguardAlpha();
+    }
+
+    private float getKeyguardHeadsUpShowingAmount() {
+        return mKeyguardHeadsUpShowingAmount;
     }
 
     public void setHeadsUpAnimatingAway(boolean headsUpAnimatingAway) {
         mHeadsUpAnimatingAway = headsUpAnimatingAway;
         mNotificationStackScroller.setHeadsUpAnimatingAway(headsUpAnimatingAway);
+        updateHeadsUpVisibility();
+    }
+
+    private void updateHeadsUpVisibility() {
+        ((PhoneStatusBarView) mBar).setHeadsUpVisible(mHeadsUpAnimatingAway || mHeadsUpPinnedMode);
     }
 
     @Override
     public void onHeadsUpPinned(NotificationEntry entry) {
-        mNotificationStackScroller.generateHeadsUpAnimation(entry.getHeadsUpAnimationView(), true);
+        if (!isOnKeyguard()) {
+            mNotificationStackScroller.generateHeadsUpAnimation(entry.getHeadsUpAnimationView(),
+                    true);
+        }
     }
 
     @Override
@@ -2633,7 +2914,7 @@
         // When we're unpinning the notification via active edge they remain heads-upped,
         // we need to make sure that an animation happens in this case, otherwise the notification
         // will stick to the top without any interaction.
-        if (isFullyCollapsed() && entry.isRowHeadsUp()) {
+        if (isFullyCollapsed() && entry.isRowHeadsUp() && !isOnKeyguard()) {
             mNotificationStackScroller.generateHeadsUpAnimation(
                     entry.getHeadsUpAnimationView(), false);
             entry.setHeadsUpIsVisible();
@@ -2700,7 +2981,7 @@
     }
 
     protected void setHorizontalPanelTranslation(float translation) {
-        mNotificationStackScroller.setHorizontalPanelTranslation(translation);
+        mNotificationStackScroller.setTranslationX(translation);
         mQsFrame.setTranslationX(translation);
         int size = mVerticalTranslationListener.size();
         for (int i = 0; i < size; i++) {
@@ -2712,6 +2993,10 @@
         if (mTracking) {
             mNotificationStackScroller.setExpandingVelocity(getCurrentExpandVelocity());
         }
+        if (mKeyguardBypassController.getBypassEnabled() && isOnKeyguard()) {
+            // The expandedHeight is always the full panel Height when bypassing
+            expandedHeight = getMaxPanelHeightNonBypass();
+        }
         mNotificationStackScroller.setExpandedHeight(expandedHeight);
         updateKeyguardBottomAreaAlpha();
         updateBigClockAlpha();
@@ -2752,7 +3037,8 @@
 
     @Override
     protected boolean isPanelVisibleBecauseOfHeadsUp() {
-        return mHeadsUpManager.hasPinnedHeadsUp() || mHeadsUpAnimatingAway;
+        return (mHeadsUpManager.hasPinnedHeadsUp() || mHeadsUpAnimatingAway)
+                && mBarState == StatusBarState.SHADE;
     }
 
     @Override
@@ -2777,7 +3063,6 @@
         // nor setting these flags, since the occluded state doesn't change anymore, hence it's
         // never reset.
         if (!isFullyCollapsed()) {
-            mLaunchingAffordance = true;
             setLaunchingAffordance(true);
         } else {
             animate = false;
@@ -2787,7 +3072,6 @@
     }
 
     public void onAffordanceLaunchEnded() {
-        mLaunchingAffordance = false;
         setLaunchingAffordance(false);
     }
 
@@ -2796,8 +3080,10 @@
      * launched via a camera gesture.
      */
     private void setLaunchingAffordance(boolean launchingAffordance) {
+        mLaunchingAffordance = launchingAffordance;
         getLeftIcon().setLaunchingAffordance(launchingAffordance);
         getRightIcon().setLaunchingAffordance(launchingAffordance);
+        mKeyguardBypassController.setLaunchingAffordance(launchingAffordance);
         if (mAffordanceLaunchListener != null) {
             mAffordanceLaunchListener.accept(launchingAffordance);
         }
@@ -2861,7 +3147,7 @@
             mQs.setPanelView(NotificationPanelView.this);
             mQs.setExpandClickListener(NotificationPanelView.this);
             mQs.setHeaderClickable(mQsExpansionEnabled);
-            mQs.setKeyguardShowing(mKeyguardShowing);
+            updateQSPulseExpansion();
             mQs.setOverscrolling(mStackScrollerOverscrolling);
 
             // recompute internal state when qspanel height changes
@@ -2910,7 +3196,7 @@
     public void setDozing(boolean dozing, boolean animate, PointF wakeUpTouchLocation) {
         if (dozing == mDozing) return;
         mDozing = dozing;
-        mNotificationStackScroller.setDark(mDozing, animate, wakeUpTouchLocation);
+        mNotificationStackScroller.setDozing(mDozing, animate, wakeUpTouchLocation);
         mKeyguardBottomArea.setDozing(mDozing, animate);
 
         if (dozing) {
@@ -2922,8 +3208,8 @@
             updateDozingVisibilities(animate);
         }
 
-        final float darkAmount = dozing ? 1 : 0;
-        mStatusBarStateController.setDozeAmount(darkAmount, animate);
+        final float dozeAmount = dozing ? 1 : 0;
+        mStatusBarStateController.setDozeAmount(dozeAmount, animate);
     }
 
     @Override
@@ -3088,10 +3374,6 @@
         return mNotificationStackScroller.hasPulsingNotifications();
     }
 
-    public boolean isFullyDark() {
-        return mNotificationStackScroller.isFullyDark();
-    }
-
     public ActivatableNotificationView getActivatedChild() {
         return mNotificationStackScroller.getActivatedChild();
     }
@@ -3119,7 +3401,6 @@
         mNotificationStackScroller.setIconAreaController(notificationIconAreaController);
         mNotificationStackScroller.setStatusBar(statusBar);
         mNotificationStackScroller.setGroupManager(groupManager);
-        mNotificationStackScroller.setHeadsUpManager(headsUpManager);
         mNotificationStackScroller.setShelf(notificationShelf);
         mNotificationStackScroller.setScrimController(scrimController);
         updateShowEmptyShadeView();
@@ -3131,27 +3412,16 @@
 
     @Override
     public void onDynamicPrivacyChanged() {
+        // Do not request animation when pulsing or waking up, otherwise the clock wiill be out
+        // of sync with the notification panel.
+        if (mLinearDarkAmount != 0) {
+            return;
+        }
         mAnimateNextPositionUpdate = true;
     }
 
-    /**
-     * Panel and QS expansion callbacks.
-     */
-    public interface PanelExpansionListener {
-        /**
-         * Invoked whenever the notification panel expansion changes, at every animation frame.
-         * This is the main expansion that happens when the user is swiping up to dismiss the
-         * lock screen.
-         *
-         * @param expansion 0 when collapsed, 1 when expanded.
-         * @param tracking {@code true} when the user is actively dragging the panel.
-         */
-        void onPanelExpansionChanged(float expansion, boolean tracking);
-
-        /**
-         * Invoked whenever the QS expansion changes, at every animation frame.
-         * @param expansion 0 when collapsed, 1 when expanded.
-         */
-        void onQsExpansionChanged(float expansion);
+    public void setOnReinflationListener(Runnable onReinflationListener) {
+        mOnReinflationListener = onReinflationListener;
     }
+
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationsQuickSettingsContainer.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationsQuickSettingsContainer.java
index ca762cd..27c94d2 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationsQuickSettingsContainer.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationsQuickSettingsContainer.java
@@ -36,6 +36,9 @@
 import com.android.systemui.statusbar.notification.AboveShelfObserver;
 import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayout;
 
+import java.util.ArrayList;
+import java.util.Comparator;
+
 /**
  * The container with notification stack scroller and quick settings inside.
  */
@@ -54,6 +57,9 @@
     private int mBottomPadding;
     private int mStackScrollerMargin;
     private boolean mHasViewsAboveShelf;
+    private ArrayList<View> mDrawingOrderedChildren = new ArrayList<>();
+    private ArrayList<View> mLayoutDrawingOrder = new ArrayList<>();
+    private final Comparator<View> mIndexComparator = Comparator.comparingInt(this::indexOfChild);
 
     public NotificationsQuickSettingsContainer(Context context, AttributeSet attrs) {
         super(context, attrs);
@@ -107,35 +113,44 @@
     }
 
     @Override
-    protected boolean drawChild(Canvas canvas, View child, long drawingTime) {
-        boolean userSwitcherVisible = mInflated && mUserSwitcher.getVisibility() == View.VISIBLE;
-        boolean statusBarVisible = mKeyguardStatusBar.getVisibility() == View.VISIBLE;
-
-        final boolean qsBottom = mHasViewsAboveShelf;
-        View stackQsTop = qsBottom ? mStackScroller : mQsFrame;
-        View stackQsBottom = !qsBottom ? mStackScroller : mQsFrame;
+    protected void dispatchDraw(Canvas canvas) {
         // Invert the order of the scroll view and user switcher such that the notifications receive
         // touches first but the panel gets drawn above.
-        if (child == mQsFrame) {
-            return super.drawChild(canvas, userSwitcherVisible && statusBarVisible ? mUserSwitcher
-                    : statusBarVisible ? mKeyguardStatusBar
-                    : userSwitcherVisible ? mUserSwitcher
-                    : stackQsBottom, drawingTime);
-        } else if (child == mStackScroller) {
-            return super.drawChild(canvas,
-                    userSwitcherVisible && statusBarVisible ? mKeyguardStatusBar
-                    : statusBarVisible || userSwitcherVisible ? stackQsBottom
-                    : stackQsTop,
-                    drawingTime);
-        } else if (child == mUserSwitcher) {
-            return super.drawChild(canvas,
-                    userSwitcherVisible && statusBarVisible ? stackQsBottom
-                    : stackQsTop,
-                    drawingTime);
-        } else if (child == mKeyguardStatusBar) {
-            return super.drawChild(canvas,
-                    stackQsTop,
-                    drawingTime);
+        mDrawingOrderedChildren.clear();
+        mLayoutDrawingOrder.clear();
+        if (mInflated && mUserSwitcher.getVisibility() == View.VISIBLE) {
+            mDrawingOrderedChildren.add(mUserSwitcher);
+            mLayoutDrawingOrder.add(mUserSwitcher);
+        }
+        if (mKeyguardStatusBar.getVisibility() == View.VISIBLE) {
+            mDrawingOrderedChildren.add(mKeyguardStatusBar);
+            mLayoutDrawingOrder.add(mKeyguardStatusBar);
+        }
+        if (mStackScroller.getVisibility() == View.VISIBLE) {
+            mDrawingOrderedChildren.add(mStackScroller);
+            mLayoutDrawingOrder.add(mStackScroller);
+        }
+        if (mQsFrame.getVisibility() == View.VISIBLE) {
+            mDrawingOrderedChildren.add(mQsFrame);
+            mLayoutDrawingOrder.add(mQsFrame);
+        }
+
+        if (mHasViewsAboveShelf) {
+            // StackScroller needs to be on top
+            mDrawingOrderedChildren.remove(mStackScroller);
+            mDrawingOrderedChildren.add(mStackScroller);
+        }
+
+        // Let's now find the order that the view has when drawing regulary by sorting
+        mLayoutDrawingOrder.sort(mIndexComparator);
+        super.dispatchDraw(canvas);
+    }
+
+    @Override
+    protected boolean drawChild(Canvas canvas, View child, long drawingTime) {
+        int layoutIndex = mLayoutDrawingOrder.indexOf(child);
+        if (layoutIndex >= 0) {
+            return super.drawChild(canvas, mDrawingOrderedChildren.get(layoutIndex), drawingTime);
         } else {
             return super.drawChild(canvas, child, drawingTime);
         }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelBar.java
index 65b0ecc..063d00b 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelBar.java
@@ -107,8 +107,12 @@
         return mExpanded;
     }
 
-    private void updateVisibility() {
-        mPanel.setVisibility(mExpanded || mBouncerShowing ? VISIBLE : INVISIBLE);
+    protected void updateVisibility() {
+        mPanel.setVisibility(shouldPanelBeVisible() ? VISIBLE : INVISIBLE);
+    }
+
+    protected boolean shouldPanelBeVisible() {
+        return mExpanded || mBouncerShowing;
     }
 
     public boolean panelEnabled() {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelExpansionListener.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelExpansionListener.java
new file mode 100644
index 0000000..655a25d
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelExpansionListener.java
@@ -0,0 +1,38 @@
+/*
+ * 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.systemui.statusbar.phone;
+
+/**
+ * Panel and QS expansion callbacks.
+ */
+public interface PanelExpansionListener {
+    /**
+     * Invoked whenever the notification panel expansion changes, at every animation frame.
+     * This is the main expansion that happens when the user is swiping up to dismiss the
+     * lock screen.
+     *
+     * @param expansion 0 when collapsed, 1 when expanded.
+     * @param tracking {@code true} when the user is actively dragging the panel.
+     */
+    void onPanelExpansionChanged(float expansion, boolean tracking);
+
+    /**
+     * Invoked whenever the QS expansion changes, at every animation frame.
+     * @param expansion 0 when collapsed, 1 when expanded.
+     */
+    default void onQsExpansionChanged(float expansion) {};
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java
index a9a3b2d..f8e1093 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java
@@ -50,11 +50,11 @@
 import com.android.systemui.statusbar.StatusBarState;
 import com.android.systemui.statusbar.SysuiStatusBarStateController;
 import com.android.systemui.statusbar.VibratorHelper;
-import com.android.systemui.statusbar.phone.NotificationPanelView.PanelExpansionListener;
 import com.android.systemui.statusbar.policy.KeyguardMonitor;
 
 import java.io.FileDescriptor;
 import java.io.PrintWriter;
+import java.util.ArrayList;
 
 public abstract class PanelView extends FrameLayout {
     public static final boolean DEBUG = PanelBar.DEBUG;
@@ -62,14 +62,15 @@
     private static final int INITIAL_OPENING_PEEK_DURATION = 200;
     private static final int PEEK_ANIMATION_DURATION = 360;
     private static final int NO_FIXED_DURATION = -1;
-    private long mDownTime;
+    protected long mDownTime;
+    protected boolean mTouchSlopExceededBeforeDown;
     private float mMinExpandHeight;
     private LockscreenGestureLogger mLockscreenGestureLogger = new LockscreenGestureLogger();
     private boolean mPanelUpdateWhenAnimatorEnds;
     private boolean mVibrateOnOpening;
     protected boolean mLaunchingNotification;
     private int mFixedDuration = NO_FIXED_DURATION;
-    protected PanelExpansionListener mExpansionListener;
+    protected ArrayList<PanelExpansionListener> mExpansionListeners = new ArrayList<>();
 
     private final void logf(String fmt, Object... args) {
         Log.v(TAG, (mViewName != null ? (mViewName + ": ") : "") + String.format(fmt, args));
@@ -301,7 +302,7 @@
         final float y = event.getY(pointerIndex);
 
         if (event.getActionMasked() == MotionEvent.ACTION_DOWN) {
-            mGestureWaitForTouchSlop = isFullyCollapsed() || hasConflictingGestures();
+            mGestureWaitForTouchSlop = shouldGestureWaitForTouchSlop();
             mIgnoreXTouchSlop = isFullyCollapsed() || shouldGestureIgnoreXTouchSlop(x, y);
         }
 
@@ -323,7 +324,7 @@
                 if (!mGestureWaitForTouchSlop || (mHeightAnimator != null && !mHintAnimationRunning)
                         || mPeekAnimator != null) {
                     mTouchSlopExceeded = (mHeightAnimator != null && !mHintAnimationRunning)
-                            || mPeekAnimator != null;
+                            || mPeekAnimator != null || mTouchSlopExceededBeforeDown;
                     cancelHeightAnimator();
                     cancelPeek();
                     onTrackingStarted();
@@ -409,9 +410,7 @@
         runPeekAnimation(INITIAL_OPENING_PEEK_DURATION, getOpeningHeight(),
                 false /* collapseWhenFinished */);
         notifyBarPanelExpansionChanged();
-        if (mVibrateOnOpening) {
-            mVibratorHelper.vibrate(VibrationEffect.EFFECT_TICK);
-        }
+        maybeVibrateOnOpening();
 
         //TODO: keyguard opens QS a different way; log that too?
 
@@ -426,6 +425,12 @@
                 rot);
     }
 
+    protected void maybeVibrateOnOpening() {
+        if (mVibrateOnOpening) {
+            mVibratorHelper.vibrate(VibrationEffect.EFFECT_TICK);
+        }
+    }
+
     protected abstract float getOpeningHeight();
 
     /**
@@ -519,7 +524,7 @@
         return (int) (mUnlockFalsingThreshold * factor);
     }
 
-    protected abstract boolean hasConflictingGestures();
+    protected abstract boolean shouldGestureWaitForTouchSlop();
 
     protected abstract boolean shouldGestureIgnoreXTouchSlop(float x, float y);
 
@@ -577,7 +582,7 @@
                 mInitialTouchY = y;
                 mInitialTouchX = x;
                 mTouchStartedInEmptyArea = !isInContentBounds(x, y);
-                mTouchSlopExceeded = false;
+                mTouchSlopExceeded = mTouchSlopExceededBeforeDown;
                 mJustPeeked = false;
                 mMotionAborted = false;
                 mPanelClosedOnDown = isFullyCollapsed();
@@ -680,12 +685,16 @@
             return true;
         }
         if (Math.abs(vectorVel) < mFlingAnimationUtils.getMinVelocityPxPerSecond()) {
-            return getExpandedFraction() > 0.5f;
+            return shouldExpandWhenNotFlinging();
         } else {
             return vel > 0;
         }
     }
 
+    protected boolean shouldExpandWhenNotFlinging() {
+        return getExpandedFraction() > 0.5f;
+    }
+
     /**
      * @param x the final x-coordinate when the finger was lifted
      * @param y the final y-coordinate when the finger was lifted
@@ -1174,13 +1183,13 @@
                     || mPeekAnimator != null || mInstantExpanding
                     || isPanelVisibleBecauseOfHeadsUp() || mTracking || mHeightAnimator != null);
         }
-        if (mExpansionListener != null) {
-            mExpansionListener.onPanelExpansionChanged(mExpandedFraction, mTracking);
+        for (int i = 0; i < mExpansionListeners.size(); i++) {
+            mExpansionListeners.get(i).onPanelExpansionChanged(mExpandedFraction, mTracking);
         }
     }
 
-    public void setExpansionListener(PanelExpansionListener panelExpansionListener) {
-        mExpansionListener = panelExpansionListener;
+    public void addExpansionListener(PanelExpansionListener panelExpansionListener) {
+        mExpansionListeners.add(panelExpansionListener);
     }
 
     protected abstract boolean isPanelVisibleBecauseOfHeadsUp();
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarView.java
index 68eba50..8efd952 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarView.java
@@ -82,6 +82,7 @@
      * Draw this many pixels into the left/right side of the cutout to optimally use the space
      */
     private int mCutoutSideNudge = 0;
+    private boolean mHeadsUpVisible;
 
     public PhoneStatusBarView(Context context, AttributeSet attrs) {
         super(context, attrs);
@@ -277,7 +278,7 @@
         super.panelExpansionChanged(frac, expanded);
         updateScrimFraction();
         if ((frac == 0 || frac == 1) && mBar.getNavigationBarView() != null) {
-            mBar.getNavigationBarView().onPanelExpandedChange();
+            mBar.getNavigationBarView().onStatusBarPanelStateChanged();
         }
     }
 
@@ -379,4 +380,14 @@
         }
         return null;
     }
+
+    public void setHeadsUpVisible(boolean headsUpVisible) {
+        mHeadsUpVisible = headsUpVisible;
+        updateVisibility();
+    }
+
+    @Override
+    protected boolean shouldPanelBeVisible() {
+        return mHeadsUpVisible || super.shouldPanelBeVisible();
+    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java
index 3f38c04..a7262cf 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java
@@ -47,6 +47,7 @@
 import com.android.systemui.colorextraction.SysuiColorExtractor;
 import com.android.systemui.statusbar.ScrimView;
 import com.android.systemui.statusbar.notification.stack.ViewState;
+import com.android.systemui.statusbar.policy.KeyguardMonitor;
 import com.android.systemui.util.AlarmTimeout;
 import com.android.systemui.util.wakelock.DelayedWakeLock;
 import com.android.systemui.util.wakelock.WakeLock;
@@ -177,7 +178,7 @@
     public ScrimController(ScrimView scrimBehind, ScrimView scrimInFront,
             TriConsumer<ScrimState, Float, GradientColors> scrimStateListener,
             Consumer<Integer> scrimVisibleListener, DozeParameters dozeParameters,
-            AlarmManager alarmManager) {
+            AlarmManager alarmManager, KeyguardMonitor keyguardMonitor) {
         mScrimBehind = scrimBehind;
         mScrimInFront = scrimInFront;
         mScrimStateListener = scrimStateListener;
@@ -197,6 +198,13 @@
         // to make sure that text on top of it is legible.
         mScrimBehindAlpha = mScrimBehindAlphaResValue;
         mDozeParameters = dozeParameters;
+        keyguardMonitor.addCallback(new KeyguardMonitor.Callback() {
+            @Override
+            public void onKeyguardFadingAwayChanged() {
+                setKeyguardFadingAway(keyguardMonitor.isKeyguardFadingAway(),
+                        keyguardMonitor.getKeyguardFadingAwayDuration());
+            }
+        });
 
         mColorExtractor = Dependency.get(SysuiColorExtractor.class);
         mColorExtractor.addOnColorsChangedListener(this);
@@ -487,6 +495,22 @@
     }
 
     /**
+     * Set front scrim to black, cancelling animations, in order to prepare to fade them
+     * away once the display turns on.
+     */
+    public void prepareForGentleWakeUp() {
+        if (mState == ScrimState.AOD) {
+            mCurrentInFrontAlpha = 1f;
+            mCurrentInFrontTint = Color.BLACK;
+            mCurrentBehindTint = Color.BLACK;
+            mAnimateChange = false;
+            updateScrims();
+            mAnimateChange = true;
+            mAnimationDuration = ANIMATION_DURATION_LONG;
+        }
+    }
+
+    /**
      * If the lock screen sensor is active.
      */
     public void setWakeLockScreenSensorActive(boolean active) {
@@ -932,6 +956,12 @@
         }
     }
 
+    private void setKeyguardFadingAway(boolean fadingAway, long duration) {
+        for (ScrimState state : ScrimState.values()) {
+            state.setKeyguardFadingAway(fadingAway, duration);
+        }
+    }
+
     public void setLaunchingAffordanceWithPreview(boolean launchingAffordanceWithPreview) {
         for (ScrimState state : ScrimState.values()) {
             state.setLaunchingAffordanceWithPreview(launchingAffordanceWithPreview);
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 d152ecd..9fdd3b8 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimState.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimState.java
@@ -129,7 +129,16 @@
         public void prepare(ScrimState previousState) {
             mCurrentInFrontAlpha = 0f;
             mCurrentBehindTint = Color.BLACK;
+            mCurrentInFrontTint = Color.BLACK;
             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
@@ -147,7 +156,9 @@
         public void prepare(ScrimState previousState) {
             mCurrentBehindAlpha = 0;
             mCurrentInFrontAlpha = 0;
-            mAnimationDuration = StatusBar.FADE_KEYGUARD_DURATION;
+            mAnimationDuration = mKeyguardFadingAway
+                    ? mKeyguardFadingAwayDuration
+                    : StatusBar.FADE_KEYGUARD_DURATION;
             mAnimateChange = !mLaunchingAffordanceWithPreview;
 
             if (previousState == ScrimState.AOD) {
@@ -198,6 +209,8 @@
     boolean mHasBackdrop;
     boolean mLaunchingAffordanceWithPreview;
     boolean mWakeLockScreenSensorActive;
+    boolean mKeyguardFadingAway;
+    long mKeyguardFadingAwayDuration;
 
     ScrimState(int index) {
         mIndex = index;
@@ -285,4 +298,9 @@
     public void setWakeLockScreenSensorActive(boolean active) {
         mWakeLockScreenSensorActive = active;
     }
+
+    public void setKeyguardFadingAway(boolean fadingAway, long duration) {
+        mKeyguardFadingAway = fadingAway;
+        mKeyguardFadingAwayDuration = duration;
+    }
 }
\ No newline at end of file
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
index c6de829..d12bed9 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
@@ -172,7 +172,6 @@
 import com.android.systemui.shared.system.WindowManagerWrapper;
 import com.android.systemui.stackdivider.Divider;
 import com.android.systemui.stackdivider.WindowManagerProxy;
-import com.android.systemui.statusbar.AmbientPulseManager;
 import com.android.systemui.statusbar.BackDropView;
 import com.android.systemui.statusbar.CommandQueue;
 import com.android.systemui.statusbar.CrossFadeHelper;
@@ -194,6 +193,8 @@
 import com.android.systemui.statusbar.SysuiStatusBarStateController;
 import com.android.systemui.statusbar.VibratorHelper;
 import com.android.systemui.statusbar.notification.ActivityLaunchAnimator;
+import com.android.systemui.statusbar.notification.BypassHeadsUpNotifier;
+import com.android.systemui.statusbar.notification.DynamicPrivacyController;
 import com.android.systemui.statusbar.notification.NotificationActivityStarter;
 import com.android.systemui.statusbar.notification.NotificationAlertingManager;
 import com.android.systemui.statusbar.notification.NotificationClicker;
@@ -201,6 +202,7 @@
 import com.android.systemui.statusbar.notification.NotificationInterruptionStateProvider;
 import com.android.systemui.statusbar.notification.NotificationListController;
 import com.android.systemui.statusbar.notification.NotificationWakeUpCoordinator;
+import com.android.systemui.statusbar.notification.ViewGroupFadeHelper;
 import com.android.systemui.statusbar.notification.VisualStabilityManager;
 import com.android.systemui.statusbar.notification.collection.NotificationEntry;
 import com.android.systemui.statusbar.notification.collection.NotificationRowBinderImpl;
@@ -227,7 +229,6 @@
 import com.android.systemui.statusbar.policy.UserInfoControllerImpl;
 import com.android.systemui.statusbar.policy.UserSwitcherController;
 import com.android.systemui.statusbar.policy.ZenModeController;
-import com.android.systemui.tuner.TunerService;
 import com.android.systemui.util.InjectionInflationController;
 import com.android.systemui.volume.VolumeComponent;
 
@@ -246,8 +247,7 @@
         OnHeadsUpChangedListener, CommandQueue.Callbacks, ZenModeController.Callback,
         ColorExtractor.OnColorsChangedListener, ConfigurationListener,
         StatusBarStateController.StateListener, ShadeController,
-        ActivityLaunchAnimator.Callback, AmbientPulseManager.OnAmbientChangedListener,
-        AppOpsController.Callback {
+        ActivityLaunchAnimator.Callback, AppOpsController.Callback {
     public static final boolean MULTIUSER_DEBUG = false;
 
     public static final boolean ENABLE_CHILD_NOTIFICATIONS
@@ -372,6 +372,17 @@
     PulseExpansionHandler mPulseExpansionHandler;
     @Inject
     NotificationWakeUpCoordinator mWakeUpCoordinator;
+    @Inject
+    KeyguardBypassController mKeyguardBypassController;
+    @Inject
+    protected HeadsUpManagerPhone mHeadsUpManager;
+    @Inject
+    DynamicPrivacyController mDynamicPrivacyController;
+    @Inject
+    BypassHeadsUpNotifier mBypassHeadsUpNotifier;
+    @Nullable
+    @Inject
+    protected KeyguardLiftController mKeyguardLiftController;
 
     // expanded notifications
     protected NotificationPanelView mNotificationPanel; // the sliding/resizing panel within the notification window
@@ -584,7 +595,7 @@
     private boolean mVibrateOnOpening;
     private VibratorHelper mVibratorHelper;
     private ActivityLaunchAnimator mActivityLaunchAnimator;
-    protected NotificationPresenter mPresenter;
+    protected StatusBarNotificationPresenter mPresenter;
     private NotificationActivityStarter mNotificationActivityStarter;
     private boolean mPulsing;
     protected BubbleController mBubbleController;
@@ -632,6 +643,7 @@
         mGutsManager = Dependency.get(NotificationGutsManager.class);
         mMediaManager = Dependency.get(NotificationMediaManager.class);
         mEntryManager = Dependency.get(NotificationEntryManager.class);
+        mBypassHeadsUpNotifier.setUp(mEntryManager);
         mNotificationInterruptionStateProvider =
                 Dependency.get(NotificationInterruptionStateProvider.class);
         mViewHierarchyManager = Dependency.get(NotificationViewHierarchyManager.class);
@@ -647,7 +659,8 @@
         mActivityIntentHelper = new ActivityIntentHelper(mContext);
         KeyguardSliceProvider sliceProvider = KeyguardSliceProvider.getAttachedInstance();
         if (sliceProvider != null) {
-            sliceProvider.initDependencies(mMediaManager, mStatusBarStateController);
+            sliceProvider.initDependencies(mMediaManager, mStatusBarStateController,
+                    mKeyguardBypassController, DozeParameters.getInstance(mContext));
         } else {
             Log.w(TAG, "Cannot init KeyguardSliceProvider dependencies");
         }
@@ -681,6 +694,7 @@
 
         mPowerManager = (PowerManager) mContext.getSystemService(Context.POWER_SERVICE);
         mKeyguardUpdateMonitor = KeyguardUpdateMonitor.getInstance(mContext);
+        mKeyguardUpdateMonitor.setKeyguardBypassController(mKeyguardBypassController);
         mBarService = IStatusBarService.Stub.asInterface(
                 ServiceManager.getService(Context.STATUS_BAR_SERVICE));
 
@@ -787,6 +801,7 @@
 
         inflateStatusBarWindow(context);
         mStatusBarWindow.setService(this);
+        mStatusBarWindow.setBypassController(mKeyguardBypassController);
         mStatusBarWindow.setOnTouchListener(getStatusBarWindowTouchListener());
 
         // TODO: Deal with the ugliness that comes from having some of the statusbar broken out
@@ -798,9 +813,14 @@
         mNotificationLogger.setUpWithContainer(notifListContainer);
 
         mNotificationIconAreaController = SystemUIFactory.getInstance()
-                .createNotificationIconAreaController(context, this, mStatusBarStateController);
+                .createNotificationIconAreaController(context, this,
+                        mWakeUpCoordinator, mKeyguardBypassController,
+                        mStatusBarStateController);
+        mWakeUpCoordinator.setIconAreaController(mNotificationIconAreaController);
         inflateShelf();
         mNotificationIconAreaController.setupShelf(mNotificationShelf);
+        mNotificationPanel.setOnReinflationListener(mNotificationIconAreaController::initAodIcons);
+        mNotificationPanel.addExpansionListener(mWakeUpCoordinator);
 
         Dependency.get(DarkIconDispatcher.class).addDarkReceiver(mNotificationIconAreaController);
         // Allow plugins to reference DarkIconDispatcher and StatusBarStateController
@@ -842,7 +862,9 @@
                         mHeadsUpAppearanceController.destroy();
                     }
                     mHeadsUpAppearanceController = new HeadsUpAppearanceController(
-                            mNotificationIconAreaController, mHeadsUpManager, mStatusBarWindow);
+                            mNotificationIconAreaController, mHeadsUpManager, mStatusBarWindow,
+                            mStatusBarStateController, mKeyguardBypassController,
+                            mWakeUpCoordinator);
                     mHeadsUpAppearanceController.readFrom(oldController);
                     mStatusBarWindow.setStatusBarView(mStatusBarView);
                     updateAreThereNotifications();
@@ -854,17 +876,13 @@
                 .commit();
         mIconController = Dependency.get(StatusBarIconController.class);
 
-        mHeadsUpManager = new HeadsUpManagerPhone(context, mStatusBarWindow, mGroupManager, this,
-                mVisualStabilityManager);
+        mHeadsUpManager.setUp(mStatusBarWindow, mGroupManager, this, mVisualStabilityManager);
         Dependency.get(ConfigurationController.class).addCallback(mHeadsUpManager);
         mHeadsUpManager.addListener(this);
         mHeadsUpManager.addListener(mNotificationPanel);
         mHeadsUpManager.addListener(mGroupManager);
         mHeadsUpManager.addListener(mGroupAlertTransferHelper);
         mHeadsUpManager.addListener(mVisualStabilityManager);
-        mAmbientPulseManager.addListener(this);
-        mAmbientPulseManager.addListener(mGroupManager);
-        mAmbientPulseManager.addListener(mGroupAlertTransferHelper);
         mNotificationPanel.setHeadsUpManager(mHeadsUpManager);
         mGroupManager.setHeadsUpManager(mHeadsUpManager);
         mGroupAlertTransferHelper.setHeadsUpManager(mHeadsUpManager);
@@ -920,7 +938,8 @@
                         mStatusBarWindow.onScrimVisibilityChanged(scrimsVisible);
                     }
                 }, DozeParameters.getInstance(mContext),
-                mContext.getSystemService(AlarmManager.class));
+                mContext.getSystemService(AlarmManager.class),
+                mKeyguardMonitor);
         mNotificationPanel.initDependencies(this, mGroupManager, mNotificationShelf,
                 mHeadsUpManager, mNotificationIconAreaController, mScrimController);
         mDozeScrimController = new DozeScrimController(DozeParameters.getInstance(context));
@@ -1046,11 +1065,13 @@
         final NotificationRowBinderImpl rowBinder =
                 new NotificationRowBinderImpl(
                         mContext,
-                        SystemUIFactory.getInstance().provideAllowNotificationLongPress());
+                        SystemUIFactory.getInstance().provideAllowNotificationLongPress(),
+                        mKeyguardBypassController,
+                        mStatusBarStateController);
 
         mPresenter = new StatusBarNotificationPresenter(mContext, mNotificationPanel,
                 mHeadsUpManager, mStatusBarWindow, mStackScroller, mDozeScrimController,
-                mScrimController, mActivityLaunchAnimator, mStatusBarKeyguardViewManager,
+                mScrimController, mActivityLaunchAnimator, mDynamicPrivacyController,
                 mNotificationAlertingManager, rowBinder);
 
         mNotificationListController =
@@ -1147,8 +1168,9 @@
 
     private void inflateShelf() {
         mNotificationShelf =
-                (NotificationShelf) LayoutInflater.from(mContext).inflate(
-                        R.layout.status_bar_notification_shelf, mStackScroller, false);
+                (NotificationShelf) mInjectionInflater.injectable(
+                        LayoutInflater.from(mContext)).inflate(
+                                R.layout.status_bar_notification_shelf, mStackScroller, false);
         mNotificationShelf.setOnClickListener(mGoToLockedShadeListener);
     }
 
@@ -1177,6 +1199,7 @@
         if (mAmbientIndicationContainer instanceof AutoReinflateContainer) {
             ((AutoReinflateContainer) mAmbientIndicationContainer).inflateLayout();
         }
+        mNotificationIconAreaController.onThemeChanged();
     }
 
     @Override
@@ -1215,15 +1238,17 @@
         mBiometricUnlockController = new BiometricUnlockController(mContext,
                 mDozeScrimController, keyguardViewMediator,
                 mScrimController, this, UnlockMethodCache.getInstance(mContext),
-                new Handler(), mKeyguardUpdateMonitor, Dependency.get(TunerService.class));
+                new Handler(), mKeyguardUpdateMonitor, mKeyguardBypassController);
         putComponent(BiometricUnlockController.class, mBiometricUnlockController);
         mStatusBarKeyguardViewManager = keyguardViewMediator.registerStatusBar(this,
                 getBouncerContainer(), mNotificationPanel, mBiometricUnlockController,
-                mStatusBarWindow.findViewById(R.id.lock_icon_container));
+                mStatusBarWindow.findViewById(R.id.lock_icon_container), mStackScroller,
+                mKeyguardBypassController);
         mKeyguardIndicationController
                 .setStatusBarKeyguardViewManager(mStatusBarKeyguardViewManager);
         mBiometricUnlockController.setStatusBarKeyguardViewManager(mStatusBarKeyguardViewManager);
         mRemoteInputManager.getController().addCallback(mStatusBarKeyguardViewManager);
+        mDynamicPrivacyController.setStatusBarKeyguardViewManager(mStatusBarKeyguardViewManager);
 
         mKeyguardViewMediatorCallback = keyguardViewMediator.getViewMediatorCallback();
         mLightBarController.setBiometricUnlockController(mBiometricUnlockController);
@@ -1493,6 +1518,9 @@
         mNotificationPanel.setStatusAccessibilityImportance(expanded
                 ? View.IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS
                 : View.IMPORTANT_FOR_ACCESSIBILITY_AUTO);
+        if (getNavigationBarView() != null) {
+            getNavigationBarView().onStatusBarPanelStateChanged();
+        }
     }
 
     public boolean isWakeUpComingFromTouch() {
@@ -1534,10 +1562,16 @@
                 });
             }
         } else {
-            if (!mNotificationPanel.isFullyCollapsed() || mNotificationPanel.isTracking()) {
+            boolean bypassKeyguard = mKeyguardBypassController.getBypassEnabled()
+                    && mState == StatusBarState.KEYGUARD;
+            if (!mNotificationPanel.isFullyCollapsed() || mNotificationPanel.isTracking()
+                    || bypassKeyguard) {
                 // We are currently tracking or is open and the shade doesn't need to be kept
                 // open artificially.
                 mStatusBarWindowController.setHeadsUpShowing(false);
+                if (bypassKeyguard) {
+                    mStatusBarWindowController.setForceStatusBarVisible(false);
+                }
             } else {
                 // we need to keep the panel open artificially, let's wait until the animation
                 // is finished.
@@ -1554,25 +1588,16 @@
     }
 
     @Override
-    public void onHeadsUpPinned(NotificationEntry entry) {
-        dismissVolumeDialog();
-    }
-
-    @Override
-    public void onHeadsUpUnPinned(NotificationEntry entry) {
-    }
-
-    @Override
     public void onHeadsUpStateChanged(NotificationEntry entry, boolean isHeadsUp) {
         mEntryManager.updateNotifications();
-    }
-
-    @Override
-    public void onAmbientStateChanged(NotificationEntry entry, boolean isAmbient) {
-        mEntryManager.updateNotifications();
-        if (isAmbient) {
-            mDozeServiceHost.fireNotificationPulse();
-        } else if (!mAmbientPulseManager.hasNotifications()) {
+        if (isDozing() && isHeadsUp) {
+            entry.setPulseSuppressed(false);
+            mDozeServiceHost.fireNotificationPulse(entry);
+            if (mPulsing) {
+                mDozeScrimController.cancelPendingPulseTimeout();
+            }
+        }
+        if (!isHeadsUp && !mHeadsUpManager.hasNotifications()) {
             // There are no longer any notifications to show.  We should end the pulse now.
             mDozeScrimController.pulseOutNow();
         }
@@ -1670,7 +1695,7 @@
         }
     }
 
-    public boolean isHeadsUpShouldBeVisible() {
+    public boolean headsUpShouldBeVisible() {
         return mHeadsUpAppearanceController.shouldBeVisible();
     }
 
@@ -1791,6 +1816,8 @@
                     mVibratorHelper.vibrate(VibrationEffect.EFFECT_TICK);
                 }
                 mNotificationPanel.expand(true /* animate */);
+                ((NotificationListContainer) mStackScroller).setWillExpand(true);
+                mHeadsUpManager.unpinAll(true /* userUnpinned */);
                 mMetricsLogger.count(NotificationPanelView.COUNTER_PANEL_OPEN, 1);
             } else if (!mNotificationPanel.isInSettings() && !mNotificationPanel.isExpanding()){
                 mNotificationPanel.flingSettings(0 /* velocity */,
@@ -1918,19 +1945,18 @@
         mStatusBarKeyguardViewManager.readyForKeyguardDone();
     }
 
-    public void dispatchNotificationsPanelTouchEvent(MotionEvent ev) {
+    /**
+     * Called when another window is about to transfer it's input focus.
+     */
+    public void onInputFocusTransfer(boolean start, float velocity) {
         if (!mCommandQueue.panelsEnabled()) {
             return;
         }
-        mNotificationPanel.dispatchTouchEvent(ev);
 
-        int action = ev.getAction();
-        if (action == MotionEvent.ACTION_DOWN) {
-            // Start ignoring all touch events coming to status bar window.
-            // TODO: handle case where ACTION_UP is not sent over the binder
-            mStatusBarWindowController.setNotTouchable(true);
-        } else if (action == MotionEvent.ACTION_UP || action == MotionEvent.ACTION_CANCEL) {
-            mStatusBarWindowController.setNotTouchable(false);
+        if (start) {
+            mNotificationPanel.startWaitingForOpenPanelGesture();
+        } else {
+            mNotificationPanel.stopWaitingForOpenPanelGesture(velocity);
         }
     }
 
@@ -2120,6 +2146,7 @@
                 checkBarModes();
                 mAutoHideController.touchAutoHide();
             }
+            mStatusBarStateController.setSystemUiVisibility(mSystemUiVisibility);
         }
         mLightBarController.onSystemUiVisibilityChanged(fullscreenStackVis, dockedStackVis,
                 mask, fullscreenStackBounds, dockedStackBounds, sbModeChanged, mStatusBarMode,
@@ -2376,6 +2403,14 @@
             mLightBarController.dump(fd, pw, args);
         }
 
+        if (mUnlockMethodCache != null) {
+            mUnlockMethodCache.dump(pw);
+        }
+
+        if (mKeyguardBypassController != null) {
+            mKeyguardBypassController.dump(pw);
+        }
+
         if (mKeyguardUpdateMonitor != null) {
             mKeyguardUpdateMonitor.dump(fd, pw, args);
         }
@@ -2609,8 +2644,8 @@
         }
     }
 
-    private void executeWhenUnlocked(OnDismissAction action) {
-        if (mStatusBarKeyguardViewManager.isShowing()) {
+    private void executeWhenUnlocked(OnDismissAction action, boolean requiresShadeOpen) {
+        if (mStatusBarKeyguardViewManager.isShowing() && requiresShadeOpen) {
             mStatusBarStateController.setLeaveOpenOnKeyguardHide(true);
         }
         dismissKeyguardThenExecute(action, null /* cancelAction */, false /* afterKeyguardGone */);
@@ -3160,6 +3195,7 @@
         mNotificationPanel.onAffordanceLaunchEnded();
         mNotificationPanel.animate().cancel();
         mNotificationPanel.setAlpha(1f);
+        ViewGroupFadeHelper.reset(mNotificationPanel);
         updateScrimController();
         Trace.endSection();
         return staying;
@@ -3183,12 +3219,13 @@
 
     /**
      * Notifies the status bar the Keyguard is fading away with the specified timings.
-     *
-     * @param startTime the start time of the animations in uptime millis
+     *  @param startTime the start time of the animations in uptime millis
      * @param delay the precalculated animation delay in milliseconds
      * @param fadeoutDuration the duration of the exit animation, in milliseconds
+     * @param isBypassFading is this a fading away animation while bypassing
      */
-    public void setKeyguardFadingAway(long startTime, long delay, long fadeoutDuration) {
+    public void setKeyguardFadingAway(long startTime, long delay, long fadeoutDuration,
+            boolean isBypassFading) {
         mCommandQueue.appTransitionStarting(mDisplayId, startTime + fadeoutDuration
                         - LightBarTransitionsController.DEFAULT_TINT_ANIMATION_DURATION,
                 LightBarTransitionsController.DEFAULT_TINT_ANIMATION_DURATION, true);
@@ -3196,7 +3233,7 @@
         mCommandQueue.appTransitionStarting(mDisplayId,
                     startTime - LightBarTransitionsController.DEFAULT_TINT_ANIMATION_DURATION,
                     LightBarTransitionsController.DEFAULT_TINT_ANIMATION_DURATION, true);
-        mKeyguardMonitor.notifyKeyguardFadingAway(delay, fadeoutDuration);
+        mKeyguardMonitor.notifyKeyguardFadingAway(delay, fadeoutDuration, isBypassFading);
     }
 
     /**
@@ -3424,7 +3461,7 @@
         mNotificationPanel.resetViews(dozingAnimated);
 
         updateQsExpansionEnabled();
-        mKeyguardViewMediator.setAodShowing(mDozing);
+        mKeyguardViewMediator.setDozing(mDozing);
 
         mEntryManager.updateNotifications();
         updateDozingState();
@@ -3546,6 +3583,9 @@
                 userAllowsPrivateNotificationsInPublic(mLockscreenUserManager.getCurrentUserId())
                 || !mLockscreenUserManager.shouldShowLockscreenNotifications()
                 || mFalsingManager.shouldEnforceBouncer();
+        if (mKeyguardBypassController.getBypassEnabled()) {
+            fullShadeNeedsBouncer = false;
+        }
         if (mLockscreenUserManager.isLockscreenPublicMode(userId) && fullShadeNeedsBouncer) {
             mStatusBarStateController.setLeaveOpenOnKeyguardHide(true);
             showBouncerIfKeyguard();
@@ -3571,6 +3611,9 @@
      */
     public void setBouncerShowing(boolean bouncerShowing) {
         mBouncerShowing = bouncerShowing;
+        mKeyguardBypassController.setBouncerShowing(bouncerShowing);
+        mPulseExpansionHandler.setBouncerShowing(bouncerShowing);
+        mStatusBarWindow.setBouncerShowingScrimmed(isBouncerShowingScrimmed());
         if (mStatusBarView != null) mStatusBarView.setBouncerShowing(bouncerShowing);
         updateHideIconsForBouncer(true /* animate */);
         mCommandQueue.recomputeDisableFlags(mDisplayId, true /* animate */);
@@ -3622,13 +3665,18 @@
             updateNotificationPanelTouchState();
             notifyHeadsUpGoingToSleep();
             dismissVolumeDialog();
+            mWakeUpCoordinator.setFullyAwake(false);
+            mBypassHeadsUpNotifier.setFullyAwake(false);
+            mKeyguardBypassController.onStartedGoingToSleep();
         }
 
         @Override
         public void onStartedWakingUp() {
             mDeviceInteractive = true;
             mWakeUpCoordinator.setWakingUp(true);
-            mAmbientPulseManager.releaseAllImmediately();
+            if (!mKeyguardBypassController.getBypassEnabled()) {
+                mHeadsUpManager.releaseAllImmediately();
+            }
             mVisualStabilityManager.setScreenOn(true);
             updateVisibleToUser();
             updateIsKeyguard();
@@ -3642,6 +3690,8 @@
 
         @Override
         public void onFinishedWakingUp() {
+            mWakeUpCoordinator.setFullyAwake(true);
+            mBypassHeadsUpNotifier.setFullyAwake(true);
             mWakeUpCoordinator.setWakingUp(false);
             if (mLaunchCameraWhenFinishedWaking) {
                 mNotificationPanel.launchCamera(false /* animate */, mLastCameraLaunchSource);
@@ -3659,8 +3709,9 @@
     private void updateNotificationPanelTouchState() {
         boolean goingToSleepWithoutAnimation = isGoingToSleep()
                 && !DozeParameters.getInstance(mContext).shouldControlScreenOff();
-        mNotificationPanel.setTouchAndAnimationDisabled((!mDeviceInteractive && !mPulsing)
-                || goingToSleepWithoutAnimation);
+        boolean disabled = (!mDeviceInteractive && !mPulsing) || goingToSleepWithoutAnimation;
+        mNotificationPanel.setTouchAndAnimationDisabled(disabled);
+        mNotificationIconAreaController.setAnimationsEnabled(!disabled);
     }
 
     final ScreenLifecycle.Observer mScreenObserver = new ScreenLifecycle.Observer() {
@@ -3741,7 +3792,8 @@
             return;
         }
         if (!mNotificationPanel.canCameraGestureBeLaunched(
-                mStatusBarKeyguardViewManager.isShowing() && mExpandedVisible)) {
+                mStatusBarKeyguardViewManager.isShowing()
+                        && (mExpandedVisible || mBouncerShowing))) {
             if (DEBUG_CAMERA_LIFT) Slog.d(TAG, "Can't launch camera right now, mExpandedVisible: " +
                     mExpandedVisible);
             return;
@@ -3752,6 +3804,12 @@
                     "com.android.systemui:CAMERA_GESTURE");
         }
         vibrateForCameraGesture();
+
+        if (source == StatusBarManager.CAMERA_LAUNCH_SOURCE_POWER_DOUBLE_TAP) {
+            Log.v(TAG, "Camera launch");
+            mKeyguardUpdateMonitor.onCameraLaunched();
+        }
+
         if (!mStatusBarKeyguardViewManager.isShowing()) {
             startActivityDismissingKeyguard(KeyguardBottomAreaView.INSECURE_CAMERA_INTENT,
                     false /* onlyProvisioned */, true /* dismissShade */,
@@ -3808,7 +3866,8 @@
     public void notifyBiometricAuthModeChanged() {
         updateDozing();
         updateScrimController();
-        mStatusBarWindow.onBiometricAuthModeChanged(mBiometricUnlockController.isWakeAndUnlock());
+        mStatusBarWindow.onBiometricAuthModeChanged(mBiometricUnlockController.isWakeAndUnlock(),
+                mBiometricUnlockController.isBiometricUnlock());
     }
 
     @VisibleForTesting
@@ -3817,7 +3876,8 @@
 
         // We don't want to end up in KEYGUARD state when we're unlocking with
         // fingerprint from doze. We should cross fade directly from black.
-        boolean wakeAndUnlocking = mBiometricUnlockController.isWakeAndUnlock();
+        boolean unlocking = mBiometricUnlockController.isWakeAndUnlock()
+                || mKeyguardMonitor.isKeyguardFadingAway();
 
         // Do not animate the scrim expansion when triggered by the fingerprint sensor.
         mScrimController.setExpansionAffectsAlpha(
@@ -3842,9 +3902,9 @@
         } else if (isPulsing()) {
             mScrimController.transitionTo(ScrimState.PULSING,
                     mDozeScrimController.getScrimCallback());
-        } else if (mDozing && !wakeAndUnlocking) {
+        } else if (mDozing && !unlocking) {
             mScrimController.transitionTo(ScrimState.AOD);
-        } else if (mIsKeyguard && !wakeAndUnlocking) {
+        } else if (mIsKeyguard && !unlocking) {
             mScrimController.transitionTo(ScrimState.KEYGUARD);
         } else if (mBubbleController.isStackExpanded()) {
             mScrimController.transitionTo(ScrimState.BUBBLE_EXPANDED);
@@ -3868,6 +3928,9 @@
         private boolean mAnimateWakeup;
         private boolean mAnimateScreenOff;
         private boolean mIgnoreTouchWhilePulsing;
+        @VisibleForTesting
+        boolean mWakeLockScreenPerformsAuth = SystemProperties.getBoolean(
+                "persist.sysui.wake_performs_auth", true);
 
         @Override
         public String toString() {
@@ -3880,9 +3943,13 @@
             }
         }
 
-        public void fireNotificationPulse() {
+        public void fireNotificationPulse(NotificationEntry entry) {
+            Runnable pulseSupressedListener = () -> {
+                entry.setPulseSuppressed(true);
+                mNotificationIconAreaController.updateAodNotificationIcons();
+            };
             for (Callback callback : mCallbacks) {
-                callback.onNotificationAlerted();
+                callback.onNotificationAlerted(pulseSupressedListener);
             }
         }
 
@@ -3923,7 +3990,8 @@
                 mStatusBarWindow.suppressWakeUpGesture(true);
             }
 
-            boolean passiveAuthInterrupt = reason == DozeLog.PULSE_REASON_NOTIFICATION;
+            boolean passiveAuthInterrupt = reason == DozeLog.PULSE_REASON_SENSOR_WAKE_LOCK_SCREEN
+                            && mWakeLockScreenPerformsAuth;
             // Set the state to pulsing, so ScrimController will know what to do once we ask it to
             // execute the transition. The pulse callback will then be invoked when the scrims
             // are black, indicating that StatusBar is ready to present the rest of the UI.
@@ -3949,6 +4017,7 @@
                 }
 
                 private void setPulsing(boolean pulsing) {
+                    mStatusBarStateController.setPulsing(pulsing);
                     mStatusBarKeyguardViewManager.setPulsing(pulsing);
                     mKeyguardViewMediator.setPulsing(pulsing);
                     mNotificationPanel.setPulsing(pulsing);
@@ -4027,8 +4096,8 @@
             if (reason == DozeLog.PULSE_REASON_SENSOR_WAKE_LOCK_SCREEN) {
                 mScrimController.setWakeLockScreenSensorActive(true);
             }
-            if (mDozeScrimController.isPulsing() && mAmbientPulseManager.hasNotifications()) {
-                mAmbientPulseManager.extendPulse();
+            if (mDozeScrimController.isPulsing() && mHeadsUpManager.hasNotifications()) {
+                mHeadsUpManager.extendHeadsUp();
             } else {
                 mDozeScrimController.extendPulse();
             }
@@ -4080,6 +4149,11 @@
             mScrimController.setAodFrontScrimAlpha(scrimOpacity);
         }
 
+        @Override
+        public void prepareForGentleWakeUp() {
+            mScrimController.prepareForGentleWakeUp();
+        }
+
         private void dispatchTap(View view, float x, float y) {
             long now = SystemClock.elapsedRealtime();
             dispatchTouchEvent(view, x, y, now, MotionEvent.ACTION_DOWN);
@@ -4117,12 +4191,6 @@
 
     protected NotificationGroupAlertTransferHelper mGroupAlertTransferHelper;
 
-
-    // for heads up notifications
-    protected HeadsUpManagerPhone mHeadsUpManager;
-
-    protected AmbientPulseManager mAmbientPulseManager = Dependency.get(AmbientPulseManager.class);
-
     // handling reordering
     protected VisualStabilityManager mVisualStabilityManager;
 
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java
index 93168db..7e86651 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java
@@ -17,6 +17,7 @@
 package com.android.systemui.statusbar.phone;
 
 import static com.android.systemui.plugins.ActivityStarter.OnDismissAction;
+import static com.android.systemui.statusbar.phone.BiometricUnlockController.MODE_UNLOCK_FADING;
 import static com.android.systemui.statusbar.phone.BiometricUnlockController.MODE_WAKE_AND_UNLOCK;
 import static com.android.systemui.statusbar.phone.BiometricUnlockController.MODE_WAKE_AND_UNLOCK_PULSING;
 
@@ -51,6 +52,7 @@
 import com.android.systemui.statusbar.RemoteInputController;
 import com.android.systemui.statusbar.StatusBarState;
 import com.android.systemui.statusbar.SysuiStatusBarStateController;
+import com.android.systemui.statusbar.notification.ViewGroupFadeHelper;
 import com.android.systemui.statusbar.phone.KeyguardBouncer.BouncerExpansionCallback;
 import com.android.systemui.statusbar.policy.ConfigurationController;
 import com.android.systemui.statusbar.policy.KeyguardMonitor;
@@ -67,7 +69,7 @@
  */
 public class StatusBarKeyguardViewManager implements RemoteInputController.Callback,
         StatusBarStateController.StateListener, ConfigurationController.ConfigurationListener,
-        NotificationPanelView.PanelExpansionListener, NavigationModeController.ModeChangedListener {
+        PanelExpansionListener, NavigationModeController.ModeChangedListener {
 
     // When hiding the Keyguard with timing supplied from WindowManager, better be early than late.
     private static final long HIDE_TIMING_CORRECTION_MS = - 16 * 3;
@@ -132,6 +134,7 @@
 
     private ViewGroup mContainer;
     private ViewGroup mLockIconContainer;
+    private View mNotificationContainer;
 
     protected KeyguardBouncer mBouncer;
     protected boolean mShowing;
@@ -165,9 +168,10 @@
             (KeyguardMonitorImpl) Dependency.get(KeyguardMonitor.class);
     private final NotificationMediaManager mMediaManager =
             Dependency.get(NotificationMediaManager.class);
-    private final StatusBarStateController mStatusBarStateController =
-            Dependency.get(StatusBarStateController.class);
+    private final SysuiStatusBarStateController mStatusBarStateController =
+            (SysuiStatusBarStateController) Dependency.get(StatusBarStateController.class);
     private final DockManager mDockManager;
+    private KeyguardBypassController mBypassController;
 
     private final KeyguardUpdateMonitorCallback mUpdateMonitorCallback =
             new KeyguardUpdateMonitorCallback() {
@@ -205,7 +209,8 @@
             NotificationPanelView notificationPanelView,
             BiometricUnlockController biometricUnlockController,
             DismissCallbackRegistry dismissCallbackRegistry,
-            ViewGroup lockIconContainer) {
+            ViewGroup lockIconContainer, View notificationContainer,
+            KeyguardBypassController bypassController) {
         mStatusBar = statusBar;
         mContainer = container;
         mLockIconContainer = lockIconContainer;
@@ -215,9 +220,11 @@
         mBiometricUnlockController = biometricUnlockController;
         mBouncer = SystemUIFactory.getInstance().createKeyguardBouncer(mContext,
                 mViewMediatorCallback, mLockPatternUtils, container, dismissCallbackRegistry,
-                mExpansionCallback);
+                mExpansionCallback, bypassController);
         mNotificationPanelView = notificationPanelView;
-        notificationPanelView.setExpansionListener(this);
+        notificationPanelView.addExpansionListener(this);
+        mBypassController = bypassController;
+        mNotificationContainer = notificationContainer;
     }
 
     @Override
@@ -261,7 +268,7 @@
         boolean keyguardWithoutQs = mStatusBarStateController.getState() == StatusBarState.KEYGUARD
                 && !mNotificationPanelView.isQsExpanded();
         boolean lockVisible = (mBouncer.isShowing() || keyguardWithoutQs)
-                && !mBouncer.isAnimatingAway();
+                && !mBouncer.isAnimatingAway() && !mKeyguardMonitor.isKeyguardFadingAway();
 
         if (mLastLockVisible != lockVisible) {
             mLastLockVisible = lockVisible;
@@ -270,8 +277,14 @@
                         AppearAnimationUtils.DEFAULT_APPEAR_DURATION /* duration */,
                         0 /* delay */);
             } else {
+                final long duration;
+                if (needsBypassFading()) {
+                    duration = KeyguardBypassController.BYPASS_PANEL_FADE_DURATION;
+                } else {
+                    duration = AppearAnimationUtils.DEFAULT_APPEAR_DURATION / 2;
+                }
                 CrossFadeHelper.fadeOut(mLockIconContainer,
-                        AppearAnimationUtils.DEFAULT_APPEAR_DURATION / 2 /* duration */,
+                        duration /* duration */,
                         0 /* delay */, null /* runnable */);
             }
         }
@@ -547,20 +560,44 @@
             executeAfterKeyguardGoneAction();
             boolean wakeUnlockPulsing =
                     mBiometricUnlockController.getMode() == MODE_WAKE_AND_UNLOCK_PULSING;
-            if (wakeUnlockPulsing) {
+            boolean needsFading = needsBypassFading();
+            if (needsFading) {
+                delay = 0;
+                fadeoutDuration = KeyguardBypassController.BYPASS_PANEL_FADE_DURATION;
+            } else if (wakeUnlockPulsing) {
                 delay = 0;
                 fadeoutDuration = 240;
             }
-            mStatusBar.setKeyguardFadingAway(startTime, delay, fadeoutDuration);
+            mStatusBar.setKeyguardFadingAway(startTime, delay, fadeoutDuration, needsFading);
             mBiometricUnlockController.startKeyguardFadingAway();
             hideBouncer(true /* destroyView */);
             if (wakeUnlockPulsing) {
-                mStatusBar.fadeKeyguardWhilePulsing();
+                if (needsFading) {
+                    ViewGroupFadeHelper.fadeOutAllChildrenExcept(mNotificationPanelView,
+                            mNotificationContainer,
+                            fadeoutDuration,
+                                    () -> {
+                        mStatusBar.hideKeyguard();
+                        onKeyguardFadedAway();
+                    });
+                } else {
+                    mStatusBar.fadeKeyguardWhilePulsing();
+                }
                 wakeAndUnlockDejank();
             } else {
-                boolean staying = mStatusBar.hideKeyguard();
+                boolean staying = mStatusBarStateController.leaveOpenOnKeyguardHide();
                 if (!staying) {
                     mStatusBarWindowController.setKeyguardFadingAway(true);
+                    if (needsFading) {
+                        ViewGroupFadeHelper.fadeOutAllChildrenExcept(mNotificationPanelView,
+                                mNotificationContainer,
+                                fadeoutDuration,
+                                () -> {
+                                    mStatusBar.hideKeyguard();
+                                });
+                    } else {
+                        mStatusBar.hideKeyguard();
+                    }
                     // hide() will happen asynchronously and might arrive after the scrims
                     // were already hidden, this means that the transition callback won't
                     // be triggered anymore and StatusBarWindowController will be forever in
@@ -568,10 +605,12 @@
                     mStatusBar.updateScrimController();
                     wakeAndUnlockDejank();
                 } else {
+                    mStatusBar.hideKeyguard();
                     mStatusBar.finishKeyguardFadingAway();
                     mBiometricUnlockController.finishKeyguardFadingAway();
                 }
             }
+            updateLockIcon();
             updateStates();
             mStatusBarWindowController.setKeyguardShowing(false);
             mViewMediatorCallback.keyguardGone();
@@ -580,6 +619,13 @@
             StatsLog.KEYGUARD_STATE_CHANGED__STATE__HIDDEN);
     }
 
+    private boolean needsBypassFading() {
+        return (mBiometricUnlockController.getMode() == MODE_UNLOCK_FADING
+                || mBiometricUnlockController.getMode() == MODE_WAKE_AND_UNLOCK_PULSING
+                || mBiometricUnlockController.getMode() == MODE_WAKE_AND_UNLOCK)
+                && mBypassController.getBypassEnabled();
+    }
+
     @Override
     public void onDensityOrFontScaleChanged() {
         hideBouncer(true /* destroyView */);
@@ -602,6 +648,7 @@
     public void onKeyguardFadedAway() {
         mContainer.postDelayed(() -> mStatusBarWindowController.setKeyguardFadingAway(false),
                 100);
+        ViewGroupFadeHelper.reset(mNotificationPanelView);
         mStatusBar.finishKeyguardFadingAway();
         mBiometricUnlockController.finishKeyguardFadingAway();
         WindowManagerGlobal.getInstance().trimMemory(
@@ -677,8 +724,12 @@
         return mBouncer.isShowing();
     }
 
-    public boolean isBouncerPartiallyVisible() {
-        return mBouncer.isPartiallyVisible();
+    /**
+     * When bouncer is fully visible or {@link KeyguardBouncer#show(boolean)} was called but
+     * animation didn't finish yet.
+     */
+    public boolean bouncerIsOrWillBeShowing() {
+        return mBouncer.isShowing() || mBouncer.inTransit();
     }
 
     public boolean isFullscreenBouncer() {
@@ -812,6 +863,14 @@
         return mStatusBar.isInLaunchTransition();
     }
 
+
+    /**
+     * @return Whether subtle animation should be used for unlocking the device.
+     */
+    public boolean shouldSubtleWindowAnimationsForUnlock() {
+        return needsBypassFading();
+    }
+
     public boolean isGoingToNotificationShade() {
         return ((SysuiStatusBarStateController) Dependency.get(StatusBarStateController.class))
                 .leaveOpenOnKeyguardHide();
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarter.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarter.java
index e00d439..bec53a1 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarter.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarter.java
@@ -406,8 +406,7 @@
     }
 
     private void handleFullScreenIntent(NotificationEntry entry) {
-        boolean isHeadsUped = mNotificationInterruptionStateProvider.shouldHeadsUp(entry);
-        if (!isHeadsUped && entry.notification.getNotification().fullScreenIntent != null) {
+        if (mNotificationInterruptionStateProvider.shouldLaunchFullScreenIntentWhenAdded(entry)) {
             if (shouldSuppressFullScreenIntent(entry)) {
                 if (DEBUG) {
                     Log.d(TAG, "No Fullscreen intent: suppressed by DND: " + entry.key);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationPresenter.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationPresenter.java
index 6fe8964..a870590 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationPresenter.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationPresenter.java
@@ -49,7 +49,6 @@
 import com.android.systemui.plugins.ActivityStarter;
 import com.android.systemui.plugins.ActivityStarter.OnDismissAction;
 import com.android.systemui.plugins.statusbar.StatusBarStateController;
-import com.android.systemui.statusbar.AmbientPulseManager;
 import com.android.systemui.statusbar.CommandQueue;
 import com.android.systemui.statusbar.NotificationLockscreenUserManager;
 import com.android.systemui.statusbar.NotificationMediaManager;
@@ -60,6 +59,7 @@
 import com.android.systemui.statusbar.SysuiStatusBarStateController;
 import com.android.systemui.statusbar.notification.AboveShelfObserver;
 import com.android.systemui.statusbar.notification.ActivityLaunchAnimator;
+import com.android.systemui.statusbar.notification.DynamicPrivacyController;
 import com.android.systemui.statusbar.notification.NotificationAlertingManager;
 import com.android.systemui.statusbar.notification.NotificationEntryListener;
 import com.android.systemui.statusbar.notification.NotificationEntryManager;
@@ -106,7 +106,6 @@
             Dependency.get(VisualStabilityManager.class);
     private final NotificationGutsManager mGutsManager =
             Dependency.get(NotificationGutsManager.class);
-    protected AmbientPulseManager mAmbientPulseManager = Dependency.get(AmbientPulseManager.class);
 
     private final NotificationPanelView mNotificationPanel;
     private final HeadsUpManagerPhone mHeadsUpManager;
@@ -119,9 +118,9 @@
     private final AccessibilityManager mAccessibilityManager;
     private final KeyguardManager mKeyguardManager;
     private final ActivityLaunchAnimator mActivityLaunchAnimator;
-    private final StatusBarKeyguardViewManager mStatusBarKeyguardViewManager;
     private final int mMaxAllowedKeyguardNotifications;
     private final IStatusBarService mBarService;
+    private final DynamicPrivacyController mDynamicPrivacyController;
     private boolean mReinflateNotificationsOnUserSwitched;
     private boolean mDispatchUiModeChangeOnUserSwitched;
     private final UnlockMethodCache mUnlockMethodCache;
@@ -138,16 +137,16 @@
             DozeScrimController dozeScrimController,
             ScrimController scrimController,
             ActivityLaunchAnimator activityLaunchAnimator,
-            StatusBarKeyguardViewManager statusBarKeyguardViewManager,
+            DynamicPrivacyController dynamicPrivacyController,
             NotificationAlertingManager notificationAlertingManager,
             NotificationRowBinderImpl notificationRowBinder) {
         mContext = context;
         mNotificationPanel = panel;
         mHeadsUpManager = headsUp;
+        mDynamicPrivacyController = dynamicPrivacyController;
         mCommandQueue = getComponent(context, CommandQueue.class);
         mAboveShelfObserver = new AboveShelfObserver(stackScroller);
         mActivityLaunchAnimator = activityLaunchAnimator;
-        mStatusBarKeyguardViewManager = statusBarKeyguardViewManager;
         mAboveShelfObserver.setListener(statusBarWindow.findViewById(
                 R.id.notification_container_parent));
         mAccessibilityManager = context.getSystemService(AccessibilityManager.class);
@@ -213,7 +212,6 @@
             mEntryManager.setUpWithPresenter(this, notifListContainer, mHeadsUpManager);
             mEntryManager.addNotificationEntryListener(notificationEntryListener);
             mEntryManager.addNotificationLifetimeExtender(mHeadsUpManager);
-            mEntryManager.addNotificationLifetimeExtender(mAmbientPulseManager);
             mEntryManager.addNotificationLifetimeExtender(mGutsManager);
             mEntryManager.addNotificationLifetimeExtenders(
                     remoteInputManager.getLifetimeExtenders());
@@ -297,7 +295,7 @@
 
     private void maybeEndAmbientPulse() {
         if (mNotificationPanel.hasPulsingNotifications() &&
-                !mAmbientPulseManager.hasNotifications()) {
+                !mHeadsUpManager.hasNotifications()) {
             // We were showing a pulse for a notification, but no notifications are pulsing anymore.
             // Finish the pulse.
             mDozeScrimController.pulseOutNow();
@@ -343,10 +341,6 @@
     }
 
     public boolean canHeadsUp(NotificationEntry entry, StatusBarNotification sbn) {
-        if (mShadeController.isDozing()) {
-            return false;
-        }
-
         if (mShadeController.isOccluded()) {
             boolean devicePublic = mLockscreenUserManager.
                     isLockscreenPublicMode(mLockscreenUserManager.getCurrentUserId());
@@ -354,6 +348,7 @@
                     || mLockscreenUserManager.isLockscreenPublicMode(sbn.getUserId());
             boolean needsRedaction = mLockscreenUserManager.needsRedaction(entry);
             if (userPublic && needsRedaction) {
+                // TODO(b/135046837): we can probably relax this with dynamic privacy
                 return false;
             }
         }
@@ -460,8 +455,15 @@
     @Override
     public void onExpandClicked(NotificationEntry clickedEntry, boolean nowExpanded) {
         mHeadsUpManager.setExpanded(clickedEntry, nowExpanded);
-        if (mStatusBarStateController.getState() == StatusBarState.KEYGUARD && nowExpanded) {
-            mShadeController.goToLockedShade(clickedEntry.getRow());
+        if (nowExpanded) {
+            if (mStatusBarStateController.getState() == StatusBarState.KEYGUARD) {
+                mShadeController.goToLockedShade(clickedEntry.getRow());
+            } else if (clickedEntry.isSensitive()
+                    && mDynamicPrivacyController.isInLockedDownShade()) {
+                mStatusBarStateController.setLeaveOpenOnKeyguardHide(true);
+                mActivityStarter.dismissKeyguardThenExecute(() -> false /* dismissAction */
+                        , null /* cancelRunnable */, false /* afterKeyguardGone */);
+            }
         }
     }
 
@@ -470,12 +472,6 @@
         return mVrMode;
     }
 
-    @Override
-    public boolean isPresenterLocked() {
-        return mStatusBarKeyguardViewManager.isShowing()
-                && mStatusBarKeyguardViewManager.isSecure();
-    }
-
     private void onLockedNotificationImportanceChange(OnDismissAction dismissAction) {
         mStatusBarStateController.setLeaveOpenOnKeyguardHide(true);
         mActivityStarter.dismissKeyguardThenExecute(dismissAction, null,
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarRemoteInputCallback.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarRemoteInputCallback.java
index 6691f7a..13d4b8e 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarRemoteInputCallback.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarRemoteInputCallback.java
@@ -48,6 +48,7 @@
 import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
 import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayout;
 import com.android.systemui.statusbar.policy.KeyguardMonitor;
+import com.android.systemui.statusbar.policy.RemoteInputView;
 
 import javax.inject.Inject;
 import javax.inject.Singleton;
@@ -93,9 +94,11 @@
 
     @Override
     public void onStateChanged(int state) {
-        if (state == StatusBarState.SHADE && mStatusBarStateController.leaveOpenOnKeyguardHide()) {
+        boolean hasPendingRemoteInput = mPendingRemoteInputView != null;
+        if (state == StatusBarState.SHADE
+                && (mStatusBarStateController.leaveOpenOnKeyguardHide() || hasPendingRemoteInput)) {
             if (!mStatusBarStateController.isKeyguardRequested()) {
-                if (mPendingRemoteInputView != null) {
+                if (hasPendingRemoteInput) {
                     mMainHandler.post(mPendingRemoteInputView::callOnClick);
                 }
                 mPendingRemoteInputView = null;
@@ -105,7 +108,9 @@
 
     @Override
     public void onLockedRemoteInput(ExpandableNotificationRow row, View clicked) {
-        mStatusBarStateController.setLeaveOpenOnKeyguardHide(true);
+        if (!row.isPinned()) {
+            mStatusBarStateController.setLeaveOpenOnKeyguardHide(true);
+        }
         mShadeController.showBouncer(true /* scrimmed */);
         mPendingRemoteInputView = clicked;
     }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarTouchableRegionManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarTouchableRegionManager.java
index e949ade..3d25749 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarTouchableRegionManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarTouchableRegionManager.java
@@ -26,7 +26,6 @@
 import android.view.ViewTreeObserver.OnComputeInternalInsetsListener;
 
 import com.android.systemui.Dependency;
-import com.android.systemui.assist.AssistManager;
 import com.android.systemui.bubbles.BubbleController;
 import com.android.systemui.statusbar.policy.ConfigurationController;
 import com.android.systemui.statusbar.policy.ConfigurationController.ConfigurationListener;
@@ -38,7 +37,6 @@
 public final class StatusBarTouchableRegionManager implements
         OnComputeInternalInsetsListener, ConfigurationListener {
 
-    private final AssistManager mAssistManager = Dependency.get(AssistManager.class);
     private final BubbleController mBubbleController = Dependency.get(BubbleController.class);
     private final Context mContext;
     private final HeadsUpManagerPhone mHeadsUpManager;
@@ -48,6 +46,7 @@
     private int mStatusBarHeight;
     private final View mStatusBarWindowView;
     private boolean mForceCollapsedUntilLayout = false;
+    private final StatusBarWindowController mStatusBarWindowController;
 
     public StatusBarTouchableRegionManager(@NonNull Context context,
                                            HeadsUpManagerPhone headsUpManager,
@@ -57,12 +56,17 @@
         mHeadsUpManager = headsUpManager;
         mStatusBar = statusBar;
         mStatusBarWindowView = statusBarWindowView;
+        mStatusBarWindowController = Dependency.get(StatusBarWindowController.class);
 
         initResources();
 
         mBubbleController.setBubbleStateChangeListener((hasBubbles) -> {
             updateTouchableRegion();
         });
+
+        mStatusBarWindowController.setForcePluginOpenListener((forceOpen) -> {
+            updateTouchableRegion();
+        });
         Dependency.get(ConfigurationController.class).addCallback(this);
     }
 
@@ -77,7 +81,8 @@
                 mHeadsUpManager.hasPinnedHeadsUp() || mHeadsUpManager.isHeadsUpGoingAway()
                         || mBubbleController.hasBubbles()
                         || mForceCollapsedUntilLayout
-                        || hasCutoutInset;
+                        || hasCutoutInset
+                        || mStatusBarWindowController.getForcePluginOpen();
         if (shouldObserve == mShouldAdjustInsets) {
             return;
         }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowController.java
index 8621b72..0ef981b 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowController.java
@@ -29,7 +29,9 @@
 import android.os.Binder;
 import android.os.RemoteException;
 import android.os.SystemProperties;
+import android.os.Trace;
 import android.util.Log;
+import android.view.Display;
 import android.view.Gravity;
 import android.view.View;
 import android.view.ViewGroup;
@@ -51,12 +53,14 @@
 import com.android.systemui.statusbar.policy.ConfigurationController.ConfigurationListener;
 
 import com.google.android.collect.Lists;
+
 import java.io.FileDescriptor;
 import java.io.PrintWriter;
 import java.lang.ref.WeakReference;
 import java.lang.reflect.Field;
-
 import java.util.ArrayList;
+import java.util.Arrays;
+
 import javax.inject.Inject;
 import javax.inject.Singleton;
 
@@ -72,41 +76,69 @@
     private final WindowManager mWindowManager;
     private final IActivityManager mActivityManager;
     private final DozeParameters mDozeParameters;
-    private final WindowManager.LayoutParams mLpChanged;
+    private final LayoutParams mLpChanged;
     private final boolean mKeyguardScreenRotation;
+    private final long mLockScreenDisplayTimeout;
+    private final Display.Mode mKeyguardDisplayMode;
+    private final KeyguardBypassController mKeyguardBypassController;
     private ViewGroup mStatusBarView;
-    private WindowManager.LayoutParams mLp;
+    private LayoutParams mLp;
     private boolean mHasTopUi;
     private boolean mHasTopUiChanged;
     private int mBarHeight;
     private float mScreenBrightnessDoze;
     private final State mCurrentState = new State();
     private OtherwisedCollapsedListener mListener;
+    private ForcePluginOpenListener mForcePluginOpenListener;
     private final ArrayList<WeakReference<StatusBarWindowCallback>>
             mCallbacks = Lists.newArrayList();
 
     private final SysuiColorExtractor mColorExtractor = Dependency.get(SysuiColorExtractor.class);
 
     @Inject
-    public StatusBarWindowController(Context context) {
+    public StatusBarWindowController(Context context,
+            StatusBarStateController statusBarStateController,
+            ConfigurationController configurationController,
+            KeyguardBypassController keyguardBypassController) {
         this(context, context.getSystemService(WindowManager.class), ActivityManager.getService(),
-                DozeParameters.getInstance(context));
+                DozeParameters.getInstance(context), statusBarStateController,
+                configurationController, keyguardBypassController);
     }
 
     @VisibleForTesting
     public StatusBarWindowController(Context context, WindowManager windowManager,
-            IActivityManager activityManager, DozeParameters dozeParameters) {
+            IActivityManager activityManager, DozeParameters dozeParameters,
+            StatusBarStateController statusBarStateController,
+            ConfigurationController configurationController,
+            KeyguardBypassController keyguardBypassController) {
         mContext = context;
         mWindowManager = windowManager;
         mActivityManager = activityManager;
         mKeyguardScreenRotation = shouldEnableKeyguardScreenRotation();
         mDozeParameters = dozeParameters;
         mScreenBrightnessDoze = mDozeParameters.getScreenBrightnessDoze();
-        mLpChanged = new WindowManager.LayoutParams();
-        ((SysuiStatusBarStateController) Dependency.get(StatusBarStateController.class))
+        mLpChanged = new LayoutParams();
+        mKeyguardBypassController = keyguardBypassController;
+        mLockScreenDisplayTimeout = context.getResources()
+                .getInteger(R.integer.config_lockScreenDisplayTimeout);
+        ((SysuiStatusBarStateController) statusBarStateController)
                 .addCallback(mStateListener,
                         SysuiStatusBarStateController.RANK_STATUS_BAR_WINDOW_CONTROLLER);
-        Dependency.get(ConfigurationController.class).addCallback(this);
+        configurationController.addCallback(this);
+
+        Display.Mode[] supportedModes = context.getDisplay().getSupportedModes();
+        Display.Mode currentMode = context.getDisplay().getMode();
+        // Running on the highest frame rate available can be expensive.
+        // Let's specify a preferred refresh rate, and allow higher FPS only when we
+        // know that we're not falsing (because we unlocked.)
+        int keyguardRefreshRate = context.getResources()
+                .getInteger(R.integer.config_keyguardRefreshRate);
+        // Find supported display mode with the same resolution and requested refresh rate.
+        mKeyguardDisplayMode = Arrays.stream(supportedModes).filter(mode ->
+                (int) mode.getRefreshRate() == keyguardRefreshRate
+                        && mode.getPhysicalWidth() == currentMode.getPhysicalWidth()
+                        && mode.getPhysicalHeight() == currentMode.getPhysicalHeight())
+                .findFirst().orElse(null);
     }
 
     /**
@@ -139,19 +171,19 @@
         // Now that the status bar window encompasses the sliding panel and its
         // translucent backdrop, the entire thing is made TRANSLUCENT and is
         // hardware-accelerated.
-        mLp = new WindowManager.LayoutParams(
+        mLp = new LayoutParams(
                 ViewGroup.LayoutParams.MATCH_PARENT,
                 barHeight,
-                WindowManager.LayoutParams.TYPE_STATUS_BAR,
-                WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
-                        | WindowManager.LayoutParams.FLAG_TOUCHABLE_WHEN_WAKING
-                        | WindowManager.LayoutParams.FLAG_SPLIT_TOUCH
-                        | WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH
-                        | WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS,
+                LayoutParams.TYPE_STATUS_BAR,
+                LayoutParams.FLAG_NOT_FOCUSABLE
+                        | LayoutParams.FLAG_TOUCHABLE_WHEN_WAKING
+                        | LayoutParams.FLAG_SPLIT_TOUCH
+                        | LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH
+                        | LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS,
                 PixelFormat.TRANSLUCENT);
         mLp.token = new Binder();
         mLp.gravity = Gravity.TOP;
-        mLp.softInputMode = WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE;
+        mLp.softInputMode = LayoutParams.SOFT_INPUT_ADJUST_RESIZE;
         mLp.setTitle("StatusBar");
         mLp.packageName = mContext.getPackageName();
         mLp.layoutInDisplayCutoutMode = LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS;
@@ -184,9 +216,9 @@
 
     private void applyKeyguardFlags(State state) {
         if (state.keyguardShowing) {
-            mLpChanged.privateFlags |= WindowManager.LayoutParams.PRIVATE_FLAG_KEYGUARD;
+            mLpChanged.privateFlags |= LayoutParams.PRIVATE_FLAG_KEYGUARD;
         } else {
-            mLpChanged.privateFlags &= ~WindowManager.LayoutParams.PRIVATE_FLAG_KEYGUARD;
+            mLpChanged.privateFlags &= ~LayoutParams.PRIVATE_FLAG_KEYGUARD;
         }
 
         final boolean scrimsOccludingWallpaper =
@@ -194,9 +226,9 @@
         final boolean keyguardOrAod = state.keyguardShowing
                 || (state.dozing && mDozeParameters.getAlwaysOn());
         if (keyguardOrAod && !state.backdropShowing && !scrimsOccludingWallpaper) {
-            mLpChanged.flags |= WindowManager.LayoutParams.FLAG_SHOW_WALLPAPER;
+            mLpChanged.flags |= LayoutParams.FLAG_SHOW_WALLPAPER;
         } else {
-            mLpChanged.flags &= ~WindowManager.LayoutParams.FLAG_SHOW_WALLPAPER;
+            mLpChanged.flags &= ~LayoutParams.FLAG_SHOW_WALLPAPER;
         }
 
         if (state.dozing) {
@@ -204,6 +236,18 @@
         } else {
             mLpChanged.privateFlags &= ~LayoutParams.SYSTEM_FLAG_HIDE_NON_SYSTEM_OVERLAY_WINDOWS;
         }
+
+        if (mKeyguardDisplayMode != null) {
+            boolean bypassOnKeyguard = mKeyguardBypassController.getBypassEnabled()
+                    && state.statusBarState == StatusBarState.KEYGUARD && !state.keyguardFadingAway
+                    && !state.keyguardGoingAway;
+            if (state.dozing || bypassOnKeyguard) {
+                mLpChanged.preferredDisplayModeId = mKeyguardDisplayMode.getModeId();
+            } else {
+                mLpChanged.preferredDisplayModeId = 0;
+            }
+            Trace.setCounter("display_mode_id", mLpChanged.preferredDisplayModeId);
+        }
     }
 
     private void adjustScreenOrientation(State state) {
@@ -223,17 +267,17 @@
         if (state.bouncerShowing && (state.keyguardOccluded || state.keyguardNeedsInput)
                 || ENABLE_REMOTE_INPUT && state.remoteInputActive
                 || state.bubbleExpanded) {
-            mLpChanged.flags &= ~WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;
-            mLpChanged.flags &= ~WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM;
+            mLpChanged.flags &= ~LayoutParams.FLAG_NOT_FOCUSABLE;
+            mLpChanged.flags &= ~LayoutParams.FLAG_ALT_FOCUSABLE_IM;
         } else if (state.isKeyguardShowingAndNotOccluded() || panelFocusable) {
-            mLpChanged.flags &= ~WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;
-            mLpChanged.flags |= WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM;
+            mLpChanged.flags &= ~LayoutParams.FLAG_NOT_FOCUSABLE;
+            mLpChanged.flags |= LayoutParams.FLAG_ALT_FOCUSABLE_IM;
         } else {
-            mLpChanged.flags |= WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;
-            mLpChanged.flags &= ~WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM;
+            mLpChanged.flags |= LayoutParams.FLAG_NOT_FOCUSABLE;
+            mLpChanged.flags &= ~LayoutParams.FLAG_ALT_FOCUSABLE_IM;
         }
 
-        mLpChanged.softInputMode = WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE;
+        mLpChanged.softInputMode = LayoutParams.SOFT_INPUT_ADJUST_RESIZE;
     }
 
     private void applyForceShowNavigationFlag(State state) {
@@ -279,7 +323,8 @@
         if (state.isKeyguardShowingAndNotOccluded()
                 && state.statusBarState == StatusBarState.KEYGUARD
                 && !state.qsExpanded) {
-            mLpChanged.userActivityTimeout = KeyguardViewMediator.AWAKE_INTERVAL_DEFAULT_MS;
+            mLpChanged.userActivityTimeout = state.bouncerShowing
+                    ? KeyguardViewMediator.AWAKE_INTERVAL_BOUNCER_MS : mLockScreenDisplayTimeout;
         } else {
             mLpChanged.userActivityTimeout = -1;
         }
@@ -290,19 +335,19 @@
                 && state.statusBarState == StatusBarState.KEYGUARD
                 && !state.qsExpanded && !state.forceUserActivity) {
             mLpChanged.inputFeatures |=
-                    WindowManager.LayoutParams.INPUT_FEATURE_DISABLE_USER_ACTIVITY;
+                    LayoutParams.INPUT_FEATURE_DISABLE_USER_ACTIVITY;
         } else {
             mLpChanged.inputFeatures &=
-                    ~WindowManager.LayoutParams.INPUT_FEATURE_DISABLE_USER_ACTIVITY;
+                    ~LayoutParams.INPUT_FEATURE_DISABLE_USER_ACTIVITY;
         }
     }
 
     private void applyStatusBarColorSpaceAgnosticFlag(State state) {
         if (!isExpanded(state)) {
-            mLpChanged.privateFlags |= WindowManager.LayoutParams.PRIVATE_FLAG_COLOR_SPACE_AGNOSTIC;
+            mLpChanged.privateFlags |= LayoutParams.PRIVATE_FLAG_COLOR_SPACE_AGNOSTIC;
         } else {
             mLpChanged.privateFlags &=
-                    ~WindowManager.LayoutParams.PRIVATE_FLAG_COLOR_SPACE_AGNOSTIC;
+                    ~LayoutParams.PRIVATE_FLAG_COLOR_SPACE_AGNOSTIC;
         }
     }
 
@@ -347,20 +392,20 @@
     }
 
     private void applyForceStatusBarVisibleFlag(State state) {
-        if (state.forceStatusBarVisible) {
+        if (state.forceStatusBarVisible || state.forcePluginOpen) {
             mLpChanged.privateFlags |= WindowManager
                     .LayoutParams.PRIVATE_FLAG_FORCE_STATUS_BAR_VISIBLE_TRANSPARENT;
         } else {
-            mLpChanged.privateFlags &= ~WindowManager
-                    .LayoutParams.PRIVATE_FLAG_FORCE_STATUS_BAR_VISIBLE_TRANSPARENT;
+            mLpChanged.privateFlags
+                    &= ~LayoutParams.PRIVATE_FLAG_FORCE_STATUS_BAR_VISIBLE_TRANSPARENT;
         }
     }
 
     private void applyModalFlag(State state) {
         if (state.headsUpShowing) {
-            mLpChanged.flags |= WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL;
+            mLpChanged.flags |= LayoutParams.FLAG_NOT_TOUCH_MODAL;
         } else {
-            mLpChanged.flags &= ~WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL;
+            mLpChanged.flags &= ~LayoutParams.FLAG_NOT_TOUCH_MODAL;
         }
     }
 
@@ -368,12 +413,12 @@
         if (state.forceDozeBrightness) {
             mLpChanged.screenBrightness = mScreenBrightnessDoze;
         } else {
-            mLpChanged.screenBrightness = WindowManager.LayoutParams.BRIGHTNESS_OVERRIDE_NONE;
+            mLpChanged.screenBrightness = LayoutParams.BRIGHTNESS_OVERRIDE_NONE;
         }
     }
 
     private void applyHasTopUi(State state) {
-        mHasTopUiChanged = isExpanded(state);
+        mHasTopUiChanged = state.forceHasTopUi || isExpanded(state);
     }
 
     private void applyNotTouchable(State state) {
@@ -506,6 +551,16 @@
     public void setForcePluginOpen(boolean forcePluginOpen) {
         mCurrentState.forcePluginOpen = forcePluginOpen;
         apply(mCurrentState);
+        if (mForcePluginOpenListener != null) {
+            mForcePluginOpenListener.onChange(forcePluginOpen);
+        }
+    }
+
+    /**
+     * The forcePluginOpen state for the status bar.
+     */
+    public boolean getForcePluginOpen() {
+        return mCurrentState.forcePluginOpen;
     }
 
     public void setNotTouchable(boolean notTouchable) {
@@ -554,8 +609,13 @@
         mListener = listener;
     }
 
+    public void setForcePluginOpenListener(ForcePluginOpenListener listener) {
+        mForcePluginOpenListener = listener;
+    }
+
     public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
-        pw.println("StatusBarWindowController state:");
+        pw.println("StatusBarWindowController:");
+        pw.println("  mKeyguardDisplayMode=" + mKeyguardDisplayMode);
         pw.println(mCurrentState);
     }
 
@@ -574,6 +634,23 @@
         setKeyguardDark(useDarkText);
     }
 
+    /**
+     * When keyguard will be dismissed but didn't start animation yet.
+     */
+    public void setKeyguardGoingAway(boolean goingAway) {
+        mCurrentState.keyguardGoingAway = goingAway;
+        apply(mCurrentState);
+    }
+
+    public boolean getForceHasTopUi() {
+        return mCurrentState.forceHasTopUi;
+    }
+
+    public void setForceHasTopUi(boolean forceHasTopUi) {
+        mCurrentState.forceHasTopUi = forceHasTopUi;
+        apply(mCurrentState);
+    }
+
     private static class State {
         boolean keyguardShowing;
         boolean keyguardOccluded;
@@ -583,6 +660,7 @@
         boolean statusBarFocusable;
         boolean bouncerShowing;
         boolean keyguardFadingAway;
+        boolean keyguardGoingAway;
         boolean qsExpanded;
         boolean headsUpShowing;
         boolean forceStatusBarVisible;
@@ -594,6 +672,7 @@
         boolean notTouchable;
         boolean bubblesShowing;
         boolean bubbleExpanded;
+        boolean forceHasTopUi;
 
         /**
          * The {@link StatusBar} state from the status bar.
@@ -656,4 +735,14 @@
     public interface OtherwisedCollapsedListener {
         void setWouldOtherwiseCollapse(boolean otherwiseCollapse);
     }
+
+    /**
+     * Listener to indicate forcePluginOpen has changed
+     */
+    public interface ForcePluginOpenListener {
+        /**
+         * Called when mState.forcePluginOpen is changed
+         */
+        void onChange(boolean forceOpen);
+    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowView.java
index 7d5f23b..1081bad 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowView.java
@@ -67,6 +67,7 @@
 import com.android.systemui.plugins.statusbar.StatusBarStateController;
 import com.android.systemui.statusbar.DragDownHelper;
 import com.android.systemui.statusbar.StatusBarState;
+import com.android.systemui.statusbar.notification.DynamicPrivacyController;
 import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayout;
 import com.android.systemui.statusbar.phone.ScrimController.ScrimVisibility;
 import com.android.systemui.tuner.TunerService;
@@ -149,6 +150,7 @@
      * events manually as it's outside of the regular view bounds.
      */
     private boolean mExpandingBelowNotch;
+    private KeyguardBypassController mBypassController;
 
     public StatusBarWindowView(Context context, AttributeSet attrs) {
         super(context, attrs);
@@ -271,10 +273,11 @@
     /**
      * Called when the biometric authentication mode changes.
      * @param wakeAndUnlock If the type is {@link BiometricUnlockController#isWakeAndUnlock()}
+     * @param isUnlock If the type is {@link BiometricUnlockController#isBiometricUnlock()} ()
      */
-    public void onBiometricAuthModeChanged(boolean wakeAndUnlock) {
+    public void onBiometricAuthModeChanged(boolean wakeAndUnlock, boolean isUnlock) {
         if (mLockIcon != null) {
-            mLockIcon.onBiometricAuthModeChanged(wakeAndUnlock);
+            mLockIcon.onBiometricAuthModeChanged(wakeAndUnlock, isUnlock);
         }
     }
 
@@ -415,8 +418,7 @@
         }
         boolean intercept = false;
         if (mNotificationPanel.isFullyExpanded()
-                && stackScrollLayout.getVisibility() == View.VISIBLE
-                && mStatusBarStateController.getState() == StatusBarState.KEYGUARD
+                && mDragDownHelper.isDragDownEnabled()
                 && !mService.isBouncerShowing()
                 && !mService.isDozing()) {
             intercept = mDragDownHelper.onInterceptTouchEvent(ev);
@@ -440,8 +442,7 @@
         if (mService.isDozing()) {
             handled = !mService.isPulsing();
         }
-        if ((mStatusBarStateController.getState() == StatusBarState.KEYGUARD && !handled)
-                || mDragDownHelper.isDraggingDown()) {
+        if ((mDragDownHelper.isDragDownEnabled() && !handled) || mDragDownHelper.isDraggingDown()) {
             // we still want to finish our drag down gesture when locking the screen
             handled = mDragDownHelper.onTouchEvent(ev);
         }
@@ -519,6 +520,16 @@
         }
     }
 
+    public void setBypassController(KeyguardBypassController bypassController) {
+        mBypassController = bypassController;
+    }
+
+    public void setBouncerShowingScrimmed(boolean bouncerShowing) {
+        if (mLockIcon != null) {
+            mLockIcon.setBouncerShowingScrimmed(bouncerShowing);
+        }
+    }
+
     public class LayoutParams extends FrameLayout.LayoutParams {
 
         public boolean ignoreRightInset;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/UnlockMethodCache.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/UnlockMethodCache.java
index 39bf728..b1d6ca6 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/UnlockMethodCache.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/UnlockMethodCache.java
@@ -16,22 +16,19 @@
 
 package com.android.systemui.statusbar.phone;
 
-import android.app.admin.DevicePolicyManager;
 import android.content.BroadcastReceiver;
 import android.content.Context;
 import android.content.Intent;
 import android.content.IntentFilter;
 import android.hardware.biometrics.BiometricSourceType;
-import android.media.AudioManager;
 import android.os.Build;
 import android.os.Trace;
-import android.telephony.TelephonyManager;
 
-import com.android.internal.telephony.TelephonyIntents;
 import com.android.internal.widget.LockPatternUtils;
 import com.android.keyguard.KeyguardUpdateMonitor;
 import com.android.keyguard.KeyguardUpdateMonitorCallback;
 
+import java.io.PrintWriter;
 import java.util.ArrayList;
 
 /**
@@ -55,6 +52,7 @@
     private boolean mTrustManaged;
     private boolean mTrusted;
     private boolean mDebugUnlocked = false;
+    private boolean mFaceAuthEnabled;
 
     private UnlockMethodCache(Context ctx) {
         mLockPatternUtils = new LockPatternUtils(ctx);
@@ -110,6 +108,13 @@
         mListeners.remove(listener);
     }
 
+    /**
+     * If there are faces enrolled and user enabled face auth on keyguard.
+     */
+    public boolean isFaceAuthEnabled() {
+        return mFaceAuthEnabled;
+    }
+
     private void update(boolean updateAlways) {
         Trace.beginSection("UnlockMethodCache#update");
         int user = KeyguardUpdateMonitor.getCurrentUser();
@@ -118,13 +123,16 @@
                 || (Build.IS_DEBUGGABLE && DEBUG_AUTH_WITH_ADB && mDebugUnlocked);
         boolean trustManaged = mKeyguardUpdateMonitor.getUserTrustIsManaged(user);
         boolean trusted = mKeyguardUpdateMonitor.getUserHasTrust(user);
-        boolean changed = secure != mSecure || canSkipBouncer != mCanSkipBouncer ||
-                trustManaged != mTrustManaged;
+        boolean faceAuthEnabled = mKeyguardUpdateMonitor.isFaceAuthEnabledForUser(user);
+        boolean changed = secure != mSecure || canSkipBouncer != mCanSkipBouncer
+                || trustManaged != mTrustManaged
+                || mFaceAuthEnabled != faceAuthEnabled;
         if (changed || updateAlways) {
             mSecure = secure;
             mCanSkipBouncer = canSkipBouncer;
             mTrusted = trusted;
             mTrustManaged = trustManaged;
+            mFaceAuthEnabled = faceAuthEnabled;
             notifyListeners();
         }
         Trace.endSection();
@@ -136,6 +144,16 @@
         }
     }
 
+    public void dump(PrintWriter pw) {
+        pw.println("UnlockMethodCache");
+        pw.println("  mSecure: " + mSecure);
+        pw.println("  mCanSkipBouncer: " + mCanSkipBouncer);
+        pw.println("  mTrustManaged: " + mTrustManaged);
+        pw.println("  mTrusted: " + mTrusted);
+        pw.println("  mDebugUnlocked: " + mDebugUnlocked);
+        pw.println("  mFaceAuthEnabled: " + mFaceAuthEnabled);
+    }
+
     private final KeyguardUpdateMonitorCallback mCallback = new KeyguardUpdateMonitorCallback() {
         @Override
         public void onUserSwitchComplete(int userId) {
@@ -187,6 +205,11 @@
         public void onKeyguardVisibilityChanged(boolean showing) {
             update(false /* updateAlways */);
         }
+
+        @Override
+        public void onBiometricsCleared() {
+            update(false /* alwaysUpdate */);
+        }
     };
 
     public boolean isTrustManaged() {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/HeadsUpManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/HeadsUpManager.java
index d1a2253..b84dc47 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/HeadsUpManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/HeadsUpManager.java
@@ -356,6 +356,10 @@
     public void onDensityOrFontScaleChanged() {
     }
 
+    public boolean isEntryAutoHeadsUpped(String key) {
+        return false;
+    }
+
     /**
      * This represents a notification and how long it is in a heads up mode. It also manages its
      * lifecycle automatically when created.
@@ -416,16 +420,17 @@
 
         @Override
         protected long calculateFinishTime() {
-            return mPostTime + getRecommendedTimeoutMillis();
+            return mPostTime + getRecommendedHeadsUpTimeoutMs(mAutoDismissNotificationDecay);
         }
 
         /**
          * Get user-preferred or default timeout duration. The larger one will be returned.
          * @return milliseconds before auto-dismiss
+         * @param requestedTimeout
          */
-        private int getRecommendedTimeoutMillis() {
+        protected int getRecommendedHeadsUpTimeoutMs(int requestedTimeout) {
             return mAccessibilityMgr.getRecommendedTimeoutMillis(
-                    mAutoDismissNotificationDecay,
+                    requestedTimeout,
                     AccessibilityManager.FLAG_CONTENT_CONTROLS
                             | AccessibilityManager.FLAG_CONTENT_ICONS
                             | AccessibilityManager.FLAG_CONTENT_TEXT);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardMonitor.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardMonitor.java
index 01498e6..6dc90b9 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardMonitor.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardMonitor.java
@@ -19,7 +19,6 @@
 public interface KeyguardMonitor extends CallbackController<Callback> {
 
     boolean isSecure();
-    boolean canSkipBouncer();
     boolean isShowing();
     boolean isOccluded();
     boolean isKeyguardFadingAway();
@@ -29,6 +28,19 @@
     long getKeyguardFadingAwayDelay();
     long calculateGoingToFullShadeDelay();
 
+    /**
+     * @return a shortened fading away duration similar to
+     * {{@link #getKeyguardFadingAwayDuration()}} which may only span half of the duration, unless
+     * we're bypassing
+     */
+    default long getShortenedFadingAwayDuration() {
+        if (isBypassFadingAnimation()) {
+            return getKeyguardFadingAwayDuration();
+        } else {
+            return getKeyguardFadingAwayDuration() / 2;
+        }
+    }
+
     default boolean isDeviceInteractive() {
         return false;
     }
@@ -39,7 +51,21 @@
     default void notifyKeyguardGoingAway(boolean b) {
     }
 
-    default void notifyKeyguardFadingAway(long delay, long fadeoutDuration) {
+    /**
+     * @return {@code true} if the current fading away animation is the fast bypass fading.
+     */
+    default boolean isBypassFadingAnimation() {
+        return false;
+    }
+
+    /**
+     * Notifies that the Keyguard is fading away with the specified timings.
+     * @param delay the precalculated animation delay in milliseconds
+     * @param fadeoutDuration the duration of the exit animation, in milliseconds
+     * @param isBypassFading is this a fading away animation while bypassing
+     */
+    default void notifyKeyguardFadingAway(long delay, long fadeoutDuration,
+            boolean isBypassFading) {
     }
 
     default void notifyKeyguardDoneFading() {
@@ -49,6 +75,7 @@
     }
 
     interface Callback {
-        void onKeyguardShowingChanged();
+        default void onKeyguardShowingChanged() {}
+        default void onKeyguardFadingAwayChanged() {}
     }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardMonitorImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardMonitorImpl.java
index b53ff0e..26d615c 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardMonitorImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardMonitorImpl.java
@@ -17,13 +17,11 @@
 package com.android.systemui.statusbar.policy;
 
 import android.annotation.NonNull;
-import android.app.ActivityManager;
 import android.content.Context;
 
 import com.android.internal.util.Preconditions;
 import com.android.keyguard.KeyguardUpdateMonitor;
 import com.android.keyguard.KeyguardUpdateMonitorCallback;
-import com.android.systemui.settings.CurrentUserTracker;
 
 import java.util.ArrayList;
 
@@ -39,14 +37,11 @@
     private final ArrayList<Callback> mCallbacks = new ArrayList<>();
 
     private final Context mContext;
-    private final CurrentUserTracker mUserTracker;
     private final KeyguardUpdateMonitor mKeyguardUpdateMonitor;
 
-    private int mCurrentUser;
     private boolean mShowing;
     private boolean mSecure;
     private boolean mOccluded;
-    private boolean mCanSkipBouncer;
 
     private boolean mListening;
     private boolean mKeyguardFadingAway;
@@ -54,6 +49,7 @@
     private long mKeyguardFadingAwayDuration;
     private boolean mKeyguardGoingAway;
     private boolean mLaunchTransitionFadingAway;
+    private boolean mBypassFadingAnimation;
 
     /**
      */
@@ -61,13 +57,6 @@
     public KeyguardMonitorImpl(Context context) {
         mContext = context;
         mKeyguardUpdateMonitor = KeyguardUpdateMonitor.getInstance(mContext);
-        mUserTracker = new CurrentUserTracker(mContext) {
-            @Override
-            public void onUserSwitched(int newUserId) {
-                mCurrentUser = newUserId;
-                updateCanSkipBouncerState();
-            }
-        };
     }
 
     @Override
@@ -76,10 +65,7 @@
         mCallbacks.add(callback);
         if (mCallbacks.size() != 0 && !mListening) {
             mListening = true;
-            mCurrentUser = ActivityManager.getCurrentUser();
-            updateCanSkipBouncerState();
             mKeyguardUpdateMonitor.registerCallback(this);
-            mUserTracker.startTracking();
         }
     }
 
@@ -89,7 +75,6 @@
         if (mCallbacks.remove(callback) && mCallbacks.size() == 0 && mListening) {
             mListening = false;
             mKeyguardUpdateMonitor.removeCallback(this);
-            mUserTracker.stopTracking();
         }
     }
 
@@ -108,11 +93,6 @@
         return mOccluded;
     }
 
-    @Override
-    public boolean canSkipBouncer() {
-        return mCanSkipBouncer;
-    }
-
     public void notifyKeyguardState(boolean showing, boolean secure, boolean occluded) {
         if (mShowing == showing && mSecure == secure && mOccluded == occluded) return;
         mShowing = showing;
@@ -123,7 +103,6 @@
 
     @Override
     public void onTrustChanged(int userId) {
-        updateCanSkipBouncerState();
         notifyKeyguardChanged();
     }
 
@@ -131,24 +110,31 @@
         return mKeyguardUpdateMonitor.isDeviceInteractive();
     }
 
-    private void updateCanSkipBouncerState() {
-        mCanSkipBouncer = mKeyguardUpdateMonitor.getUserCanSkipBouncer(mCurrentUser);
-    }
-
     private void notifyKeyguardChanged() {
         // Copy the list to allow removal during callback.
         new ArrayList<>(mCallbacks).forEach(Callback::onKeyguardShowingChanged);
     }
 
-    public void notifyKeyguardFadingAway(long delay, long fadeoutDuration) {
-        mKeyguardFadingAway = true;
+    public void notifyKeyguardFadingAway(long delay, long fadeoutDuration, boolean isBypassFading) {
         mKeyguardFadingAwayDelay = delay;
         mKeyguardFadingAwayDuration = fadeoutDuration;
+        mBypassFadingAnimation = isBypassFading;
+        setKeyguardFadingAway(true);
+    }
+
+    private void setKeyguardFadingAway(boolean keyguardFadingAway) {
+        if (mKeyguardFadingAway != keyguardFadingAway) {
+            mKeyguardFadingAway = keyguardFadingAway;
+            ArrayList<Callback> callbacks = new ArrayList<>(mCallbacks);
+            for (int i = 0; i < callbacks.size(); i++) {
+                callbacks.get(i).onKeyguardFadingAwayChanged();
+            }
+        }
     }
 
     public void notifyKeyguardDoneFading() {
-        mKeyguardFadingAway = false;
         mKeyguardGoingAway = false;
+        setKeyguardFadingAway(false);
     }
 
     @Override
@@ -162,6 +148,11 @@
     }
 
     @Override
+    public boolean isBypassFadingAnimation() {
+        return mBypassFadingAnimation;
+    }
+
+    @Override
     public long getKeyguardFadingAwayDelay() {
         return mKeyguardFadingAwayDelay;
     }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/MobileSignalController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/MobileSignalController.java
index 13f93b9..e75365e 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/MobileSignalController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/MobileSignalController.java
@@ -163,7 +163,8 @@
                         | PhoneStateListener.LISTEN_CALL_STATE
                         | PhoneStateListener.LISTEN_DATA_CONNECTION_STATE
                         | PhoneStateListener.LISTEN_DATA_ACTIVITY
-                        | PhoneStateListener.LISTEN_CARRIER_NETWORK_CHANGE);
+                        | PhoneStateListener.LISTEN_CARRIER_NETWORK_CHANGE
+                        | PhoneStateListener.LISTEN_ACTIVE_DATA_SUBSCRIPTION_ID_CHANGE);
         mContext.getContentResolver().registerContentObserver(Global.getUriFor(Global.MOBILE_DATA),
                 true, mObserver);
         mContext.getContentResolver().registerContentObserver(Global.getUriFor(
@@ -215,10 +216,14 @@
 
         MobileIconGroup hGroup = TelephonyIcons.THREE_G;
         MobileIconGroup hPlusGroup = TelephonyIcons.THREE_G;
-        if (mConfig.hspaDataDistinguishable) {
+        if (mConfig.show4gFor3g) {
+            hGroup = TelephonyIcons.FOUR_G;
+            hPlusGroup = TelephonyIcons.FOUR_G;
+        } else if (mConfig.hspaDataDistinguishable) {
             hGroup = TelephonyIcons.H;
             hPlusGroup = TelephonyIcons.H_PLUS;
         }
+
         mNetworkToIconLookup.put(TelephonyManager.NETWORK_TYPE_HSDPA, hGroup);
         mNetworkToIconLookup.put(TelephonyManager.NETWORK_TYPE_HSUPA, hGroup);
         mNetworkToIconLookup.put(TelephonyManager.NETWORK_TYPE_HSPA, hGroup);
@@ -376,9 +381,9 @@
     }
 
     private void updateDataSim() {
-        int defaultDataSub = mDefaults.getDefaultDataSubId();
-        if (SubscriptionManager.isValidSubscriptionId(defaultDataSub)) {
-            mCurrentState.dataSim = defaultDataSub == mSubscriptionInfo.getSubscriptionId();
+        int activeDataSubId = mDefaults.getActiveDataSubId();
+        if (SubscriptionManager.isValidSubscriptionId(activeDataSubId)) {
+            mCurrentState.dataSim = activeDataSubId == mSubscriptionInfo.getSubscriptionId();
         } else {
             // There doesn't seem to be a data sim selected, however if
             // there isn't a MobileSignalController with dataSim set, then
@@ -636,6 +641,13 @@
 
             updateTelephony();
         }
+
+        @Override
+        public void onActiveDataSubscriptionIdChanged(int subId) {
+            if (DEBUG) Log.d(mTag, "onActiveDataSubscriptionIdChanged: subId=" + subId);
+            updateDataSim();
+            updateTelephony();
+        }
     };
 
     static class MobileIconGroup extends SignalController.IconGroup {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java
index b2972fc..1c24bb9 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java
@@ -361,7 +361,7 @@
     }
 
     private MobileSignalController getDataController() {
-        int dataSubId = mSubDefaults.getDefaultDataSubId();
+        int dataSubId = mSubDefaults.getActiveDataSubId();
         if (!SubscriptionManager.isValidSubscriptionId(dataSubId)) {
             if (DEBUG) Log.e(TAG, "No data sim selected");
             return mDefaultSignalController;
@@ -1098,6 +1098,10 @@
         public int getDefaultDataSubId() {
             return SubscriptionManager.getDefaultDataSubscriptionId();
         }
+
+        public int getActiveDataSubId() {
+            return SubscriptionManager.getActiveDataSubscriptionId();
+        }
     }
 
     @VisibleForTesting
@@ -1110,6 +1114,7 @@
         Map<Integer, MobileIconGroup> nr5GIconMap = new HashMap<>();
 
         boolean showAtLeast3G = false;
+        boolean show4gFor3g = false;
         boolean alwaysShowCdmaRssi = false;
         boolean show4gForLte = false;
         boolean hideLtePlus = false;
@@ -1154,6 +1159,8 @@
                         CarrierConfigManager.KEY_ALWAYS_SHOW_DATA_RAT_ICON_BOOL);
                 config.show4gForLte = b.getBoolean(
                         CarrierConfigManager.KEY_SHOW_4G_FOR_LTE_DATA_ICON_BOOL);
+                config.show4gFor3g = b.getBoolean(
+                        CarrierConfigManager.KEY_SHOW_4G_FOR_3G_DATA_ICON_BOOL);
                 config.hideLtePlus = b.getBoolean(
                         CarrierConfigManager.KEY_HIDE_LTE_PLUS_DATA_ICON_BOOL);
                 config.patternOfCarrierSpecificDataIcon = b.getString(
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/OnHeadsUpChangedListener.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/OnHeadsUpChangedListener.java
index 438226a..94aa391 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/OnHeadsUpChangedListener.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/OnHeadsUpChangedListener.java
@@ -16,6 +16,8 @@
 
 package com.android.systemui.statusbar.policy;
 
+import android.annotation.NonNull;
+
 import com.android.systemui.statusbar.notification.collection.NotificationEntry;
 
 /**
@@ -45,5 +47,5 @@
      * @param entry     the entry of the changed notification
      * @param isHeadsUp whether the notification is now a headsUp notification
      */
-    default void onHeadsUpStateChanged(NotificationEntry entry, boolean isHeadsUp) {}
+    default void onHeadsUpStateChanged(@NonNull NotificationEntry entry, boolean isHeadsUp) {}
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/SmartReplyView.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/SmartReplyView.java
index 640f0f0..282d28c 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/SmartReplyView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/SmartReplyView.java
@@ -303,7 +303,7 @@
         };
 
         OnClickListener onClickListener = view ->
-            smartReplyView.mKeyguardDismissUtil.executeWhenUnlocked(action);
+            smartReplyView.mKeyguardDismissUtil.executeWhenUnlocked(action, !entry.isRowPinned());
         if (useDelayedOnClickListener) {
             onClickListener = new DelayedOnClickListener(onClickListener,
                     smartReplyView.mConstants.getOnClickInitDelay());
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/UserSwitcherController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/UserSwitcherController.java
index 395add7..35e3923 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/UserSwitcherController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/UserSwitcherController.java
@@ -61,6 +61,7 @@
 import com.android.systemui.plugins.qs.DetailAdapter;
 import com.android.systemui.qs.tiles.UserDetailView;
 import com.android.systemui.statusbar.phone.SystemUIDialog;
+import com.android.systemui.statusbar.phone.UnlockMethodCache;
 
 import java.io.FileDescriptor;
 import java.io.PrintWriter;
@@ -595,17 +596,19 @@
 
         final UserSwitcherController mController;
         private final KeyguardMonitor mKeyguardMonitor;
+        private final UnlockMethodCache mUnlockMethodCache;
 
         protected BaseUserAdapter(UserSwitcherController controller) {
             mController = controller;
             mKeyguardMonitor = controller.mKeyguardMonitor;
+            mUnlockMethodCache = UnlockMethodCache.getInstance(controller.mContext);
             controller.addAdapter(new WeakReference<>(this));
         }
 
         public int getUserCount() {
             boolean secureKeyguardShowing = mKeyguardMonitor.isShowing()
                     && mKeyguardMonitor.isSecure()
-                    && !mKeyguardMonitor.canSkipBouncer();
+                    && !mUnlockMethodCache.canSkipBouncer();
             if (!secureKeyguardShowing) {
                 return mController.getUsers().size();
             }
@@ -627,7 +630,7 @@
         public int getCount() {
             boolean secureKeyguardShowing = mKeyguardMonitor.isShowing()
                     && mKeyguardMonitor.isSecure()
-                    && !mKeyguardMonitor.canSkipBouncer();
+                    && !mUnlockMethodCache.canSkipBouncer();
             if (!secureKeyguardShowing) {
                 return mController.getUsers().size();
             }
diff --git a/packages/SystemUI/src/com/android/systemui/theme/ThemeOverlayManager.java b/packages/SystemUI/src/com/android/systemui/theme/ThemeOverlayManager.java
index 930016b..41e026a 100644
--- a/packages/SystemUI/src/com/android/systemui/theme/ThemeOverlayManager.java
+++ b/packages/SystemUI/src/com/android/systemui/theme/ThemeOverlayManager.java
@@ -172,10 +172,15 @@
     private void setEnabledAsync(String pkg, UserHandle userHandle, boolean enabled) {
         mExecutor.execute(() -> {
             if (DEBUG) Log.d(TAG, String.format("setEnabled: %s %s %b", pkg, userHandle, enabled));
-            if (enabled) {
-                mOverlayManager.setEnabledExclusiveInCategory(pkg, userHandle);
-            } else {
-                mOverlayManager.setEnabled(pkg, false, userHandle);
+            try {
+                if (enabled) {
+                    mOverlayManager.setEnabledExclusiveInCategory(pkg, userHandle);
+                } else {
+                    mOverlayManager.setEnabled(pkg, false, userHandle);
+                }
+            } catch (IllegalStateException e) {
+                Log.e(TAG,
+                        String.format("setEnabled failed: %s %s %b", pkg, userHandle, enabled), e);
             }
         });
     }
diff --git a/packages/SystemUI/src/com/android/systemui/util/AsyncSensorManager.java b/packages/SystemUI/src/com/android/systemui/util/AsyncSensorManager.java
index 31f4991..b9c5ee5 100644
--- a/packages/SystemUI/src/com/android/systemui/util/AsyncSensorManager.java
+++ b/packages/SystemUI/src/com/android/systemui/util/AsyncSensorManager.java
@@ -156,17 +156,21 @@
      * Requests for all sensors that match the given type from all plugins.
      * @param sensor
      * @param listener
+     * @return true if there were plugins to register the listener to
      */
-    public void registerPluginListener(SensorManagerPlugin.Sensor sensor,
+    public boolean registerPluginListener(SensorManagerPlugin.Sensor sensor,
             SensorManagerPlugin.SensorEventListener listener) {
         if (mPlugins.isEmpty()) {
             Log.w(TAG, "No plugins registered");
+            return false;
         }
         mHandler.post(() -> {
             for (int i = 0; i < mPlugins.size(); i++) {
                 mPlugins.get(i).registerListener(sensor, listener);
             }
         });
+
+        return true;
     }
 
     /**
diff --git a/packages/SystemUI/src/com/android/systemui/util/InjectionInflationController.java b/packages/SystemUI/src/com/android/systemui/util/InjectionInflationController.java
index d521e55..ede3004 100644
--- a/packages/SystemUI/src/com/android/systemui/util/InjectionInflationController.java
+++ b/packages/SystemUI/src/com/android/systemui/util/InjectionInflationController.java
@@ -32,6 +32,7 @@
 import com.android.systemui.qs.QSPanel;
 import com.android.systemui.qs.QuickQSPanel;
 import com.android.systemui.qs.QuickStatusBarHeader;
+import com.android.systemui.statusbar.NotificationShelf;
 import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayout;
 import com.android.systemui.statusbar.phone.LockIcon;
 import com.android.systemui.statusbar.phone.NotificationPanelView;
@@ -138,6 +139,11 @@
         QSCarrierGroup createQSCarrierGroup();
 
         /**
+         * Creates the Shelf.
+         */
+        NotificationShelf creatNotificationShelf();
+
+        /**
          * Creates the KeyguardClockSwitch.
          */
         KeyguardClockSwitch createKeyguardClockSwitch();
diff --git a/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogControllerImpl.java b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogControllerImpl.java
index 69d2e31..d3862b6 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogControllerImpl.java
@@ -43,6 +43,7 @@
 import android.os.Message;
 import android.os.RemoteException;
 import android.os.ServiceManager;
+import android.os.UserHandle;
 import android.os.VibrationEffect;
 import android.os.Vibrator;
 import android.provider.Settings;
@@ -272,14 +273,14 @@
     }
 
     public boolean areCaptionsEnabled() {
-        int currentValue = Settings.Secure.getInt(mContext.getContentResolver(),
-                Settings.Secure.ODI_CAPTIONS_ENABLED, 0);
+        int currentValue = Settings.Secure.getIntForUser(mContext.getContentResolver(),
+                Settings.Secure.ODI_CAPTIONS_ENABLED, 0, UserHandle.USER_CURRENT);
         return currentValue == 1;
     }
 
     public void setCaptionsEnabled(boolean isEnabled) {
-        Settings.Secure.putInt(mContext.getContentResolver(),
-                Settings.Secure.ODI_CAPTIONS_ENABLED, isEnabled ? 1 : 0);
+        Settings.Secure.putIntForUser(mContext.getContentResolver(),
+                Settings.Secure.ODI_CAPTIONS_ENABLED, isEnabled ? 1 : 0, UserHandle.USER_CURRENT);
     }
 
     @Override
diff --git a/packages/SystemUI/tests/res/values/overlayable_icons_test.xml b/packages/SystemUI/tests/res/values/overlayable_icons_test.xml
index ba651ac..24cd8cb 100644
--- a/packages/SystemUI/tests/res/values/overlayable_icons_test.xml
+++ b/packages/SystemUI/tests/res/values/overlayable_icons_test.xml
@@ -59,6 +59,8 @@
     <item>@drawable/ic_volume_bt_sco</item>
     <item>@drawable/ic_volume_media</item>
     <item>@drawable/ic_volume_media_mute</item>
+    <item>@drawable/ic_volume_odi_captions</item>
+    <item>@drawable/ic_volume_odi_captions_disabled</item>
     <item>@drawable/ic_volume_ringer</item>
     <item>@drawable/ic_volume_ringer_mute</item>
     <item>@drawable/ic_volume_ringer_vibrate</item>
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/keyguard/KeyguardUpdateMonitorTest.java b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardUpdateMonitorTest.java
index 6208ab8..db6177a 100644
--- a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardUpdateMonitorTest.java
+++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardUpdateMonitorTest.java
@@ -21,6 +21,7 @@
 import static org.mockito.ArgumentMatchers.any;
 import static org.mockito.ArgumentMatchers.anyInt;
 import static org.mockito.ArgumentMatchers.anyString;
+import static org.mockito.Mockito.clearInvocations;
 import static org.mockito.Mockito.doAnswer;
 import static org.mockito.Mockito.never;
 import static org.mockito.Mockito.reset;
@@ -52,6 +53,7 @@
 import com.android.internal.telephony.PhoneConstants;
 import com.android.internal.telephony.TelephonyIntents;
 import com.android.systemui.SysuiTestCase;
+import com.android.systemui.statusbar.phone.KeyguardBypassController;
 
 import org.junit.Assert;
 import org.junit.Before;
@@ -88,6 +90,8 @@
     private UserManager mUserManager;
     @Mock
     private DevicePolicyManager mDevicePolicyManager;
+    @Mock
+    private KeyguardBypassController mKeyguardBypassController;
     private TestableLooper mTestableLooper;
     private TestableKeyguardUpdateMonitor mKeyguardUpdateMonitor;
 
@@ -99,7 +103,8 @@
         when(context.getPackageManager()).thenReturn(mPackageManager);
         doAnswer(invocation -> {
             IBiometricEnabledOnKeyguardCallback callback = invocation.getArgument(0);
-            callback.onChanged(BiometricSourceType.FACE, true /* enabled */);
+            callback.onChanged(BiometricSourceType.FACE, true /* enabled */,
+                    KeyguardUpdateMonitor.getCurrentUser());
             return null;
         }).when(mBiometricManager).registerEnabledOnKeyguardCallback(any());
         when(mFaceManager.isHardwareDetected()).thenReturn(true);
@@ -314,13 +319,44 @@
 
     @Test
     public void skipsAuthentication_whenEncryptedKeyguard() {
-        reset(mUserManager);
-        when(mUserManager.isUserUnlocked(anyInt())).thenReturn(false);
+        when(mStrongAuthTracker.getStrongAuthForUser(anyInt())).thenReturn(
+                KeyguardUpdateMonitor.StrongAuthTracker.STRONG_AUTH_REQUIRED_AFTER_BOOT);
+        mKeyguardUpdateMonitor.setKeyguardBypassController(mKeyguardBypassController);
 
         mKeyguardUpdateMonitor.dispatchStartedWakingUp();
         mTestableLooper.processAllMessages();
         mKeyguardUpdateMonitor.onKeyguardVisibilityChanged(true);
-        verify(mFaceManager, never()).authenticate(any(), any(), anyInt(), any(), any());
+        verify(mFaceManager, never()).authenticate(any(), any(), anyInt(), any(), any(), anyInt());
+    }
+
+    @Test
+    public void requiresAuthentication_whenEncryptedKeyguard_andBypass() {
+        testStrongAuthExceptOnBouncer(
+                KeyguardUpdateMonitor.StrongAuthTracker.STRONG_AUTH_REQUIRED_AFTER_BOOT);
+    }
+
+    @Test
+    public void requiresAuthentication_whenTimeoutKeyguard_andBypass() {
+        testStrongAuthExceptOnBouncer(
+                KeyguardUpdateMonitor.StrongAuthTracker.STRONG_AUTH_REQUIRED_AFTER_TIMEOUT);
+    }
+
+    private void testStrongAuthExceptOnBouncer(int strongAuth) {
+        when(mKeyguardBypassController.canBypass()).thenReturn(true);
+        mKeyguardUpdateMonitor.setKeyguardBypassController(mKeyguardBypassController);
+        when(mStrongAuthTracker.getStrongAuthForUser(anyInt())).thenReturn(strongAuth);
+
+        mKeyguardUpdateMonitor.dispatchStartedWakingUp();
+        mTestableLooper.processAllMessages();
+        mKeyguardUpdateMonitor.onKeyguardVisibilityChanged(true);
+        verify(mFaceManager).authenticate(any(), any(), anyInt(), any(), any(), anyInt());
+
+        // Stop scanning when bouncer becomes visible
+        mKeyguardUpdateMonitor.sendKeyguardBouncerChanged(true /* showingBouncer */);
+        mTestableLooper.processAllMessages();
+        clearInvocations(mFaceManager);
+        mKeyguardUpdateMonitor.requestFaceAuth();
+        verify(mFaceManager, never()).authenticate(any(), any(), anyInt(), any(), any(), anyInt());
     }
 
     @Test
@@ -332,6 +368,50 @@
     }
 
     @Test
+    public void testTriesToAuthenticate_whenTrustOnAgentKeyguard_ifBypass() {
+        mKeyguardUpdateMonitor.setKeyguardBypassController(mKeyguardBypassController);
+        mKeyguardUpdateMonitor.dispatchStartedWakingUp();
+        mTestableLooper.processAllMessages();
+        when(mKeyguardBypassController.canBypass()).thenReturn(true);
+        mKeyguardUpdateMonitor.onTrustChanged(true /* enabled */,
+                KeyguardUpdateMonitor.getCurrentUser(), 0 /* flags */);
+        mKeyguardUpdateMonitor.onKeyguardVisibilityChanged(true);
+        verify(mFaceManager).authenticate(any(), any(), anyInt(), any(), any(), anyInt());
+    }
+
+    @Test
+    public void testIgnoresAuth_whenTrustAgentOnKeyguard_withoutBypass() {
+        mKeyguardUpdateMonitor.dispatchStartedWakingUp();
+        mTestableLooper.processAllMessages();
+        mKeyguardUpdateMonitor.onTrustChanged(true /* enabled */,
+                KeyguardUpdateMonitor.getCurrentUser(), 0 /* flags */);
+        mKeyguardUpdateMonitor.onKeyguardVisibilityChanged(true);
+        verify(mFaceManager, never()).authenticate(any(), any(), anyInt(), any(), any(), anyInt());
+    }
+
+    @Test
+    public void testIgnoresAuth_whenLockdown() {
+        mKeyguardUpdateMonitor.dispatchStartedWakingUp();
+        mTestableLooper.processAllMessages();
+        when(mStrongAuthTracker.getStrongAuthForUser(anyInt())).thenReturn(
+                KeyguardUpdateMonitor.StrongAuthTracker.STRONG_AUTH_REQUIRED_AFTER_USER_LOCKDOWN);
+
+        mKeyguardUpdateMonitor.onKeyguardVisibilityChanged(true);
+        verify(mFaceManager, never()).authenticate(any(), any(), anyInt(), any(), any(), anyInt());
+    }
+
+    @Test
+    public void testIgnoresAuth_whenLockout() {
+        mKeyguardUpdateMonitor.dispatchStartedWakingUp();
+        mTestableLooper.processAllMessages();
+        when(mStrongAuthTracker.getStrongAuthForUser(anyInt())).thenReturn(
+                KeyguardUpdateMonitor.StrongAuthTracker.STRONG_AUTH_REQUIRED_AFTER_LOCKOUT);
+
+        mKeyguardUpdateMonitor.onKeyguardVisibilityChanged(true);
+        verify(mFaceManager, never()).authenticate(any(), any(), anyInt(), any(), any(), anyInt());
+    }
+
+    @Test
     public void testOnFaceAuthenticated_skipsFaceWhenAuthenticated() {
         mKeyguardUpdateMonitor.onFaceAuthenticated(KeyguardUpdateMonitor.getCurrentUser());
         mKeyguardUpdateMonitor.sendKeyguardBouncerChanged(true);
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/clock/AnalogClockControllerTest.java b/packages/SystemUI/tests/src/com/android/keyguard/clock/AnalogClockControllerTest.java
index 3f48ea7..ef3af8a 100644
--- a/packages/SystemUI/tests/src/com/android/keyguard/clock/AnalogClockControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/keyguard/clock/AnalogClockControllerTest.java
@@ -18,6 +18,7 @@
 import static com.google.common.truth.Truth.assertThat;
 
 import android.content.res.Resources;
+import android.graphics.Color;
 import android.test.suitebuilder.annotation.SmallTest;
 import android.testing.AndroidTestingRunner;
 import android.testing.TestableLooper.RunWithLooper;
@@ -67,9 +68,9 @@
     public void setColorPalette_setDigitalClock() {
         ViewGroup smallClock = (ViewGroup) mClockController.getView();
         // WHEN color palette is set
-        mClockController.setColorPalette(true, new int[]{42});
+        mClockController.setColorPalette(true, new int[]{Color.RED});
         // THEN child of small clock should have text color set.
         TextView digitalClock = (TextView) smallClock.getChildAt(0);
-        assertThat(digitalClock.getCurrentTextColor()).isEqualTo(42);
+        assertThat(digitalClock.getCurrentTextColor()).isEqualTo(Color.RED);
     }
 }
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/clock/BubbleClockControllerTest.java b/packages/SystemUI/tests/src/com/android/keyguard/clock/BubbleClockControllerTest.java
index 90083b4..b56986e 100644
--- a/packages/SystemUI/tests/src/com/android/keyguard/clock/BubbleClockControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/keyguard/clock/BubbleClockControllerTest.java
@@ -18,6 +18,7 @@
 import static com.google.common.truth.Truth.assertThat;
 
 import android.content.res.Resources;
+import android.graphics.Color;
 import android.test.suitebuilder.annotation.SmallTest;
 import android.testing.AndroidTestingRunner;
 import android.testing.TestableLooper.RunWithLooper;
@@ -66,9 +67,9 @@
     public void setColorPalette_setDigitalClock() {
         ViewGroup smallClock = (ViewGroup) mClockController.getView();
         // WHEN text color is set
-        mClockController.setColorPalette(true, new int[]{42});
+        mClockController.setColorPalette(true, new int[]{Color.RED});
         // THEN child of small clock should have text color set.
         TextView digitalClock = (TextView) smallClock.getChildAt(0);
-        assertThat(digitalClock.getCurrentTextColor()).isEqualTo(42);
+        assertThat(digitalClock.getCurrentTextColor()).isEqualTo(Color.RED);
     }
 }
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/clock/ClockPaletteTest.kt b/packages/SystemUI/tests/src/com/android/keyguard/clock/ClockPaletteTest.kt
new file mode 100644
index 0000000..347b26d
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/keyguard/clock/ClockPaletteTest.kt
@@ -0,0 +1,97 @@
+/*
+ * 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.keyguard.clock
+
+import android.graphics.Color
+import android.testing.AndroidTestingRunner
+import androidx.test.filters.SmallTest
+import com.android.systemui.SysuiTestCase
+import com.google.common.truth.Truth.assertThat
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@RunWith(AndroidTestingRunner::class)
+@SmallTest
+class ClockPaletteTest : SysuiTestCase() {
+
+    private lateinit var clockPalette: ClockPalette
+    private lateinit var colors: IntArray
+
+    @Before
+    fun setUp() {
+        clockPalette = ClockPalette()
+        // colors used are reds from light to dark.
+        val hsv: FloatArray = FloatArray(3)
+        Color.colorToHSV(Color.RED, hsv)
+        colors = IntArray(10)
+        val step: Float = (0f - hsv[2]) / colors.size
+        for (i in 0 until colors.size) {
+            hsv[2] += step
+            colors[i] = Color.HSVToColor(hsv)
+        }
+    }
+
+    @Test
+    fun testDark() {
+        // GIVEN on AOD
+        clockPalette.setDarkAmount(1f)
+        // AND GIVEN that wallpaper doesn't support dark text
+        clockPalette.setColorPalette(false, colors)
+        // THEN the secondary color should be lighter than the primary color
+        assertThat(value(clockPalette.getPrimaryColor()))
+                .isGreaterThan(value(clockPalette.getSecondaryColor()))
+    }
+
+    @Test
+    fun testDarkText() {
+        // GIVEN on lock screen
+        clockPalette.setDarkAmount(0f)
+        // AND GIVEN that wallpaper supports dark text
+        clockPalette.setColorPalette(true, colors)
+        // THEN the secondary color should be darker the primary color
+        assertThat(value(clockPalette.getPrimaryColor()))
+                .isLessThan(value(clockPalette.getSecondaryColor()))
+    }
+
+    @Test
+    fun testLightText() {
+        // GIVEN on lock screen
+        clockPalette.setDarkAmount(0f)
+        // AND GIVEN that wallpaper doesn't support dark text
+        clockPalette.setColorPalette(false, colors)
+        // THEN the secondary color should be darker than the primary color
+        assertThat(value(clockPalette.getPrimaryColor()))
+                .isGreaterThan(value(clockPalette.getSecondaryColor()))
+    }
+
+    @Test
+    fun testNullColors() {
+        // GIVEN on AOD
+        clockPalette.setDarkAmount(1f)
+        // AND GIVEN that wallpaper colors are null
+        clockPalette.setColorPalette(false, null)
+        // THEN the primary color should be whilte
+        assertThat(clockPalette.getPrimaryColor()).isEqualTo(Color.WHITE)
+    }
+
+    private fun value(color: Int): Float {
+        val hsv: FloatArray = FloatArray(3)
+        Color.colorToHSV(color, hsv)
+        return hsv[2]
+    }
+}
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/clock/SettingsWrapperTest.kt b/packages/SystemUI/tests/src/com/android/keyguard/clock/SettingsWrapperTest.kt
new file mode 100644
index 0000000..573581d
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/keyguard/clock/SettingsWrapperTest.kt
@@ -0,0 +1,93 @@
+/*
+ * 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.keyguard.clock
+
+import android.testing.AndroidTestingRunner
+import androidx.test.filters.SmallTest
+import com.android.systemui.SysuiTestCase
+import com.google.common.truth.Truth.assertThat
+import org.json.JSONObject
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.mockito.Mockito.mock
+import org.mockito.Mockito.never
+import org.mockito.Mockito.verify
+
+private const val PACKAGE = "com.android.keyguard.clock.Clock"
+private const val CLOCK_FIELD = "clock"
+private const val TIMESTAMP_FIELD = "_applied_timestamp"
+private const val USER_ID = 0
+
+@RunWith(AndroidTestingRunner::class)
+@SmallTest
+class SettingsWrapperTest : SysuiTestCase() {
+
+    private lateinit var wrapper: SettingsWrapper
+    private lateinit var migration: SettingsWrapper.Migration
+
+    @Before
+    fun setUp() {
+        migration = mock(SettingsWrapper.Migration::class.java)
+        wrapper = SettingsWrapper(getContext().contentResolver, migration)
+    }
+
+    @Test
+    fun testDecodeUnnecessary() {
+        // GIVEN a settings value that doesn't need to be decoded
+        val value = PACKAGE
+        // WHEN the value is decoded
+        val decoded = wrapper.decode(value, USER_ID)
+        // THEN the same value is returned, because decoding isn't necessary.
+        // TODO(b/135674383): Null should be returned when the migration code in removed.
+        assertThat(decoded).isEqualTo(value)
+        // AND the value is migrated to JSON format
+        verify(migration).migrate(value, USER_ID)
+    }
+
+    @Test
+    fun testDecodeJSON() {
+        // GIVEN a settings value that is encoded in JSON
+        val json: JSONObject = JSONObject()
+        json.put(CLOCK_FIELD, PACKAGE)
+        json.put(TIMESTAMP_FIELD, System.currentTimeMillis())
+        val value = json.toString()
+        // WHEN the value is decoded
+        val decoded = wrapper.decode(value, USER_ID)
+        // THEN the clock field should have been extracted
+        assertThat(decoded).isEqualTo(PACKAGE)
+    }
+
+    @Test
+    fun testDecodeJSONWithoutClockField() {
+        // GIVEN a settings value that doesn't contain the CLOCK_FIELD
+        val json: JSONObject = JSONObject()
+        json.put(TIMESTAMP_FIELD, System.currentTimeMillis())
+        val value = json.toString()
+        // WHEN the value is decoded
+        val decoded = wrapper.decode(value, USER_ID)
+        // THEN null is returned
+        assertThat(decoded).isNull()
+        // AND the value is not migrated to JSON format
+        verify(migration, never()).migrate(value, USER_ID)
+    }
+
+    @Test
+    fun testDecodeNullJSON() {
+        assertThat(wrapper.decode(null, USER_ID)).isNull()
+    }
+}
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/clock/SmallClockPositionTest.kt b/packages/SystemUI/tests/src/com/android/keyguard/clock/SmallClockPositionTest.kt
index f4d59cc..456f32b 100644
--- a/packages/SystemUI/tests/src/com/android/keyguard/clock/SmallClockPositionTest.kt
+++ b/packages/SystemUI/tests/src/com/android/keyguard/clock/SmallClockPositionTest.kt
@@ -52,8 +52,8 @@
     fun darkPosition() {
         // GIVEN on AOD
         position.setDarkAmount(1f)
-        // THEN Y position is statusBarHeight + lockPadding + burnInY (100 + 15 + 20 = 135)
-        assertThat(position.preferredY).isEqualTo(135)
+        // THEN Y is sum of statusBarHeight, lockPadding, lockHeight, lockPadding, burnInY
+        assertThat(position.preferredY).isEqualTo(185)
     }
 
     @Test
@@ -64,4 +64,4 @@
         // (100 + 15 + 35 + 15 = 165)
         assertThat(position.preferredY).isEqualTo(165)
     }
-}
\ No newline at end of file
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/IconPackOverlayTest.java b/packages/SystemUI/tests/src/com/android/systemui/IconPackOverlayTest.java
new file mode 100644
index 0000000..ccc9afc
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/IconPackOverlayTest.java
@@ -0,0 +1,192 @@
+/*
+ * 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.systemui;
+
+import static junit.framework.Assert.fail;
+
+import static org.junit.Assert.assertEquals;
+
+import android.annotation.DrawableRes;
+import android.content.pm.PackageManager;
+import android.content.res.Resources;
+import android.content.res.TypedArray;
+import android.content.res.XmlResourceParser;
+import android.text.TextUtils;
+import android.util.TypedValue;
+
+import androidx.test.filters.MediumTest;
+import androidx.test.runner.AndroidJUnit4;
+
+import com.android.internal.util.XmlUtils;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.xmlpull.v1.XmlPullParserException;
+
+import java.io.IOException;
+
+@RunWith(AndroidJUnit4.class)
+@MediumTest
+public class IconPackOverlayTest extends SysuiTestCase {
+
+    private static final String[] ICON_PACK_OVERLAY_PACKAGES = {
+            "com.android.theme.icon_pack.circular.systemui",
+            "com.android.theme.icon_pack.rounded.systemui",
+            "com.android.theme.icon_pack.filled.systemui",
+    };
+
+    private static final int[] VECTOR_ATTRIBUTES = {
+            android.R.attr.tint,
+            android.R.attr.height,
+            android.R.attr.width,
+            android.R.attr.alpha,
+            android.R.attr.autoMirrored,
+    };
+
+    private final TypedValue mTargetTypedValue = new TypedValue();
+    private final TypedValue mOverlayTypedValue = new TypedValue();
+
+    private Resources mResources;
+    private TypedArray mOverlayableIcons;
+
+    @Before
+    public void setup() {
+        mResources = mContext.getResources();
+        mOverlayableIcons = mResources.obtainTypedArray(R.array.overlayable_icons);
+    }
+
+    @After
+    public void teardown() {
+        mOverlayableIcons.recycle();
+    }
+
+    /**
+     * Ensure that all icons contained in overlayable_icons_test.xml exist in all 3 overlay icon
+     * packs for systemui. This test fails if you remove or rename an overlaid icon. If so,
+     * make the same change to the corresponding drawables in {@link #ICON_PACK_OVERLAY_PACKAGES}.
+     */
+    @Test
+    public void testIconPack_containAllOverlayedIcons() {
+        StringBuilder errors = new StringBuilder();
+
+        for (String overlayPackage : ICON_PACK_OVERLAY_PACKAGES) {
+            Resources overlayResources;
+            try {
+                overlayResources = mContext.getPackageManager()
+                        .getResourcesForApplication(overlayPackage);
+            } catch (PackageManager.NameNotFoundException e) {
+                continue; // No need to test overlay resources if apk is not on the system.
+            }
+
+            for (int i = 0; i < mOverlayableIcons.length(); i++) {
+                int sysuiRid = mOverlayableIcons.getResourceId(i, 0);
+                String sysuiResourceName = mResources.getResourceName(sysuiRid);
+                String overlayResourceName = sysuiResourceName
+                        .replace(mContext.getPackageName(), overlayPackage);
+                if (overlayResources.getIdentifier(overlayResourceName, null, null)
+                        == Resources.ID_NULL) {
+                    errors.append(String.format("[%s] is not contained in overlay package [%s]",
+                            overlayResourceName, overlayPackage));
+                }
+            }
+        }
+
+        if (!TextUtils.isEmpty(errors)) {
+            fail(errors.toString());
+        }
+    }
+
+    /**
+     * Ensures that all overlay icons have the same values for {@link #VECTOR_ATTRIBUTES} as the
+     * underlying drawable in systemui. To fix this test, make the attribute change to all of the
+     * corresponding drawables in {@link #ICON_PACK_OVERLAY_PACKAGES}.
+     */
+    @Test
+    public void testIconPacks_haveEqualVectorDrawableAttributes() {
+        StringBuilder errors = new StringBuilder();
+
+        for (String overlayPackage : ICON_PACK_OVERLAY_PACKAGES) {
+            Resources overlayResources;
+            try {
+                overlayResources = mContext.getPackageManager()
+                        .getResourcesForApplication(overlayPackage);
+            } catch (PackageManager.NameNotFoundException e) {
+                continue; // No need to test overlay resources if apk is not on the system.
+            }
+
+            for (int i = 0; i < mOverlayableIcons.length(); i++) {
+                int sysuiRid = mOverlayableIcons.getResourceId(i, 0);
+                String sysuiResourceName = mResources.getResourceName(sysuiRid);
+                TypedArray sysuiAttrs = getAVDAttributes(mResources, sysuiRid);
+                if (sysuiAttrs == null) {
+                    errors.append(String.format("[%s] does not exist or is not a valid AVD.",
+                            sysuiResourceName));
+                    continue;
+                }
+
+                String overlayResourceName = sysuiResourceName
+                        .replace(mContext.getPackageName(), overlayPackage);
+                int overlayRid = overlayResources.getIdentifier(overlayResourceName, null, null);
+                TypedArray overlayAttrs = getAVDAttributes(overlayResources, overlayRid);
+                if (overlayAttrs == null) {
+                    errors.append(String.format("[%s] does not exist or is not a valid AVD.",
+                            overlayResourceName));
+                    continue;
+                }
+
+                if (!attributesEquals(sysuiAttrs, overlayAttrs)) {
+                    errors.append(String.format("[%s] AVD attributes do not match [%s]\n",
+                            sysuiResourceName, overlayResourceName));
+                }
+                sysuiAttrs.recycle();
+                overlayAttrs.recycle();
+            }
+        }
+
+        if (!TextUtils.isEmpty(errors)) {
+            fail(errors.toString());
+        }
+    }
+
+    private TypedArray getAVDAttributes(Resources resources, @DrawableRes int rid) {
+        try {
+            XmlResourceParser parser = resources.getXml(rid);
+            XmlUtils.nextElement(parser);
+            return resources.obtainAttributes(parser, VECTOR_ATTRIBUTES);
+        } catch (XmlPullParserException | IOException  | Resources.NotFoundException e) {
+            return null;
+        }
+    }
+
+    private boolean attributesEquals(TypedArray target, TypedArray overlay) {
+        assertEquals(target.length(), overlay.length());
+        for (int i = 0; i < target.length(); i++) {
+            target.getValue(i, mTargetTypedValue);
+            overlay.getValue(i, mOverlayTypedValue);
+            if (!attributesEquals(mTargetTypedValue, mOverlayTypedValue)) {
+                return false;
+            }
+        }
+        return true;
+    }
+
+    private boolean attributesEquals(TypedValue target, TypedValue overlay) {
+        return target.type == overlay.type && target.data == overlay.data;
+    }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/appops/AppOpsControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/appops/AppOpsControllerTest.java
index bd7f897..59d5c24 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/appops/AppOpsControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/appops/AppOpsControllerTest.java
@@ -16,9 +16,8 @@
 
 package com.android.systemui.appops;
 
-import static junit.framework.TestCase.assertFalse;
-
 import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertTrue;
 import static org.mockito.ArgumentMatchers.any;
 import static org.mockito.ArgumentMatchers.anyBoolean;
diff --git a/packages/SystemUI/tests/src/com/android/systemui/bubbles/BubbleControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/bubbles/BubbleControllerTest.java
index b3f6f4e..2221915 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/bubbles/BubbleControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/bubbles/BubbleControllerTest.java
@@ -60,6 +60,7 @@
 import com.android.systemui.statusbar.NotificationPresenter;
 import com.android.systemui.statusbar.NotificationRemoveInterceptor;
 import com.android.systemui.statusbar.NotificationTestHelper;
+import com.android.systemui.statusbar.SysuiStatusBarStateController;
 import com.android.systemui.statusbar.notification.NotificationEntryListener;
 import com.android.systemui.statusbar.notification.NotificationEntryManager;
 import com.android.systemui.statusbar.notification.NotificationInterruptionStateProvider;
@@ -67,6 +68,7 @@
 import com.android.systemui.statusbar.notification.collection.NotificationEntry;
 import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
 import com.android.systemui.statusbar.phone.DozeParameters;
+import com.android.systemui.statusbar.phone.KeyguardBypassController;
 import com.android.systemui.statusbar.phone.StatusBarWindowController;
 import com.android.systemui.statusbar.policy.ConfigurationController;
 import com.android.systemui.statusbar.policy.HeadsUpManager;
@@ -105,6 +107,10 @@
     private ZenModeController mZenModeController;
     @Mock
     private ZenModeConfig mZenModeConfig;
+    @Mock
+    private SysuiStatusBarStateController mStatusBarStateController;
+    @Mock
+    private KeyguardBypassController mKeyguardBypassController;
 
     private FrameLayout mStatusBarView;
     @Captor
@@ -143,7 +149,8 @@
 
         // Bubbles get added to status bar window view
         mStatusBarWindowController = new StatusBarWindowController(mContext, mWindowManager,
-                mActivityManager, mDozeParameters);
+                mActivityManager, mDozeParameters, mStatusBarStateController,
+                mConfigurationController, mKeyguardBypassController);
         mStatusBarWindowController.add(mStatusBarView, 120 /* height */);
 
         // Need notifications for bubbles
diff --git a/packages/SystemUI/tests/src/com/android/systemui/classifier/brightline/ZigZagClassifierTest.java b/packages/SystemUI/tests/src/com/android/systemui/classifier/brightline/ZigZagClassifierTest.java
index 25a1a75..fb4c1ec 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/classifier/brightline/ZigZagClassifierTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/classifier/brightline/ZigZagClassifierTest.java
@@ -133,8 +133,8 @@
         // This test looks just like testPass_horizontalZigZagVerticalStraight but with
         // a shorter y range, making it look more crooked.
         appendMoveEvent(0, 0);
-        appendMoveEvent(5, 10);
-        appendMoveEvent(-5, 20);
+        appendMoveEvent(6, 10);
+        appendMoveEvent(-6, 20);
         assertThat(mClassifier.isFalseTouch(), is(true));
     }
 
diff --git a/packages/SystemUI/tests/src/com/android/systemui/doze/DozeConfigurationUtil.java b/packages/SystemUI/tests/src/com/android/systemui/doze/DozeConfigurationUtil.java
index 9438cbb..2ed0970 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/doze/DozeConfigurationUtil.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/doze/DozeConfigurationUtil.java
@@ -24,6 +24,7 @@
 import static org.mockito.Mockito.withSettings;
 
 import com.android.systemui.statusbar.phone.DozeParameters;
+import com.android.systemui.utils.hardware.FakeSensorManager;
 
 import org.mockito.Answers;
 import org.mockito.MockSettings;
@@ -36,9 +37,10 @@
         when(params.getPulseOnSigMotion()).thenReturn(false);
         when(params.getPickupVibrationThreshold()).thenReturn(0);
         when(params.getProxCheckBeforePulse()).thenReturn(true);
-        when(params.getPickupSubtypePerformsProxCheck(anyInt())).thenReturn(true);
+        when(params.getPickupPerformsProxCheck()).thenReturn(true);
         when(params.getPolicy()).thenReturn(mock(AlwaysOnDisplayPolicy.class));
         when(params.doubleTapReportsTouchCoordinates()).thenReturn(false);
+        when(params.getDisplayNeedsBlanking()).thenReturn(false);
 
         doneHolder[0] = true;
         return params;
@@ -52,11 +54,17 @@
         when(config.pickupGestureEnabled(anyInt())).thenReturn(false);
         when(config.pulseOnNotificationEnabled(anyInt())).thenReturn(true);
         when(config.alwaysOnEnabled(anyInt())).thenReturn(false);
+        when(config.enabled(anyInt())).thenReturn(true);
+        when(config.getWakeLockScreenDebounce()).thenReturn(0L);
 
         when(config.doubleTapSensorType()).thenReturn(null);
         when(config.tapSensorType()).thenReturn(null);
         when(config.longPressSensorType()).thenReturn(null);
 
+        when(config.tapGestureEnabled(anyInt())).thenReturn(true);
+        when(config.tapSensorAvailable()).thenReturn(true);
+        when(config.tapSensorType()).thenReturn(FakeSensorManager.TAP_SENSOR_TYPE);
+
         when(config.dozePickupSensorAvailable()).thenReturn(false);
         when(config.wakeScreenGestureAvailable()).thenReturn(false);
 
diff --git a/packages/SystemUI/tests/src/com/android/systemui/doze/DozeSensorsTest.java b/packages/SystemUI/tests/src/com/android/systemui/doze/DozeSensorsTest.java
index 3304291..7df45a3 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/doze/DozeSensorsTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/doze/DozeSensorsTest.java
@@ -23,6 +23,7 @@
 import static org.mockito.ArgumentMatchers.anyFloat;
 import static org.mockito.ArgumentMatchers.anyInt;
 import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.clearInvocations;
 import static org.mockito.Mockito.doAnswer;
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.never;
@@ -77,7 +78,9 @@
     @Mock
     private AlwaysOnDisplayPolicy mAlwaysOnDisplayPolicy;
     @Mock
-    private TriggerSensor mMockTriggerSensor;
+    private TriggerSensor mTriggerSensor;
+    @Mock
+    private TriggerSensor mProxGatedTriggerSensor;
     private SensorManagerPlugin.SensorEventListener mWakeLockScreenListener;
     private TestableLooper mTestableLooper;
     private DozeSensors mDozeSensors;
@@ -85,6 +88,7 @@
     @Before
     public void setUp() {
         MockitoAnnotations.initMocks(this);
+        when(mProxGatedTriggerSensor.performsProxCheck()).thenReturn(true);
         mTestableLooper = TestableLooper.get(this);
         when(mAmbientDisplayConfiguration.getWakeLockScreenDebounce()).thenReturn(5000L);
         when(mAmbientDisplayConfiguration.alwaysOnEnabled(anyInt())).thenReturn(true);
@@ -114,21 +118,34 @@
 
     @Test
     public void testSetListening_firstTrue_registerSettingsObserver() {
-        mDozeSensors.mSensors = new TriggerSensor[] {mMockTriggerSensor};
-
         mDozeSensors.setListening(true);
 
-        verify(mMockTriggerSensor).registerSettingsObserver(any(ContentObserver.class));
+        verify(mTriggerSensor).registerSettingsObserver(any(ContentObserver.class));
     }
 
     @Test
     public void testSetListening_twiceTrue_onlyRegisterSettingsObserverOnce() {
-        mDozeSensors.mSensors = new TriggerSensor[] {mMockTriggerSensor};
+        mDozeSensors.setListening(true);
         mDozeSensors.setListening(true);
 
-        mDozeSensors.setListening(true);
+        verify(mTriggerSensor, times(1)).registerSettingsObserver(any(ContentObserver.class));
+    }
 
-        verify(mMockTriggerSensor, times(1)).registerSettingsObserver(any(ContentObserver.class));
+    @Test
+    public void testSetPaused_onlyPausesNonGatedSensors() {
+        mDozeSensors.setListening(true);
+        verify(mTriggerSensor).setListening(eq(true));
+        verify(mProxGatedTriggerSensor).setListening(eq(true));
+
+        clearInvocations(mTriggerSensor, mProxGatedTriggerSensor);
+        mDozeSensors.setPaused(true);
+        verify(mTriggerSensor).setListening(eq(false));
+        verify(mProxGatedTriggerSensor).setListening(eq(true));
+
+        clearInvocations(mTriggerSensor, mProxGatedTriggerSensor);
+        mDozeSensors.setPaused(false);
+        verify(mTriggerSensor).setListening(eq(true));
+        verify(mProxGatedTriggerSensor).setListening(eq(true));
     }
 
     private class TestableDozeSensors extends DozeSensors {
@@ -144,6 +161,7 @@
                     mWakeLockScreenListener = (PluginSensor) sensor;
                 }
             }
+            mSensors = new TriggerSensor[] {mTriggerSensor, mProxGatedTriggerSensor};
         }
     }
 }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/doze/DozeTriggersTest.java b/packages/SystemUI/tests/src/com/android/systemui/doze/DozeTriggersTest.java
index 6979fd8..d464223 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/doze/DozeTriggersTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/doze/DozeTriggersTest.java
@@ -19,6 +19,7 @@
 import static org.mockito.ArgumentMatchers.any;
 import static org.mockito.ArgumentMatchers.anyInt;
 import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.clearInvocations;
 import static org.mockito.Mockito.doReturn;
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.never;
@@ -27,18 +28,17 @@
 import static org.mockito.Mockito.when;
 
 import android.app.AlarmManager;
-import android.app.Instrumentation;
+import android.hardware.Sensor;
 import android.hardware.display.AmbientDisplayConfiguration;
 import android.os.Handler;
 import android.os.Looper;
 import android.testing.AndroidTestingRunner;
 import android.testing.TestableLooper.RunWithLooper;
 
-import androidx.test.InstrumentationRegistry;
 import androidx.test.filters.SmallTest;
 
 import com.android.systemui.SysuiTestCase;
-import com.android.systemui.dock.DockManagerFake;
+import com.android.systemui.dock.DockManager;
 import com.android.systemui.statusbar.phone.DozeParameters;
 import com.android.systemui.util.wakelock.WakeLock;
 import com.android.systemui.util.wakelock.WakeLockFake;
@@ -46,14 +46,12 @@
 
 import org.junit.Before;
 import org.junit.BeforeClass;
-import org.junit.Ignore;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
 @SmallTest
-@Ignore("failing")
 @RunWith(AndroidTestingRunner.class)
-@RunWithLooper
+@RunWithLooper(setAsMainLooper = true)
 public class DozeTriggersTest extends SysuiTestCase {
     private DozeTriggers mTriggers;
     private DozeMachine mMachine;
@@ -61,10 +59,10 @@
     private AmbientDisplayConfiguration mConfig;
     private DozeParameters mParameters;
     private FakeSensorManager mSensors;
+    private Sensor mTapSensor;
     private WakeLock mWakeLock;
-    private Instrumentation mInstrumentation;
     private AlarmManager mAlarmManager;
-    private DockManagerFake mDockManagerFake;
+    private DockManager mDockManagerFake;
 
     @BeforeClass
     public static void setupSuite() {
@@ -74,15 +72,15 @@
 
     @Before
     public void setUp() throws Exception {
-        mInstrumentation = InstrumentationRegistry.getInstrumentation();
         mMachine = mock(DozeMachine.class);
         mAlarmManager = mock(AlarmManager.class);
-        mHost = new DozeHostFake();
+        mHost = spy(new DozeHostFake());
         mConfig = DozeConfigurationUtil.createMockConfig();
         mParameters = DozeConfigurationUtil.createMockParameters();
-        mSensors = new FakeSensorManager(mContext);
+        mSensors = spy(new FakeSensorManager(mContext));
+        mTapSensor = mSensors.getFakeTapSensor().getSensor();
         mWakeLock = new WakeLockFake();
-        mDockManagerFake = spy(new DockManagerFake());
+        mDockManagerFake = mock(DockManager.class);
 
         mTriggers = new DozeTriggers(mContext, mMachine, mHost, mAlarmManager, mConfig, mParameters,
                 mSensors, Handler.createAsync(Looper.myLooper()), mWakeLock, true,
@@ -95,29 +93,45 @@
 
         mTriggers.transitionTo(DozeMachine.State.UNINITIALIZED, DozeMachine.State.INITIALIZED);
         mTriggers.transitionTo(DozeMachine.State.INITIALIZED, DozeMachine.State.DOZE);
+        clearInvocations(mMachine);
 
-        mHost.callback.onNotificationAlerted();
-
+        mHost.callback.onNotificationAlerted(null /* pulseSuppressedListener */);
         mSensors.getMockProximitySensor().sendProximityResult(false); /* Near */
 
         verify(mMachine, never()).requestState(any());
         verify(mMachine, never()).requestPulse(anyInt());
 
-        mHost.callback.onNotificationAlerted();
-
+        mHost.callback.onNotificationAlerted(null /* pulseSuppressedListener */);
         mSensors.getMockProximitySensor().sendProximityResult(true); /* Far */
 
         verify(mMachine).requestPulse(anyInt());
     }
 
     @Test
+    public void testTransitionTo_disablesAndEnablesTouchSensors() {
+        when(mMachine.getState()).thenReturn(DozeMachine.State.DOZE);
+
+        mTriggers.transitionTo(DozeMachine.State.INITIALIZED, DozeMachine.State.DOZE);
+        verify(mSensors).requestTriggerSensor(any(), eq(mTapSensor));
+
+        clearInvocations(mSensors);
+        mTriggers.transitionTo(DozeMachine.State.DOZE,
+                DozeMachine.State.DOZE_REQUEST_PULSE);
+        mTriggers.transitionTo(DozeMachine.State.DOZE_REQUEST_PULSE,
+                DozeMachine.State.DOZE_PULSING);
+        verify(mSensors).cancelTriggerSensor(any(), eq(mTapSensor));
+
+        clearInvocations(mSensors);
+        mTriggers.transitionTo(DozeMachine.State.DOZE_PULSING, DozeMachine.State.DOZE_PULSE_DONE);
+        verify(mSensors).requestTriggerSensor(any(), eq(mTapSensor));
+    }
+
+    @Test
     public void testDockEventListener_registerAndUnregister() {
         mTriggers.transitionTo(DozeMachine.State.UNINITIALIZED, DozeMachine.State.INITIALIZED);
-
         verify(mDockManagerFake).addListener(any());
 
         mTriggers.transitionTo(DozeMachine.State.DOZE, DozeMachine.State.FINISH);
-
         verify(mDockManagerFake).removeListener(any());
     }
 
@@ -128,7 +142,6 @@
         mTriggers.onSensor(DozeLog.REASON_SENSOR_DOUBLE_TAP,
                 false /* sensorPerformedProxCheck */, 50 /* screenX */, 50 /* screenY */,
                 null /* rawValues */);
-
         verify(mMachine, never()).wakeUp();
     }
 
@@ -142,7 +155,7 @@
                 false /* sensorPerformedProxCheck */, 50 /* screenX */, 50 /* screenY */,
                 null /* rawValues */);
 
-        verify(mHost).setAodDimmingScrim(eq(255));
+        verify(mHost).setAodDimmingScrim(eq(1f));
         verify(mMachine).wakeUp();
     }
 }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/glwallpaper/EglHelperTest.java b/packages/SystemUI/tests/src/com/android/systemui/glwallpaper/EglHelperTest.java
new file mode 100644
index 0000000..b4a60d6
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/glwallpaper/EglHelperTest.java
@@ -0,0 +1,67 @@
+/*
+ * 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.systemui.glwallpaper;
+
+import static org.junit.Assert.*;
+import static org.mockito.Mockito.RETURNS_DEFAULTS;
+import static org.mockito.Mockito.mock;
+
+import android.testing.AndroidTestingRunner;
+import android.testing.TestableLooper;
+import android.view.SurfaceHolder;
+
+import androidx.test.filters.SmallTest;
+
+import com.android.systemui.SysuiTestCase;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+
+
+@SmallTest
+@RunWith(AndroidTestingRunner.class)
+@TestableLooper.RunWithLooper
+public class EglHelperTest extends SysuiTestCase {
+
+    @Mock
+    private EglHelper mEglHelper;
+    @Mock
+    private SurfaceHolder mSurfaceHolder;
+
+    @Before
+    public void setUp() throws Exception {
+        mEglHelper = mock(EglHelper.class, RETURNS_DEFAULTS);
+        mSurfaceHolder = mock(SurfaceHolder.class, RETURNS_DEFAULTS);
+    }
+
+    @Test
+    public void testInit_finish() {
+        mEglHelper.init(mSurfaceHolder);
+        mEglHelper.finish();
+    }
+
+    @Test
+    public void testFinish_shouldNotCrash() {
+        assertFalse(mEglHelper.hasEglDisplay());
+        assertFalse(mEglHelper.hasEglSurface());
+        assertFalse(mEglHelper.hasEglContext());
+
+        mEglHelper.finish();
+    }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/KeyguardSliceProviderTest.java b/packages/SystemUI/tests/src/com/android/systemui/keyguard/KeyguardSliceProviderTest.java
index a83c4b6..9576cb2 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/KeyguardSliceProviderTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/KeyguardSliceProviderTest.java
@@ -49,6 +49,8 @@
 import com.android.systemui.plugins.statusbar.StatusBarStateController;
 import com.android.systemui.statusbar.NotificationMediaManager;
 import com.android.systemui.statusbar.StatusBarState;
+import com.android.systemui.statusbar.phone.DozeParameters;
+import com.android.systemui.statusbar.phone.KeyguardBypassController;
 import com.android.systemui.statusbar.policy.ZenModeController;
 import com.android.systemui.util.wakelock.SettableWakeLock;
 
@@ -77,11 +79,15 @@
     @Mock
     private StatusBarStateController mStatusBarStateController;
     @Mock
+    private KeyguardBypassController mKeyguardBypassController;
+    @Mock
     private ZenModeController mZenModeController;
     @Mock
     private SettableWakeLock mMediaWakeLock;
     @Mock
     private KeyguardUpdateMonitor mKeyguardUpdateMonitor;
+    @Mock
+    private DozeParameters mDozeParameters;
     private TestableKeyguardSliceProvider mProvider;
     private boolean mIsZenMode;
 
@@ -91,7 +97,8 @@
         mIsZenMode = false;
         mProvider = new TestableKeyguardSliceProvider();
         mProvider.attachInfo(getContext(), null);
-        mProvider.initDependencies(mNotificationMediaManager, mStatusBarStateController);
+        mProvider.initDependencies(mNotificationMediaManager, mStatusBarStateController,
+                mKeyguardBypassController, mDozeParameters);
         SliceProvider.setSpecs(new HashSet<>(Arrays.asList(SliceSpecs.LIST)));
     }
 
@@ -111,7 +118,7 @@
     }
 
     @Test
-    public void onBindSlice_readsMedia() {
+    public void onBindSlice_readsMedia_withoutBypass() {
         MediaMetadata metadata = mock(MediaMetadata.class);
         when(metadata.getText(any())).thenReturn("metadata");
         mProvider.onDozingChanged(true);
@@ -123,6 +130,19 @@
     }
 
     @Test
+    public void onBindSlice_readsMedia_withBypass_notDozing() {
+        MediaMetadata metadata = mock(MediaMetadata.class);
+        when(metadata.getText(any())).thenReturn("metadata");
+        when(mKeyguardBypassController.getBypassEnabled()).thenReturn(true);
+        when(mDozeParameters.getAlwaysOn()).thenReturn(true);
+        mProvider.onMetadataOrStateChanged(metadata, PlaybackState.STATE_PLAYING);
+        mProvider.onBindSlice(mProvider.getUri());
+        verify(metadata).getText(eq(MediaMetadata.METADATA_KEY_TITLE));
+        verify(metadata).getText(eq(MediaMetadata.METADATA_KEY_ARTIST));
+        verify(mNotificationMediaManager).getMediaIcon();
+    }
+
+    @Test
     public void cleansDateFormat() {
         mProvider.mKeyguardUpdateMonitorCallback.onTimeZoneChanged(null);
         TestableLooper.get(this).processAllMessages();
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/QSFragmentTest.java b/packages/SystemUI/tests/src/com/android/systemui/qs/QSFragmentTest.java
index db4f5ff..4eee230 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/QSFragmentTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/QSFragmentTest.java
@@ -39,6 +39,7 @@
 import com.android.systemui.R;
 import com.android.systemui.SystemUIFactory;
 import com.android.systemui.SysuiBaseFragmentTest;
+import com.android.systemui.plugins.statusbar.StatusBarStateController;
 import com.android.systemui.qs.tileimpl.QSFactoryImpl;
 import com.android.systemui.shared.plugins.PluginManager;
 import com.android.systemui.statusbar.phone.AutoTileManager;
@@ -139,6 +140,7 @@
                 new RemoteInputQuickSettingsDisabler(context, mock(ConfigurationController.class)),
                 new InjectionInflationController(SystemUIFactory.getInstance().getRootComponent()),
                 context,
-                mock(QSTileHost.class));
+                mock(QSTileHost.class),
+                mock(StatusBarStateController.class));
     }
 }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/shared/recents/model/TaskKeyLruCacheTest.java b/packages/SystemUI/tests/src/com/android/systemui/shared/recents/model/TaskKeyLruCacheTest.java
new file mode 100644
index 0000000..eb71dd6
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/shared/recents/model/TaskKeyLruCacheTest.java
@@ -0,0 +1,106 @@
+/*
+ * 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.systemui.shared.recents.model;
+
+
+import static junit.framework.TestCase.assertEquals;
+import static junit.framework.TestCase.assertNull;
+
+import android.test.suitebuilder.annotation.SmallTest;
+
+import com.android.systemui.SysuiTestCase;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+@SmallTest
+@RunWith(JUnit4.class)
+public class TaskKeyLruCacheTest extends SysuiTestCase {
+    private static int sCacheSize = 3;
+    private static int sIdTask1 = 1;
+    private static int sIdTask2 = 2;
+    private static int sIdTask3 = 3;
+    private static int sIdUser1 = 1;
+
+    TaskKeyCache<Integer> mCache = new TaskKeyLruCache<>(sCacheSize, null);
+    Task.TaskKey mKey1;
+    Task.TaskKey mKey2;
+    Task.TaskKey mKey3;
+
+    @Before
+    public void setup() {
+        mKey1 = new Task.TaskKey(sIdTask1, 0, null, null, sIdUser1, System.currentTimeMillis());
+        mKey2 = new Task.TaskKey(sIdTask2, 0, null, null, sIdUser1, System.currentTimeMillis());
+        mKey3 = new Task.TaskKey(sIdTask3, 0, null, null, sIdUser1, System.currentTimeMillis());
+    }
+
+    @Test
+    public void addSingleItem_get_success() {
+        mCache.put(mKey1, 1);
+
+        assertEquals(1, (int) mCache.get(mKey1));
+    }
+
+    @Test
+    public void addSingleItem_getUninsertedItem_returnsNull() {
+        mCache.put(mKey1, 1);
+
+        assertNull(mCache.get(mKey2));
+    }
+
+    @Test
+    public void emptyCache_get_returnsNull() {
+        assertNull(mCache.get(mKey1));
+    }
+
+    @Test
+    public void updateItem_get_returnsSecond() {
+        mCache.put(mKey1, 1);
+        mCache.put(mKey1, 2);
+
+        assertEquals(2, (int) mCache.get(mKey1));
+        assertEquals(1, mCache.mKeys.size());
+    }
+
+    @Test
+    public void fillCache_put_evictsOldest() {
+        mCache.put(mKey1, 1);
+        mCache.put(mKey2, 2);
+        mCache.put(mKey3, 3);
+        Task.TaskKey key4 = new Task.TaskKey(sIdTask3 + 1, 0,
+                null, null, sIdUser1, System.currentTimeMillis());
+        mCache.put(key4, 4);
+
+        assertNull(mCache.get(mKey1));
+        assertEquals(3, mCache.mKeys.size());
+        assertEquals(mKey2, mCache.mKeys.valueAt(0));
+    }
+
+    @Test
+    public void fillCache_remove_success() {
+        mCache.put(mKey1, 1);
+        mCache.put(mKey2, 2);
+        mCache.put(mKey3, 3);
+
+        mCache.remove(mKey2);
+
+        assertNull(mCache.get(mKey2));
+        assertEquals(2, mCache.mKeys.size());
+    }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/AlertingNotificationManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/AlertingNotificationManagerTest.java
index 5c1f473..881cc39 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/AlertingNotificationManagerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/AlertingNotificationManagerTest.java
@@ -64,7 +64,7 @@
     protected static final int TEST_AUTO_DISMISS_TIME = 500;
     // Number of notifications to use in tests requiring multiple notifications
     private static final int TEST_NUM_NOTIFICATIONS = 4;
-    protected static final int TEST_TIMEOUT_TIME = 10000;
+    protected static final int TEST_TIMEOUT_TIME = 15000;
     protected final Runnable TEST_TIMEOUT_RUNNABLE = () -> mTimedOut = true;
 
     private AlertingNotificationManager mAlertingNotificationManager;
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/AmbientPulseManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/AmbientPulseManagerTest.java
deleted file mode 100644
index 0b25a7c..0000000
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/AmbientPulseManagerTest.java
+++ /dev/null
@@ -1,79 +0,0 @@
-/*
- * Copyright (C) 2018 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.systemui.statusbar;
-
-import static junit.framework.Assert.assertFalse;
-import static junit.framework.Assert.assertTrue;
-
-import android.testing.AndroidTestingRunner;
-import android.testing.TestableLooper;
-
-import androidx.test.filters.SmallTest;
-
-import org.junit.Before;
-import org.junit.Rule;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.mockito.junit.MockitoJUnit;
-import org.mockito.junit.MockitoRule;
-
-@SmallTest
-@RunWith(AndroidTestingRunner.class)
-@TestableLooper.RunWithLooper
-public class AmbientPulseManagerTest extends AlertingNotificationManagerTest {
-    @Rule
-    public MockitoRule rule = MockitoJUnit.rule();
-
-    private static final int TEST_EXTENSION_TIME = 500;
-    private AmbientPulseManager mAmbientPulseManager;
-    private boolean mLivesPastNormalTime;
-
-    protected AlertingNotificationManager createAlertingNotificationManager() {
-        return mAmbientPulseManager;
-    }
-
-    @Before
-    public void setUp() {
-        mAmbientPulseManager = new AmbientPulseManager(mContext);
-        mAmbientPulseManager.mMinimumDisplayTime = TEST_MINIMUM_DISPLAY_TIME;
-        mAmbientPulseManager.mAutoDismissNotificationDecay = TEST_AUTO_DISMISS_TIME;
-        mAmbientPulseManager.mExtensionTime = TEST_EXTENSION_TIME;
-        super.setUp();
-        mAmbientPulseManager.mHandler = mTestHandler;
-    }
-
-    @Test
-    public void testExtendPulse() {
-        mAmbientPulseManager.showNotification(mEntry);
-        Runnable pastNormalTimeRunnable =
-                () -> mLivesPastNormalTime = mAmbientPulseManager.isAlerting(mEntry.key);
-        mTestHandler.postDelayed(pastNormalTimeRunnable,
-                mAmbientPulseManager.mAutoDismissNotificationDecay +
-                        mAmbientPulseManager.mExtensionTime / 2);
-        mTestHandler.postDelayed(TEST_TIMEOUT_RUNNABLE, TEST_TIMEOUT_TIME);
-
-        mAmbientPulseManager.extendPulse();
-
-        // Wait for normal time runnable and extended remove runnable and process them on arrival.
-        TestableLooper.get(this).processMessages(2);
-
-        assertFalse("Test timed out", mTimedOut);
-        assertTrue("Pulse was not extended", mLivesPastNormalTime);
-        assertFalse(mAmbientPulseManager.isAlerting(mEntry.key));
-    }
-}
-
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/MediaArtworkProcessorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/MediaArtworkProcessorTest.kt
new file mode 100644
index 0000000..72e6df2
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/MediaArtworkProcessorTest.kt
@@ -0,0 +1,109 @@
+/*
+ * 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.systemui.statusbar
+
+import com.google.common.truth.Truth.assertThat
+
+import android.graphics.Bitmap
+import android.graphics.Canvas
+import android.graphics.Color
+import android.graphics.Point
+import android.testing.AndroidTestingRunner
+import androidx.test.filters.SmallTest
+import com.android.systemui.SysuiTestCase
+import org.junit.After
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+
+private const val WIDTH = 200
+private const val HEIGHT = 200
+
+@RunWith(AndroidTestingRunner::class)
+@SmallTest
+class MediaArtworkProcessorTest : SysuiTestCase() {
+
+    private var screenWidth = 0
+    private var screenHeight = 0
+
+    private lateinit var processor: MediaArtworkProcessor
+
+    @Before
+    fun setUp() {
+        processor = MediaArtworkProcessor()
+
+        val point = Point()
+        context.display.getSize(point)
+        screenWidth = point.x
+        screenHeight = point.y
+    }
+
+    @After
+    fun tearDown() {
+        processor.clearCache()
+    }
+
+    @Test
+    fun testProcessArtwork() {
+        // GIVEN some "artwork", which is just a solid blue image
+        val artwork = Bitmap.createBitmap(WIDTH, HEIGHT, Bitmap.Config.ARGB_8888)
+        Canvas(artwork).drawColor(Color.BLUE)
+        // WHEN the background is created from the artwork
+        val background = processor.processArtwork(context, artwork)!!
+        // THEN the background has the size of the screen that has been downsamples
+        assertThat(background.height).isLessThan(screenHeight)
+        assertThat(background.width).isLessThan(screenWidth)
+        assertThat(background.config).isEqualTo(Bitmap.Config.ARGB_8888)
+    }
+
+    @Test
+    fun testCache() {
+        // GIVEN a solid blue image
+        val artwork = Bitmap.createBitmap(WIDTH, HEIGHT, Bitmap.Config.ARGB_8888)
+        Canvas(artwork).drawColor(Color.BLUE)
+        // WHEN the background is processed twice
+        val background1 = processor.processArtwork(context, artwork)!!
+        val background2 = processor.processArtwork(context, artwork)!!
+        // THEN the two bitmaps are the same
+        // Note: This is currently broken and trying to use caching causes issues
+        assertThat(background1).isNotSameAs(background2)
+    }
+
+    @Test
+    fun testConfig() {
+        // GIVEN some which is not ARGB_8888
+        val artwork = Bitmap.createBitmap(WIDTH, HEIGHT, Bitmap.Config.ALPHA_8)
+        Canvas(artwork).drawColor(Color.BLUE)
+        // WHEN the background is created from the artwork
+        val background = processor.processArtwork(context, artwork)!!
+        // THEN the background has Config ARGB_8888
+        assertThat(background.config).isEqualTo(Bitmap.Config.ARGB_8888)
+    }
+
+    @Test
+    fun testRecycledArtwork() {
+        // GIVEN some "artwork", which is just a solid blue image
+        val artwork = Bitmap.createBitmap(WIDTH, HEIGHT, Bitmap.Config.ARGB_8888)
+        Canvas(artwork).drawColor(Color.BLUE)
+        // AND the artwork is recycled
+        artwork.recycle()
+        // WHEN the background is created from the artwork
+        val background = processor.processArtwork(context, artwork)
+        // THEN the processed bitmap is null
+        assertThat(background).isNull()
+    }
+}
\ No newline at end of file
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationRemoteInputManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationRemoteInputManagerTest.java
index b81e048..da25eed 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationRemoteInputManagerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationRemoteInputManagerTest.java
@@ -1,3 +1,4 @@
+
 package com.android.systemui.statusbar;
 
 import static junit.framework.Assert.assertEquals;
@@ -22,12 +23,14 @@
 import androidx.test.filters.SmallTest;
 
 import com.android.systemui.SysuiTestCase;
+import com.android.systemui.plugins.statusbar.StatusBarStateController;
 import com.android.systemui.statusbar.NotificationRemoteInputManager.RemoteInputActiveExtender;
 import com.android.systemui.statusbar.NotificationRemoteInputManager.RemoteInputHistoryExtender;
 import com.android.systemui.statusbar.NotificationRemoteInputManager.SmartReplyHistoryExtender;
 import com.android.systemui.statusbar.notification.NotificationEntryManager;
 import com.android.systemui.statusbar.notification.collection.NotificationEntry;
 import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
+import com.android.systemui.statusbar.phone.KeyguardBypassController;
 import com.android.systemui.statusbar.phone.ShadeController;
 
 import com.google.android.collect.Sets;
@@ -54,6 +57,7 @@
     @Mock private SmartReplyController mSmartReplyController;
     @Mock private NotificationListenerService.RankingMap mRanking;
     @Mock private ExpandableNotificationRow mRow;
+    @Mock private StatusBarStateController mStateController;
 
     // Dependency mocks:
     @Mock private NotificationEntryManager mEntryManager;
@@ -73,6 +77,7 @@
         mRemoteInputManager = new TestableNotificationRemoteInputManager(mContext,
                 mLockscreenUserManager, mSmartReplyController, mEntryManager,
                 () -> mock(ShadeController.class),
+                mStateController,
                 Handler.createAsync(Looper.myLooper()));
         mSbn = new StatusBarNotification(TEST_PACKAGE_NAME, TEST_PACKAGE_NAME, 0, null, TEST_UID,
                 0, new Notification(), UserHandle.CURRENT, null, 0);
@@ -196,15 +201,15 @@
 
     private class TestableNotificationRemoteInputManager extends NotificationRemoteInputManager {
 
-
         TestableNotificationRemoteInputManager(Context context,
                 NotificationLockscreenUserManager lockscreenUserManager,
                 SmartReplyController smartReplyController,
                 NotificationEntryManager notificationEntryManager,
                 Lazy<ShadeController> shadeController,
+                StatusBarStateController statusBarStateController,
                 Handler mainHandler) {
             super(context, lockscreenUserManager, smartReplyController, notificationEntryManager,
-                    shadeController, mainHandler);
+                    shadeController, statusBarStateController, mainHandler);
         }
 
         public void setUpWithPresenterForTest(Callback callback,
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationTestHelper.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationTestHelper.java
index 028fd7a..7063ddf 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationTestHelper.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationTestHelper.java
@@ -20,6 +20,8 @@
 import static android.app.NotificationManager.IMPORTANCE_DEFAULT;
 import static android.app.NotificationManager.IMPORTANCE_HIGH;
 
+import static org.mockito.Mockito.mock;
+
 import android.annotation.Nullable;
 import android.app.ActivityManager;
 import android.app.Instrumentation;
@@ -40,11 +42,13 @@
 
 import com.android.systemui.R;
 import com.android.systemui.bubbles.BubblesTestActivity;
+import com.android.systemui.plugins.statusbar.StatusBarStateController;
 import com.android.systemui.statusbar.notification.collection.NotificationEntry;
 import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
 import com.android.systemui.statusbar.notification.row.NotificationContentInflater.InflationFlag;
 import com.android.systemui.statusbar.notification.row.NotificationContentInflaterTest;
 import com.android.systemui.statusbar.phone.HeadsUpManagerPhone;
+import com.android.systemui.statusbar.phone.KeyguardBypassController;
 import com.android.systemui.statusbar.phone.NotificationGroupManager;
 import com.android.systemui.statusbar.policy.HeadsUpManager;
 
@@ -66,14 +70,18 @@
     private final Context mContext;
     private final Instrumentation mInstrumentation;
     private int mId;
-    private final NotificationGroupManager mGroupManager = new NotificationGroupManager();
+    private final NotificationGroupManager mGroupManager;
     private ExpandableNotificationRow mRow;
-    private HeadsUpManager mHeadsUpManager;
+    private HeadsUpManagerPhone mHeadsUpManager;
 
     public NotificationTestHelper(Context context) {
         mContext = context;
         mInstrumentation = InstrumentationRegistry.getInstrumentation();
-        mHeadsUpManager = new HeadsUpManagerPhone(mContext, null, mGroupManager, null, null);
+        StatusBarStateController stateController = mock(StatusBarStateController.class);
+        mGroupManager = new NotificationGroupManager(stateController);
+        mHeadsUpManager = new HeadsUpManagerPhone(mContext, stateController,
+                mock(KeyguardBypassController.class));
+        mHeadsUpManager.setUp(null, mGroupManager, null, null);
         mGroupManager.setHeadsUpManager(mHeadsUpManager);
     }
 
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationViewHierarchyManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationViewHierarchyManagerTest.java
index 5103e8e..58fb53a 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationViewHierarchyManagerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationViewHierarchyManagerTest.java
@@ -52,6 +52,7 @@
 import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
 import com.android.systemui.statusbar.notification.row.ExpandableView;
 import com.android.systemui.statusbar.notification.stack.NotificationListContainer;
+import com.android.systemui.statusbar.phone.KeyguardBypassController;
 import com.android.systemui.statusbar.phone.NotificationGroupManager;
 import com.android.systemui.statusbar.phone.ShadeController;
 import com.android.systemui.util.Assert;
@@ -109,7 +110,9 @@
         mViewHierarchyManager = new NotificationViewHierarchyManager(mContext,
                 mHandler, mLockscreenUserManager, mGroupManager, mVisualStabilityManager,
                 mock(StatusBarStateControllerImpl.class), mEntryManager,
-                () -> mShadeController, new BubbleData(mContext), mock(DynamicPrivacyController.class));
+                () -> mShadeController, new BubbleData(mContext),
+                mock(KeyguardBypassController.class),
+                mock(DynamicPrivacyController.class));
         Dependency.get(InitController.class).executePostInitTasks();
         mViewHierarchyManager.setUpWithPresenter(mPresenter, mListContainer);
     }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/SmartReplyControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/SmartReplyControllerTest.java
index 81e373a..185723f 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/SmartReplyControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/SmartReplyControllerTest.java
@@ -38,6 +38,7 @@
 import com.android.internal.statusbar.IStatusBarService;
 import com.android.systemui.R;
 import com.android.systemui.SysuiTestCase;
+import com.android.systemui.plugins.statusbar.StatusBarStateController;
 import com.android.systemui.statusbar.notification.NotificationEntryManager;
 import com.android.systemui.statusbar.notification.collection.NotificationEntry;
 import com.android.systemui.statusbar.phone.ShadeController;
@@ -70,6 +71,7 @@
     @Mock private StatusBarNotification mSbn;
     @Mock private NotificationEntryManager mNotificationEntryManager;
     @Mock private IStatusBarService mIStatusBarService;
+    @Mock private StatusBarStateController mStatusBarStateController;
 
     @Before
     public void setUp() {
@@ -85,6 +87,7 @@
         mRemoteInputManager = new NotificationRemoteInputManager(mContext,
                 mock(NotificationLockscreenUserManager.class), mSmartReplyController,
                 mNotificationEntryManager, () -> mock(ShadeController.class),
+                mStatusBarStateController,
                 Handler.createAsync(Looper.myLooper()));
         mRemoteInputManager.setUpWithCallback(mCallback, mDelegate);
         mNotification = new Notification.Builder(mContext, "")
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/DynamicPrivacyControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/DynamicPrivacyControllerTest.java
index 6ca5d2c..d804b6f 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/DynamicPrivacyControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/DynamicPrivacyControllerTest.java
@@ -29,9 +29,12 @@
 import android.testing.TestableLooper.RunWithLooper;
 
 import com.android.systemui.SysuiTestCase;
+import com.android.systemui.plugins.statusbar.StatusBarStateController;
 import com.android.systemui.statusbar.NotificationLockscreenUserManager;
 import com.android.systemui.statusbar.NotificationViewHierarchyManager;
+import com.android.systemui.statusbar.phone.StatusBarKeyguardViewManager;
 import com.android.systemui.statusbar.phone.UnlockMethodCache;
+import com.android.systemui.statusbar.policy.KeyguardMonitor;
 
 import org.junit.Assert;
 import org.junit.Before;
@@ -51,12 +54,17 @@
             = mock(NotificationLockscreenUserManager.class);
     private DynamicPrivacyController.Listener mListener
             = mock(DynamicPrivacyController.Listener.class);
+    private KeyguardMonitor mKeyguardMonitor = mock(KeyguardMonitor.class);
 
     @Before
     public void setUp() throws Exception {
         when(mCache.canSkipBouncer()).thenReturn(false);
+        when(mKeyguardMonitor.isShowing()).thenReturn(true);
         mDynamicPrivacyController = new DynamicPrivacyController(
-                mLockScreenUserManager, mCache);
+                mLockScreenUserManager, mKeyguardMonitor, mCache,
+                mock(StatusBarStateController.class));
+        mDynamicPrivacyController.setStatusBarKeyguardViewManager(
+                mock(StatusBarKeyguardViewManager.class));
         mDynamicPrivacyController.addListener(mListener);
     }
 
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationEntryManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationEntryManagerTest.java
index 72f3a62..2ca1b06 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationEntryManagerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationEntryManagerTest.java
@@ -64,6 +64,7 @@
 import com.android.systemui.InitController;
 import com.android.systemui.R;
 import com.android.systemui.SysuiTestCase;
+import com.android.systemui.plugins.statusbar.StatusBarStateController;
 import com.android.systemui.statusbar.NotificationLifetimeExtender;
 import com.android.systemui.statusbar.NotificationListener;
 import com.android.systemui.statusbar.NotificationLockscreenUserManager;
@@ -83,6 +84,7 @@
 import com.android.systemui.statusbar.notification.row.NotificationGutsManager;
 import com.android.systemui.statusbar.notification.row.RowInflaterTask;
 import com.android.systemui.statusbar.notification.stack.NotificationListContainer;
+import com.android.systemui.statusbar.phone.KeyguardBypassController;
 import com.android.systemui.statusbar.phone.NotificationGroupManager;
 import com.android.systemui.statusbar.phone.ShadeController;
 import com.android.systemui.statusbar.policy.DeviceProvisionedController;
@@ -247,7 +249,8 @@
         mEntryManager.setNotificationRemoveInterceptor(mRemoveInterceptor);
 
         NotificationRowBinderImpl notificationRowBinder =
-                new NotificationRowBinderImpl(mContext, true /* allowLongPress */);
+                new NotificationRowBinderImpl(mContext, true, /* allowLongPress */
+                        mock(KeyguardBypassController.class), mock(StatusBarStateController.class));
         notificationRowBinder.setUpWithPresenter(
                 mPresenter, mListContainer, mHeadsUpManager, mEntryManager, mBindCallback);
         notificationRowBinder.setNotificationClicker(mock(NotificationClicker.class));
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationFilterTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationFilterTest.java
index 91a7ea8..6f7751b 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationFilterTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationFilterTest.java
@@ -40,6 +40,7 @@
 
 import com.android.systemui.ForegroundServiceController;
 import com.android.systemui.SysuiTestCase;
+import com.android.systemui.plugins.statusbar.StatusBarStateController;
 import com.android.systemui.statusbar.NotificationTestHelper;
 import com.android.systemui.statusbar.notification.collection.NotificationData;
 import com.android.systemui.statusbar.notification.collection.NotificationEntry;
@@ -90,7 +91,7 @@
                 .thenReturn(PackageManager.PERMISSION_GRANTED);
         mDependency.injectTestDependency(ForegroundServiceController.class, mFsc);
         mDependency.injectTestDependency(NotificationGroupManager.class,
-                new NotificationGroupManager());
+                new NotificationGroupManager(mock(StatusBarStateController.class)));
         mDependency.injectMockDependency(ShadeController.class);
         mDependency.injectTestDependency(NotificationData.KeyguardEnvironment.class, mEnvironment);
         when(mEnvironment.isDeviceProvisioned()).thenReturn(true);
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 f629757..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
@@ -69,6 +69,7 @@
 import com.android.systemui.ForegroundServiceController;
 import com.android.systemui.InitController;
 import com.android.systemui.SysuiTestCase;
+import com.android.systemui.plugins.statusbar.StatusBarStateController;
 import com.android.systemui.statusbar.NotificationTestHelper;
 import com.android.systemui.statusbar.notification.collection.NotificationData.KeyguardEnvironment;
 import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
@@ -127,7 +128,7 @@
 
         mDependency.injectTestDependency(ForegroundServiceController.class, mFsc);
         mDependency.injectTestDependency(NotificationGroupManager.class,
-                new NotificationGroupManager());
+                new NotificationGroupManager(mock(StatusBarStateController.class)));
         mDependency.injectMockDependency(ShadeController.class);
         mDependency.injectTestDependency(KeyguardEnvironment.class, mEnvironment);
         when(mEnvironment.isDeviceProvisioned()).thenReturn(true);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowTest.java
index 8077e3f..d526d10 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowTest.java
@@ -37,9 +37,7 @@
 import static org.mockito.Mockito.when;
 
 import android.app.AppOpsManager;
-import android.app.Notification;
 import android.app.NotificationChannel;
-import android.os.UserHandle;
 import android.testing.AndroidTestingRunner;
 import android.testing.TestableLooper;
 import android.testing.TestableLooper.RunWithLooper;
@@ -51,6 +49,7 @@
 
 import com.android.systemui.SysuiTestCase;
 import com.android.systemui.plugins.statusbar.NotificationMenuRowPlugin;
+import com.android.systemui.plugins.statusbar.StatusBarStateController;
 import com.android.systemui.statusbar.NotificationTestHelper;
 import com.android.systemui.statusbar.notification.AboveShelfChangedListener;
 import com.android.systemui.statusbar.notification.stack.NotificationChildrenContainer;
@@ -138,13 +137,6 @@
     }
 
     @Test
-    public void testIconColorShouldBeUpdatedWhenSettingDark() throws Exception {
-        ExpandableNotificationRow row = spy(mNotificationTestHelper.createRow());
-        row.setDark(true, false, 0);
-        verify(row).updateShelfIconColor();
-    }
-
-    @Test
     public void testFreeContentViewWhenSafe() throws Exception {
         ExpandableNotificationRow row = mNotificationTestHelper.createRow(FLAG_CONTENT_VIEW_ALL);
 
@@ -212,7 +204,9 @@
     @Test
     public void testClickSound() throws Exception {
         assertTrue("Should play sounds by default.", mGroupRow.isSoundEffectsEnabled());
-        mGroupRow.setDark(true /* dark */, false /* fade */, 0 /* delay */);
+        StatusBarStateController mock = mock(StatusBarStateController.class);
+        when(mock.isDozing()).thenReturn(true);
+        mGroupRow.setStatusBarStateController(mock);
         mGroupRow.setSecureStateProvider(()-> false);
         assertFalse("Shouldn't play sounds when dark and trusted.",
                 mGroupRow.isSoundEffectsEnabled());
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationContentInflaterTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationContentInflaterTest.java
index 06ff047..2ec125e 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationContentInflaterTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationContentInflaterTest.java
@@ -17,7 +17,6 @@
 package com.android.systemui.statusbar.notification.row;
 
 import static com.android.systemui.statusbar.notification.row.NotificationContentInflater.FLAG_CONTENT_VIEW_ALL;
-import static com.android.systemui.statusbar.notification.row.NotificationContentInflater.FLAG_CONTENT_VIEW_AMBIENT;
 import static com.android.systemui.statusbar.notification.row.NotificationContentInflater.FLAG_CONTENT_VIEW_EXPANDED;
 import static com.android.systemui.statusbar.notification.row.NotificationContentInflater.FLAG_CONTENT_VIEW_HEADS_UP;
 import static com.android.systemui.statusbar.notification.row.NotificationContentInflater.FLAG_CONTENT_VIEW_PUBLIC;
@@ -135,7 +134,6 @@
                 mNotificationInflater);
 
         assertNotNull(mRow.getPrivateLayout().getHeadsUpChild());
-        assertNull(mRow.getShowingLayout().getAmbientChild());
         verify(mRow).onNotificationUpdated();
     }
 
@@ -178,7 +176,7 @@
                 result,
                 FLAG_CONTENT_VIEW_EXPANDED,
                 0,
-                new ArrayMap() /* cachedContentViews */, mRow, false /* redactAmbient */,
+                new ArrayMap() /* cachedContentViews */, mRow,
                 true /* isNewView */, (v, p, r) -> true,
                 new InflationCallback() {
                     @Override
@@ -210,14 +208,12 @@
 
     @Test
     public void testUpdateNeedsRedactionReinflatesChangedContentViews() {
-        mNotificationInflater.updateInflationFlag(FLAG_CONTENT_VIEW_AMBIENT, true);
         mNotificationInflater.updateInflationFlag(FLAG_CONTENT_VIEW_PUBLIC, true);
         mNotificationInflater.updateNeedsRedaction(true);
 
         NotificationContentInflater.AsyncInflationTask asyncInflationTask =
                 (NotificationContentInflater.AsyncInflationTask) mRow.getEntry().getRunningTask();
-        assertEquals(FLAG_CONTENT_VIEW_AMBIENT | FLAG_CONTENT_VIEW_PUBLIC,
-                asyncInflationTask.getReInflateFlags());
+        assertEquals(FLAG_CONTENT_VIEW_PUBLIC, asyncInflationTask.getReInflateFlags());
         asyncInflationTask.abort();
     }
 
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationContentViewTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationContentViewTest.java
index 5cd0ca7..675b3ef 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationContentViewTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationContentViewTest.java
@@ -50,8 +50,6 @@
 
     NotificationContentView mView;
 
-    private Icon mActionIcon;
-
     @Before
     @UiThreadTest
     public void setup() {
@@ -62,12 +60,11 @@
         doReturn(10).when(mockRow).getIntrinsicHeight();
 
         mView.setContainingNotification(mockRow);
-        mView.setHeights(10, 20, 30, 40);
+        mView.setHeights(10, 20, 30);
 
         mView.setContractedChild(createViewWithHeight(10));
         mView.setExpandedChild(createViewWithHeight(20));
         mView.setHeadsUpChild(createViewWithHeight(30));
-        mView.setAmbientChild(createViewWithHeight(40));
 
         mView.measure(View.MeasureSpec.UNSPECIFIED, View.MeasureSpec.UNSPECIFIED);
         mView.layout(0, 0, mView.getMeasuredWidth(), mView.getMeasuredHeight());
@@ -81,16 +78,6 @@
 
     @Test
     @UiThreadTest
-    public void animationStartType_getsClearedAfterUpdatingVisibilitiesWithoutAnimation() {
-        mView.setHeadsUp(true);
-        mView.setDark(true, false, 0);
-        mView.setDark(false, true, 0);
-        mView.setHeadsUpAnimatingAway(true);
-        assertFalse(mView.isAnimatingVisibleType());
-    }
-
-    @Test
-    @UiThreadTest
     public void testShowAppOpsIcons() {
         NotificationHeaderView mockContracted = mock(NotificationHeaderView.class);
         when(mockContracted.findViewById(com.android.internal.R.id.notification_header))
@@ -101,14 +88,10 @@
         NotificationHeaderView mockHeadsUp = mock(NotificationHeaderView.class);
         when(mockHeadsUp.findViewById(com.android.internal.R.id.notification_header))
                 .thenReturn(mockHeadsUp);
-        NotificationHeaderView mockAmbient = mock(NotificationHeaderView.class);
-        when(mockAmbient.findViewById(com.android.internal.R.id.notification_header))
-                .thenReturn(mockAmbient);
 
         mView.setContractedChild(mockContracted);
         mView.setExpandedChild(mockExpanded);
         mView.setHeadsUpChild(mockHeadsUp);
-        mView.setAmbientChild(mockAmbient);
 
         ArraySet<Integer> ops = new ArraySet<>();
         ops.add(AppOpsManager.OP_ANSWER_PHONE_CALLS);
@@ -116,7 +99,6 @@
 
         verify(mockContracted, times(1)).showAppOpsIcons(ops);
         verify(mockExpanded, times(1)).showAppOpsIcons(ops);
-        verify(mockAmbient, never()).showAppOpsIcons(ops);
         verify(mockHeadsUp, times(1)).showAppOpsIcons(any());
     }
 }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationRoundnessManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationRoundnessManagerTest.java
index 1b4acd7..524ad85 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationRoundnessManagerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationRoundnessManagerTest.java
@@ -30,11 +30,12 @@
 import androidx.test.filters.SmallTest;
 
 import com.android.systemui.SysuiTestCase;
-import com.android.systemui.statusbar.AmbientPulseManager;
+import com.android.systemui.plugins.statusbar.StatusBarStateController;
 import com.android.systemui.statusbar.NotificationTestHelper;
 import com.android.systemui.statusbar.notification.collection.NotificationEntry;
 import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
 import com.android.systemui.statusbar.notification.row.ExpandableView;
+import com.android.systemui.statusbar.phone.KeyguardBypassController;
 
 import org.junit.Assert;
 import org.junit.Before;
@@ -56,12 +57,14 @@
     private ExpandableNotificationRow mFirst;
     private ExpandableNotificationRow mSecond;
     @Mock
-    private AmbientPulseManager mAmbientPulseManager;
+    private StatusBarStateController mStatusBarStateController;
+    @Mock
+    private KeyguardBypassController mBypassController;
 
     @Before
     public void setUp() throws Exception {
         MockitoAnnotations.initMocks(this);
-        mRoundnessManager = new NotificationRoundnessManager(mAmbientPulseManager);
+        mRoundnessManager = new NotificationRoundnessManager(mBypassController);
         com.android.systemui.util.Assert.sMainLooper = TestableLooper.get(this).getLooper();
         NotificationTestHelper testHelper = new NotificationTestHelper(getContext());
         mFirst = testHelper.createRow();
@@ -147,11 +150,15 @@
         NotificationEntry entry = mock(NotificationEntry.class);
         when(entry.getRow()).thenReturn(row);
 
-        mRoundnessManager.onAmbientStateChanged(entry, true);
+        when(mStatusBarStateController.isDozing()).thenReturn(true);
+        row.setStatusBarStateController(mStatusBarStateController);
+        row.setHeadsUp(true);
+        mRoundnessManager.onHeadsUpStateChanged(entry, true);
         Assert.assertEquals(1f, row.getCurrentBottomRoundness(), 0.0f);
         Assert.assertEquals(1f, row.getCurrentTopRoundness(), 0.0f);
 
-        mRoundnessManager.onAmbientStateChanged(entry, false);
+        row.setHeadsUp(false);
+        mRoundnessManager.onHeadsUpStateChanged(entry, false);
         Assert.assertEquals(0f, row.getCurrentBottomRoundness(), 0.0f);
         Assert.assertEquals(0f, row.getCurrentTopRoundness(), 0.0f);
     }
@@ -256,15 +263,15 @@
     }
 
     @Test
-    public void testTrackingHeadsUpNotRoundedIfPushingDown() {
+    public void testTrackingHeadsUpPartiallyRoundedIfPushingDown() {
         mRoundnessManager.setExpanded(1.0f /* expandedHeight */, 0.5f /* appearFraction */);
         mRoundnessManager.setTrackingHeadsUp(mFirst);
         mRoundnessManager.updateRoundedChildren(new NotificationSection[]{
                 createSection(mSecond, mSecond),
                 createSection(null, null)
         });
-        Assert.assertEquals(0.0f, mFirst.getCurrentBottomRoundness(), 0.0f);
-        Assert.assertEquals(0.0f, mFirst.getCurrentTopRoundness(), 0.0f);
+        Assert.assertEquals(0.5f, mFirst.getCurrentBottomRoundness(), 0.0f);
+        Assert.assertEquals(0.5f, mFirst.getCurrentTopRoundness(), 0.0f);
     }
 
     @Test
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 ff83587..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
@@ -55,13 +55,13 @@
 import com.android.systemui.SysuiTestCase;
 import com.android.systemui.plugins.statusbar.NotificationMenuRowPlugin;
 import com.android.systemui.plugins.statusbar.StatusBarStateController;
-import com.android.systemui.statusbar.AmbientPulseManager;
 import com.android.systemui.statusbar.EmptyShadeView;
 import com.android.systemui.statusbar.NotificationPresenter;
 import com.android.systemui.statusbar.NotificationRemoteInputManager;
 import com.android.systemui.statusbar.NotificationShelf;
 import com.android.systemui.statusbar.RemoteInputController;
 import com.android.systemui.statusbar.StatusBarState;
+import com.android.systemui.statusbar.SysuiStatusBarStateController;
 import com.android.systemui.statusbar.notification.DynamicPrivacyController;
 import com.android.systemui.statusbar.notification.NotificationEntryManager;
 import com.android.systemui.statusbar.notification.collection.NotificationData;
@@ -70,6 +70,7 @@
 import com.android.systemui.statusbar.notification.row.FooterView;
 import com.android.systemui.statusbar.notification.row.NotificationBlockingHelperManager;
 import com.android.systemui.statusbar.phone.HeadsUpManagerPhone;
+import com.android.systemui.statusbar.phone.KeyguardBypassController;
 import com.android.systemui.statusbar.phone.NotificationGroupManager;
 import com.android.systemui.statusbar.phone.NotificationIconAreaController;
 import com.android.systemui.statusbar.phone.ScrimController;
@@ -105,7 +106,7 @@
 
     @Rule public MockitoRule mockito = MockitoJUnit.rule();
     @Mock private StatusBar mBar;
-    @Mock private StatusBarStateController mBarState;
+    @Mock private SysuiStatusBarStateController mBarState;
     @Mock private HeadsUpManagerPhone mHeadsUpManager;
     @Mock private NotificationBlockingHelperManager mBlockingHelperManager;
     @Mock private NotificationGroupManager mGroupManager;
@@ -117,6 +118,7 @@
     @Mock private NotificationIconAreaController mNotificationIconAreaController;
     @Mock private MetricsLogger mMetricsLogger;
     @Mock private NotificationRoundnessManager mNotificationRoundnessManager;
+    @Mock private KeyguardBypassController mKeyguardBypassController;
     private TestableNotificationEntryManager mEntryManager;
     private int mOriginalInterruptionModelSetting;
 
@@ -135,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);
@@ -158,16 +160,16 @@
         // member variables, not the spy's member variables.
         mStackScrollerInternal = new NotificationStackScrollLayout(getContext(), null,
                 true /* allowLongPress */, mNotificationRoundnessManager,
-                new AmbientPulseManager(mContext),
                 mock(DynamicPrivacyController.class),
                 mock(ConfigurationController.class),
                 mock(ActivityStarterDelegate.class),
-                mock(StatusBarStateController.class));
+                mock(SysuiStatusBarStateController.class),
+                mHeadsUpManager,
+                mKeyguardBypassController);
         mStackScroller = spy(mStackScrollerInternal);
         mStackScroller.setShelf(notificationShelf);
         mStackScroller.setStatusBar(mBar);
         mStackScroller.setScrimController(mock(ScrimController.class));
-        mStackScroller.setHeadsUpManager(mHeadsUpManager);
         mStackScroller.setGroupManager(mGroupManager);
         mStackScroller.setEmptyShadeView(mEmptyShadeView);
         mStackScroller.setIconAreaController(mNotificationIconAreaController);
@@ -182,7 +184,6 @@
         doNothing().when(mGroupManager).collapseAllGroups();
         doNothing().when(mExpandHelper).cancelImmediately();
         doNothing().when(notificationShelf).setAnimationsEnabled(anyBoolean());
-        doNothing().when(notificationShelf).fadeInTranslating();
     }
 
     @After
@@ -200,17 +201,6 @@
     }
 
     @Test
-    public void testAntiBurnInOffset() {
-        final int burnInOffset = 30;
-        mStackScroller.setAntiBurnInOffsetX(burnInOffset);
-        mStackScroller.setDark(false /* dark */, false /* animated */, null /* touch */);
-        Assert.assertEquals(0 /* expected */, mStackScroller.getTranslationX(), 0.01 /* delta */);
-        mStackScroller.setDark(true /* dark */, false /* animated */, null /* touch */);
-        Assert.assertEquals(burnInOffset /* expected */, mStackScroller.getTranslationX(),
-                0.01 /* delta */);
-    }
-
-    @Test
     public void updateEmptyView_dndSuppressing() {
         when(mEmptyShadeView.willBeGone()).thenReturn(true);
         when(mBar.areNotificationsHidden()).thenReturn(true);
@@ -395,7 +385,7 @@
         NotificationSwipeHelper swipeActionHelper =
                 (NotificationSwipeHelper) mStackScroller.getSwipeActionHelper();
         swipeActionHelper.setExposedMenuView(new View(mContext));
-        mStackScroller.setDarkAmount(0.1f, 0.1f);
+        mStackScroller.setHideAmount(0.1f, 0.1f);
         assertNull(swipeActionHelper.getExposedMenuView());
     }
 
@@ -442,9 +432,7 @@
 
     @Test
     @UiThreadTest
-    public void testOnMenuShownLogging() {
-        // Set up the object under test to have a valid mHeadsUpManager. See notes in setup.
-        mStackScrollerInternal.setHeadsUpManager(mHeadsUpManager);
+    public void testOnMenuShownLogging() { ;
 
         ExpandableNotificationRow row = mock(ExpandableNotificationRow.class, RETURNS_DEEP_STUBS);
         when(row.getStatusBarNotification().getLogMaker()).thenReturn(new LogMaker(
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/BiometricsUnlockControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/BiometricsUnlockControllerTest.java
index d2d294b..fd67611 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/BiometricsUnlockControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/BiometricsUnlockControllerTest.java
@@ -16,6 +16,8 @@
 
 package com.android.systemui.statusbar.phone;
 
+import static com.google.common.truth.Truth.assertThat;
+
 import static org.mockito.ArgumentMatchers.any;
 import static org.mockito.ArgumentMatchers.anyBoolean;
 import static org.mockito.ArgumentMatchers.anyFloat;
@@ -37,7 +39,6 @@
 import com.android.systemui.SysuiTestCase;
 import com.android.systemui.keyguard.KeyguardViewMediator;
 import com.android.systemui.statusbar.NotificationMediaManager;
-import com.android.systemui.tuner.TunerService;
 
 import org.junit.Before;
 import org.junit.Test;
@@ -71,9 +72,9 @@
     @Mock
     private UnlockMethodCache mUnlockMethodCache;
     @Mock
-    private TunerService mTunerService;
-    @Mock
     private Handler mHandler;
+    @Mock
+    private KeyguardBypassController mKeyguardBypassController;
     private BiometricUnlockController mBiometricUnlockController;
 
     @Before
@@ -81,12 +82,16 @@
         MockitoAnnotations.initMocks(this);
         when(mStatusBarKeyguardViewManager.isShowing()).thenReturn(true);
         when(mUpdateMonitor.isDeviceInteractive()).thenReturn(true);
+        when(mUnlockMethodCache.isFaceAuthEnabled()).thenReturn(true);
+        when(mKeyguardBypassController.onBiometricAuthenticated(any())).thenReturn(true);
+        when(mKeyguardBypassController.canPlaySubtleWindowAnimations()).thenReturn(true);
         mContext.addMockSystemService(PowerManager.class, mPowerManager);
         mDependency.injectTestDependency(NotificationMediaManager.class, mMediaManager);
         mDependency.injectTestDependency(StatusBarWindowController.class,
                 mStatusBarWindowController);
-        mBiometricUnlockController = new TestableBiometricUnlockController(
-                false /* faceDismissesKeyguard */);
+        mBiometricUnlockController = new BiometricUnlockController(mContext, mDozeScrimController,
+                mKeyguardViewMediator, mScrimController, mStatusBar, mUnlockMethodCache,
+                mHandler, mUpdateMonitor, 0 /* wakeUpDelay */, mKeyguardBypassController);
         mBiometricUnlockController.setStatusBarKeyguardViewManager(mStatusBarKeyguardViewManager);
     }
 
@@ -124,7 +129,7 @@
     @Test
     public void onBiometricAuthenticated_whenFingerprintOnBouncer_dismissBouncer() {
         when(mUpdateMonitor.isUnlockingWithBiometricAllowed()).thenReturn(true);
-        when(mStatusBarKeyguardViewManager.isBouncerShowing()).thenReturn(true);
+        when(mStatusBarKeyguardViewManager.bouncerIsOrWillBeShowing()).thenReturn(true);
         mBiometricUnlockController.onBiometricAuthenticated(UserHandle.USER_CURRENT,
                 BiometricSourceType.FINGERPRINT);
 
@@ -138,25 +143,60 @@
                 BiometricSourceType.FACE);
 
         verify(mStatusBarKeyguardViewManager, never()).animateCollapsePanels(anyFloat());
+        verify(mStatusBarKeyguardViewManager, never()).notifyKeyguardAuthenticated(anyBoolean());
     }
 
     @Test
-    public void onBiometricAuthenticated_whenFace_dismissingKeyguard() {
-        mBiometricUnlockController = new TestableBiometricUnlockController(
-                true /* faceDismissesKeyguard */);
+    public void onBiometricAuthenticated_whenFace_andBypass_dismissKeyguard() {
+        when(mKeyguardBypassController.getBypassEnabled()).thenReturn(true);
         mBiometricUnlockController.setStatusBarKeyguardViewManager(mStatusBarKeyguardViewManager);
 
         when(mUpdateMonitor.isUnlockingWithBiometricAllowed()).thenReturn(true);
         mBiometricUnlockController.onBiometricAuthenticated(UserHandle.USER_CURRENT,
                 BiometricSourceType.FACE);
 
-        verify(mStatusBarKeyguardViewManager).animateCollapsePanels(anyFloat());
+        verify(mStatusBarKeyguardViewManager, never()).animateCollapsePanels(anyFloat());
+        verify(mStatusBarKeyguardViewManager).notifyKeyguardAuthenticated(eq(false));
+    }
+
+    @Test
+    public void onBiometricAuthenticated_whenFace_andBypass_encrypted_showBouncer() {
+        reset(mUpdateMonitor);
+        when(mKeyguardBypassController.getBypassEnabled()).thenReturn(true);
+        mBiometricUnlockController.setStatusBarKeyguardViewManager(mStatusBarKeyguardViewManager);
+
+        when(mUpdateMonitor.isUnlockingWithBiometricAllowed()).thenReturn(false);
+        mBiometricUnlockController.onBiometricAuthenticated(UserHandle.USER_CURRENT,
+                BiometricSourceType.FACE);
+
+        // Wake up before showing the bouncer
+        verify(mStatusBarKeyguardViewManager, never()).showBouncer(eq(false));
+        mBiometricUnlockController.mWakefulnessObserver.onFinishedWakingUp();
+
+        verify(mStatusBarKeyguardViewManager).showBouncer(eq(false));
+        assertThat(mBiometricUnlockController.getMode())
+                .isEqualTo(BiometricUnlockController.MODE_SHOW_BOUNCER);
+    }
+
+    @Test
+    public void onBiometricAuthenticated_whenFace_noBypass_encrypted_doNothing() {
+        reset(mUpdateMonitor);
+        mBiometricUnlockController.setStatusBarKeyguardViewManager(mStatusBarKeyguardViewManager);
+
+        when(mUpdateMonitor.isUnlockingWithBiometricAllowed()).thenReturn(false);
+        mBiometricUnlockController.onBiometricAuthenticated(UserHandle.USER_CURRENT,
+                BiometricSourceType.FACE);
+
+        verify(mStatusBarKeyguardViewManager, never()).showBouncer(anyBoolean());
+        verify(mStatusBarKeyguardViewManager, never()).animateCollapsePanels(anyFloat());
+        assertThat(mBiometricUnlockController.getMode())
+                .isEqualTo(BiometricUnlockController.MODE_NONE);
     }
 
     @Test
     public void onBiometricAuthenticated_whenFaceOnBouncer_dismissBouncer() {
         when(mUpdateMonitor.isUnlockingWithBiometricAllowed()).thenReturn(true);
-        when(mStatusBarKeyguardViewManager.isBouncerShowing()).thenReturn(true);
+        when(mStatusBarKeyguardViewManager.bouncerIsOrWillBeShowing()).thenReturn(true);
         mBiometricUnlockController.onBiometricAuthenticated(UserHandle.USER_CURRENT,
                 BiometricSourceType.FACE);
 
@@ -164,6 +204,34 @@
     }
 
     @Test
+    public void onBiometricAuthenticated_whenBypassOnBouncer_dismissBouncer() {
+        reset(mKeyguardBypassController);
+        when(mUpdateMonitor.isUnlockingWithBiometricAllowed()).thenReturn(true);
+        when(mKeyguardBypassController.getBypassEnabled()).thenReturn(true);
+        when(mKeyguardBypassController.onBiometricAuthenticated(any())).thenReturn(true);
+        when(mStatusBarKeyguardViewManager.bouncerIsOrWillBeShowing()).thenReturn(true);
+        mBiometricUnlockController.onBiometricAuthenticated(UserHandle.USER_CURRENT,
+                BiometricSourceType.FACE);
+
+        verify(mStatusBarKeyguardViewManager).notifyKeyguardAuthenticated(eq(false));
+        assertThat(mBiometricUnlockController.getMode())
+                .isEqualTo(BiometricUnlockController.MODE_DISMISS_BOUNCER);
+    }
+
+    @Test
+    public void onBiometricAuthenticated_whenBypassOnBouncer_respectsCanPlaySubtleAnim() {
+        when(mUpdateMonitor.isUnlockingWithBiometricAllowed()).thenReturn(true);
+        when(mKeyguardBypassController.getBypassEnabled()).thenReturn(true);
+        when(mStatusBarKeyguardViewManager.bouncerIsOrWillBeShowing()).thenReturn(true);
+        mBiometricUnlockController.onBiometricAuthenticated(UserHandle.USER_CURRENT,
+                BiometricSourceType.FACE);
+
+        verify(mStatusBarKeyguardViewManager).notifyKeyguardAuthenticated(eq(false));
+        assertThat(mBiometricUnlockController.getMode())
+                .isEqualTo(BiometricUnlockController.MODE_UNLOCK_FADING);
+    }
+
+    @Test
     public void onBiometricAuthenticated_whenFaceAndPulsing_dontDismissKeyguard() {
         reset(mUpdateMonitor);
         reset(mStatusBarKeyguardViewManager);
@@ -186,15 +254,4 @@
         mBiometricUnlockController.onFinishedGoingToSleep(-1);
         verify(mHandler).post(any());
     }
-
-    private class TestableBiometricUnlockController extends BiometricUnlockController {
-
-        TestableBiometricUnlockController(boolean faceDismissesKeyguard) {
-            super(mContext, mDozeScrimController,
-                    mKeyguardViewMediator, mScrimController, mStatusBar, mUnlockMethodCache,
-                    mHandler, mUpdateMonitor, mTunerService, 0 /* wakeUpDelay */,
-                    faceDismissesKeyguard);
-            mFaceDismissesKeyguard = faceDismissesKeyguard;
-        }
-    }
 }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/DozeParametersTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/DozeParametersTest.java
index f6f4eb48..60050b1 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/DozeParametersTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/DozeParametersTest.java
@@ -16,10 +16,6 @@
 
 package com.android.systemui.statusbar.phone;
 
-import static junit.framework.Assert.assertFalse;
-import static junit.framework.Assert.assertTrue;
-import static junit.framework.Assert.fail;
-
 import static org.mockito.ArgumentMatchers.eq;
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.reset;
@@ -33,7 +29,6 @@
 
 import com.android.systemui.SysuiTestCase;
 import com.android.systemui.doze.DozeScreenState;
-import com.android.systemui.statusbar.phone.DozeParameters.IntInOutMatcher;
 
 import org.junit.Assert;
 import org.junit.Test;
@@ -44,160 +39,6 @@
 public class DozeParametersTest extends SysuiTestCase {
 
     @Test
-    public void test_inOutMatcher_defaultIn() {
-        IntInOutMatcher intInOutMatcher = new IntInOutMatcher("*");
-
-        assertTrue(intInOutMatcher.isIn(1));
-        assertTrue(intInOutMatcher.isIn(-1));
-        assertTrue(intInOutMatcher.isIn(0));
-    }
-
-    @Test
-    public void test_inOutMatcher_defaultOut() {
-        IntInOutMatcher intInOutMatcher = new IntInOutMatcher("!*");
-
-        assertFalse(intInOutMatcher.isIn(1));
-        assertFalse(intInOutMatcher.isIn(-1));
-        assertFalse(intInOutMatcher.isIn(0));
-    }
-
-    @Test
-    public void test_inOutMatcher_someIn() {
-        IntInOutMatcher intInOutMatcher = new IntInOutMatcher("1,2,3,!*");
-
-        assertTrue(intInOutMatcher.isIn(1));
-        assertTrue(intInOutMatcher.isIn(2));
-        assertTrue(intInOutMatcher.isIn(3));
-
-        assertFalse(intInOutMatcher.isIn(0));
-        assertFalse(intInOutMatcher.isIn(4));
-    }
-
-    @Test
-    public void test_inOutMatcher_someOut() {
-        IntInOutMatcher intInOutMatcher = new IntInOutMatcher("!1,!2,!3,*");
-
-        assertFalse(intInOutMatcher.isIn(1));
-        assertFalse(intInOutMatcher.isIn(2));
-        assertFalse(intInOutMatcher.isIn(3));
-
-        assertTrue(intInOutMatcher.isIn(0));
-        assertTrue(intInOutMatcher.isIn(4));
-    }
-
-    @Test
-    public void test_inOutMatcher_mixed() {
-        IntInOutMatcher intInOutMatcher = new IntInOutMatcher("!1,2,!3,*");
-
-        assertFalse(intInOutMatcher.isIn(1));
-        assertTrue(intInOutMatcher.isIn(2));
-        assertFalse(intInOutMatcher.isIn(3));
-
-        assertTrue(intInOutMatcher.isIn(0));
-        assertTrue(intInOutMatcher.isIn(4));
-    }
-
-    @Test
-    public void test_inOutMatcher_failEmpty() {
-        try {
-            new IntInOutMatcher("");
-            fail("Expected IllegalArgumentException");
-        } catch (IllegalArgumentException e) {
-            // expected
-        }
-    }
-
-    @Test
-    public void test_inOutMatcher_failNull() {
-        try {
-            new IntInOutMatcher(null);
-            fail("Expected IllegalArgumentException");
-        } catch (IllegalArgumentException e) {
-            // expected
-        }
-    }
-
-    @Test
-    public void test_inOutMatcher_failEmptyClause() {
-        try {
-            new IntInOutMatcher("!1,*,");
-            fail("Expected IllegalArgumentException");
-        } catch (IllegalArgumentException e) {
-            // expected
-        }
-    }
-
-    @Test
-    public void test_inOutMatcher_failDuplicate() {
-        try {
-            new IntInOutMatcher("!1,*,!1");
-            fail("Expected IllegalArgumentException");
-        } catch (IllegalArgumentException e) {
-            // expected
-        }
-    }
-
-    @Test
-    public void test_inOutMatcher_failDuplicateDefault() {
-        try {
-            new IntInOutMatcher("!1,*,*");
-            fail("Expected IllegalArgumentException");
-        } catch (IllegalArgumentException e) {
-            // expected
-        }
-    }
-
-    @Test
-    public void test_inOutMatcher_failMalformedNot() {
-        try {
-            new IntInOutMatcher("!,*");
-            fail("Expected IllegalArgumentException");
-        } catch (IllegalArgumentException e) {
-            // expected
-        }
-    }
-
-    @Test
-    public void test_inOutMatcher_failText() {
-        try {
-            new IntInOutMatcher("!abc,*");
-            fail("Expected IllegalArgumentException");
-        } catch (IllegalArgumentException e) {
-            // expected
-        }
-    }
-
-    @Test
-    public void test_inOutMatcher_failContradiction() {
-        try {
-            new IntInOutMatcher("1,!1,*");
-            fail("Expected IllegalArgumentException");
-        } catch (IllegalArgumentException e) {
-            // expected
-        }
-    }
-
-    @Test
-    public void test_inOutMatcher_failContradictionDefault() {
-        try {
-            new IntInOutMatcher("1,*,!*");
-            fail("Expected IllegalArgumentException");
-        } catch (IllegalArgumentException e) {
-            // expected
-        }
-    }
-
-    @Test
-    public void test_inOutMatcher_failMissingDefault() {
-        try {
-            new IntInOutMatcher("1");
-            fail("Expected IllegalArgumentException");
-        } catch (IllegalArgumentException e) {
-            // expected
-        }
-    }
-
-    @Test
     public void test_setControlScreenOffAnimation_setsDozeAfterScreenOff_false() {
         TestableDozeParameters dozeParameters = new TestableDozeParameters(getContext());
         PowerManager mockedPowerManager = dozeParameters.getPowerManager();
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/HeadsUpAppearanceControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/HeadsUpAppearanceControllerTest.java
index 0479b4a..a38094d 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/HeadsUpAppearanceControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/HeadsUpAppearanceControllerTest.java
@@ -32,8 +32,10 @@
 
 import com.android.systemui.SysuiTestCase;
 import com.android.systemui.plugins.DarkIconDispatcher;
+import com.android.systemui.plugins.statusbar.StatusBarStateController;
 import com.android.systemui.statusbar.HeadsUpStatusBarView;
 import com.android.systemui.statusbar.NotificationTestHelper;
+import com.android.systemui.statusbar.notification.NotificationWakeUpCoordinator;
 import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
 import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayout;
 
@@ -56,6 +58,9 @@
     private HeadsUpStatusBarView mHeadsUpStatusBarView;
     private HeadsUpManagerPhone mHeadsUpManager;
     private View mOperatorNameView;
+    private StatusBarStateController mStatusbarStateController;
+    private KeyguardBypassController mBypassController;
+    private NotificationWakeUpCoordinator mWakeUpCoordinator;
 
     @Before
     public void setUp() throws Exception {
@@ -67,16 +72,22 @@
                 mock(TextView.class));
         mHeadsUpManager = mock(HeadsUpManagerPhone.class);
         mOperatorNameView = new View(mContext);
+        mStatusbarStateController = mock(StatusBarStateController.class);
+        mBypassController = mock(KeyguardBypassController.class);
+        mWakeUpCoordinator = mock(NotificationWakeUpCoordinator.class);
         mHeadsUpAppearanceController = new HeadsUpAppearanceController(
                 mock(NotificationIconAreaController.class),
                 mHeadsUpManager,
+                mStatusbarStateController,
+                mBypassController,
+                mWakeUpCoordinator,
                 mHeadsUpStatusBarView,
                 mStackScroller,
                 mPanelView,
                 new View(mContext),
                 mOperatorNameView,
                 new View(mContext));
-        mHeadsUpAppearanceController.setExpandedHeight(0.0f, 0.0f);
+        mHeadsUpAppearanceController.setAppearFraction(0.0f, 0.0f);
     }
 
     @Test
@@ -139,11 +150,14 @@
 
     @Test
     public void testHeaderReadFromOldController() {
-        mHeadsUpAppearanceController.setExpandedHeight(1.0f, 1.0f);
+        mHeadsUpAppearanceController.setAppearFraction(1.0f, 1.0f);
 
         HeadsUpAppearanceController newController = new HeadsUpAppearanceController(
                 mock(NotificationIconAreaController.class),
                 mHeadsUpManager,
+                mStatusbarStateController,
+                mBypassController,
+                mWakeUpCoordinator,
                 mHeadsUpStatusBarView,
                 mStackScroller,
                 mPanelView,
@@ -154,8 +168,8 @@
 
         Assert.assertEquals(mHeadsUpAppearanceController.mExpandedHeight,
                 newController.mExpandedHeight, 0.0f);
-        Assert.assertEquals(mHeadsUpAppearanceController.mExpandFraction,
-                newController.mExpandFraction, 0.0f);
+        Assert.assertEquals(mHeadsUpAppearanceController.mAppearFraction,
+                newController.mAppearFraction, 0.0f);
         Assert.assertEquals(mHeadsUpAppearanceController.mIsExpanded,
                 newController.mIsExpanded);
     }
@@ -172,7 +186,7 @@
         verify(mPanelView).removeVerticalTranslationListener(any());
         verify(mPanelView).removeTrackingHeadsUpListener(any());
         verify(mPanelView).setHeadsUpAppearanceController(any());
-        verify(mStackScroller).removeOnExpandedHeightListener(any());
+        verify(mStackScroller).removeOnExpandedHeightChangedListener(any());
         verify(mStackScroller).removeOnLayoutChangeListener(any());
     }
 }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/HeadsUpManagerPhoneTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/HeadsUpManagerPhoneTest.java
index 7bd4158..48934da 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/HeadsUpManagerPhoneTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/HeadsUpManagerPhoneTest.java
@@ -29,6 +29,7 @@
 
 import androidx.test.filters.SmallTest;
 
+import com.android.systemui.plugins.statusbar.StatusBarStateController;
 import com.android.systemui.statusbar.AlertingNotificationManager;
 import com.android.systemui.statusbar.AlertingNotificationManagerTest;
 import com.android.systemui.statusbar.notification.VisualStabilityManager;
@@ -55,12 +56,18 @@
     @Mock private View mStatusBarWindowView;
     @Mock private VisualStabilityManager mVSManager;
     @Mock private StatusBar mBar;
+    @Mock private StatusBarStateController mStatusBarStateController;
+    @Mock private KeyguardBypassController mBypassController;
+    private boolean mLivesPastNormalTime;
 
     private final class TestableHeadsUpManagerPhone extends HeadsUpManagerPhone {
         TestableHeadsUpManagerPhone(Context context, View statusBarWindowView,
                 NotificationGroupManager groupManager, StatusBar bar,
-                VisualStabilityManager vsManager) {
-            super(context, statusBarWindowView, groupManager, bar, vsManager);
+                VisualStabilityManager vsManager,
+                StatusBarStateController statusBarStateController,
+                KeyguardBypassController keyguardBypassController) {
+            super(context, statusBarStateController, keyguardBypassController);
+            setUp(statusBarWindowView, groupManager, bar, vsManager);
             mMinimumDisplayTime = TEST_MINIMUM_DISPLAY_TIME;
             mAutoDismissNotificationDecay = TEST_AUTO_DISMISS_TIME;
         }
@@ -72,13 +79,13 @@
 
     @Before
     public void setUp() {
-        AccessibilityManagerWrapper mAccessibilityMgr =
+        AccessibilityManagerWrapper accessibilityMgr =
                 mDependency.injectMockDependency(AccessibilityManagerWrapper.class);
-        when(mAccessibilityMgr.getRecommendedTimeoutMillis(anyInt(), anyInt()))
+        when(accessibilityMgr.getRecommendedTimeoutMillis(anyInt(), anyInt()))
                 .thenReturn(TEST_AUTO_DISMISS_TIME);
         when(mVSManager.isReorderingAllowed()).thenReturn(true);
         mHeadsUpManager = new TestableHeadsUpManagerPhone(mContext, mStatusBarWindowView,
-                mGroupManager, mBar, mVSManager);
+                mGroupManager, mBar, mVSManager, mStatusBarStateController, mBypassController);
         super.setUp();
         mHeadsUpManager.mHandler = mTestHandler;
     }
@@ -122,4 +129,24 @@
         // Notification is "behind" a higher priority notification so we can remove it immediately.
         assertTrue(mHeadsUpManager.canRemoveImmediately(mEntry.key));
     }
+
+
+    @Test
+    public void testExtendHeadsUp() {
+        mHeadsUpManager.showNotification(mEntry);
+        Runnable pastNormalTimeRunnable =
+                () -> mLivesPastNormalTime = mHeadsUpManager.isAlerting(mEntry.key);
+        mTestHandler.postDelayed(pastNormalTimeRunnable,
+                TEST_AUTO_DISMISS_TIME + mHeadsUpManager.mExtensionTime / 2);
+        mTestHandler.postDelayed(TEST_TIMEOUT_RUNNABLE, TEST_TIMEOUT_TIME);
+
+        mHeadsUpManager.extendHeadsUp();
+
+        // Wait for normal time runnable and extended remove runnable and process them on arrival.
+        TestableLooper.get(this).processMessages(2);
+
+        assertFalse("Test timed out", mTimedOut);
+        assertTrue("Pulse was not extended", mLivesPastNormalTime);
+        assertFalse(mHeadsUpManager.isAlerting(mEntry.key));
+    }
 }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/KeyguardBouncerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/KeyguardBouncerTest.java
index 3bc5f3e..cd60e47 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/KeyguardBouncerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/KeyguardBouncerTest.java
@@ -21,6 +21,7 @@
 import static org.mockito.ArgumentMatchers.any;
 import static org.mockito.ArgumentMatchers.anyFloat;
 import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.ArgumentMatchers.anyLong;
 import static org.mockito.ArgumentMatchers.eq;
 import static org.mockito.Mockito.doAnswer;
 import static org.mockito.Mockito.never;
@@ -82,6 +83,10 @@
     @Mock
     private KeyguardUpdateMonitor mKeyguardUpdateMonitor;
     @Mock
+    private UnlockMethodCache mUnlockMethodCache;
+    @Mock
+    private KeyguardBypassController mKeyguardBypassController;
+    @Mock
     private Handler mHandler;
 
     private KeyguardBouncer mBouncer;
@@ -96,7 +101,8 @@
         when(mKeyguardHostView.getHeight()).thenReturn(500);
         mBouncer = new KeyguardBouncer(getContext(), mViewMediatorCallback,
                 mLockPatternUtils, container, mDismissCallbackRegistry, mFalsingManager,
-                mExpansionCallback, mKeyguardUpdateMonitor, mHandler) {
+                mExpansionCallback, mUnlockMethodCache, mKeyguardUpdateMonitor,
+                mKeyguardBypassController, mHandler) {
             @Override
             protected void inflateView() {
                 super.inflateView();
@@ -377,7 +383,7 @@
 
     @Test
     public void testShow_delaysIfFaceAuthIsRunning() {
-        when(mKeyguardUpdateMonitor.isFaceDetectionRunning()).thenReturn(true);
+        when(mUnlockMethodCache.isFaceAuthEnabled()).thenReturn(true);
         mBouncer.show(true /* reset */);
 
         ArgumentCaptor<Runnable> showRunnable = ArgumentCaptor.forClass(Runnable.class);
@@ -389,7 +395,27 @@
     }
 
     @Test
+    public void testShow_delaysIfFaceAuthIsRunning_unlessBypass() {
+        when(mUnlockMethodCache.isFaceAuthEnabled()).thenReturn(true);
+        when(mKeyguardBypassController.getBypassEnabled()).thenReturn(true);
+        mBouncer.show(true /* reset */);
+
+        verify(mHandler, never()).postDelayed(any(), anyLong());
+    }
+
+    @Test
     public void testRegisterUpdateMonitorCallback() {
         verify(mKeyguardUpdateMonitor).registerCallback(any());
     }
+
+    @Test
+    public void testInTransit_whenTranslation() {
+        mBouncer.show(true);
+        mBouncer.setExpansion(KeyguardBouncer.EXPANSION_HIDDEN);
+        assertThat(mBouncer.inTransit()).isFalse();
+        mBouncer.setExpansion(0.5f);
+        assertThat(mBouncer.inTransit()).isTrue();
+        mBouncer.setExpansion(KeyguardBouncer.EXPANSION_VISIBLE);
+        assertThat(mBouncer.inTransit()).isFalse();
+    }
 }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/KeyguardClockPositionAlgorithmTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/KeyguardClockPositionAlgorithmTest.java
index f8394f0..2042fab 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/KeyguardClockPositionAlgorithmTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/KeyguardClockPositionAlgorithmTest.java
@@ -383,7 +383,8 @@
     private void positionClock() {
         mClockPositionAlgorithm.setup(EMPTY_MARGIN, SCREEN_HEIGHT, mNotificationStackHeight,
                 mPanelExpansion, SCREEN_HEIGHT, mKeyguardStatusHeight, mPreferredClockY,
-                mHasCustomClock, mHasVisibleNotifs, mDark, ZERO_DRAG);
+                mHasCustomClock, mHasVisibleNotifs, mDark, ZERO_DRAG, false /* bypassEnabled */,
+                0 /* unlockedStackScrollerPadding */);
         mClockPositionAlgorithm.run(mClockPosition);
     }
 }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationGroupAlertTransferHelperTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationGroupAlertTransferHelperTest.java
index 337c35c..b1c3c83 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationGroupAlertTransferHelperTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationGroupAlertTransferHelperTest.java
@@ -19,6 +19,7 @@
 import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertTrue;
 import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.spy;
 import static org.mockito.Mockito.times;
 import static org.mockito.Mockito.verify;
@@ -32,7 +33,7 @@
 import androidx.test.filters.SmallTest;
 
 import com.android.systemui.SysuiTestCase;
-import com.android.systemui.statusbar.AmbientPulseManager;
+import com.android.systemui.plugins.statusbar.StatusBarStateController;
 import com.android.systemui.statusbar.notification.NotificationEntryListener;
 import com.android.systemui.statusbar.notification.NotificationEntryManager;
 import com.android.systemui.statusbar.notification.collection.NotificationEntry;
@@ -58,7 +59,6 @@
 
     private NotificationGroupAlertTransferHelper mGroupAlertTransferHelper;
     private NotificationGroupManager mGroupManager;
-    private AmbientPulseManager mAmbientPulseManager;
     private HeadsUpManager mHeadsUpManager;
     @Mock private NotificationEntryManager mNotificationEntryManager;
     @Captor
@@ -71,14 +71,12 @@
 
     @Before
     public void setup() {
-        mAmbientPulseManager = new AmbientPulseManager(mContext);
-        mDependency.injectTestDependency(AmbientPulseManager.class, mAmbientPulseManager);
         mHeadsUpManager = new HeadsUpManager(mContext) {};
 
         when(mNotificationEntryManager.getPendingNotificationsIterator())
                 .thenReturn(mPendingEntries.values());
 
-        mGroupManager = new NotificationGroupManager();
+        mGroupManager = new NotificationGroupManager(mock(StatusBarStateController.class));
         mDependency.injectTestDependency(NotificationGroupManager.class, mGroupManager);
         mGroupManager.setHeadsUpManager(mHeadsUpManager);
 
@@ -89,7 +87,6 @@
         verify(mNotificationEntryManager).addNotificationEntryListener(mListenerCaptor.capture());
         mNotificationEntryListener = mListenerCaptor.getValue();
         mHeadsUpManager.addListener(mGroupAlertTransferHelper);
-        mAmbientPulseManager.addListener(mGroupAlertTransferHelper);
     }
 
     @Test
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationGroupManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationGroupManagerTest.java
index 43685f0..dd274c7 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationGroupManagerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationGroupManagerTest.java
@@ -21,6 +21,7 @@
 import static junit.framework.Assert.assertTrue;
 
 import static org.junit.Assert.assertNull;
+import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.when;
 
 import android.testing.AndroidTestingRunner;
@@ -29,7 +30,7 @@
 import androidx.test.filters.SmallTest;
 
 import com.android.systemui.SysuiTestCase;
-import com.android.systemui.statusbar.AmbientPulseManager;
+import com.android.systemui.plugins.statusbar.StatusBarStateController;
 import com.android.systemui.statusbar.notification.collection.NotificationEntry;
 import com.android.systemui.statusbar.policy.HeadsUpManager;
 
@@ -53,17 +54,14 @@
             new NotificationGroupTestHelper(mContext);
 
     @Mock HeadsUpManager mHeadsUpManager;
-    @Mock AmbientPulseManager mAmbientPulseManager;
 
     @Before
     public void setup() {
-        mDependency.injectTestDependency(AmbientPulseManager.class, mAmbientPulseManager);
-
         initializeGroupManager();
     }
 
     private void initializeGroupManager() {
-        mGroupManager = new NotificationGroupManager();
+        mGroupManager = new NotificationGroupManager(mock(StatusBarStateController.class));
         mGroupManager.setHeadsUpManager(mHeadsUpManager);
     }
 
@@ -146,21 +144,4 @@
         assertEquals(childEntry, mGroupManager.getGroupSummary(childEntry.notification));
         assertEquals(summaryEntry, mGroupManager.getLogicalGroupSummary(childEntry.notification));
     }
-
-    @Test
-    public void testAmbientPulseEntryIsIsolated() {
-        NotificationEntry childEntry = mGroupTestHelper.createChildNotification();
-        NotificationEntry summaryEntry = mGroupTestHelper.createSummaryNotification();
-        mGroupManager.onEntryAdded(summaryEntry);
-        mGroupManager.onEntryAdded(childEntry);
-        mGroupManager.onEntryAdded(mGroupTestHelper.createChildNotification());
-        when(mAmbientPulseManager.isAlerting(childEntry.key)).thenReturn(true);
-
-        mGroupManager.onAmbientStateChanged(childEntry, true);
-
-        // Child entries that are heads upped should be considered separate groups visually even if
-        // they are the same group logically
-        assertEquals(childEntry, mGroupManager.getGroupSummary(childEntry.notification));
-        assertEquals(summaryEntry, mGroupManager.getLogicalGroupSummary(childEntry.notification));
-    }
 }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationPanelViewTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationPanelViewTest.java
index 1b7ca95..d14b460 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationPanelViewTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationPanelViewTest.java
@@ -37,7 +37,6 @@
 import com.android.systemui.SystemUIFactory;
 import com.android.systemui.SysuiTestCase;
 import com.android.systemui.plugins.statusbar.StatusBarStateController;
-import com.android.systemui.statusbar.AmbientPulseManager;
 import com.android.systemui.statusbar.KeyguardAffordanceView;
 import com.android.systemui.statusbar.NotificationLockscreenUserManager;
 import com.android.systemui.statusbar.NotificationShelf;
@@ -46,9 +45,11 @@
 import com.android.systemui.statusbar.SysuiStatusBarStateController;
 import com.android.systemui.statusbar.notification.DynamicPrivacyController;
 import com.android.systemui.statusbar.notification.NotificationWakeUpCoordinator;
+import com.android.systemui.statusbar.notification.stack.NotificationRoundnessManager;
 import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayout;
 import com.android.systemui.statusbar.policy.ConfigurationController;
 import com.android.systemui.statusbar.policy.ZenModeController;
+import com.android.systemui.tuner.TunerService;
 import com.android.systemui.util.InjectionInflationController;
 
 import org.junit.Before;
@@ -111,12 +112,18 @@
         mDependency.injectMockDependency(NotificationLockscreenUserManager.class);
         mDependency.injectMockDependency(ConfigurationController.class);
         mDependency.injectMockDependency(ZenModeController.class);
+        KeyguardBypassController bypassController = new KeyguardBypassController(mContext,
+                mock(TunerService.class), mStatusBarStateController,
+                mock(NotificationLockscreenUserManager.class));
         NotificationWakeUpCoordinator coordinator =
                 new NotificationWakeUpCoordinator(mContext,
-                        new AmbientPulseManager(mContext),
-                        new StatusBarStateControllerImpl());
-        PulseExpansionHandler expansionHandler = new PulseExpansionHandler(mContext, coordinator);
-        mNotificationPanelView = new TestableNotificationPanelView(coordinator, expansionHandler);
+                        mock(HeadsUpManagerPhone.class),
+                        new StatusBarStateControllerImpl(),
+                        bypassController);
+        PulseExpansionHandler expansionHandler = new PulseExpansionHandler(mContext, coordinator,
+                bypassController, mHeadsUpManager, mock(NotificationRoundnessManager.class));
+        mNotificationPanelView = new TestableNotificationPanelView(coordinator, expansionHandler,
+                bypassController);
         mNotificationPanelView.setHeadsUpManager(mHeadsUpManager);
         mNotificationPanelView.setBar(mPanelBar);
 
@@ -128,7 +135,7 @@
     public void testSetDozing_notifiesNsslAndStateController() {
         mNotificationPanelView.setDozing(true /* dozing */, true /* animate */, null /* touch */);
         InOrder inOrder = inOrder(mNotificationStackScrollLayout, mStatusBarStateController);
-        inOrder.verify(mNotificationStackScrollLayout).setDark(eq(true), eq(true), eq(null));
+        inOrder.verify(mNotificationStackScrollLayout).setDozing(eq(true), eq(true), eq(null));
         inOrder.verify(mStatusBarStateController).setDozeAmount(eq(1f), eq(true));
     }
 
@@ -178,11 +185,13 @@
 
     private class TestableNotificationPanelView extends NotificationPanelView {
         TestableNotificationPanelView(NotificationWakeUpCoordinator coordinator,
-                PulseExpansionHandler expansionHandler) {
+                PulseExpansionHandler expansionHandler,
+                KeyguardBypassController bypassController) {
             super(NotificationPanelViewTest.this.mContext, null,
                     new InjectionInflationController(
                             SystemUIFactory.getInstance().getRootComponent()),
-                    coordinator, expansionHandler, mock(DynamicPrivacyController.class));
+                    coordinator, expansionHandler, mock(DynamicPrivacyController.class),
+                    bypassController);
             mNotificationStackScroller = mNotificationStackScrollLayout;
             mKeyguardStatusView = NotificationPanelViewTest.this.mKeyguardStatusView;
             mKeyguardStatusBar = NotificationPanelViewTest.this.mKeyguardStatusBar;
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ScrimControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ScrimControllerTest.java
index d8e90a5..97ad47e 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ScrimControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ScrimControllerTest.java
@@ -47,6 +47,7 @@
 import com.android.internal.util.function.TriConsumer;
 import com.android.systemui.SysuiTestCase;
 import com.android.systemui.statusbar.ScrimView;
+import com.android.systemui.statusbar.policy.KeyguardMonitor;
 import com.android.systemui.util.wakelock.WakeLock;
 import com.android.systemui.utils.os.FakeHandler;
 
@@ -96,7 +97,8 @@
                     mScrimBehindAlpha = scrimBehindAlpha;
                     mScrimInFrontColor = scrimInFrontColor;
                 },
-                visible -> mScrimVisibility = visible, mDozeParamenters, mAlarmManager);
+                visible -> mScrimVisibility = visible, mDozeParamenters, mAlarmManager,
+                mock(KeyguardMonitor.class));
         mScrimController.setHasBackdrop(false);
         mScrimController.setWallpaperSupportsAmbientMode(false);
         mScrimController.transitionTo(ScrimState.KEYGUARD);
@@ -225,11 +227,12 @@
 
         mScrimController.transitionTo(ScrimState.PULSING);
         mScrimController.finishAnimationsImmediately();
-        // Front scrim should be transparent
+        // Front scrim should be transparent, but tinted
         // Back scrim should be semi-transparent so the user can see the wallpaper
         // Pulse callback should have been invoked
         assertScrimVisibility(VISIBILITY_FULLY_TRANSPARENT, VISIBILITY_FULLY_OPAQUE);
         assertScrimTint(mScrimBehind, true /* tinted */);
+        assertScrimTint(mScrimInFront, true /* tinted */);
 
         mScrimController.setWakeLockScreenSensorActive(true);
         mScrimController.finishAnimationsImmediately();
@@ -680,9 +683,9 @@
         SynchronousScrimController(ScrimView scrimBehind, ScrimView scrimInFront,
                 TriConsumer<ScrimState, Float, GradientColors> scrimStateListener,
                 Consumer<Integer> scrimVisibleListener, DozeParameters dozeParameters,
-                AlarmManager alarmManager) {
+                AlarmManager alarmManager, KeyguardMonitor keyguardMonitor) {
             super(scrimBehind, scrimInFront, scrimStateListener, scrimVisibleListener,
-                    dozeParameters, alarmManager);
+                    dozeParameters, alarmManager, keyguardMonitor);
         }
 
         @Override
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManagerTest.java
index f50cf5a..da2e8dc 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManagerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManagerTest.java
@@ -19,6 +19,7 @@
 import static org.mockito.ArgumentMatchers.anyBoolean;
 import static org.mockito.ArgumentMatchers.anyFloat;
 import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.RETURNS_DEEP_STUBS;
 import static org.mockito.Mockito.clearInvocations;
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.never;
@@ -29,7 +30,9 @@
 import android.content.Context;
 import android.testing.AndroidTestingRunner;
 import android.testing.TestableLooper;
+import android.view.View;
 import android.view.ViewGroup;
+import android.view.ViewPropertyAnimator;
 
 import androidx.test.filters.SmallTest;
 
@@ -39,6 +42,7 @@
 import com.android.systemui.keyguard.DismissCallbackRegistry;
 import com.android.systemui.plugins.ActivityStarter.OnDismissAction;
 import com.android.systemui.plugins.statusbar.StatusBarStateController;
+import com.android.systemui.statusbar.SysuiStatusBarStateController;
 
 import org.junit.Before;
 import org.junit.Test;
@@ -70,7 +74,11 @@
     @Mock
     private ViewGroup mLockIconContainer;
     @Mock
-    private StatusBarStateController mStatusBarStateController;
+    private SysuiStatusBarStateController mStatusBarStateController;
+    @Mock
+    private View mNotificationContainer;
+    @Mock
+    private KeyguardBypassController mBypassController;
     private StatusBarKeyguardViewManager mStatusBarKeyguardViewManager;
 
     @Before
@@ -79,11 +87,13 @@
         mDependency.injectMockDependency(StatusBarWindowController.class);
         mDependency.injectTestDependency(StatusBarStateController.class, mStatusBarStateController);
         when(mLockIconContainer.getParent()).thenReturn(mock(ViewGroup.class));
+        when(mLockIconContainer.animate()).thenReturn(mock(ViewPropertyAnimator.class,
+                RETURNS_DEEP_STUBS));
         mStatusBarKeyguardViewManager = new TestableStatusBarKeyguardViewManager(getContext(),
                 mViewMediatorCallback, mLockPatternUtils);
         mStatusBarKeyguardViewManager.registerStatusBar(mStatusBar, mContainer,
                 mNotificationPanelView, mBiometrucUnlockController, mDismissCallbackRegistry,
-                mLockIconContainer);
+                mLockIconContainer, mNotificationContainer, mBypassController);
         mStatusBarKeyguardViewManager.show(null);
     }
 
@@ -221,9 +231,11 @@
                 NotificationPanelView notificationPanelView,
                 BiometricUnlockController fingerprintUnlockController,
                 DismissCallbackRegistry dismissCallbackRegistry,
-                ViewGroup lockIconContainer) {
+                ViewGroup lockIconContainer, View notificationContainer,
+                KeyguardBypassController bypassController) {
             super.registerStatusBar(statusBar, container, notificationPanelView,
-                    fingerprintUnlockController, dismissCallbackRegistry, lockIconContainer);
+                    fingerprintUnlockController, dismissCallbackRegistry, lockIconContainer,
+                    notificationContainer, bypassController);
             mBouncer = StatusBarKeyguardViewManagerTest.this.mBouncer;
         }
     }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarNotificationPresenterTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarNotificationPresenterTest.java
index e811e1d..186a8c7 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarNotificationPresenterTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarNotificationPresenterTest.java
@@ -40,6 +40,7 @@
 import com.android.systemui.SysuiTestCase;
 import com.android.systemui.statusbar.CommandQueue;
 import com.android.systemui.statusbar.notification.ActivityLaunchAnimator;
+import com.android.systemui.statusbar.notification.DynamicPrivacyController;
 import com.android.systemui.statusbar.notification.NotificationAlertingManager;
 import com.android.systemui.statusbar.notification.collection.NotificationEntry;
 import com.android.systemui.statusbar.notification.collection.NotificationRowBinderImpl;
@@ -75,7 +76,7 @@
                 mock(NotificationPanelView.class), mock(HeadsUpManagerPhone.class),
                 statusBarWindowView, mock(NotificationListContainerViewGroup.class),
                 mock(DozeScrimController.class), mock(ScrimController.class),
-                mock(ActivityLaunchAnimator.class), mock(StatusBarKeyguardViewManager.class),
+                mock(ActivityLaunchAnimator.class), mock(DynamicPrivacyController.class),
                 mock(NotificationAlertingManager.class),
                 mock(NotificationRowBinderImpl.class));
     }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarTest.java
index 79e05c3..fa235bd 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarTest.java
@@ -157,7 +157,7 @@
     @Mock private RemoteInputController mRemoteInputController;
     @Mock private StatusBarStateControllerImpl mStatusBarStateController;
     @Mock private DeviceProvisionedController mDeviceProvisionedController;
-    @Mock private NotificationPresenter mNotificationPresenter;
+    @Mock private StatusBarNotificationPresenter mNotificationPresenter;
     @Mock
     private NotificationEntryListener mEntryListener;
     @Mock
@@ -222,6 +222,7 @@
         mNotificationLogger = new NotificationLogger(mNotificationListener,
                 Dependency.get(UiOffloadThread.class), mEntryManager, mStatusBarStateController,
                 mExpansionStateLogger);
+        mNotificationLogger.setVisibilityReporter(mock(Runnable.class));
         mDependency.injectTestDependency(NotificationLogger.class, mNotificationLogger);
         DozeLog.traceDozing(mContext, false /* dozing */);
 
@@ -253,7 +254,7 @@
 
         when(mRemoteInputManager.getController()).thenReturn(mRemoteInputController);
         mStatusBar = new TestableStatusBar(mStatusBarKeyguardViewManager, mUnlockMethodCache,
-                mKeyguardIndicationController, mStackScroller, mHeadsUpManager,
+                mKeyguardIndicationController, mStackScroller,
                 mPowerManager, mNotificationPanelView, mBarService, mNotificationListener,
                 mNotificationLogger, mVisualStabilityManager, mViewHierarchyManager,
                 mEntryManager, mScrimController, mBiometricUnlockController,
@@ -269,19 +270,13 @@
         SystemUIFactory.getInstance().getRootComponent()
                 .getStatusBarInjector()
                 .createStatusBar(mStatusBar);
+        mStatusBar.setHeadsUpManager(mHeadsUpManager);
         mStatusBar.putComponent(StatusBar.class, mStatusBar);
         Dependency.get(InitController.class).executePostInitTasks();
         mEntryManager.setUpForTest(mock(NotificationPresenter.class), mStackScroller,
                 mHeadsUpManager, mNotificationData);
         mEntryManager.addNotificationEntryListener(mEntryListener);
         mNotificationLogger.setUpWithContainer(mStackScroller);
-
-        TestableLooper.get(this).setMessageHandler(m -> {
-            if (m.getCallback() == mStatusBar.mNotificationLogger.getVisibilityReporter()) {
-                return false;
-            }
-            return true;
-        });
     }
 
     @Test
@@ -644,10 +639,10 @@
     @Test
     public void testPulseWhileDozing_notifyAuthInterrupt() {
         HashSet<Integer> reasonsWantingAuth = new HashSet<>(
-                Collections.singletonList(DozeLog.PULSE_REASON_NOTIFICATION));
+                Collections.singletonList(DozeLog.PULSE_REASON_SENSOR_WAKE_LOCK_SCREEN));
         HashSet<Integer> reasonsSkippingAuth = new HashSet<>(
                 Arrays.asList(DozeLog.PULSE_REASON_INTENT,
-                        DozeLog.PULSE_REASON_SENSOR_WAKE_LOCK_SCREEN,
+                        DozeLog.PULSE_REASON_NOTIFICATION,
                         DozeLog.PULSE_REASON_SENSOR_SIGMOTION,
                         DozeLog.REASON_SENSOR_PICKUP,
                         DozeLog.REASON_SENSOR_DOUBLE_TAP,
@@ -666,6 +661,7 @@
             return null;
         }).when(mDozeScrimController).pulse(any(), anyInt());
 
+        mStatusBar.mDozeServiceHost.mWakeLockScreenPerformsAuth = true;
         for (int i = 0; i < DozeLog.REASONS; i++) {
             reset(mKeyguardUpdateMonitor);
             mStatusBar.mDozeServiceHost.pulseWhileDozing(mock(DozeHost.PulseCallback.class), i);
@@ -765,7 +761,7 @@
     static class TestableStatusBar extends StatusBar {
         public TestableStatusBar(StatusBarKeyguardViewManager man,
                 UnlockMethodCache unlock, KeyguardIndicationController key,
-                NotificationStackScrollLayout stack, HeadsUpManagerPhone hum,
+                NotificationStackScrollLayout stack,
                 PowerManager pm, NotificationPanelView panelView,
                 IStatusBarService barService, NotificationListener notificationListener,
                 NotificationLogger notificationLogger,
@@ -784,7 +780,7 @@
                 NotificationShelf notificationShelf,
                 NotificationLockscreenUserManager notificationLockscreenUserManager,
                 CommandQueue commandQueue,
-                NotificationPresenter notificationPresenter,
+                StatusBarNotificationPresenter notificationPresenter,
                 BubbleController bubbleController,
                 NavigationBarController navBarController,
                 AutoHideController autoHideController,
@@ -794,7 +790,6 @@
             mUnlockMethodCache = unlock;
             mKeyguardIndicationController = key;
             mStackScroller = stack;
-            mHeadsUpManager = hum;
             mPowerManager = pm;
             mNotificationPanel = panelView;
             mBarService = barService;
@@ -824,6 +819,7 @@
             mAutoHideController = autoHideController;
             mKeyguardUpdateMonitor = keyguardUpdateMonitor;
             mStatusBarWindow = statusBarWindow;
+            mDozeServiceHost.mWakeLockScreenPerformsAuth = false;
         }
 
         private WakefulnessLifecycle createAwakeWakefulnessLifecycle() {
@@ -842,6 +838,10 @@
             mState = state;
         }
 
+        void setHeadsUpManager(HeadsUpManagerPhone headsUpManager) {
+            mHeadsUpManager = headsUpManager;
+        }
+
         public void setUserSetupForTest(boolean userSetup) {
             mUserSetup = userSetup;
         }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarWindowControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarWindowControllerTest.java
index fea41a4..4ffaeae 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarWindowControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarWindowControllerTest.java
@@ -33,6 +33,8 @@
 import androidx.test.filters.SmallTest;
 
 import com.android.systemui.SysuiTestCase;
+import com.android.systemui.statusbar.SysuiStatusBarStateController;
+import com.android.systemui.statusbar.policy.ConfigurationController;
 
 import org.junit.Before;
 import org.junit.Test;
@@ -54,6 +56,12 @@
     private ViewGroup mStatusBarView;
     @Mock
     private IActivityManager mActivityManager;
+    @Mock
+    private SysuiStatusBarStateController mStatusBarStateController;
+    @Mock
+    private ConfigurationController mConfigurationController;
+    @Mock
+    private KeyguardBypassController mKeyguardBypassController;
 
     private StatusBarWindowController mStatusBarWindowController;
 
@@ -63,7 +71,8 @@
         when(mDozeParameters.getAlwaysOn()).thenReturn(true);
 
         mStatusBarWindowController = new StatusBarWindowController(mContext, mWindowManager,
-                mActivityManager, mDozeParameters);
+                mActivityManager, mDozeParameters, mStatusBarStateController,
+                mConfigurationController, mKeyguardBypassController);
         mStatusBarWindowController.add(mStatusBarView, 100 /* height */);
     }
 
@@ -88,7 +97,8 @@
     @Test
     public void testOnThemeChanged_doesntCrash() {
         mStatusBarWindowController = new StatusBarWindowController(mContext, mWindowManager,
-                mActivityManager, mDozeParameters);
+                mActivityManager, mDozeParameters, mStatusBarStateController,
+                mConfigurationController, mKeyguardBypassController);
         mStatusBarWindowController.onThemeChanged();
     }
 
@@ -100,7 +110,8 @@
     @Test
     public void testSetForcePluginOpen_beforeStatusBarInitialization() {
         mStatusBarWindowController = new StatusBarWindowController(mContext, mWindowManager,
-                mActivityManager, mDozeParameters);
+                mActivityManager, mDozeParameters, mStatusBarStateController,
+                mConfigurationController, mKeyguardBypassController);
         mStatusBarWindowController.setForcePluginOpen(true);
     }
 }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerBaseTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerBaseTest.java
index 3464fe5..9ae9ceb 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerBaseTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerBaseTest.java
@@ -181,6 +181,7 @@
     protected void setDefaultSubId(int subId) {
         when(mMockSubDefaults.getDefaultDataSubId()).thenReturn(subId);
         when(mMockSubDefaults.getDefaultVoiceSubId()).thenReturn(subId);
+        when(mMockSubDefaults.getActiveDataSubId()).thenReturn(subId);
     }
 
     protected void setSubscriptions(int... subIds) {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/SmartReplyViewTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/SmartReplyViewTest.java
index 8c5fac4..0cb5754 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/SmartReplyViewTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/SmartReplyViewTest.java
@@ -109,7 +109,9 @@
         MockitoAnnotations.initMocks(this);
         mReceiver = new BlockingQueueIntentReceiver();
         mContext.registerReceiver(mReceiver, new IntentFilter(TEST_ACTION));
-        mDependency.get(KeyguardDismissUtil.class).setDismissHandler(action -> action.onDismiss());
+        mDependency.get(KeyguardDismissUtil.class).setDismissHandler((action, unused) -> {
+            action.onDismiss();
+        });
         mDependency.injectMockDependency(ShadeController.class);
         mDependency.injectTestDependency(ActivityStarter.class, mActivityStarter);
         mDependency.injectTestDependency(SmartReplyConstants.class, mConstants);
@@ -162,7 +164,7 @@
 
     @Test
     public void testSendSmartReply_keyguardCancelled() throws InterruptedException {
-        mDependency.get(KeyguardDismissUtil.class).setDismissHandler(action -> {});
+        mDependency.get(KeyguardDismissUtil.class).setDismissHandler((action, unused) -> {});
         setSmartReplies(TEST_CHOICES);
 
         mView.getChildAt(2).performClick();
@@ -173,7 +175,9 @@
     @Test
     public void testSendSmartReply_waitsForKeyguard() throws InterruptedException {
         AtomicReference<OnDismissAction> actionRef = new AtomicReference<>();
-        mDependency.get(KeyguardDismissUtil.class).setDismissHandler(actionRef::set);
+        mDependency.get(KeyguardDismissUtil.class).setDismissHandler((action, unused) -> {
+            actionRef.set(action);
+        });
         setSmartReplies(TEST_CHOICES);
 
         mView.getChildAt(2).performClick();
diff --git a/packages/SystemUI/tests/src/com/android/systemui/utils/hardware/FakeSensorManager.java b/packages/SystemUI/tests/src/com/android/systemui/utils/hardware/FakeSensorManager.java
index a4ae166..29b8ab60 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/utils/hardware/FakeSensorManager.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/utils/hardware/FakeSensorManager.java
@@ -40,18 +40,23 @@
 import java.util.List;
 import java.util.stream.Collectors;
 
+import javax.annotation.Nullable;
+
 /**
  * Rudimentary fake for SensorManager
  *
- * Currently only supports the proximity sensor.
+ * Currently only supports proximity, light and tap sensors.
  *
  * Note that this class ignores the "Handler" argument, so the test is responsible for calling the
  * listener on the right thread.
  */
 public class FakeSensorManager extends SensorManager {
 
+    public static final String TAP_SENSOR_TYPE = "tapSensorType";
+
     private final MockProximitySensor mMockProximitySensor;
     private final FakeGenericSensor mFakeLightSensor;
+    private final FakeGenericSensor mFakeTapSensor;
     private final FakeGenericSensor[] mSensors;
 
     public FakeSensorManager(Context context) throws Exception {
@@ -59,12 +64,13 @@
                 .getDefaultSensor(Sensor.TYPE_PROXIMITY);
         if (proxSensor == null) {
             // No prox? Let's create a fake one!
-            proxSensor = createSensor(Sensor.TYPE_PROXIMITY);
+            proxSensor = createSensor(Sensor.TYPE_PROXIMITY, null);
         }
 
         mSensors = new FakeGenericSensor[]{
                 mMockProximitySensor = new MockProximitySensor(proxSensor),
-                mFakeLightSensor = new FakeGenericSensor(createSensor(Sensor.TYPE_LIGHT)),
+                mFakeLightSensor = new FakeGenericSensor(createSensor(Sensor.TYPE_LIGHT, null)),
+                mFakeTapSensor = new FakeGenericSensor(createSensor(99, TAP_SENSOR_TYPE))
         };
     }
 
@@ -76,6 +82,10 @@
         return mFakeLightSensor;
     }
 
+    public FakeGenericSensor getFakeTapSensor() {
+        return mFakeTapSensor;
+    }
+
     @Override
     public Sensor getDefaultSensor(int type) {
         Sensor s = super.getDefaultSensor(type);
@@ -160,13 +170,13 @@
 
     @Override
     protected boolean requestTriggerSensorImpl(TriggerEventListener listener, Sensor sensor) {
-        return false;
+        return true;
     }
 
     @Override
     protected boolean cancelTriggerSensorImpl(TriggerEventListener listener, Sensor sensor,
             boolean disable) {
-        return false;
+        return true;
     }
 
     @Override
@@ -185,12 +195,15 @@
         return false;
     }
 
-    private Sensor createSensor(int type) throws Exception {
+    private Sensor createSensor(int type, @Nullable String stringType) throws Exception {
         Constructor<Sensor> constr = Sensor.class.getDeclaredConstructor();
         constr.setAccessible(true);
         Sensor sensor = constr.newInstance();
 
         setSensorType(sensor, type);
+        if (stringType != null) {
+            setSensorField(sensor, "mStringType", stringType);
+        }
         setSensorField(sensor, "mName", "Mock " + sensor.getStringType() + "/" + type);
         setSensorField(sensor, "mVendor", "Mock Vendor");
         setSensorField(sensor, "mVersion", 1);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/utils/leaks/FakeKeyguardMonitor.java b/packages/SystemUI/tests/src/com/android/systemui/utils/leaks/FakeKeyguardMonitor.java
index 95c7a4d..2fb0e0e 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/utils/leaks/FakeKeyguardMonitor.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/utils/leaks/FakeKeyguardMonitor.java
@@ -80,9 +80,4 @@
     public long calculateGoingToFullShadeDelay() {
         return 0;
     }
-
-    @Override
-    public boolean canSkipBouncer() {
-        return false;
-    }
 }
diff --git a/packages/overlays/Android.mk b/packages/overlays/Android.mk
index 3f16c12..3eb9049 100644
--- a/packages/overlays/Android.mk
+++ b/packages/overlays/Android.mk
@@ -44,7 +44,6 @@
 	IconPackRoundedSystemUIOverlay \
 	IconPackRoundedThemePickerUIOverlay \
 	IconShapeRoundedRectOverlay \
-	IconShapeSquareOverlay \
 	IconShapeSquircleOverlay \
 	IconShapeTeardropOverlay \
 	NavigationBarMode3ButtonOverlay \
diff --git a/packages/overlays/IconPackFilledSettingsOverlay/res/drawable/ic_battery_status_bad_24dp.xml b/packages/overlays/IconPackCircularAndroidOverlay/res/drawable/ic_battery_80_24dp.xml
similarity index 73%
copy from packages/overlays/IconPackFilledSettingsOverlay/res/drawable/ic_battery_status_bad_24dp.xml
copy to packages/overlays/IconPackCircularAndroidOverlay/res/drawable/ic_battery_80_24dp.xml
index 22e183c..4d8dbdb 100644
--- a/packages/overlays/IconPackFilledSettingsOverlay/res/drawable/ic_battery_status_bad_24dp.xml
+++ b/packages/overlays/IconPackCircularAndroidOverlay/res/drawable/ic_battery_80_24dp.xml
@@ -21,5 +21,5 @@
     android:width="24dp" >
     <path
         android:fillColor="@android:color/white"
-        android:pathData="M10,2v2H8.33C7.6,4,7,4.6,7,5.33v15.33C7,21.4,7.6,22,8.33,22h7.33C16.4,22,17,21.4,17,20.67V5.33C17,4.6,16.4,4,15.67,4 H14V2H10z M15,13c0,0.55-0.45,1-1,1h-1v1c0,0.55-0.45,1-1,1s-1-0.45-1-1v-1h-1c-0.55,0-1-0.45-1-1s0.45-1,1-1h1v-1 c0-0.55,0.45-1,1-1s1,0.45,1,1v1h1C14.55,12,15,12.45,15,13z" />
+        android:pathData="M18,19V7c0-1.66-1.34-3-3-3h-1c0-0.55-0.45-1-1-1h-2c-0.55,0-1,0.45-1,1H9C7.34,4,6,5.34,6,7v12c0,1.66,1.34,3,3,3h6 C16.66,22,18,20.66,18,19z M9,5.5h6c0.83,0,1.5,0.67,1.5,1.5v1h-9V7C7.5,6.17,8.17,5.5,9,5.5z" />
 </vector>
\ No newline at end of file
diff --git a/packages/overlays/IconPackCircularAndroidOverlay/res/drawable/ic_bt_misc_hid.xml b/packages/overlays/IconPackCircularAndroidOverlay/res/drawable/ic_bt_misc_hid.xml
index e182886..5096f2f 100644
--- a/packages/overlays/IconPackCircularAndroidOverlay/res/drawable/ic_bt_misc_hid.xml
+++ b/packages/overlays/IconPackCircularAndroidOverlay/res/drawable/ic_bt_misc_hid.xml
@@ -20,7 +20,6 @@
     android:viewportHeight="24"
     android:viewportWidth="24"
     android:width="24dp" >
-    <path android:pathData="M0,0h24v24H0V0z" />
     <path
         android:fillColor="@android:color/white"
         android:pathData="M9,16.5V20c0,1.1,0.9,2,2,2h2c1.1,0,2-0.9,2-2v-3.5l-3-3L9,16.5z M13.5,20c0,0.28-0.22,0.5-0.5,0.5h-2 c-0.28,0-0.5-0.22-0.5-0.5v-2.88l1.5-1.5l1.5,1.5V20z M15,7.5V4c0-1.1-0.9-2-2-2h-2C9.9,2,9,2.9,9,4v3.5l3,3L15,7.5z M10.5,4 c0-0.28,0.22-0.5,0.5-0.5h2c0.28,0,0.5,0.22,0.5,0.5v2.88L12,8.38l-1.5-1.5V4z M7.5,9H4c-1.1,0-2,0.9-2,2v2c0,1.1,0.9,2,2,2h3.5 l3-3L7.5,9z M6.88,13.5H4c-0.28,0-0.5-0.22-0.5-0.5v-2c0-0.28,0.22-0.5,0.5-0.5h2.88l1.5,1.5L6.88,13.5z M20,9h-3.5l-3,3l3,3H20 c1.1,0,2-0.9,2-2v-2C22,9.9,21.1,9,20,9z M20.5,13c0,0.28-0.22,0.5-0.5,0.5h-2.88l-1.5-1.5l1.5-1.5H20c0.28,0,0.5,0.22,0.5,0.5V13z" />
diff --git a/packages/overlays/IconPackCircularAndroidOverlay/res/drawable/ic_file_copy.xml b/packages/overlays/IconPackCircularAndroidOverlay/res/drawable/ic_file_copy.xml
index dc6ab95..b8e9845 100644
--- a/packages/overlays/IconPackCircularAndroidOverlay/res/drawable/ic_file_copy.xml
+++ b/packages/overlays/IconPackCircularAndroidOverlay/res/drawable/ic_file_copy.xml
@@ -16,7 +16,7 @@
 -->
 <vector xmlns:android="http://schemas.android.com/apk/res/android"
     android:height="24dp"
-    android:tint="#FF737373"
+    android:tint="@*android:color/material_grey_600"
     android:viewportHeight="24"
     android:viewportWidth="24"
     android:width="24dp" >
diff --git a/packages/overlays/IconPackCircularAndroidOverlay/res/drawable/ic_lock.xml b/packages/overlays/IconPackCircularAndroidOverlay/res/drawable/ic_lock.xml
index 1e3400b..5a67f95 100644
--- a/packages/overlays/IconPackCircularAndroidOverlay/res/drawable/ic_lock.xml
+++ b/packages/overlays/IconPackCircularAndroidOverlay/res/drawable/ic_lock.xml
@@ -16,7 +16,6 @@
 -->
 <vector xmlns:android="http://schemas.android.com/apk/res/android"
     android:height="32dp"
-    android:tint="?android:attr/textColor"
     android:viewportHeight="24"
     android:viewportWidth="24"
     android:width="32dp" >
diff --git a/packages/overlays/IconPackCircularAndroidOverlay/res/drawable/ic_lock_open.xml b/packages/overlays/IconPackCircularAndroidOverlay/res/drawable/ic_lock_open.xml
index f4606a2..21abd6e 100644
--- a/packages/overlays/IconPackCircularAndroidOverlay/res/drawable/ic_lock_open.xml
+++ b/packages/overlays/IconPackCircularAndroidOverlay/res/drawable/ic_lock_open.xml
@@ -16,7 +16,6 @@
 -->
 <vector xmlns:android="http://schemas.android.com/apk/res/android"
     android:height="32dp"
-    android:tint="?android:attr/textColor"
     android:viewportHeight="24"
     android:viewportWidth="24"
     android:width="32dp" >
diff --git a/packages/overlays/IconPackCircularAndroidOverlay/res/drawable/ic_lockscreen_ime.xml b/packages/overlays/IconPackCircularAndroidOverlay/res/drawable/ic_lockscreen_ime.xml
index 4344e32..455bdd5 100644
--- a/packages/overlays/IconPackCircularAndroidOverlay/res/drawable/ic_lockscreen_ime.xml
+++ b/packages/overlays/IconPackCircularAndroidOverlay/res/drawable/ic_lockscreen_ime.xml
@@ -16,6 +16,7 @@
 -->
 <vector xmlns:android="http://schemas.android.com/apk/res/android"
     android:height="24dp"
+    android:tint="?android:attr/colorControlNormal"
     android:viewportHeight="24"
     android:viewportWidth="24"
     android:width="24dp" >
diff --git a/packages/overlays/IconPackCircularAndroidOverlay/res/drawable/ic_mode_edit.xml b/packages/overlays/IconPackCircularAndroidOverlay/res/drawable/ic_mode_edit.xml
index f0d782e..aca3d52 100644
--- a/packages/overlays/IconPackCircularAndroidOverlay/res/drawable/ic_mode_edit.xml
+++ b/packages/overlays/IconPackCircularAndroidOverlay/res/drawable/ic_mode_edit.xml
@@ -16,6 +16,7 @@
 -->
 <vector xmlns:android="http://schemas.android.com/apk/res/android"
     android:height="24dp"
+    android:tint="?android:attr/colorControlNormal"
     android:viewportHeight="24"
     android:viewportWidth="24"
     android:width="24dp" >
diff --git a/packages/overlays/IconPackCircularAndroidOverlay/res/drawable/ic_notifications_alerted.xml b/packages/overlays/IconPackCircularAndroidOverlay/res/drawable/ic_notifications_alerted.xml
new file mode 100644
index 0000000..86863b3
--- /dev/null
+++ b/packages/overlays/IconPackCircularAndroidOverlay/res/drawable/ic_notifications_alerted.xml
@@ -0,0 +1,34 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+   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.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:height="24dp"
+    android:viewportHeight="24"
+    android:viewportWidth="24"
+    android:width="24dp" >
+    <path
+        android:fillColor="@android:color/white"
+        android:pathData="M5.85,3.01C3.72,4.82,2.5,7.46,2.5,10.25C2.5,10.66,2.84,11,3.25,11S4,10.66,4,10.25c0-2.35,1.03-4.57,2.82-6.1 C7.14,3.88,7.17,3.41,6.91,3.1C6.64,2.78,6.17,2.74,5.85,3.01z" />
+    <path
+        android:fillColor="@android:color/white"
+        android:pathData="M21.5,10.25c0-2.79-1.22-5.43-3.35-7.24c-0.32-0.27-0.79-0.23-1.06,0.08c-0.27,0.32-0.23,0.79,0.08,1.06 C18.97,5.68,20,7.9,20,10.25c0,0.41,0.34,0.75,0.75,0.75S21.5,10.66,21.5,10.25z" />
+    <path
+        android:fillColor="@android:color/white"
+        android:pathData="M12,2.5c-0.83,0-1.5,0.67-1.5,1.5v0.7C7.91,5.36,6,7.71,6,10.5V15c0,0.55-0.45,1-1,1s-1,0.45-1,1v2h16v-2 c0-0.55-0.45-1-1-1s-1-0.45-1-1v-4.5c0-2.79-1.91-5.14-4.5-5.8V4C13.5,3.17,12.83,2.5,12,2.5z M16.5,10.5V15 c0,1.21,0.86,2.22,2,2.45v0.05h-13v-0.05c1.14-0.23,2-1.24,2-2.45v-4.5C7.5,8.02,9.52,6,12,6S16.5,8.02,16.5,10.5z" />
+    <path
+        android:fillColor="@android:color/white"
+        android:pathData="M14,20h-4c0,1.1,0.9,2,2,2S14,21.1,14,20z" />
+</vector>
\ No newline at end of file
diff --git a/packages/overlays/IconPackCircularAndroidOverlay/res/drawable/ic_phone.xml b/packages/overlays/IconPackCircularAndroidOverlay/res/drawable/ic_phone.xml
index 28733c1..85c184b 100644
--- a/packages/overlays/IconPackCircularAndroidOverlay/res/drawable/ic_phone.xml
+++ b/packages/overlays/IconPackCircularAndroidOverlay/res/drawable/ic_phone.xml
@@ -15,7 +15,9 @@
    limitations under the License.
 -->
 <vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:autoMirrored="true"
     android:height="24dp"
+    android:tint="?android:attr/colorControlNormal"
     android:viewportHeight="24"
     android:viewportWidth="24"
     android:width="24dp" >
diff --git a/packages/overlays/IconPackCircularAndroidOverlay/res/drawable/ic_qs_battery_saver.xml b/packages/overlays/IconPackCircularAndroidOverlay/res/drawable/ic_qs_battery_saver.xml
index a558337..73310b0 100644
--- a/packages/overlays/IconPackCircularAndroidOverlay/res/drawable/ic_qs_battery_saver.xml
+++ b/packages/overlays/IconPackCircularAndroidOverlay/res/drawable/ic_qs_battery_saver.xml
@@ -15,7 +15,9 @@
    limitations under the License.
 -->
 <vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:autoMirrored="true"
     android:height="24dp"
+    android:tint="?android:attr/colorControlNormal"
     android:viewportHeight="24"
     android:viewportWidth="24"
     android:width="24dp" >
diff --git a/packages/overlays/IconPackCircularAndroidOverlay/res/drawable/ic_qs_bluetooth.xml b/packages/overlays/IconPackCircularAndroidOverlay/res/drawable/ic_qs_bluetooth.xml
index 452a032..1973124 100644
--- a/packages/overlays/IconPackCircularAndroidOverlay/res/drawable/ic_qs_bluetooth.xml
+++ b/packages/overlays/IconPackCircularAndroidOverlay/res/drawable/ic_qs_bluetooth.xml
@@ -16,6 +16,7 @@
 -->
 <vector xmlns:android="http://schemas.android.com/apk/res/android"
     android:height="24dp"
+    android:tint="?android:attr/colorControlNormal"
     android:viewportHeight="24"
     android:viewportWidth="24"
     android:width="24dp" >
diff --git a/packages/overlays/IconPackFilledSettingsOverlay/res/drawable/ic_delete_accent.xml b/packages/overlays/IconPackCircularAndroidOverlay/res/drawable/ic_qs_ui_mode_night.xml
similarity index 64%
copy from packages/overlays/IconPackFilledSettingsOverlay/res/drawable/ic_delete_accent.xml
copy to packages/overlays/IconPackCircularAndroidOverlay/res/drawable/ic_qs_ui_mode_night.xml
index e65987e..3cf7541 100644
--- a/packages/overlays/IconPackFilledSettingsOverlay/res/drawable/ic_delete_accent.xml
+++ b/packages/overlays/IconPackCircularAndroidOverlay/res/drawable/ic_qs_ui_mode_night.xml
@@ -16,14 +16,12 @@
 -->
 <vector xmlns:android="http://schemas.android.com/apk/res/android"
     android:height="24dp"
-    android:tint="?android:attr/colorAccent"
     android:viewportHeight="24"
     android:viewportWidth="24"
     android:width="24dp" >
     <path
         android:fillColor="@android:color/white"
-        android:pathData="M18,4h-2.5l-0.71-0.71C14.61,3.11,14.35,3,14.09,3H9.9C9.64,3,9.38,3.11,9.2,3.29L8.49,4h-2.5c-0.55,0-1,0.45-1,1 s0.45,1,1,1h12c0.55,0,1-0.45,1-1C19,4.45,18.55,4,18,4z" />
-    <path
-        android:fillColor="@android:color/white"
-        android:pathData="M6,19c0,1.1,0.9,2,2,2h8c1.1,0,2-0.9,2-2V7H6V19z" />
-</vector>
\ No newline at end of file
+        android:fillType="evenOdd"
+        android:pathData="M12,20.5 L12,3.5 C16.687,3.5 20.5,7.313 20.5,12 C20.5,16.687 16.687,20.5 12,20.5 M12,2 C10.619,2 9.304,2.279 8.107,2.786 C7.51,3.039 6.941,3.349 6.409,3.708 C6.143,3.888 5.886,4.08 5.639,4.283 C4.651,5.099 3.822,6.1 3.207,7.233 C2.899,7.8 2.645,8.4 2.449,9.026 C2.255,9.652 2.12,10.305 2.052,10.978 C2.018,11.313 2,11.654 2,12 C2,17.522 6.478,22 12,22 C17.522,22 22,17.522 22,12 C22,6.478 17.522,2 12,2"
+        android:strokeWidth="1" />
+</vector>
diff --git a/packages/overlays/IconPackCircularAndroidOverlay/res/drawable/ic_signal_cellular_0_4_bar.xml b/packages/overlays/IconPackCircularAndroidOverlay/res/drawable/ic_signal_cellular_0_4_bar.xml
index e09aeb7..d9dfa54 100644
--- a/packages/overlays/IconPackCircularAndroidOverlay/res/drawable/ic_signal_cellular_0_4_bar.xml
+++ b/packages/overlays/IconPackCircularAndroidOverlay/res/drawable/ic_signal_cellular_0_4_bar.xml
@@ -19,28 +19,32 @@
     android:viewportHeight="24"
     android:viewportWidth="24"
     android:width="24dp" >
-    <path
-        android:fillAlpha="0.3"
-        android:fillColor="@android:color/white"
-        android:pathData="M20,22H18.5V4.75A0.76 0.76 ,0,0,1,19.25,4h0a0.76 0.76 ,0,0,1,0.75 0.75 Z"
-        android:strokeAlpha="0.3"
-        android:strokeWidth="1" />
-    <path
-        android:fillAlpha="0.3"
-        android:fillColor="@android:color/white"
-        android:pathData="M15.33,22h-1.5V9.75A0.76 0.76 ,0,0,1,14.58,9h0a0.75 0.75 ,0,0,1,0.75 0.75 Z"
-        android:strokeAlpha="0.3"
-        android:strokeWidth="1" />
-    <path
-        android:fillAlpha="0.3"
-        android:fillColor="@android:color/white"
-        android:pathData="M10.67,22H9.17V14.75A0.75 0.75 ,0,0,1,9.92,14h0a0.76 0.76 ,0,0,1,0.75 0.75 Z"
-        android:strokeAlpha="0.3"
-        android:strokeWidth="1" />
-    <path
-        android:fillAlpha="0.3"
-        android:fillColor="@android:color/white"
-        android:pathData="M6,22H4.5V19.75A0.76 0.76 ,0,0,1,5.25,19h0a0.76 0.76 ,0,0,1,0.75 0.75 Z"
-        android:strokeAlpha="0.3"
-        android:strokeWidth="1" />
+    <group
+        android:translateX="4.000000"
+        android:translateY="3.000000" >
+        <path
+            android:fillAlpha="0.3"
+            android:fillColor="@android:color/white"
+            android:pathData="M16,18 L14.5,18 L14.5,0.75 C14.5053858,0.338037936 14.8380379,0.00538581231 15.25,0 L15.25,0 C15.6619621,0.00538581231 15.9946142,0.338037936 16,0.75 L16,18 Z"
+            android:strokeAlpha="0.3"
+            android:strokeWidth="1" />
+        <path
+            android:fillAlpha="0.3"
+            android:fillColor="@android:color/white"
+            android:pathData="M11.33,18 L9.83,18 L9.83,5.75 C9.83538581,5.33803794 10.1680379,5.00538581 10.58,5 L10.58,5 C10.9942136,5 11.33,5.33578644 11.33,5.75 L11.33,18 Z"
+            android:strokeAlpha="0.3"
+            android:strokeWidth="1" />
+        <path
+            android:fillAlpha="0.3"
+            android:fillColor="@android:color/white"
+            android:pathData="M6.67,18 L5.17,18 L5.17,10.75 C5.17,10.3357864 5.50578644,10 5.92,10 L5.92,10 C6.33196206,10.0053858 6.66461419,10.3380379 6.67,10.75 L6.67,18 Z"
+            android:strokeAlpha="0.3"
+            android:strokeWidth="1" />
+        <path
+            android:fillAlpha="0.3"
+            android:fillColor="@android:color/white"
+            android:pathData="M2,18 L0.5,18 L0.5,15.75 C0.505385812,15.3380379 0.838037936,15.0053858 1.25,15 L1.25,15 C1.66196206,15.0053858 1.99461419,15.3380379 2,15.75 L2,18 Z"
+            android:strokeAlpha="0.3"
+            android:strokeWidth="1" />
+    </group>
 </vector>
\ No newline at end of file
diff --git a/packages/overlays/IconPackCircularAndroidOverlay/res/drawable/ic_signal_cellular_1_4_bar.xml b/packages/overlays/IconPackCircularAndroidOverlay/res/drawable/ic_signal_cellular_1_4_bar.xml
index 26e96ab..70f91af 100644
--- a/packages/overlays/IconPackCircularAndroidOverlay/res/drawable/ic_signal_cellular_1_4_bar.xml
+++ b/packages/overlays/IconPackCircularAndroidOverlay/res/drawable/ic_signal_cellular_1_4_bar.xml
@@ -19,25 +19,30 @@
     android:viewportHeight="24"
     android:viewportWidth="24"
     android:width="24dp" >
-    <path
-        android:fillAlpha="0.3"
-        android:fillColor="@android:color/white"
-        android:pathData="M20,22H18.5V4.75A0.76 0.76 ,0,0,1,19.25,4h0a0.76 0.76 ,0,0,1,0.75 0.75 Z"
-        android:strokeAlpha="0.3"
-        android:strokeWidth="1" />
-    <path
-        android:fillAlpha="0.3"
-        android:fillColor="@android:color/white"
-        android:pathData="M15.33,22h-1.5V9.75A0.76 0.76 ,0,0,1,14.58,9h0a0.75 0.75 ,0,0,1,0.75 0.75 Z"
-        android:strokeAlpha="0.3"
-        android:strokeWidth="1" />
-    <path
-        android:fillAlpha="0.3"
-        android:fillColor="@android:color/white"
-        android:pathData="M10.67,22H9.17V14.75A0.75 0.75 ,0,0,1,9.92,14h0a0.76 0.76 ,0,0,1,0.75 0.75 Z"
-        android:strokeAlpha="0.3"
-        android:strokeWidth="1" />
-    <path
-        android:fillColor="@android:color/white"
-        android:pathData="M6,22H4.5V19.75A0.76 0.76 ,0,0,1,5.25,19h0a0.76 0.76 ,0,0,1,0.75 0.75 Z" />
+    <group
+        android:translateX="4.000000"
+        android:translateY="3.000000" >
+        <path
+            android:fillAlpha="0.3"
+            android:fillColor="@android:color/white"
+            android:pathData="M16,18 L14.5,18 L14.5,0.75 C14.5053858,0.338037936 14.8380379,0.00538581231 15.25,0 L15.25,0 C15.6619621,0.00538581231 15.9946142,0.338037936 16,0.75 L16,18 Z"
+            android:strokeAlpha="0.3"
+            android:strokeWidth="1" />
+        <path
+            android:fillAlpha="0.3"
+            android:fillColor="@android:color/white"
+            android:pathData="M11.33,18 L9.83,18 L9.83,5.75 C9.83538581,5.33803794 10.1680379,5.00538581 10.58,5 L10.58,5 C10.9942136,5 11.33,5.33578644 11.33,5.75 L11.33,18 Z"
+            android:strokeAlpha="0.3"
+            android:strokeWidth="1" />
+        <path
+            android:fillAlpha="0.3"
+            android:fillColor="@android:color/white"
+            android:pathData="M6.67,18 L5.17,18 L5.17,10.75 C5.17,10.3357864 5.50578644,10 5.92,10 L5.92,10 C6.33196206,10.0053858 6.66461419,10.3380379 6.67,10.75 L6.67,18 Z"
+            android:strokeAlpha="0.3"
+            android:strokeWidth="1" />
+        <path
+            android:fillColor="@android:color/white"
+            android:pathData="M2,18 L0.5,18 L0.5,15.75 C0.505385812,15.3380379 0.838037936,15.0053858 1.25,15 L1.25,15 C1.66196206,15.0053858 1.99461419,15.3380379 2,15.75 L2,18 Z"
+            android:strokeWidth="1" />
+    </group>
 </vector>
\ No newline at end of file
diff --git a/packages/overlays/IconPackCircularAndroidOverlay/res/drawable/ic_signal_cellular_2_4_bar.xml b/packages/overlays/IconPackCircularAndroidOverlay/res/drawable/ic_signal_cellular_2_4_bar.xml
index 53be899..f014eea 100644
--- a/packages/overlays/IconPackCircularAndroidOverlay/res/drawable/ic_signal_cellular_2_4_bar.xml
+++ b/packages/overlays/IconPackCircularAndroidOverlay/res/drawable/ic_signal_cellular_2_4_bar.xml
@@ -19,22 +19,28 @@
     android:viewportHeight="24"
     android:viewportWidth="24"
     android:width="24dp" >
-    <path
-        android:fillAlpha="0.3"
-        android:fillColor="@android:color/white"
-        android:pathData="M20,22H18.5V4.75A0.76 0.76 ,0,0,1,19.25,4h0a0.76 0.76 ,0,0,1,0.75 0.75 Z"
-        android:strokeAlpha="0.3"
-        android:strokeWidth="1" />
-    <path
-        android:fillAlpha="0.3"
-        android:fillColor="@android:color/white"
-        android:pathData="M15.33,22h-1.5V9.75A0.76 0.76 ,0,0,1,14.58,9h0a0.75 0.75 ,0,0,1,0.75 0.75 Z"
-        android:strokeAlpha="0.3"
-        android:strokeWidth="1" />
-    <path
-        android:fillColor="@android:color/white"
-        android:pathData="M10.67,22H9.17V14.75A0.75 0.75 ,0,0,1,9.92,14h0a0.76 0.76 ,0,0,1,0.75 0.75 Z" />
-    <path
-        android:fillColor="@android:color/white"
-        android:pathData="M6,22H4.5V19.75A0.76 0.76 ,0,0,1,5.25,19h0a0.76 0.76 ,0,0,1,0.75 0.75 Z" />
+    <group
+        android:translateX="4.000000"
+        android:translateY="3.000000" >
+        <path
+            android:fillAlpha="0.3"
+            android:fillColor="@android:color/white"
+            android:pathData="M16,18 L14.5,18 L14.5,0.75 C14.5053858,0.338037936 14.8380379,0.00538581231 15.25,0 L15.25,0 C15.6619621,0.00538581231 15.9946142,0.338037936 16,0.75 L16,18 Z"
+            android:strokeAlpha="0.3"
+            android:strokeWidth="1" />
+        <path
+            android:fillAlpha="0.3"
+            android:fillColor="@android:color/white"
+            android:pathData="M11.33,18 L9.83,18 L9.83,5.75 C9.83538581,5.33803794 10.1680379,5.00538581 10.58,5 L10.58,5 C10.9942136,5 11.33,5.33578644 11.33,5.75 L11.33,18 Z"
+            android:strokeAlpha="0.3"
+            android:strokeWidth="1" />
+        <path
+            android:fillColor="@android:color/white"
+            android:pathData="M6.67,18 L5.17,18 L5.17,10.75 C5.17,10.3357864 5.50578644,10 5.92,10 L5.92,10 C6.33196206,10.0053858 6.66461419,10.3380379 6.67,10.75 L6.67,18 Z"
+            android:strokeWidth="1" />
+        <path
+            android:fillColor="@android:color/white"
+            android:pathData="M2,18 L0.5,18 L0.5,15.75 C0.505385812,15.3380379 0.838037936,15.0053858 1.25,15 L1.25,15 C1.66196206,15.0053858 1.99461419,15.3380379 2,15.75 L2,18 Z"
+            android:strokeWidth="1" />
+    </group>
 </vector>
\ No newline at end of file
diff --git a/packages/overlays/IconPackCircularAndroidOverlay/res/drawable/ic_signal_cellular_3_4_bar.xml b/packages/overlays/IconPackCircularAndroidOverlay/res/drawable/ic_signal_cellular_3_4_bar.xml
index 9139bb4..9b83fab 100644
--- a/packages/overlays/IconPackCircularAndroidOverlay/res/drawable/ic_signal_cellular_3_4_bar.xml
+++ b/packages/overlays/IconPackCircularAndroidOverlay/res/drawable/ic_signal_cellular_3_4_bar.xml
@@ -19,19 +19,26 @@
     android:viewportHeight="24"
     android:viewportWidth="24"
     android:width="24dp" >
-    <path
-        android:fillAlpha="0.3"
-        android:fillColor="@android:color/white"
-        android:pathData="M20,22H18.5V4.75A0.76 0.76 ,0,0,1,19.25,4h0a0.76 0.76 ,0,0,1,0.75 0.75 Z"
-        android:strokeAlpha="0.3"
-        android:strokeWidth="1" />
-    <path
-        android:fillColor="@android:color/white"
-        android:pathData="M15.33,22h-1.5V9.75A0.76 0.76 ,0,0,1,14.58,9h0a0.75 0.75 ,0,0,1,0.75 0.75 Z" />
-    <path
-        android:fillColor="@android:color/white"
-        android:pathData="M10.67,22H9.17V14.75A0.75 0.75 ,0,0,1,9.92,14h0a0.76 0.76 ,0,0,1,0.75 0.75 Z" />
-    <path
-        android:fillColor="@android:color/white"
-        android:pathData="M6,22H4.5V19.75A0.76 0.76 ,0,0,1,5.25,19h0a0.76 0.76 ,0,0,1,0.75 0.75 Z" />
+    <group
+        android:translateX="4.000000"
+        android:translateY="3.000000" >
+        <path
+            android:fillAlpha="0.3"
+            android:fillColor="@android:color/white"
+            android:pathData="M16,18 L14.5,18 L14.5,0.75 C14.5053858,0.338037936 14.8380379,0.00538581231 15.25,0 L15.25,0 C15.6619621,0.00538581231 15.9946142,0.338037936 16,0.75 L16,18 Z"
+            android:strokeAlpha="0.3"
+            android:strokeWidth="1" />
+        <path
+            android:fillColor="@android:color/white"
+            android:pathData="M11.33,18 L9.83,18 L9.83,5.75 C9.83538581,5.33803794 10.1680379,5.00538581 10.58,5 L10.58,5 C10.9942136,5 11.33,5.33578644 11.33,5.75 L11.33,18 Z"
+            android:strokeWidth="1" />
+        <path
+            android:fillColor="@android:color/white"
+            android:pathData="M6.67,18 L5.17,18 L5.17,10.75 C5.17,10.3357864 5.50578644,10 5.92,10 L5.92,10 C6.33196206,10.0053858 6.66461419,10.3380379 6.67,10.75 L6.67,18 Z"
+            android:strokeWidth="1" />
+        <path
+            android:fillColor="@android:color/white"
+            android:pathData="M2,18 L0.5,18 L0.5,15.75 C0.505385812,15.3380379 0.838037936,15.0053858 1.25,15 L1.25,15 C1.66196206,15.0053858 1.99461419,15.3380379 2,15.75 L2,18 Z"
+            android:strokeWidth="1" />
+    </group>
 </vector>
\ No newline at end of file
diff --git a/packages/overlays/IconPackCircularAndroidOverlay/res/drawable/ic_signal_cellular_4_4_bar.xml b/packages/overlays/IconPackCircularAndroidOverlay/res/drawable/ic_signal_cellular_4_4_bar.xml
index 2c8d7012..6f7f48d 100644
--- a/packages/overlays/IconPackCircularAndroidOverlay/res/drawable/ic_signal_cellular_4_4_bar.xml
+++ b/packages/overlays/IconPackCircularAndroidOverlay/res/drawable/ic_signal_cellular_4_4_bar.xml
@@ -19,16 +19,24 @@
     android:viewportHeight="24"
     android:viewportWidth="24"
     android:width="24dp" >
-    <path
-        android:fillColor="@android:color/white"
-        android:pathData="M20,22H18.5V4.75A0.76 0.76 ,0,0,1,19.25,4h0a0.76 0.76 ,0,0,1,0.75 0.75 Z" />
-    <path
-        android:fillColor="@android:color/white"
-        android:pathData="M15.33,22h-1.5V9.75A0.76 0.76 ,0,0,1,14.58,9h0a0.75 0.75 ,0,0,1,0.75 0.75 Z" />
-    <path
-        android:fillColor="@android:color/white"
-        android:pathData="M10.67,22H9.17V14.75A0.75 0.75 ,0,0,1,9.92,14h0a0.76 0.76 ,0,0,1,0.75 0.75 Z" />
-    <path
-        android:fillColor="@android:color/white"
-        android:pathData="M6,22H4.5V19.75A0.76 0.76 ,0,0,1,5.25,19h0a0.76 0.76 ,0,0,1,0.75 0.75 Z" />
+    <group
+        android:translateX="4.000000"
+        android:translateY="3.000000" >
+        <path
+            android:fillColor="@android:color/white"
+            android:pathData="M16,18 L14.5,18 L14.5,0.75 C14.5053858,0.338037936 14.8380379,0.00538581231 15.25,0 L15.25,0 C15.6619621,0.00538581231 15.9946142,0.338037936 16,0.75 L16,18 Z"
+            android:strokeWidth="1" />
+        <path
+            android:fillColor="@android:color/white"
+            android:pathData="M11.33,18 L9.83,18 L9.83,5.75 C9.83538581,5.33803794 10.1680379,5.00538581 10.58,5 L10.58,5 C10.9942136,5 11.33,5.33578644 11.33,5.75 L11.33,18 Z"
+            android:strokeWidth="1" />
+        <path
+            android:fillColor="@android:color/white"
+            android:pathData="M6.67,18 L5.17,18 L5.17,10.75 C5.17,10.3357864 5.50578644,10 5.92,10 L5.92,10 C6.33196206,10.0053858 6.66461419,10.3380379 6.67,10.75 L6.67,18 Z"
+            android:strokeWidth="1" />
+        <path
+            android:fillColor="@android:color/white"
+            android:pathData="M2,18 L0.5,18 L0.5,15.75 C0.505385812,15.3380379 0.838037936,15.0053858 1.25,15 L1.25,15 C1.66196206,15.0053858 1.99461419,15.3380379 2,15.75 L2,18 Z"
+            android:strokeWidth="1" />
+    </group>
 </vector>
\ No newline at end of file
diff --git a/packages/overlays/IconPackCircularAndroidOverlay/res/drawable/perm_group_activity_recognition.xml b/packages/overlays/IconPackCircularAndroidOverlay/res/drawable/perm_group_activity_recognition.xml
index 5ad146e..cbd60d8 100644
--- a/packages/overlays/IconPackCircularAndroidOverlay/res/drawable/perm_group_activity_recognition.xml
+++ b/packages/overlays/IconPackCircularAndroidOverlay/res/drawable/perm_group_activity_recognition.xml
@@ -16,7 +16,7 @@
 -->
 <vector xmlns:android="http://schemas.android.com/apk/res/android"
     android:height="24dp"
-    android:tint="@android:color/black"
+    android:tint="?android:attr/colorControlNormal"
     android:viewportHeight="24"
     android:viewportWidth="24"
     android:width="24dp" >
diff --git a/packages/overlays/IconPackCircularAndroidOverlay/res/drawable/perm_group_aural.xml b/packages/overlays/IconPackCircularAndroidOverlay/res/drawable/perm_group_aural.xml
new file mode 100644
index 0000000..6480264
--- /dev/null
+++ b/packages/overlays/IconPackCircularAndroidOverlay/res/drawable/perm_group_aural.xml
@@ -0,0 +1,40 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+   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.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:height="24dp"
+    android:tint="?android:attr/colorControlNormal"
+    android:viewportHeight="24"
+    android:viewportWidth="24"
+    android:width="24dp" >
+    <group
+        android:translateX="2.000000"
+        android:translateY="2.000000" >
+        <path
+            android:fillColor="@android:color/white"
+            android:fillType="evenOdd"
+            android:pathData="M12.64,3 L12.64,8.82352941 C12.2536,8.5 11.772,8.29411765 11.24,8.29411765 C10.0024,8.29411765 9,9.34705882 9,10.6470588 C9,11.9470588 10.0024,13 11.24,13 C12.4776,13 13.48,11.9470588 13.48,10.6470588 L13.48,5.00157166 L15.02,5.00157166 C15.5576,5.00157166 16,4.53686577 16,3.97215989 L16,3 L12.64,3 Z"
+            android:strokeWidth="1" />
+        <path
+            android:fillColor="@android:color/white"
+            android:pathData="M20,2 C20,0.9 19.1,0 18,0 L6,0 C4.9,0 4,0.9 4,2 L4,14 C4,15.1 4.9,16 6,16 L18,16 C19.1,16 20,15.1 20,14 L20,2 Z M18.5,14 C18.5,14.28 18.28,14.5 18,14.5 L6,14.5 C5.72,14.5 5.5,14.28 5.5,14 L5.5,2 C5.5,1.72 5.72,1.5 6,1.5 L18,1.5 C18.28,1.5 18.5,1.72 18.5,2 L18.5,14 Z"
+            android:strokeWidth="1" />
+        <path
+            android:fillColor="@android:color/white"
+            android:pathData="M0.5,4.75 L0.5,16.75 C0.5,18.27 1.73,19.5 3.25,19.5 L15.25,19.5 C15.66,19.5 16,19.16 16,18.75 C16,18.34 15.66,18 15.25,18 L3.25,18 C2.56,18 2,17.44 2,16.75 L2,4.75 C2,4.34 1.66,4 1.25,4 C0.84,4 0.5,4.34 0.5,4.75 Z"
+            android:strokeWidth="1" />
+    </group>
+</vector>
\ No newline at end of file
diff --git a/packages/overlays/IconPackCircularAndroidOverlay/res/drawable/perm_group_calendar.xml b/packages/overlays/IconPackCircularAndroidOverlay/res/drawable/perm_group_calendar.xml
index 781c0f8..397050f 100644
--- a/packages/overlays/IconPackCircularAndroidOverlay/res/drawable/perm_group_calendar.xml
+++ b/packages/overlays/IconPackCircularAndroidOverlay/res/drawable/perm_group_calendar.xml
@@ -16,6 +16,7 @@
 -->
 <vector xmlns:android="http://schemas.android.com/apk/res/android"
     android:height="24dp"
+    android:tint="?android:attr/colorControlNormal"
     android:viewportHeight="24"
     android:viewportWidth="24"
     android:width="24dp" >
diff --git a/packages/overlays/IconPackCircularAndroidOverlay/res/drawable/perm_group_call_log.xml b/packages/overlays/IconPackCircularAndroidOverlay/res/drawable/perm_group_call_log.xml
index 126b70c..b56eec3 100644
--- a/packages/overlays/IconPackCircularAndroidOverlay/res/drawable/perm_group_call_log.xml
+++ b/packages/overlays/IconPackCircularAndroidOverlay/res/drawable/perm_group_call_log.xml
@@ -16,7 +16,7 @@
 -->
 <vector xmlns:android="http://schemas.android.com/apk/res/android"
     android:height="24dp"
-    android:tint="@android:color/black"
+    android:tint="?android:attr/colorControlNormal"
     android:viewportHeight="24"
     android:viewportWidth="24"
     android:width="24dp" >
diff --git a/packages/overlays/IconPackCircularAndroidOverlay/res/drawable/perm_group_camera.xml b/packages/overlays/IconPackCircularAndroidOverlay/res/drawable/perm_group_camera.xml
index 70d4fcc..c8cb2e2 100644
--- a/packages/overlays/IconPackCircularAndroidOverlay/res/drawable/perm_group_camera.xml
+++ b/packages/overlays/IconPackCircularAndroidOverlay/res/drawable/perm_group_camera.xml
@@ -16,7 +16,7 @@
 -->
 <vector xmlns:android="http://schemas.android.com/apk/res/android"
     android:height="24dp"
-    android:tint="@android:color/black"
+    android:tint="?android:attr/colorControlNormal"
     android:viewportHeight="24"
     android:viewportWidth="24"
     android:width="24dp" >
diff --git a/packages/overlays/IconPackCircularAndroidOverlay/res/drawable/perm_group_contacts.xml b/packages/overlays/IconPackCircularAndroidOverlay/res/drawable/perm_group_contacts.xml
index 6da4b26..6124df8 100644
--- a/packages/overlays/IconPackCircularAndroidOverlay/res/drawable/perm_group_contacts.xml
+++ b/packages/overlays/IconPackCircularAndroidOverlay/res/drawable/perm_group_contacts.xml
@@ -16,7 +16,7 @@
 -->
 <vector xmlns:android="http://schemas.android.com/apk/res/android"
     android:height="24dp"
-    android:tint="@android:color/black"
+    android:tint="?android:attr/colorControlNormal"
     android:viewportHeight="24"
     android:viewportWidth="24"
     android:width="24dp" >
diff --git a/packages/overlays/IconPackCircularAndroidOverlay/res/drawable/perm_group_location.xml b/packages/overlays/IconPackCircularAndroidOverlay/res/drawable/perm_group_location.xml
index d443a74..77ff42a 100644
--- a/packages/overlays/IconPackCircularAndroidOverlay/res/drawable/perm_group_location.xml
+++ b/packages/overlays/IconPackCircularAndroidOverlay/res/drawable/perm_group_location.xml
@@ -16,7 +16,7 @@
 -->
 <vector xmlns:android="http://schemas.android.com/apk/res/android"
     android:height="24dp"
-    android:tint="@android:color/black"
+    android:tint="?android:attr/colorControlNormal"
     android:viewportHeight="24"
     android:viewportWidth="24"
     android:width="24dp" >
diff --git a/packages/overlays/IconPackCircularAndroidOverlay/res/drawable/perm_group_microphone.xml b/packages/overlays/IconPackCircularAndroidOverlay/res/drawable/perm_group_microphone.xml
index cdac2d8..06aa0cd 100644
--- a/packages/overlays/IconPackCircularAndroidOverlay/res/drawable/perm_group_microphone.xml
+++ b/packages/overlays/IconPackCircularAndroidOverlay/res/drawable/perm_group_microphone.xml
@@ -16,7 +16,7 @@
 -->
 <vector xmlns:android="http://schemas.android.com/apk/res/android"
     android:height="24dp"
-    android:tint="@android:color/black"
+    android:tint="?android:attr/colorControlNormal"
     android:viewportHeight="24"
     android:viewportWidth="24"
     android:width="24dp" >
diff --git a/packages/overlays/IconPackCircularAndroidOverlay/res/drawable/perm_group_phone_calls.xml b/packages/overlays/IconPackCircularAndroidOverlay/res/drawable/perm_group_phone_calls.xml
index 991f320a..3aea5f4 100644
--- a/packages/overlays/IconPackCircularAndroidOverlay/res/drawable/perm_group_phone_calls.xml
+++ b/packages/overlays/IconPackCircularAndroidOverlay/res/drawable/perm_group_phone_calls.xml
@@ -16,7 +16,7 @@
 -->
 <vector xmlns:android="http://schemas.android.com/apk/res/android"
     android:height="24dp"
-    android:tint="@android:color/black"
+    android:tint="?android:attr/colorControlNormal"
     android:viewportHeight="24"
     android:viewportWidth="24"
     android:width="24dp" >
diff --git a/packages/overlays/IconPackCircularAndroidOverlay/res/drawable/perm_group_sensors.xml b/packages/overlays/IconPackCircularAndroidOverlay/res/drawable/perm_group_sensors.xml
index e4dee2a..4d70fc9 100644
--- a/packages/overlays/IconPackCircularAndroidOverlay/res/drawable/perm_group_sensors.xml
+++ b/packages/overlays/IconPackCircularAndroidOverlay/res/drawable/perm_group_sensors.xml
@@ -16,7 +16,7 @@
 -->
 <vector xmlns:android="http://schemas.android.com/apk/res/android"
     android:height="24dp"
-    android:tint="@android:color/black"
+    android:tint="?android:attr/colorControlNormal"
     android:viewportHeight="24"
     android:viewportWidth="24"
     android:width="24dp" >
diff --git a/packages/overlays/IconPackCircularAndroidOverlay/res/drawable/perm_group_sms.xml b/packages/overlays/IconPackCircularAndroidOverlay/res/drawable/perm_group_sms.xml
index d15cfa3..30ed8c9 100644
--- a/packages/overlays/IconPackCircularAndroidOverlay/res/drawable/perm_group_sms.xml
+++ b/packages/overlays/IconPackCircularAndroidOverlay/res/drawable/perm_group_sms.xml
@@ -16,7 +16,7 @@
 -->
 <vector xmlns:android="http://schemas.android.com/apk/res/android"
     android:height="24dp"
-    android:tint="@android:color/black"
+    android:tint="?android:attr/colorControlNormal"
     android:viewportHeight="24"
     android:viewportWidth="24"
     android:width="24dp" >
diff --git a/packages/overlays/IconPackCircularAndroidOverlay/res/drawable/perm_group_storage.xml b/packages/overlays/IconPackCircularAndroidOverlay/res/drawable/perm_group_storage.xml
index 29d2673..52cd4c1 100644
--- a/packages/overlays/IconPackCircularAndroidOverlay/res/drawable/perm_group_storage.xml
+++ b/packages/overlays/IconPackCircularAndroidOverlay/res/drawable/perm_group_storage.xml
@@ -16,7 +16,7 @@
 -->
 <vector xmlns:android="http://schemas.android.com/apk/res/android"
     android:height="24dp"
-    android:tint="@android:color/black"
+    android:tint="?android:attr/colorControlNormal"
     android:viewportHeight="24"
     android:viewportWidth="24"
     android:width="24dp" >
diff --git a/packages/overlays/IconPackCircularAndroidOverlay/res/drawable/perm_group_visual.xml b/packages/overlays/IconPackCircularAndroidOverlay/res/drawable/perm_group_visual.xml
index 519136a..1c46179 100644
--- a/packages/overlays/IconPackCircularAndroidOverlay/res/drawable/perm_group_visual.xml
+++ b/packages/overlays/IconPackCircularAndroidOverlay/res/drawable/perm_group_visual.xml
@@ -16,7 +16,7 @@
 -->
 <vector xmlns:android="http://schemas.android.com/apk/res/android"
     android:height="24dp"
-    android:tint="@android:color/black"
+    android:tint="?android:attr/colorControlNormal"
     android:viewportHeight="24"
     android:viewportWidth="24"
     android:width="24dp" >
diff --git a/packages/overlays/IconPackCircularAndroidOverlay/res/values/config.xml b/packages/overlays/IconPackCircularAndroidOverlay/res/values/config.xml
index ae5cc2b..30f29f7 100644
--- a/packages/overlays/IconPackCircularAndroidOverlay/res/values/config.xml
+++ b/packages/overlays/IconPackCircularAndroidOverlay/res/values/config.xml
@@ -30,4 +30,12 @@
     <string name="config_batterymeterPowersavePath" translatable="false">
         M 3.75,11.25 H 5.25 V 12.75 C 5.25,13.16 5.59,13.5 6,13.5 6.41,13.5 6.75,13.16 6.75,12.75 V 11.25 H 8.25 C 8.66,11.25 9,10.91 9,10.5 9,10.09 8.6601,9.75 8.25,9.75 H 6.75 V 8.25 C 6.75,7.84 6.41,7.5 6,7.5 5.59,7.5 5.25,7.84 5.25,8.25 V 9.75 H 3.75 C 3.34,9.75 3,10.09 3,10.5 3,10.91 3.34,11.25 3.75,11.25 Z
     </string>
+    <!-- X path for SignalDrawable as defined on a 24x24 canvas. -->
+    <string name="config_signalXPath" translatable="false">
+        M 17.81,18.75 L 19.81,16.75 C 20.01,16.56 20.09,16.28 20.02,16.02 C 19.96,15.75 19.75,15.54 19.48,15.47 C 19.22,15.41 18.94,15.49 18.75,15.69 L 16.75,17.69 L 14.75,15.69 C 14.56,15.49 14.28,15.41 14.02,15.47 C 13.75,15.54 13.54,15.75 13.47,16.02 C 13.41,16.28 13.49,16.56 13.69,16.75 L 15.69,18.75 L 13.69,20.75 C 13.4,21.04 13.4,21.52 13.69,21.81 C 13.98,22.1 14.46,22.1 14.75,21.81 L 16.75,19.81 L 18.75,21.81 C 19.04,22.1 19.52,22.1 19.81,21.81 C 20.1,21.52 20.1,21.04 19.81,20.75 Z
+    </string>
+    <!-- config_signalCutout{Height,Width}Fraction define fraction of the 24x24 canvas that
+         should be cut out to display config_signalXPath.-->
+    <item name="config_signalCutoutWidthFraction" format="float" type="dimen">10.5</item>
+    <item name="config_signalCutoutHeightFraction" format="float" type="dimen">11</item>
 </resources>
diff --git a/packages/overlays/IconPackCircularLauncherOverlay/res/drawable/ic_setting.xml b/packages/overlays/IconPackCircularLauncherOverlay/res/drawable/ic_setting.xml
index 4c9b5d7..f1f0f50 100644
--- a/packages/overlays/IconPackCircularLauncherOverlay/res/drawable/ic_setting.xml
+++ b/packages/overlays/IconPackCircularLauncherOverlay/res/drawable/ic_setting.xml
@@ -16,6 +16,7 @@
 -->
 <vector xmlns:android="http://schemas.android.com/apk/res/android"
     android:height="24dp"
+    android:tint="?android:attr/textColorPrimary"
     android:viewportHeight="24"
     android:viewportWidth="24"
     android:width="24dp" >
diff --git a/packages/overlays/IconPackCircularSettingsOverlay/res/drawable/ic_arrow_back.xml b/packages/overlays/IconPackCircularSettingsOverlay/res/drawable/ic_arrow_back.xml
index 920ecb5..a9e1ffe 100644
--- a/packages/overlays/IconPackCircularSettingsOverlay/res/drawable/ic_arrow_back.xml
+++ b/packages/overlays/IconPackCircularSettingsOverlay/res/drawable/ic_arrow_back.xml
@@ -15,6 +15,7 @@
    limitations under the License.
 -->
 <vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:autoMirrored="true"
     android:height="24dp"
     android:tint="?android:attr/colorControlNormal"
     android:viewportHeight="24"
diff --git a/packages/overlays/IconPackCircularSettingsOverlay/res/drawable/ic_battery_saver_accent_24dp.xml b/packages/overlays/IconPackCircularSettingsOverlay/res/drawable/ic_battery_saver_accent_24dp.xml
deleted file mode 100644
index 01d87ce..0000000
--- a/packages/overlays/IconPackCircularSettingsOverlay/res/drawable/ic_battery_saver_accent_24dp.xml
+++ /dev/null
@@ -1,29 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-   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.
--->
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
-    android:height="24dp"
-    android:tint="?android:attr/colorAccent"
-    android:viewportHeight="24"
-    android:viewportWidth="24"
-    android:width="24dp" >
-    <path
-        android:fillColor="@android:color/white"
-        android:pathData="M9.75,13.75h1.5v1.5c0,0.41,0.34,0.75,0.75,0.75s0.75-0.34,0.75-0.75v-1.5h1.5c0.41,0,0.75-0.34,0.75-0.75 s-0.34-0.75-0.75-0.75h-1.5v-1.5c0-0.41-0.34-0.75-0.75-0.75s-0.75,0.34-0.75,0.75v1.5h-1.5C9.34,12.25,9,12.59,9,13 S9.34,13.75,9.75,13.75z" />
-    <path
-        android:fillColor="@android:color/white"
-        android:pathData="M6,19c0,1.66,1.34,3,3,3h6c1.66,0,3-1.34,3-3V7c0-1.66-1.34-3-3-3h-1c0-0.55-0.45-1-1-1h-2c-0.55,0-1,0.45-1,1H9 C7.34,4,6,5.34,6,7V19z M7.5,7c0-0.83,0.67-1.5,1.5-1.5h6c0.83,0,1.5,0.67,1.5,1.5v12c0,0.83-0.67,1.5-1.5,1.5H9 c-0.83,0-1.5-0.67-1.5-1.5V7z" />
-</vector>
\ No newline at end of file
diff --git a/packages/overlays/IconPackCircularSettingsOverlay/res/drawable/ic_battery_status_bad_24dp.xml b/packages/overlays/IconPackCircularSettingsOverlay/res/drawable/ic_battery_status_bad_24dp.xml
deleted file mode 100644
index a558337..0000000
--- a/packages/overlays/IconPackCircularSettingsOverlay/res/drawable/ic_battery_status_bad_24dp.xml
+++ /dev/null
@@ -1,28 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-   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.
--->
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
-    android:height="24dp"
-    android:viewportHeight="24"
-    android:viewportWidth="24"
-    android:width="24dp" >
-    <path
-        android:fillColor="@android:color/white"
-        android:pathData="M9.75,13.75h1.5v1.5c0,0.41,0.34,0.75,0.75,0.75s0.75-0.34,0.75-0.75v-1.5h1.5c0.41,0,0.75-0.34,0.75-0.75 s-0.34-0.75-0.75-0.75h-1.5v-1.5c0-0.41-0.34-0.75-0.75-0.75s-0.75,0.34-0.75,0.75v1.5h-1.5C9.34,12.25,9,12.59,9,13 S9.34,13.75,9.75,13.75z" />
-    <path
-        android:fillColor="@android:color/white"
-        android:pathData="M6,19c0,1.66,1.34,3,3,3h6c1.66,0,3-1.34,3-3V7c0-1.66-1.34-3-3-3h-1c0-0.55-0.45-1-1-1h-2c-0.55,0-1,0.45-1,1H9 C7.34,4,6,5.34,6,7V19z M7.5,7c0-0.83,0.67-1.5,1.5-1.5h6c0.83,0,1.5,0.67,1.5,1.5v12c0,0.83-0.67,1.5-1.5,1.5H9 c-0.83,0-1.5-0.67-1.5-1.5V7z" />
-</vector>
\ No newline at end of file
diff --git a/packages/overlays/IconPackCircularSettingsOverlay/res/drawable/ic_cellular_off.xml b/packages/overlays/IconPackCircularSettingsOverlay/res/drawable/ic_cellular_off.xml
index 57fcebc..6df4756 100644
--- a/packages/overlays/IconPackCircularSettingsOverlay/res/drawable/ic_cellular_off.xml
+++ b/packages/overlays/IconPackCircularSettingsOverlay/res/drawable/ic_cellular_off.xml
@@ -15,6 +15,7 @@
    limitations under the License.
 -->
 <vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:autoMirrored="true"
     android:height="24dp"
     android:tint="?android:attr/colorAccent"
     android:viewportHeight="24"
diff --git a/packages/overlays/IconPackCircularSettingsOverlay/res/drawable/ic_chevron_right_24dp.xml b/packages/overlays/IconPackCircularSettingsOverlay/res/drawable/ic_chevron_right_24dp.xml
index 9569e68..82df1de 100644
--- a/packages/overlays/IconPackCircularSettingsOverlay/res/drawable/ic_chevron_right_24dp.xml
+++ b/packages/overlays/IconPackCircularSettingsOverlay/res/drawable/ic_chevron_right_24dp.xml
@@ -15,6 +15,7 @@
    limitations under the License.
 -->
 <vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:autoMirrored="true"
     android:height="24dp"
     android:tint="?android:attr/colorControlNormal"
     android:viewportHeight="24"
diff --git a/packages/overlays/IconPackCircularSettingsOverlay/res/drawable/ic_content_copy_grey600_24dp.xml b/packages/overlays/IconPackCircularSettingsOverlay/res/drawable/ic_content_copy_grey600_24dp.xml
index 9dea4ca..b8e9845 100644
--- a/packages/overlays/IconPackCircularSettingsOverlay/res/drawable/ic_content_copy_grey600_24dp.xml
+++ b/packages/overlays/IconPackCircularSettingsOverlay/res/drawable/ic_content_copy_grey600_24dp.xml
@@ -16,7 +16,7 @@
 -->
 <vector xmlns:android="http://schemas.android.com/apk/res/android"
     android:height="24dp"
-    android:tint="#757575"
+    android:tint="@*android:color/material_grey_600"
     android:viewportHeight="24"
     android:viewportWidth="24"
     android:width="24dp" >
diff --git a/packages/overlays/IconPackCircularSettingsOverlay/res/drawable/ic_data_saver.xml b/packages/overlays/IconPackCircularSettingsOverlay/res/drawable/ic_data_saver.xml
index 77c0a15..ba3c580 100644
--- a/packages/overlays/IconPackCircularSettingsOverlay/res/drawable/ic_data_saver.xml
+++ b/packages/overlays/IconPackCircularSettingsOverlay/res/drawable/ic_data_saver.xml
@@ -15,18 +15,19 @@
    limitations under the License.
 -->
 <vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:autoMirrored="true"
     android:height="24dp"
     android:tint="?android:attr/colorControlNormal"
     android:viewportHeight="24"
     android:viewportWidth="24"
     android:width="24dp" >
-    <path
-        android:fillColor="@android:color/white"
-        android:pathData="M12,7a0.76 0.76 ,0,0,0-0.75 0.75 v3.5H7.75a0.75 0.75 ,0,0,0,0,1.5h3.5v3.5a0.75 0.75 ,0,0,0,1.5,0v-3.5h3.5a0.75 0.75 ,0,0,0,0-1.5h-3.5V7.75A0.76 0.76 ,0,0,0,12,7Z" />
-    <path
-        android:fillColor="@android:color/white"
-        android:pathData="M3.36,7A10,10,0,0,0,20.27,17.64L18.1,16.39A7.5,7.5,0,1,1,11.25,4.56V2.05A10,10,0,0,0,3.36,7Z" />
-    <path
-        android:fillColor="@android:color/white"
-        android:pathData="M21,16.35a10,10,0,0,0-8.27-14.3V4.56a7.48,7.48,0,0,1,6.1,10.54Z" />
+    <group
+        android:translateX="2.000000"
+        android:translateY="2.000000" >
+        <path
+            android:fillColor="@android:color/white"
+            android:fillType="evenOdd"
+            android:pathData="M17.5000671,10 C17.5000671,6.198 14.6680671,3.064 11.0000671,2.574 L11.0000671,0.05 C16.0500671,0.55 20.0000671,4.82 20.0000671,10 C20.0000671,11.45 19.6800671,12.83 19.1200671,14.07 L16.9560671,12.796 C17.3040671,11.932 17.5000671,10.989 17.5000671,10 Z M10.0000671,17.5 C12.3900671,17.5 14.5140671,16.378 15.8870671,14.637 C16.6270671,15.073 18.0500671,15.91 18.0500671,15.91 C15.9790671,18.732 12.4710671,20.427 8.60106711,19.906 C4.22106711,19.316 0.68406711,15.774 0.0940671101,11.394 C-0.68693289,5.591 3.49306711,0.594 9.00006711,0.05 L9.00006711,2.574 C5.33206711,3.064 2.50006711,6.198 2.50006711,10 C2.50006711,14.142 5.85806711,17.5 10.0000671,17.5 Z M6,10 C6.00538581,9.58803794 6.33803794,9.25538581 6.75,9.25 L9.25,9.25 L9.25,6.75 C9.25,6.33578644 9.58578644,6 10,6 C10.4142136,6 10.75,6.33578644 10.75,6.75 L10.75,9.25 L13.25,9.25 C13.6642136,9.25 14,9.58578644 14,10 C14,10.4142136 13.6642136,10.75 13.25,10.75 L10.75,10.75 L10.75,13.25 C10.75,13.6642136 10.4142136,14 10,14 C9.58578644,14 9.25,13.6642136 9.25,13.25 L9.25,10.75 L6.75,10.75 C6.33803794,10.7446142 6.00538581,10.4119621 6,10 Z"
+            android:strokeWidth="1" />
+    </group>
 </vector>
\ No newline at end of file
diff --git a/packages/overlays/IconPackCircularSettingsOverlay/res/drawable/ic_delete_accent.xml b/packages/overlays/IconPackCircularSettingsOverlay/res/drawable/ic_delete_accent.xml
deleted file mode 100644
index b4d8827..0000000
--- a/packages/overlays/IconPackCircularSettingsOverlay/res/drawable/ic_delete_accent.xml
+++ /dev/null
@@ -1,32 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-   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.
--->
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
-    android:height="24dp"
-    android:tint="?android:attr/colorAccent"
-    android:viewportHeight="24"
-    android:viewportWidth="24"
-    android:width="24dp" >
-    <path
-        android:fillColor="@android:color/white"
-        android:pathData="M9,20h6c1.66,0,3-1.34,3-3V6h0.5c0.41,0,0.75-0.34,0.75-0.75S18.91,4.5,18.5,4.5H18h-3l-1-1h-4l-1,1H6H5.5 c-0.41,0-0.75,0.34-0.75,0.75S5.09,6,5.5,6H6v11C6,18.66,7.34,20,9,20z M16.5,6v11c0,0.83-0.67,1.5-1.5,1.5H9 c-0.83,0-1.5-0.67-1.5-1.5V6H16.5z" />
-    <path
-        android:fillColor="@android:color/white"
-        android:pathData="M13.97,16c0.41,0,0.75-0.34,0.75-0.75v-6.5c0-0.41-0.34-0.75-0.75-0.75s-0.75,0.34-0.75,0.75v6.5 C13.22,15.66,13.55,16,13.97,16z" />
-    <path
-        android:fillColor="@android:color/white"
-        android:pathData="M10,16c0.41,0,0.75-0.34,0.75-0.75v-6.5C10.75,8.34,10.41,8,10,8S9.25,8.34,9.25,8.75v6.5C9.25,15.66,9.59,16,10,16z" />
-</vector>
\ No newline at end of file
diff --git a/packages/overlays/IconPackCircularSettingsOverlay/res/drawable/ic_devices_other.xml b/packages/overlays/IconPackCircularSettingsOverlay/res/drawable/ic_devices_other.xml
index 17a191e..14898c4 100644
--- a/packages/overlays/IconPackCircularSettingsOverlay/res/drawable/ic_devices_other.xml
+++ b/packages/overlays/IconPackCircularSettingsOverlay/res/drawable/ic_devices_other.xml
@@ -15,6 +15,7 @@
    limitations under the License.
 -->
 <vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:autoMirrored="true"
     android:height="24dp"
     android:viewportHeight="24"
     android:viewportWidth="24"
diff --git a/packages/overlays/IconPackCircularSettingsOverlay/res/drawable/ic_eject_24dp.xml b/packages/overlays/IconPackCircularSettingsOverlay/res/drawable/ic_eject_24dp.xml
index 1c1fa4b..abbab51 100644
--- a/packages/overlays/IconPackCircularSettingsOverlay/res/drawable/ic_eject_24dp.xml
+++ b/packages/overlays/IconPackCircularSettingsOverlay/res/drawable/ic_eject_24dp.xml
@@ -16,6 +16,7 @@
 -->
 <vector xmlns:android="http://schemas.android.com/apk/res/android"
     android:height="24dp"
+    android:tint="?android:attr/colorControlNormal"
     android:viewportHeight="24"
     android:viewportWidth="24"
     android:width="24dp" >
diff --git a/packages/overlays/IconPackCircularSettingsOverlay/res/drawable/ic_find_in_page_24px.xml b/packages/overlays/IconPackCircularSettingsOverlay/res/drawable/ic_find_in_page_24px.xml
new file mode 100644
index 0000000..fd1a00d
--- /dev/null
+++ b/packages/overlays/IconPackCircularSettingsOverlay/res/drawable/ic_find_in_page_24px.xml
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+   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.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:height="24dp"
+    android:tint="?android:attr/colorControlNormal"
+    android:viewportHeight="24"
+    android:viewportWidth="24"
+    android:width="24dp" >
+    <group
+        android:translateX="4.000100"
+        android:translateY="2.000100" >
+        <path
+            android:fillColor="@android:color/white"
+            android:fillType="evenOdd"
+            android:pathData="M7.9999,15.2499 C6.2079,15.2499 4.7499,13.7919 4.7499,11.9999 C4.7499,10.2079 6.2079,8.7499 7.9999,8.7499 C9.7919,8.7499 11.2499,10.2079 11.2499,11.9999 C11.2499,13.7919 9.7919,15.2499 7.9999,15.2499 L7.9999,15.2499 Z M1.4999,17.7779 L1.4999,2.2219 C1.4999,1.8239 1.8529,1.4999 2.2859,1.4999 L9.6769,1.4999 L14.4999,6.1889 L14.4999,17.5799 L11.8269,14.7879 C12.3999,14.0029 12.7499,13.0439 12.7499,11.9999 C12.7499,9.3809 10.6189,7.2499 7.9999,7.2499 C5.3809,7.2499 3.2499,9.3809 3.2499,11.9999 C3.2499,14.6189 5.3809,16.7499 7.9999,16.7499 C9.0329,16.7499 9.9829,16.4089 10.7649,15.8469 L13.3039,18.4999 L2.2859,18.4999 C1.8529,18.4999 1.4999,18.1759 1.4999,17.7779 L1.4999,17.7779 Z M10.2859,-0.0001 L2.2859,-0.0001 C1.0229,-0.0001 -0.0001,0.9949 -0.0001,2.2219 L-0.0001,17.7779 C-0.0001,19.0049 1.0229,19.9999 2.2859,19.9999 L13.7139,19.9999 C14.9769,19.9999 15.9999,19.0049 15.9999,17.7779 L15.9999,5.5559 L10.2859,-0.0001 Z"
+            android:strokeWidth="1" />
+    </group>
+</vector>
\ No newline at end of file
diff --git a/packages/overlays/IconPackCircularSettingsOverlay/res/drawable/ic_help_actionbar.xml b/packages/overlays/IconPackCircularSettingsOverlay/res/drawable/ic_help_actionbar.xml
index 8b388f2..b980a2c 100644
--- a/packages/overlays/IconPackCircularSettingsOverlay/res/drawable/ic_help_actionbar.xml
+++ b/packages/overlays/IconPackCircularSettingsOverlay/res/drawable/ic_help_actionbar.xml
@@ -15,6 +15,7 @@
    limitations under the License.
 -->
 <vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:autoMirrored="true"
     android:height="24dp"
     android:tint="?android:attr/colorControlNormal"
     android:viewportHeight="24"
diff --git a/packages/overlays/IconPackCircularSettingsOverlay/res/drawable/ic_network_cell.xml b/packages/overlays/IconPackCircularSettingsOverlay/res/drawable/ic_network_cell.xml
index b6fa9fc..1d72e5f 100644
--- a/packages/overlays/IconPackCircularSettingsOverlay/res/drawable/ic_network_cell.xml
+++ b/packages/overlays/IconPackCircularSettingsOverlay/res/drawable/ic_network_cell.xml
@@ -15,21 +15,30 @@
    limitations under the License.
 -->
 <vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:autoMirrored="true"
     android:height="24dp"
     android:tint="?android:attr/colorControlNormal"
     android:viewportHeight="24"
     android:viewportWidth="24"
     android:width="24dp" >
-    <path
-        android:fillColor="@android:color/white"
-        android:pathData="M20,22H18.5V4.75A0.76 0.76 ,0,0,1,19.25,4h0a0.76 0.76 ,0,0,1,0.75 0.75 Z" />
-    <path
-        android:fillColor="@android:color/white"
-        android:pathData="M15.33,22h-1.5V9.75A0.76 0.76 ,0,0,1,14.58,9h0a0.75 0.75 ,0,0,1,0.75 0.75 Z" />
-    <path
-        android:fillColor="@android:color/white"
-        android:pathData="M10.67,22H9.17V14.75A0.75 0.75 ,0,0,1,9.92,14h0a0.76 0.76 ,0,0,1,0.75 0.75 Z" />
-    <path
-        android:fillColor="@android:color/white"
-        android:pathData="M6,22H4.5V19.75A0.76 0.76 ,0,0,1,5.25,19h0a0.76 0.76 ,0,0,1,0.75 0.75 Z" />
+    <group
+        android:translateX="4.000000"
+        android:translateY="3.000000" >
+        <path
+            android:fillColor="@android:color/white"
+            android:pathData="M16,18 L14.5,18 L14.5,0.75 C14.5053858,0.338037936 14.8380379,0.00538581231 15.25,0 L15.25,0 C15.6619621,0.00538581231 15.9946142,0.338037936 16,0.75 L16,18 Z"
+            android:strokeWidth="1" />
+        <path
+            android:fillColor="@android:color/white"
+            android:pathData="M11.33,18 L9.83,18 L9.83,5.75 C9.83538581,5.33803794 10.1680379,5.00538581 10.58,5 L10.58,5 C10.9942136,5 11.33,5.33578644 11.33,5.75 L11.33,18 Z"
+            android:strokeWidth="1" />
+        <path
+            android:fillColor="@android:color/white"
+            android:pathData="M6.67,18 L5.17,18 L5.17,10.75 C5.17,10.3357864 5.50578644,10 5.92,10 L5.92,10 C6.33196206,10.0053858 6.66461419,10.3380379 6.67,10.75 L6.67,18 Z"
+            android:strokeWidth="1" />
+        <path
+            android:fillColor="@android:color/white"
+            android:pathData="M2,18 L0.5,18 L0.5,15.75 C0.505385812,15.3380379 0.838037936,15.0053858 1.25,15 L1.25,15 C1.66196206,15.0053858 1.99461419,15.3380379 2,15.75 L2,18 Z"
+            android:strokeWidth="1" />
+    </group>
 </vector>
\ No newline at end of file
diff --git a/packages/overlays/IconPackCircularSettingsOverlay/res/drawable/ic_notifications_off_24dp.xml b/packages/overlays/IconPackCircularSettingsOverlay/res/drawable/ic_notifications_off_24dp.xml
index 2dc6545..2a21776 100644
--- a/packages/overlays/IconPackCircularSettingsOverlay/res/drawable/ic_notifications_off_24dp.xml
+++ b/packages/overlays/IconPackCircularSettingsOverlay/res/drawable/ic_notifications_off_24dp.xml
@@ -15,6 +15,7 @@
    limitations under the License.
 -->
 <vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:autoMirrored="true"
     android:height="24dp"
     android:tint="?android:attr/colorControlNormal"
     android:viewportHeight="24"
diff --git a/packages/overlays/IconPackCircularSettingsOverlay/res/drawable/ic_scan_24dp.xml b/packages/overlays/IconPackCircularSettingsOverlay/res/drawable/ic_scan_24dp.xml
new file mode 100644
index 0000000..f160fe9
--- /dev/null
+++ b/packages/overlays/IconPackCircularSettingsOverlay/res/drawable/ic_scan_24dp.xml
@@ -0,0 +1,55 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+   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.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:height="24dp"
+    android:tint="?android:attr/colorAccent"
+    android:viewportHeight="24"
+    android:viewportWidth="24"
+    android:width="24dp" >
+    <group
+        android:translateX="3.000000"
+        android:translateY="3.000000" >
+        <path
+            android:fillColor="@android:color/white"
+            android:pathData="M1.5,4.5 L1.5,1.9 C1.5,1.6790861 1.6790861,1.5 1.9,1.5 L4.1,1.5 C4.3209139,1.5 4.5,1.6790861 4.5,1.9 L4.5,4.5 L1.5,4.5 L1.5,4.5 Z M0,6 L6,6 L6,1.5 C6,0.671572875 5.32842712,0 4.5,0 L1.5,0 C0.671572875,0 0,0.671572875 0,1.5 L0,6 Z"
+            android:strokeWidth="1" />
+        <path
+            android:fillColor="@android:color/white"
+            android:pathData="M13.5,4.5 L13.5,1.9 C13.5,1.6790861 13.6790861,1.5 13.9,1.5 L16.1,1.5 C16.3209139,1.5 16.5,1.6790861 16.5,1.9 L16.5,4.5 L13.5,4.5 L13.5,4.5 Z M12,6 L18,6 L18,1.5 C18,0.671572875 17.3284271,0 16.5,0 L13.5,0 C12.6715729,0 12,0.671572875 12,1.5 L12,6 Z"
+            android:strokeWidth="1" />
+        <path
+            android:fillColor="@android:color/white"
+            android:pathData="M4.5,13.5 L4.5,16.1 C4.5,16.3209139 4.3209139,16.5 4.1,16.5 L1.9,16.5 C1.6790861,16.5 1.5,16.3209139 1.5,16.1 L1.5,13.5 L4.5,13.5 L4.5,13.5 Z M6,12 L0,12 L0,16.5 C0,17.3284271 0.671572875,18 1.5,18 L4.5,18 C5.32842712,18 6,17.3284271 6,16.5 L6,12 Z"
+            android:strokeWidth="1" />
+        <path
+            android:fillColor="@android:color/white"
+            android:pathData="M 2 8 L 0 8 L 0 10 L 2 10 L 2 8 Z"
+            android:strokeWidth="1" />
+        <path
+            android:fillColor="@android:color/white"
+            android:pathData="M9,0 C8.58803794,0.00538581231 8.25538581,0.338037936 8.25,0.75 L8.25,5.75 C8.25000002,6.16421355 8.58578645,6.49999997 9,6.49999997 C9.41421355,6.49999997 9.74999998,6.16421355 9.75,5.75 L9.75,0.75 C9.74461419,0.338037936 9.41196206,0.00538581231 9,0 L9,0 Z"
+            android:strokeWidth="1" />
+        <path
+            android:fillColor="@android:color/white"
+            android:pathData="M13.75,12.25 L17.25,12.25 C17.6619621,12.2553858 17.9946142,12.5880379 18,13 C17.9946142,13.4119621 17.6619621,13.7446142 17.25,13.75 L13.75,13.75 L13.75,17.25 C13.75,17.6642136 13.4142136,18 13,18 C12.5857864,18 12.25,17.6642136 12.25,17.25 L12.25,13.75 L8.74999997,13.75 C8.33578642,13.75 8,13.4142136 8,13 C8,12.5857864 8.33578642,12.25 8.74999997,12.25 L12.25,12.25 L12.25,8.75 C12.2553858,8.33803794 12.5880379,8.00538581 13,8 C13.4119621,8.00538581 13.7446142,8.33803794 13.75,8.75 L13.75,12.25 Z"
+            android:strokeWidth="1" />
+        <path
+            android:fillColor="@android:color/white"
+            android:pathData="M 6 8 L 4 8 L 4 10 L 6 10 L 6 8 Z"
+            android:strokeWidth="1" />
+    </group>
+</vector>
\ No newline at end of file
diff --git a/packages/overlays/IconPackCircularSettingsOverlay/res/drawable/ic_settings_data_usage.xml b/packages/overlays/IconPackCircularSettingsOverlay/res/drawable/ic_settings_data_usage.xml
index e48cc14..855e4bb 100644
--- a/packages/overlays/IconPackCircularSettingsOverlay/res/drawable/ic_settings_data_usage.xml
+++ b/packages/overlays/IconPackCircularSettingsOverlay/res/drawable/ic_settings_data_usage.xml
@@ -22,8 +22,7 @@
     android:width="24dp" >
     <path
         android:fillColor="@android:color/white"
-        android:pathData="M12,19.52a7.5,7.5,0,0,1-0.77-15V2.06A10,10,0,1,0,22,12.77h-2.5A7.52,7.52,0,0,1,12,19.52Z" />
-    <path
-        android:fillColor="@android:color/white"
-        android:pathData="M19.48,11.27H22a10,10,0,0,0-9.23-9.22v2.5A7.51,7.51,0,0,1,19.48,11.27Z" />
+        android:fillType="evenOdd"
+        android:pathData="M19.5000671,12 C19.5000671,8.198 16.6680671,5.064 13.0000671,4.574 L13.0000671,2.05 C18.0500671,2.55 22.0000671,6.82 22.0000671,12 C22.0000671,13.45 21.6800671,14.83 21.1200671,16.07 L18.9560671,14.796 C19.3040671,13.932 19.5000671,12.989 19.5000671,12 Z M12.0000671,19.5 C14.3900671,19.5 16.5140671,18.378 17.8870671,16.637 C18.6270671,17.073 20.0500671,17.91 20.0500671,17.91 C17.9790671,20.732 14.4710671,22.427 10.6010671,21.906 C6.22106711,21.316 2.68406711,17.774 2.09406711,13.394 C1.31306711,7.591 5.49306711,2.594 11.0000671,2.05 L11.0000671,4.574 C7.33206711,5.064 4.50006711,8.198 4.50006711,12 C4.50006711,16.142 7.85806711,19.5 12.0000671,19.5 Z"
+        android:strokeWidth="1" />
 </vector>
\ No newline at end of file
diff --git a/packages/overlays/IconPackCircularSettingsOverlay/res/drawable/ic_settings_disable.xml b/packages/overlays/IconPackCircularSettingsOverlay/res/drawable/ic_settings_disable.xml
new file mode 100644
index 0000000..0572fb7
--- /dev/null
+++ b/packages/overlays/IconPackCircularSettingsOverlay/res/drawable/ic_settings_disable.xml
@@ -0,0 +1,37 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+   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.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:height="24dp"
+    android:tint="?android:attr/colorControlNormal"
+    android:viewportHeight="24"
+    android:viewportWidth="24"
+    android:width="24dp" >
+    <group
+        android:translateX="1.000000"
+        android:translateY="2.000000" >
+        <path
+            android:fillColor="@android:color/white"
+            android:fillType="evenOdd"
+            android:pathData="M11,18.5 C6.313,18.5 2.5,14.687 2.5,10 C2.5,8.182 3.078,6.498 4.055,5.114 L15.887,16.945 C14.503,17.922 12.818,18.5 11,18.5 M20.031,18.969 L2.032,0.971 C1.739,0.678 1.264,0.678 0.971,0.971 C0.678,1.264 0.678,1.738 0.971,2.031 L2.983,4.043 C1.742,5.707 1,7.765 1,10 C1,15.522 5.477,20 11,20 C13.236,20 15.293,19.258 16.957,18.017 L18.971,20.029 C19.117,20.176 19.309,20.249 19.501,20.249 C19.693,20.249 19.885,20.176 20.031,20.029 C20.324,19.736 20.324,19.262 20.031,18.969"
+            android:strokeWidth="1" />
+        <path
+            android:fillColor="@android:color/white"
+            android:fillType="evenOdd"
+            android:pathData="M11,1.5 C15.687,1.5 19.5,5.313 19.5,10 C19.5,11.782 18.946,13.436 18.006,14.804 L19.078,15.877 C20.281,14.226 21,12.199 21,10 C21,4.478 16.522,0 11,0 C8.801,0 6.774,0.719 5.124,1.922 L6.196,2.994 C7.564,2.054 9.218,1.5 11,1.5"
+            android:strokeWidth="1" />
+    </group>
+</vector>
\ No newline at end of file
diff --git a/packages/overlays/IconPackCircularSettingsOverlay/res/drawable/ic_settings_enable.xml b/packages/overlays/IconPackCircularSettingsOverlay/res/drawable/ic_settings_enable.xml
new file mode 100644
index 0000000..41962b2
--- /dev/null
+++ b/packages/overlays/IconPackCircularSettingsOverlay/res/drawable/ic_settings_enable.xml
@@ -0,0 +1,37 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+   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.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:height="24dp"
+    android:tint="?android:attr/colorControlNormal"
+    android:viewportHeight="24"
+    android:viewportWidth="24"
+    android:width="24dp" >
+    <group
+        android:translateX="2.000000"
+        android:translateY="2.000000" >
+        <path
+            android:fillColor="@android:color/white"
+            android:fillType="evenOdd"
+            android:pathData="M12.25,0.2637 L12.25,1.8127 C15.847,2.8017 18.5,6.0927 18.5,9.9997 C18.5,14.6867 14.687,18.4997 10,18.4997 C5.313,18.4997 1.5,14.6867 1.5,9.9997 C1.5,6.0927 4.153,2.8017 7.75,1.8127 L7.75,0.2637 C3.312,1.2847 0,5.2517 0,9.9997 C0,15.5227 4.477,19.9997 10,19.9997 C15.523,19.9997 20,15.5227 20,9.9997 C20,5.2517 16.687,1.2847 12.25,0.2637"
+            android:strokeWidth="1" />
+        <path
+            android:fillColor="@android:color/white"
+            android:fillType="evenOdd"
+            android:pathData="M15.0303,9.9697 C14.7373,9.6767 14.2623,9.6767 13.9693,9.9697 L10.7503,13.1897 L10.7503,0.7387 C10.7503,0.3307 10.4143,-0.0003 10.0003,-0.0003 C9.5863,-0.0003 9.2503,0.3307 9.2503,0.7387 L9.2503,13.1897 L6.0303,9.9697 C5.7373,9.6767 5.2623,9.6767 4.9693,9.9697 C4.6763,10.2627 4.6763,10.7377 4.9693,11.0307 L10.0003,16.0607 L15.0303,11.0307 C15.3233,10.7377 15.3233,10.2627 15.0303,9.9697"
+            android:strokeWidth="1" />
+    </group>
+</vector>
\ No newline at end of file
diff --git a/packages/overlays/IconPackCircularSettingsOverlay/res/drawable/ic_settings_language.xml b/packages/overlays/IconPackCircularSettingsOverlay/res/drawable/ic_settings_language.xml
new file mode 100644
index 0000000..2c83c34
--- /dev/null
+++ b/packages/overlays/IconPackCircularSettingsOverlay/res/drawable/ic_settings_language.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+   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.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:height="24dp"
+    android:tint="?android:attr/colorControlNormal"
+    android:viewportHeight="24"
+    android:viewportWidth="24"
+    android:width="24dp" >
+    <path
+        android:fillColor="@android:color/white"
+        android:pathData="M12,2C6.48,2,2,6.48,2,12c0,5.15,3.89,9.38,8.89,9.93c0.01,0.01,0.01,0.01,0.01,0.02l0.02-0.02C11.28,21.98,11.64,22,12,22 s0.72-0.02,1.08-0.06l0.02,0.02c0.01-0.01,0.01-0.01,0.01-0.02c5-0.55,8.89-4.79,8.89-9.93C22,6.48,17.52,2,12,2z M19.35,7.75 h-3.39c-0.39-1.35-0.97-2.67-1.73-3.94C16.41,4.4,18.24,5.84,19.35,7.75z M20.5,12c0,0.96-0.17,1.89-0.47,2.75h-3.69 c0.33-1.82,0.32-3.67-0.02-5.5h3.71C20.33,10.11,20.5,11.04,20.5,12z M12,20.5c-0.1,0-0.2-0.01-0.3-0.02 c-0.96-1.36-1.68-2.78-2.14-4.23h4.89c-0.47,1.45-1.18,2.87-2.14,4.23C12.2,20.49,12.1,20.5,12,20.5z M9.16,14.75 c-0.37-1.82-0.36-3.67,0.02-5.5h5.64c0.38,1.83,0.39,3.68,0.02,5.5H9.16z M3.5,12c0-0.96,0.17-1.89,0.47-2.75h3.71 c-0.34,1.83-0.35,3.68-0.02,5.5H3.97C3.67,13.89,3.5,12.96,3.5,12z M12,3.5c0.09,0,0.17,0.01,0.26,0.01 c0.96,1.37,1.68,2.79,2.16,4.24H9.58c0.48-1.45,1.2-2.87,2.16-4.24C11.83,3.51,11.91,3.5,12,3.5z M9.77,3.81 C9.01,5.08,8.43,6.4,8.04,7.75H4.65C5.76,5.84,7.59,4.4,9.77,3.81z M4.65,16.25h3.36c0.38,1.34,0.95,2.66,1.71,3.93 C7.56,19.58,5.75,18.15,4.65,16.25z M14.28,20.18c0.75-1.27,1.32-2.59,1.71-3.93h3.36C18.25,18.15,16.44,19.58,14.28,20.18z" />
+</vector>
\ No newline at end of file
diff --git a/packages/overlays/IconPackFilledSettingsOverlay/res/drawable/ic_delete_accent.xml b/packages/overlays/IconPackCircularSettingsOverlay/res/drawable/ic_settings_multiuser.xml
similarity index 71%
copy from packages/overlays/IconPackFilledSettingsOverlay/res/drawable/ic_delete_accent.xml
copy to packages/overlays/IconPackCircularSettingsOverlay/res/drawable/ic_settings_multiuser.xml
index e65987e..d6d6558 100644
--- a/packages/overlays/IconPackFilledSettingsOverlay/res/drawable/ic_delete_accent.xml
+++ b/packages/overlays/IconPackCircularSettingsOverlay/res/drawable/ic_settings_multiuser.xml
@@ -16,14 +16,14 @@
 -->
 <vector xmlns:android="http://schemas.android.com/apk/res/android"
     android:height="24dp"
-    android:tint="?android:attr/colorAccent"
+    android:tint="?android:attr/colorControlNormal"
     android:viewportHeight="24"
     android:viewportWidth="24"
     android:width="24dp" >
     <path
         android:fillColor="@android:color/white"
-        android:pathData="M18,4h-2.5l-0.71-0.71C14.61,3.11,14.35,3,14.09,3H9.9C9.64,3,9.38,3.11,9.2,3.29L8.49,4h-2.5c-0.55,0-1,0.45-1,1 s0.45,1,1,1h12c0.55,0,1-0.45,1-1C19,4.45,18.55,4,18,4z" />
+        android:pathData="M8,8c0,2.21,1.79,4,4,4s4-1.79,4-4c0-2.21-1.79-4-4-4S8,5.79,8,8z M12,5.5c1.38,0,2.5,1.12,2.5,2.5 c0,1.38-1.12,2.5-2.5,2.5S9.5,9.38,9.5,8C9.5,6.62,10.62,5.5,12,5.5z" />
     <path
         android:fillColor="@android:color/white"
-        android:pathData="M6,19c0,1.1,0.9,2,2,2h8c1.1,0,2-0.9,2-2V7H6V19z" />
+        android:pathData="M20,20c0-3.99-4-6-8-6s-8,2.01-8,6H20z M12,15.5c2.57,0,5.3,0.95,6.2,3H5.8C6.7,16.45,9.43,15.5,12,15.5z" />
 </vector>
\ No newline at end of file
diff --git a/packages/overlays/IconPackCircularSettingsOverlay/res/drawable/ic_settings_wireless_white.xml b/packages/overlays/IconPackCircularSettingsOverlay/res/drawable/ic_settings_wireless_white.xml
deleted file mode 100644
index fde9965..0000000
--- a/packages/overlays/IconPackCircularSettingsOverlay/res/drawable/ic_settings_wireless_white.xml
+++ /dev/null
@@ -1,34 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-   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.
--->
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
-    android:height="24dp"
-    android:viewportHeight="24"
-    android:viewportWidth="24"
-    android:width="24dp" >
-    <path
-        android:fillColor="@android:color/white"
-        android:pathData="M 12 17 C 12.8284271247 17 13.5 17.6715728753 13.5 18.5 C 13.5 19.3284271247 12.8284271247 20 12 20 C 11.1715728753 20 10.5 19.3284271247 10.5 18.5 C 10.5 17.6715728753 11.1715728753 17 12 17 Z" />
-    <path
-        android:fillColor="@android:color/white"
-        android:pathData="M19.42,11.84c-0.19,0-0.38-0.07-0.53-0.22C17.05,9.77,14.6,8.75,12,8.75s-5.05,1.02-6.89,2.86 c-0.29,0.29-0.77,0.29-1.06,0c-0.29-0.29-0.29-0.77,0-1.06C6.17,8.43,9,7.25,12,7.25s5.83,1.17,7.95,3.3 c0.29,0.29,0.29,0.77,0,1.06C19.8,11.76,19.61,11.84,19.42,11.84z" />
-    <path
-        android:fillColor="@android:color/white"
-        android:pathData="M22.61,8.65c-0.19,0-0.38-0.07-0.53-0.22C19.38,5.74,15.81,4.25,12,4.25S4.62,5.74,1.92,8.43c-0.29,0.29-0.77,0.29-1.06,0 s-0.29-0.77,0-1.06C3.84,4.39,7.79,2.75,12,2.75s8.16,1.64,11.14,4.61c0.29,0.29,0.29,0.77,0,1.06 C22.99,8.57,22.8,8.65,22.61,8.65z" />
-    <path
-        android:fillColor="@android:color/white"
-        android:pathData="M16.25,15c-0.19,0-0.38-0.07-0.53-0.22c-1-0.99-2.32-1.53-3.73-1.53s-2.73,0.54-3.73,1.53c-0.29,0.29-0.77,0.29-1.06-0.01 s-0.29-0.77,0.01-1.06c1.28-1.27,2.98-1.96,4.78-1.96s3.5,0.7,4.78,1.96c0.29,0.29,0.3,0.77,0.01,1.06 C16.64,14.93,16.45,15,16.25,15z" />
-</vector>
\ No newline at end of file
diff --git a/packages/overlays/IconPackCircularSettingsOverlay/res/drawable/ic_sync_problem_24dp.xml b/packages/overlays/IconPackCircularSettingsOverlay/res/drawable/ic_sync_problem_24dp.xml
new file mode 100644
index 0000000..a0233ba
--- /dev/null
+++ b/packages/overlays/IconPackCircularSettingsOverlay/res/drawable/ic_sync_problem_24dp.xml
@@ -0,0 +1,37 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+   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.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:height="24dp"
+    android:tint="?android:attr/colorControlNormal"
+    android:viewportHeight="24"
+    android:viewportWidth="24"
+    android:width="24dp" >
+    <group
+        android:translateX="4.000000"
+        android:translateY="3.000000" >
+        <path
+            android:fillColor="@android:color/white"
+            android:fillType="evenOdd"
+            android:pathData="M12.9902,13.5098 C12.9902,13.7858 12.7652,14.0098 12.4902,14.0098 C12.2142,14.0098 11.9902,13.7858 11.9902,13.5098 L11.9902,11.5098 C11.9902,11.2348 12.2142,11.0098 12.4902,11.0098 C12.7652,11.0098 12.9902,11.2348 12.9902,11.5098 L12.9902,13.5098 Z M12.4902,16.0098 C12.2142,16.0098 11.9902,15.7858 11.9902,15.5098 C11.9902,15.2348 12.2142,15.0098 12.4902,15.0098 C12.7652,15.0098 12.9902,15.2348 12.9902,15.5098 C12.9902,15.7858 12.7652,16.0098 12.4902,16.0098 L12.4902,16.0098 Z M15.5182,11.7848 C15.8372,10.9048 16.0102,9.9558 16.0102,8.9698 C16.0102,6.0698 14.5002,3.4798 12.1102,2.0098 L14.5102,2.0098 C14.9102,1.9998 15.2502,1.6598 15.2502,1.2498 C15.2502,0.8398 14.9102,0.4998 14.5002,0.4998 L9.2502,0.4998 L9.2502,6.2498 C9.2502,6.6598 9.5902,6.9998 10.0002,6.9998 C10.4102,6.9998 10.7502,6.6598 10.7502,6.2498 L10.7502,2.9398 C13.0302,4.0598 14.5002,6.3698 14.5002,8.9698 C14.5002,9.5068 14.4172,10.0238 14.2982,10.5268 C13.7682,10.2048 13.1542,10.0098 12.4902,10.0098 C10.5562,10.0098 8.9902,11.5768 8.9902,13.5098 C8.9902,15.4438 10.5562,17.0098 12.4902,17.0098 C14.4232,17.0098 15.9902,15.4438 15.9902,13.5098 C15.9902,12.8798 15.8092,12.2958 15.5182,11.7848 L15.5182,11.7848 Z"
+            android:strokeWidth="1" />
+        <path
+            android:fillColor="@android:color/white"
+            android:fillType="evenOdd"
+            android:pathData="M6.3901,1.04 C2.6301,1.91 0.0001,5.21 0.0001,9.07 C0.0001,11.65 1.2001,13.98 3.1301,15.5 L1.5001,15.5 C1.0901,15.5 0.7501,15.84 0.7501,16.25 C0.7501,16.66 1.0901,17 1.5001,17 L6.7501,17 L6.7501,11.75 C6.7501,11.34 6.4101,11 6.0001,11 C5.5901,11 5.2501,11.34 5.2501,11.75 L5.2501,15.09 C2.9701,13.97 1.5001,11.66 1.5001,9.06 C1.5001,5.91 3.6501,3.21 6.7301,2.5 C7.1301,2.41 7.3901,2 7.2901,1.6 C7.2001,1.2 6.8001,0.95 6.3901,1.04"
+            android:strokeWidth="1" />
+    </group>
+</vector>
\ No newline at end of file
diff --git a/packages/overlays/IconPackCircularSystemUIOverlay/res/drawable/ic_arrow_back.xml b/packages/overlays/IconPackCircularSystemUIOverlay/res/drawable/ic_arrow_back.xml
index 920ecb5..a9e1ffe 100644
--- a/packages/overlays/IconPackCircularSystemUIOverlay/res/drawable/ic_arrow_back.xml
+++ b/packages/overlays/IconPackCircularSystemUIOverlay/res/drawable/ic_arrow_back.xml
@@ -15,6 +15,7 @@
    limitations under the License.
 -->
 <vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:autoMirrored="true"
     android:height="24dp"
     android:tint="?android:attr/colorControlNormal"
     android:viewportHeight="24"
diff --git a/packages/overlays/IconPackCircularSystemUIOverlay/res/drawable/ic_brightness_thumb.xml b/packages/overlays/IconPackCircularSystemUIOverlay/res/drawable/ic_brightness_thumb.xml
index dbd9b8e..fae73a4 100644
--- a/packages/overlays/IconPackCircularSystemUIOverlay/res/drawable/ic_brightness_thumb.xml
+++ b/packages/overlays/IconPackCircularSystemUIOverlay/res/drawable/ic_brightness_thumb.xml
@@ -20,7 +20,7 @@
     android:viewportWidth="24"
     android:width="24dp" >
     <path
-        android:fillColor="?android:attr/colorPrimary"
+        android:fillColor="?android:attr/colorBackgroundFloating"
         android:pathData="M18.94,9.75L18.5,9.31V8.69V6c0-0.28-0.22-0.5-0.5-0.5h-2.69h-0.62l-0.44-0.44l-1.9-1.9 C12.23,3.04,12.08,3.02,12,3.02c-0.08,0-0.23,0.02-0.35,0.15l-1.9,1.9L9.31,5.5H8.69H6C5.72,5.5,5.5,5.72,5.5,6v2.69v0.62 L5.06,9.75l-1.9,1.9C3.04,11.77,3.02,11.92,3.02,12s0.02,0.23,0.15,0.35l1.9,1.9l0.44,0.44v0.62V18c0,0.28,0.22,0.5,0.5,0.5h2.69 h0.62l0.44,0.44l1.9,1.9c0.13,0.13,0.28,0.15,0.35,0.15c0.08,0,0.23-0.02,0.35-0.15l1.9-1.9l0.44-0.44h0.62H18 c0.28,0,0.5-0.22,0.5-0.5v-2.69v-0.62l0.44-0.44l1.9-1.9c0.13-0.13,0.15-0.28,0.15-0.35s-0.02-0.23-0.15-0.35L18.94,9.75z M12,17 c-2.76,0-5-2.24-5-5s2.24-5,5-5s5,2.24,5,5S14.76,17,12,17z" />
     <path
         android:fillColor="?android:attr/colorControlActivated"
diff --git a/packages/overlays/IconPackCircularSystemUIOverlay/res/drawable/ic_camera.xml b/packages/overlays/IconPackCircularSystemUIOverlay/res/drawable/ic_camera.xml
index c4728eb..77197a5 100644
--- a/packages/overlays/IconPackCircularSystemUIOverlay/res/drawable/ic_camera.xml
+++ b/packages/overlays/IconPackCircularSystemUIOverlay/res/drawable/ic_camera.xml
@@ -15,10 +15,10 @@
    limitations under the License.
 -->
 <vector xmlns:android="http://schemas.android.com/apk/res/android"
-    android:height="24dp"
+    android:height="17dp"
     android:viewportHeight="24"
     android:viewportWidth="24"
-    android:width="24dp" >
+    android:width="17dp" >
     <path
         android:fillColor="@android:color/white"
         android:pathData="M22,8c0-1.66-1.34-3-3-3h-2l-2-2H9L7,5H5C3.34,5,2,6.34,2,8v13h20V8z M20.5,19.5h-17V8c0-0.83,0.67-1.5,1.5-1.5h14 c0.83,0,1.5,0.67,1.5,1.5V19.5z" />
diff --git a/packages/overlays/IconPackCircularSystemUIOverlay/res/drawable/ic_data_saver.xml b/packages/overlays/IconPackCircularSystemUIOverlay/res/drawable/ic_data_saver.xml
index 938d241..cdc3bfb 100644
--- a/packages/overlays/IconPackCircularSystemUIOverlay/res/drawable/ic_data_saver.xml
+++ b/packages/overlays/IconPackCircularSystemUIOverlay/res/drawable/ic_data_saver.xml
@@ -15,17 +15,17 @@
    limitations under the License.
 -->
 <vector xmlns:android="http://schemas.android.com/apk/res/android"
-    android:height="18dp "
+    android:height="18dp"
     android:viewportHeight="24"
     android:viewportWidth="24"
-    android:width="18dp " >
-    <path
-        android:fillColor="@android:color/white"
-        android:pathData="M12,7a0.76 0.76 ,0,0,0-0.75 0.75 v3.5H7.75a0.75 0.75 ,0,0,0,0,1.5h3.5v3.5a0.75 0.75 ,0,0,0,1.5,0v-3.5h3.5a0.75 0.75 ,0,0,0,0-1.5h-3.5V7.75A0.76 0.76 ,0,0,0,12,7Z" />
-    <path
-        android:fillColor="@android:color/white"
-        android:pathData="M3.36,7A10,10,0,0,0,20.27,17.64L18.1,16.39A7.5,7.5,0,1,1,11.25,4.56V2.05A10,10,0,0,0,3.36,7Z" />
-    <path
-        android:fillColor="@android:color/white"
-        android:pathData="M21,16.35a10,10,0,0,0-8.27-14.3V4.56a7.48,7.48,0,0,1,6.1,10.54Z" />
+    android:width="18dp" >
+    <group
+        android:translateX="2.000000"
+        android:translateY="2.000000" >
+        <path
+            android:fillColor="@android:color/white"
+            android:fillType="evenOdd"
+            android:pathData="M17.5000671,10 C17.5000671,6.198 14.6680671,3.064 11.0000671,2.574 L11.0000671,0.05 C16.0500671,0.55 20.0000671,4.82 20.0000671,10 C20.0000671,11.45 19.6800671,12.83 19.1200671,14.07 L16.9560671,12.796 C17.3040671,11.932 17.5000671,10.989 17.5000671,10 Z M10.0000671,17.5 C12.3900671,17.5 14.5140671,16.378 15.8870671,14.637 C16.6270671,15.073 18.0500671,15.91 18.0500671,15.91 C15.9790671,18.732 12.4710671,20.427 8.60106711,19.906 C4.22106711,19.316 0.68406711,15.774 0.0940671101,11.394 C-0.68693289,5.591 3.49306711,0.594 9.00006711,0.05 L9.00006711,2.574 C5.33206711,3.064 2.50006711,6.198 2.50006711,10 C2.50006711,14.142 5.85806711,17.5 10.0000671,17.5 Z M6,10 C6.00538581,9.58803794 6.33803794,9.25538581 6.75,9.25 L9.25,9.25 L9.25,6.75 C9.25,6.33578644 9.58578644,6 10,6 C10.4142136,6 10.75,6.33578644 10.75,6.75 L10.75,9.25 L13.25,9.25 C13.6642136,9.25 14,9.58578644 14,10 C14,10.4142136 13.6642136,10.75 13.25,10.75 L10.75,10.75 L10.75,13.25 C10.75,13.6642136 10.4142136,14 10,14 C9.58578644,14 9.25,13.6642136 9.25,13.25 L9.25,10.75 L6.75,10.75 C6.33803794,10.7446142 6.00538581,10.4119621 6,10 Z"
+            android:strokeWidth="1" />
+    </group>
 </vector>
\ No newline at end of file
diff --git a/packages/overlays/IconPackCircularSystemUIOverlay/res/drawable/ic_data_saver_off.xml b/packages/overlays/IconPackCircularSystemUIOverlay/res/drawable/ic_data_saver_off.xml
index 3d620a1..7dab949 100644
--- a/packages/overlays/IconPackCircularSystemUIOverlay/res/drawable/ic_data_saver_off.xml
+++ b/packages/overlays/IconPackCircularSystemUIOverlay/res/drawable/ic_data_saver_off.xml
@@ -21,8 +21,7 @@
     android:width="24dp" >
     <path
         android:fillColor="@android:color/white"
-        android:pathData="M3.36,7A10,10,0,0,0,20.27,17.64L18.1,16.39A7.5,7.5,0,1,1,11.25,4.56V2.05A10,10,0,0,0,3.36,7Z" />
-    <path
-        android:fillColor="@android:color/white"
-        android:pathData="M21,16.35a10,10,0,0,0-8.27-14.3V4.56a7.48,7.48,0,0,1,6.1,10.54Z" />
+        android:fillType="evenOdd"
+        android:pathData="M19.5000671,12 C19.5000671,8.198 16.6680671,5.064 13.0000671,4.574 L13.0000671,2.05 C18.0500671,2.55 22.0000671,6.82 22.0000671,12 C22.0000671,13.45 21.6800671,14.83 21.1200671,16.07 L18.9560671,14.796 C19.3040671,13.932 19.5000671,12.989 19.5000671,12 Z M12.0000671,19.5 C14.3900671,19.5 16.5140671,18.378 17.8870671,16.637 C18.6270671,17.073 20.0500671,17.91 20.0500671,17.91 C17.9790671,20.732 14.4710671,22.427 10.6010671,21.906 C6.22106711,21.316 2.68406711,17.774 2.09406711,13.394 C1.31306711,7.591 5.49306711,2.594 11.0000671,2.05 L11.0000671,4.574 C7.33206711,5.064 4.50006711,8.198 4.50006711,12 C4.50006711,16.142 7.85806711,19.5 12.0000671,19.5 Z"
+        android:strokeWidth="1" />
 </vector>
\ No newline at end of file
diff --git a/packages/overlays/IconPackCircularSystemUIOverlay/res/drawable/ic_qs_bluetooth_connecting.xml b/packages/overlays/IconPackCircularSystemUIOverlay/res/drawable/ic_qs_bluetooth_connecting.xml
index fc38ed4..c7a0266 100644
--- a/packages/overlays/IconPackCircularSystemUIOverlay/res/drawable/ic_qs_bluetooth_connecting.xml
+++ b/packages/overlays/IconPackCircularSystemUIOverlay/res/drawable/ic_qs_bluetooth_connecting.xml
@@ -16,6 +16,7 @@
 -->
 <vector xmlns:android="http://schemas.android.com/apk/res/android"
     android:height="24dp"
+    android:tint="?android:attr/colorControlNormal"
     android:viewportHeight="24"
     android:viewportWidth="24"
     android:width="24dp" >
diff --git a/packages/overlays/IconPackCircularSystemUIOverlay/res/drawable/ic_volume_alarm_mute.xml b/packages/overlays/IconPackCircularSystemUIOverlay/res/drawable/ic_volume_alarm_mute.xml
index 659b4e1..9bdc79a 100644
--- a/packages/overlays/IconPackCircularSystemUIOverlay/res/drawable/ic_volume_alarm_mute.xml
+++ b/packages/overlays/IconPackCircularSystemUIOverlay/res/drawable/ic_volume_alarm_mute.xml
@@ -16,6 +16,7 @@
 -->
 <vector xmlns:android="http://schemas.android.com/apk/res/android"
     android:height="24dp"
+    android:tint="?android:attr/colorControlNormal"
     android:viewportHeight="24"
     android:viewportWidth="24"
     android:width="24dp" >
diff --git a/packages/overlays/IconPackCircularSystemUIOverlay/res/drawable/ic_volume_odi_captions.xml b/packages/overlays/IconPackCircularSystemUIOverlay/res/drawable/ic_volume_odi_captions.xml
new file mode 100644
index 0000000..e210bcb0
--- /dev/null
+++ b/packages/overlays/IconPackCircularSystemUIOverlay/res/drawable/ic_volume_odi_captions.xml
@@ -0,0 +1,51 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+   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.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:height="24dp"
+    android:viewportHeight="24"
+    android:viewportWidth="24"
+    android:width="24dp" >
+    <group
+        android:translateX="2.000000"
+        android:translateY="4.000000" >
+        <path
+            android:fillColor="@android:color/white"
+            android:fillType="evenOdd"
+            android:pathData="M3.75,11.5 L13.25,11.5 C13.664,11.5 14,11.836 14,12.25 C14,12.664 13.664,13 13.25,13 L3.75,13 C3.336,13 3,12.664 3,12.25 C3,11.836 3.336,11.5 3.75,11.5"
+            android:strokeWidth="1" />
+        <path
+            android:fillColor="@android:color/white"
+            android:fillType="evenOdd"
+            android:pathData="M3.75,8.5 L3.75,8.5 C4.164,8.5 4.5,8.836 4.5,9.25 C4.5,9.664 4.164,10 3.75,10 C3.336,10 3,9.664 3,9.25 C3,8.836 3.336,8.5 3.75,8.5"
+            android:strokeWidth="1" />
+        <path
+            android:fillColor="@android:color/white"
+            android:fillType="evenOdd"
+            android:pathData="M17,12.25 L17,12.25 C17,12.664 16.664,13 16.25,13 C15.836,13 15.5,12.664 15.5,12.25 C15.5,11.836 15.836,11.5 16.25,11.5 C16.664,11.5 17,11.836 17,12.25"
+            android:strokeWidth="1" />
+        <path
+            android:fillColor="@android:color/white"
+            android:fillType="evenOdd"
+            android:pathData="M17,9.25 L17,9.25 C17,9.664 16.664,10 16.25,10 L6.75,10 C6.336,10 6,9.664 6,9.25 C6,8.836 6.336,8.5 6.75,8.5 L16.25,8.5 C16.664,8.5 17,8.836 17,9.25"
+            android:strokeWidth="1" />
+        <path
+            android:fillColor="@android:color/white"
+            android:fillType="evenOdd"
+            android:pathData="M18,0 L2,0 C0.896,0 0,0.896 0,2 L0,14 C0,15.104 0.896,16 2,16 L18,16 C19.104,16 20,15.104 20,14 L20,2 C20,0.896 19.104,0 18,0 M18,1.5 C18.275,1.5 18.5,1.725 18.5,2 L18.5,14 C18.5,14.275 18.275,14.5 18,14.5 L2,14.5 C1.725,14.5 1.5,14.275 1.5,14 L1.5,2 C1.5,1.725 1.725,1.5 2,1.5 L18,1.5"
+            android:strokeWidth="1" />
+    </group>
+</vector>
\ No newline at end of file
diff --git a/packages/overlays/IconPackCircularSystemUIOverlay/res/drawable/ic_volume_odi_captions_disabled.xml b/packages/overlays/IconPackCircularSystemUIOverlay/res/drawable/ic_volume_odi_captions_disabled.xml
new file mode 100644
index 0000000..660f64a
--- /dev/null
+++ b/packages/overlays/IconPackCircularSystemUIOverlay/res/drawable/ic_volume_odi_captions_disabled.xml
@@ -0,0 +1,56 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+   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.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:height="24dp"
+    android:viewportHeight="24"
+    android:viewportWidth="24"
+    android:width="24dp" >
+    <group
+        android:translateX="1.000000"
+        android:translateY="2.000000" >
+        <path
+            android:fillColor="@android:color/white"
+            android:fillType="evenOdd"
+            android:pathData="M19,3.5 C19.275,3.5 19.5,3.725 19.5,4 L19.5,16 C19.5,16.09 19.47,16.17 19.428,16.244 L20.497,17.313 C20.807,16.961 21,16.506 21,16 L21,4 C21,2.896 20.104,2 19,2 L5.184,2 L6.684,3.5 L19,3.5 Z"
+            android:strokeWidth="1" />
+        <path
+            android:fillColor="@android:color/white"
+            android:fillType="evenOdd"
+            android:pathData="M19,3.5 C19.275,3.5 19.5,3.725 19.5,4 L19.5,16 C19.5,16.09 19.47,16.17 19.428,16.244 L20.497,17.313 C20.807,16.961 21,16.506 21,16 L21,4 C21,2.896 20.104,2 19,2 L5.184,2 L6.684,3.5 L19,3.5 Z"
+            android:strokeWidth="1" />
+        <path
+            android:fillColor="@android:color/white"
+            android:fillType="evenOdd"
+            android:pathData="M18,14.25 C18,13.836 17.664,13.5 17.25,13.5 C17.091,13.5 16.951,13.561 16.829,13.646 L17.854,14.671 C17.939,14.549 18,14.409 18,14.25"
+            android:strokeWidth="1" />
+        <path
+            android:fillColor="@android:color/white"
+            android:fillType="evenOdd"
+            android:pathData="M4.75,12 C5.164,12 5.5,11.664 5.5,11.25 C5.5,10.836 5.164,10.5 4.75,10.5 C4.336,10.5 4,10.836 4,11.25 C4,11.664 4.336,12 4.75,12"
+            android:strokeWidth="1" />
+        <path
+            android:fillColor="@android:color/white"
+            android:fillType="evenOdd"
+            android:pathData="M3,16.5 C2.725,16.5 2.5,16.275 2.5,16 L2.5,4 C2.5,3.878 2.549,3.77 2.622,3.684 L9.439,10.5 L7.75,10.5 C7.336,10.5 7,10.836 7,11.25 C7,11.664 7.336,12 7.75,12 L10.939,12 L12.439,13.5 L4.75,13.5 C4.336,13.5 4,13.836 4,14.25 C4,14.664 4.336,15 4.75,15 L13.939,15 L15.44,16.5 L3,16.5 Z M20.03,18.969 L2.03,0.971 C1.737,0.678 1.263,0.678 0.97,0.971 C0.677,1.264 0.677,1.738 0.97,2.031 L1.558,2.619 C1.214,2.979 1,3.463 1,4 L1,16 C1,17.104 1.896,18 3,18 L16.94,18 L18.97,20.029 C19.116,20.176 19.308,20.249 19.5,20.249 C19.692,20.249 19.884,20.176 20.03,20.029 C20.323,19.736 20.323,19.262 20.03,18.969 L20.03,18.969 Z"
+            android:strokeWidth="1" />
+        <path
+            android:fillColor="@android:color/white"
+            android:fillType="evenOdd"
+            android:pathData="M17.25,12 C17.664,12 18,11.664 18,11.25 C18,10.836 17.664,10.5 17.25,10.5 L13.684,10.5 L15.184,12 L17.25,12 Z"
+            android:strokeWidth="1" />
+    </group>
+</vector>
\ No newline at end of file
diff --git a/packages/overlays/IconPackFilledSettingsOverlay/res/drawable/ic_delete_accent.xml b/packages/overlays/IconPackFilledAndroidOverlay/res/drawable/ic_battery_80_24dp.xml
similarity index 74%
rename from packages/overlays/IconPackFilledSettingsOverlay/res/drawable/ic_delete_accent.xml
rename to packages/overlays/IconPackFilledAndroidOverlay/res/drawable/ic_battery_80_24dp.xml
index e65987e..eb8550f 100644
--- a/packages/overlays/IconPackFilledSettingsOverlay/res/drawable/ic_delete_accent.xml
+++ b/packages/overlays/IconPackFilledAndroidOverlay/res/drawable/ic_battery_80_24dp.xml
@@ -16,14 +16,16 @@
 -->
 <vector xmlns:android="http://schemas.android.com/apk/res/android"
     android:height="24dp"
-    android:tint="?android:attr/colorAccent"
     android:viewportHeight="24"
     android:viewportWidth="24"
     android:width="24dp" >
     <path
+        android:fillAlpha="0.3"
         android:fillColor="@android:color/white"
-        android:pathData="M18,4h-2.5l-0.71-0.71C14.61,3.11,14.35,3,14.09,3H9.9C9.64,3,9.38,3.11,9.2,3.29L8.49,4h-2.5c-0.55,0-1,0.45-1,1 s0.45,1,1,1h12c0.55,0,1-0.45,1-1C19,4.45,18.55,4,18,4z" />
+        android:pathData="M17,5.33C17,4.6,16.4,4,15.67,4H14V2h-4v2H8.33C7.6,4,7,4.6,7,5.33V9h10V5.33z"
+        android:strokeAlpha="0.3"
+        android:strokeWidth="1" />
     <path
         android:fillColor="@android:color/white"
-        android:pathData="M6,19c0,1.1,0.9,2,2,2h8c1.1,0,2-0.9,2-2V7H6V19z" />
+        android:pathData="M7,9v11.67C7,21.4,7.6,22,8.33,22h7.33C16.4,22,17,21.4,17,20.67V9H7z" />
 </vector>
\ No newline at end of file
diff --git a/packages/overlays/IconPackFilledAndroidOverlay/res/drawable/ic_bluetooth_share_icon.xml b/packages/overlays/IconPackFilledAndroidOverlay/res/drawable/ic_bluetooth_share_icon.xml
index df79827..8ff3c1c 100644
--- a/packages/overlays/IconPackFilledAndroidOverlay/res/drawable/ic_bluetooth_share_icon.xml
+++ b/packages/overlays/IconPackFilledAndroidOverlay/res/drawable/ic_bluetooth_share_icon.xml
@@ -22,5 +22,5 @@
     android:width="24dp" >
     <path
         android:fillColor="@android:color/white"
-        android:pathData="M17.21,6.79l-4.5-4.5c-0.29-0.29-0.72-0.37-1.09-0.22C11.25,2.23,11,2.6,11,3v6.59l-3.8-3.8c-0.39-0.39-1.02-0.39-1.41,0 c-0.39,0.39-0.39,1.02,0,1.41l4.8,4.8l-4.8,4.8c-0.39,0.39-0.39,1.02,0,1.41c0.39,0.39,1.02,0.39,1.41,0l3.8-3.8V21 c0,0.4,0.24,0.77,0.62,0.92C11.74,21.98,11.87,22,12,22c0.26,0,0.52-0.1,0.71-0.29l4.5-4.5c0.39-0.39,0.39-1.02,0-1.41L13.42,12 l3.79-3.79C17.6,7.82,17.6,7.18,17.21,6.79z M15.09,16.5L13,18.58v-4.17L15.09,16.5z M13,9.58V5.42l2.08,2.08L13,9.58z" />
+        android:pathData="M13.51,12l3.75-3.74c0.41-0.41,0.41-1.07,0-1.48l-4.47-4.47l-0.03-0.03c-0.42-0.39-1.08-0.37-1.48,0.05 C11.1,2.52,11,2.78,11,3.04v6.44L6.95,5.43c-0.41-0.41-1.06-0.41-1.47,0c-0.41,0.41-0.41,1.06,0,1.47l5.09,5.1l-5.09,5.09 c-0.41,0.41-0.41,1.06,0,1.47c0.41,0.41,1.06,0.41,1.47,0L11,14.51v6.45c0,0.57,0.47,1.04,1.04,1.04c0.26,0,0.52-0.1,0.71-0.28 l0.05-0.05l4.46-4.46c0.41-0.41,0.41-1.07,0-1.48L13.51,12z M12.99,5.37l2.15,2.15l-2.15,2.15V5.37z M12.99,18.62v-4.3l2.15,2.15 L12.99,18.62z" />
 </vector>
\ No newline at end of file
diff --git a/packages/overlays/IconPackFilledAndroidOverlay/res/drawable/ic_bt_misc_hid.xml b/packages/overlays/IconPackFilledAndroidOverlay/res/drawable/ic_bt_misc_hid.xml
index b86d9ba..6b9735c 100644
--- a/packages/overlays/IconPackFilledAndroidOverlay/res/drawable/ic_bt_misc_hid.xml
+++ b/packages/overlays/IconPackFilledAndroidOverlay/res/drawable/ic_bt_misc_hid.xml
@@ -20,7 +20,6 @@
     android:viewportHeight="24"
     android:viewportWidth="24"
     android:width="24dp" >
-    <path android:pathData="M0,0h24v24H0V0z" />
     <path
         android:fillColor="@android:color/white"
         android:pathData="M15,7.09V3c0-0.55-0.45-1-1-1h-4C9.45,2,9,2.45,9,3v4.09c0,0.27,0.11,0.52,0.29,0.71l2,2c0.39,0.39,1.02,0.39,1.41,0l2-2 C14.89,7.61,15,7.35,15,7.09z M7.09,9H3c-0.55,0-1,0.45-1,1v4c0,0.55,0.45,1,1,1h4.09c0.27,0,0.52-0.11,0.71-0.29l2-2 c0.39-0.39,0.39-1.02,0-1.41l-2-2C7.61,9.11,7.35,9,7.09,9z M9,16.91V21c0,0.55,0.45,1,1,1h4c0.55,0,1-0.45,1-1v-4.09 c0-0.27-0.11-0.52-0.29-0.71l-2-2c-0.39-0.39-1.02-0.39-1.41,0l-2,2C9.11,16.39,9,16.65,9,16.91z M16.21,9.29l-2,2 c-0.39,0.39-0.39,1.02,0,1.41l2,2c0.19,0.19,0.44,0.29,0.71,0.29H21c0.55,0,1-0.45,1-1v-4c0-0.55-0.45-1-1-1h-4.09 C16.65,9,16.39,9.11,16.21,9.29z" />
diff --git a/packages/overlays/IconPackFilledAndroidOverlay/res/drawable/ic_file_copy.xml b/packages/overlays/IconPackFilledAndroidOverlay/res/drawable/ic_file_copy.xml
index 6245147..e479f50 100644
--- a/packages/overlays/IconPackFilledAndroidOverlay/res/drawable/ic_file_copy.xml
+++ b/packages/overlays/IconPackFilledAndroidOverlay/res/drawable/ic_file_copy.xml
@@ -16,7 +16,7 @@
 -->
 <vector xmlns:android="http://schemas.android.com/apk/res/android"
     android:height="24dp"
-    android:tint="#FF737373"
+    android:tint="@*android:color/material_grey_600"
     android:viewportHeight="24"
     android:viewportWidth="24"
     android:width="24dp" >
diff --git a/packages/overlays/IconPackFilledAndroidOverlay/res/drawable/ic_lock.xml b/packages/overlays/IconPackFilledAndroidOverlay/res/drawable/ic_lock.xml
index 07c81dd..b2fa85f 100644
--- a/packages/overlays/IconPackFilledAndroidOverlay/res/drawable/ic_lock.xml
+++ b/packages/overlays/IconPackFilledAndroidOverlay/res/drawable/ic_lock.xml
@@ -16,7 +16,6 @@
 -->
 <vector xmlns:android="http://schemas.android.com/apk/res/android"
     android:height="32dp"
-    android:tint="?android:attr/textColor"
     android:viewportHeight="24"
     android:viewportWidth="24"
     android:width="32dp" >
diff --git a/packages/overlays/IconPackFilledAndroidOverlay/res/drawable/ic_lock_open.xml b/packages/overlays/IconPackFilledAndroidOverlay/res/drawable/ic_lock_open.xml
index 698ce66..13bfbf9 100644
--- a/packages/overlays/IconPackFilledAndroidOverlay/res/drawable/ic_lock_open.xml
+++ b/packages/overlays/IconPackFilledAndroidOverlay/res/drawable/ic_lock_open.xml
@@ -16,7 +16,6 @@
 -->
 <vector xmlns:android="http://schemas.android.com/apk/res/android"
     android:height="32dp"
-    android:tint="?android:attr/textColor"
     android:viewportHeight="24"
     android:viewportWidth="24"
     android:width="32dp" >
diff --git a/packages/overlays/IconPackFilledAndroidOverlay/res/drawable/ic_lockscreen_ime.xml b/packages/overlays/IconPackFilledAndroidOverlay/res/drawable/ic_lockscreen_ime.xml
index 4cd05f3..16541e6 100644
--- a/packages/overlays/IconPackFilledAndroidOverlay/res/drawable/ic_lockscreen_ime.xml
+++ b/packages/overlays/IconPackFilledAndroidOverlay/res/drawable/ic_lockscreen_ime.xml
@@ -16,6 +16,7 @@
 -->
 <vector xmlns:android="http://schemas.android.com/apk/res/android"
     android:height="24dp"
+    android:tint="?android:attr/colorControlNormal"
     android:viewportHeight="24"
     android:viewportWidth="24"
     android:width="24dp" >
diff --git a/packages/overlays/IconPackFilledAndroidOverlay/res/drawable/ic_mode_edit.xml b/packages/overlays/IconPackFilledAndroidOverlay/res/drawable/ic_mode_edit.xml
index bf8df45..bb3c043 100644
--- a/packages/overlays/IconPackFilledAndroidOverlay/res/drawable/ic_mode_edit.xml
+++ b/packages/overlays/IconPackFilledAndroidOverlay/res/drawable/ic_mode_edit.xml
@@ -16,6 +16,7 @@
 -->
 <vector xmlns:android="http://schemas.android.com/apk/res/android"
     android:height="24dp"
+    android:tint="?android:attr/colorControlNormal"
     android:viewportHeight="24"
     android:viewportWidth="24"
     android:width="24dp" >
diff --git a/packages/overlays/IconPackFilledAndroidOverlay/res/drawable/ic_notifications_alerted.xml b/packages/overlays/IconPackFilledAndroidOverlay/res/drawable/ic_notifications_alerted.xml
new file mode 100644
index 0000000..0847a35
--- /dev/null
+++ b/packages/overlays/IconPackFilledAndroidOverlay/res/drawable/ic_notifications_alerted.xml
@@ -0,0 +1,34 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+   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.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:height="24dp"
+    android:viewportHeight="24"
+    android:viewportWidth="24"
+    android:width="24dp" >
+    <path
+        android:fillColor="@android:color/white"
+        android:pathData="M4.12,9.67C4.42,7.73,5.38,6,6.77,4.73C7.19,4.35,7.2,3.7,6.8,3.3c-0.39-0.39-1-0.39-1.4-0.03 C3.7,4.84,2.52,6.96,2.15,9.34c-0.1,0.61,0.37,1.16,0.99,1.16C3.63,10.5,4.04,10.15,4.12,9.67z" />
+    <path
+        android:fillColor="@android:color/white"
+        android:pathData="M18.6,3.28c-0.4-0.37-1.02-0.36-1.4,0.02c-0.4,0.4-0.38,1.04,0.03,1.42c1.38,1.27,2.35,3,2.65,4.94 c0.08,0.49,0.5,0.84,0.98,0.84c0.61,0,1.09-0.55,0.99-1.16C21.47,6.96,20.29,4.84,18.6,3.28z" />
+    <path
+        android:fillColor="@android:color/white"
+        android:pathData="M12,22c1.1,0,2-0.9,2-2h-4C10,21.1,10.9,22,12,22z" />
+    <path
+        android:fillColor="@android:color/white"
+        android:pathData="M18,16v-5c0-3.07-1.64-5.64-4.5-6.32V4c0-0.83-0.67-1.5-1.5-1.5S10.5,3.17,10.5,4v0.68C7.63,5.36,6,7.92,6,11v5 l-2.15,2.15c-0.19,0.2-0.19,0.51,0.01,0.71C3.95,18.95,4.07,19,4.2,19h15.6c0.45,0,0.67-0.54,0.35-0.85L18,16z" />
+</vector>
\ No newline at end of file
diff --git a/packages/overlays/IconPackFilledAndroidOverlay/res/drawable/ic_phone.xml b/packages/overlays/IconPackFilledAndroidOverlay/res/drawable/ic_phone.xml
index de34815..adf521c 100644
--- a/packages/overlays/IconPackFilledAndroidOverlay/res/drawable/ic_phone.xml
+++ b/packages/overlays/IconPackFilledAndroidOverlay/res/drawable/ic_phone.xml
@@ -15,7 +15,9 @@
    limitations under the License.
 -->
 <vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:autoMirrored="true"
     android:height="24dp"
+    android:tint="?android:attr/colorControlNormal"
     android:viewportHeight="24"
     android:viewportWidth="24"
     android:width="24dp" >
diff --git a/packages/overlays/IconPackFilledAndroidOverlay/res/drawable/ic_qs_battery_saver.xml b/packages/overlays/IconPackFilledAndroidOverlay/res/drawable/ic_qs_battery_saver.xml
index 22e183c..4f7d963 100644
--- a/packages/overlays/IconPackFilledAndroidOverlay/res/drawable/ic_qs_battery_saver.xml
+++ b/packages/overlays/IconPackFilledAndroidOverlay/res/drawable/ic_qs_battery_saver.xml
@@ -15,7 +15,9 @@
    limitations under the License.
 -->
 <vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:autoMirrored="true"
     android:height="24dp"
+    android:tint="?android:attr/colorControlNormal"
     android:viewportHeight="24"
     android:viewportWidth="24"
     android:width="24dp" >
diff --git a/packages/overlays/IconPackFilledAndroidOverlay/res/drawable/ic_qs_bluetooth.xml b/packages/overlays/IconPackFilledAndroidOverlay/res/drawable/ic_qs_bluetooth.xml
index 09643e6..18a60d8 100644
--- a/packages/overlays/IconPackFilledAndroidOverlay/res/drawable/ic_qs_bluetooth.xml
+++ b/packages/overlays/IconPackFilledAndroidOverlay/res/drawable/ic_qs_bluetooth.xml
@@ -16,10 +16,11 @@
 -->
 <vector xmlns:android="http://schemas.android.com/apk/res/android"
     android:height="24dp"
+    android:tint="?android:attr/colorControlNormal"
     android:viewportHeight="24"
     android:viewportWidth="24"
     android:width="24dp" >
     <path
         android:fillColor="@android:color/white"
-        android:pathData="M17.21,6.79l-4.5-4.5c-0.29-0.29-0.72-0.37-1.09-0.22C11.25,2.23,11,2.6,11,3v6.59l-3.8-3.8c-0.39-0.39-1.02-0.39-1.41,0 c-0.39,0.39-0.39,1.02,0,1.41l4.8,4.8l-4.8,4.8c-0.39,0.39-0.39,1.02,0,1.41c0.39,0.39,1.02,0.39,1.41,0l3.8-3.8V21 c0,0.4,0.24,0.77,0.62,0.92C11.74,21.98,11.87,22,12,22c0.26,0,0.52-0.1,0.71-0.29l4.5-4.5c0.39-0.39,0.39-1.02,0-1.41L13.42,12 l3.79-3.79C17.6,7.82,17.6,7.18,17.21,6.79z M15.09,16.5L13,18.58v-4.17L15.09,16.5z M13,9.58V5.42l2.08,2.08L13,9.58z" />
+        android:pathData="M13.51,12l3.75-3.74c0.41-0.41,0.41-1.07,0-1.48l-4.47-4.47l-0.03-0.03c-0.42-0.39-1.08-0.37-1.48,0.05 C11.1,2.52,11,2.78,11,3.04v6.44L6.95,5.43c-0.41-0.41-1.06-0.41-1.47,0c-0.41,0.41-0.41,1.06,0,1.47l5.09,5.1l-5.09,5.09 c-0.41,0.41-0.41,1.06,0,1.47c0.41,0.41,1.06,0.41,1.47,0L11,14.51v6.45c0,0.57,0.47,1.04,1.04,1.04c0.26,0,0.52-0.1,0.71-0.28 l0.05-0.05l4.46-4.46c0.41-0.41,0.41-1.07,0-1.48L13.51,12z M12.99,5.37l2.15,2.15l-2.15,2.15V5.37z M12.99,18.62v-4.3l2.15,2.15 L12.99,18.62z" />
 </vector>
\ No newline at end of file
diff --git a/packages/overlays/IconPackFilledSettingsOverlay/res/drawable/ic_battery_status_bad_24dp.xml b/packages/overlays/IconPackFilledAndroidOverlay/res/drawable/ic_qs_ui_mode_night.xml
similarity index 73%
copy from packages/overlays/IconPackFilledSettingsOverlay/res/drawable/ic_battery_status_bad_24dp.xml
copy to packages/overlays/IconPackFilledAndroidOverlay/res/drawable/ic_qs_ui_mode_night.xml
index 22e183c..5eea889 100644
--- a/packages/overlays/IconPackFilledSettingsOverlay/res/drawable/ic_battery_status_bad_24dp.xml
+++ b/packages/overlays/IconPackFilledAndroidOverlay/res/drawable/ic_qs_ui_mode_night.xml
@@ -21,5 +21,5 @@
     android:width="24dp" >
     <path
         android:fillColor="@android:color/white"
-        android:pathData="M10,2v2H8.33C7.6,4,7,4.6,7,5.33v15.33C7,21.4,7.6,22,8.33,22h7.33C16.4,22,17,21.4,17,20.67V5.33C17,4.6,16.4,4,15.67,4 H14V2H10z M15,13c0,0.55-0.45,1-1,1h-1v1c0,0.55-0.45,1-1,1s-1-0.45-1-1v-1h-1c-0.55,0-1-0.45-1-1s0.45-1,1-1h1v-1 c0-0.55,0.45-1,1-1s1,0.45,1,1v1h1C14.55,12,15,12.45,15,13z" />
-</vector>
\ No newline at end of file
+        android:pathData="M12,2C6.48,2,2,6.48,2,12c0,5.52,4.48,10,10,10c5.52,0,10-4.48,10-10C22,6.48,17.52,2,12,2z M12,20V4c4.41,0,8,3.59,8,8 C20,16.41,16.41,20,12,20z" />
+</vector>
diff --git a/packages/overlays/IconPackFilledAndroidOverlay/res/drawable/ic_settings_bluetooth.xml b/packages/overlays/IconPackFilledAndroidOverlay/res/drawable/ic_settings_bluetooth.xml
index 58800c8..18a60d8 100644
--- a/packages/overlays/IconPackFilledAndroidOverlay/res/drawable/ic_settings_bluetooth.xml
+++ b/packages/overlays/IconPackFilledAndroidOverlay/res/drawable/ic_settings_bluetooth.xml
@@ -22,5 +22,5 @@
     android:width="24dp" >
     <path
         android:fillColor="@android:color/white"
-        android:pathData="M17.21,6.79l-4.5-4.5c-0.29-0.29-0.72-0.37-1.09-0.22C11.25,2.23,11,2.6,11,3v6.59l-3.8-3.8c-0.39-0.39-1.02-0.39-1.41,0 c-0.39,0.39-0.39,1.02,0,1.41l4.8,4.8l-4.8,4.8c-0.39,0.39-0.39,1.02,0,1.41c0.39,0.39,1.02,0.39,1.41,0l3.8-3.8V21 c0,0.4,0.24,0.77,0.62,0.92C11.74,21.98,11.87,22,12,22c0.26,0,0.52-0.1,0.71-0.29l4.5-4.5c0.39-0.39,0.39-1.02,0-1.41L13.42,12 l3.79-3.79C17.6,7.82,17.6,7.18,17.21,6.79z M15.09,16.5L13,18.58v-4.17L15.09,16.5z M13,9.58V5.42l2.08,2.08L13,9.58z" />
+        android:pathData="M13.51,12l3.75-3.74c0.41-0.41,0.41-1.07,0-1.48l-4.47-4.47l-0.03-0.03c-0.42-0.39-1.08-0.37-1.48,0.05 C11.1,2.52,11,2.78,11,3.04v6.44L6.95,5.43c-0.41-0.41-1.06-0.41-1.47,0c-0.41,0.41-0.41,1.06,0,1.47l5.09,5.1l-5.09,5.09 c-0.41,0.41-0.41,1.06,0,1.47c0.41,0.41,1.06,0.41,1.47,0L11,14.51v6.45c0,0.57,0.47,1.04,1.04,1.04c0.26,0,0.52-0.1,0.71-0.28 l0.05-0.05l4.46-4.46c0.41-0.41,0.41-1.07,0-1.48L13.51,12z M12.99,5.37l2.15,2.15l-2.15,2.15V5.37z M12.99,18.62v-4.3l2.15,2.15 L12.99,18.62z" />
 </vector>
\ No newline at end of file
diff --git a/packages/overlays/IconPackFilledAndroidOverlay/res/drawable/perm_group_activity_recognition.xml b/packages/overlays/IconPackFilledAndroidOverlay/res/drawable/perm_group_activity_recognition.xml
index e1849bb..67d28c6 100644
--- a/packages/overlays/IconPackFilledAndroidOverlay/res/drawable/perm_group_activity_recognition.xml
+++ b/packages/overlays/IconPackFilledAndroidOverlay/res/drawable/perm_group_activity_recognition.xml
@@ -16,7 +16,7 @@
 -->
 <vector xmlns:android="http://schemas.android.com/apk/res/android"
     android:height="24dp"
-    android:tint="@android:color/black"
+    android:tint="?android:attr/colorControlNormal"
     android:viewportHeight="24"
     android:viewportWidth="24"
     android:width="24dp" >
diff --git a/packages/overlays/IconPackFilledSettingsOverlay/res/drawable/ic_battery_status_bad_24dp.xml b/packages/overlays/IconPackFilledAndroidOverlay/res/drawable/perm_group_aural.xml
similarity index 71%
copy from packages/overlays/IconPackFilledSettingsOverlay/res/drawable/ic_battery_status_bad_24dp.xml
copy to packages/overlays/IconPackFilledAndroidOverlay/res/drawable/perm_group_aural.xml
index 22e183c..3f5c75b 100644
--- a/packages/overlays/IconPackFilledSettingsOverlay/res/drawable/ic_battery_status_bad_24dp.xml
+++ b/packages/overlays/IconPackFilledAndroidOverlay/res/drawable/perm_group_aural.xml
@@ -16,10 +16,12 @@
 -->
 <vector xmlns:android="http://schemas.android.com/apk/res/android"
     android:height="24dp"
+    android:tint="?android:attr/colorControlNormal"
     android:viewportHeight="24"
     android:viewportWidth="24"
     android:width="24dp" >
+    <path android:pathData="M0 0h24v24H0z" />
     <path
         android:fillColor="@android:color/white"
-        android:pathData="M10,2v2H8.33C7.6,4,7,4.6,7,5.33v15.33C7,21.4,7.6,22,8.33,22h7.33C16.4,22,17,21.4,17,20.67V5.33C17,4.6,16.4,4,15.67,4 H14V2H10z M15,13c0,0.55-0.45,1-1,1h-1v1c0,0.55-0.45,1-1,1s-1-0.45-1-1v-1h-1c-0.55,0-1-0.45-1-1s0.45-1,1-1h1v-1 c0-0.55,0.45-1,1-1s1,0.45,1,1v1h1C14.55,12,15,12.45,15,13z" />
+        android:pathData="M20 2H8c-1.1 0-2 0.9-2 2v12c0 1.1 0.9 2 2 2h12c1.1 0 2-0.9 2-2V4c0-1.1-0.9-2-2-2zm-2 5h-3v5.5c0 1.38-1.12 2.5-2.5 2.5S10 13.88 10 12.5s1.12-2.5 2.5-2.5c0.57 0 1.08 0.19 1.5 0.51 V5h4v2zM4 6H2v14c0 1.1 0.9 2 2 2h14v-2H4V6z" />
 </vector>
\ No newline at end of file
diff --git a/packages/overlays/IconPackFilledAndroidOverlay/res/drawable/perm_group_calendar.xml b/packages/overlays/IconPackFilledAndroidOverlay/res/drawable/perm_group_calendar.xml
index 16359b0..0144ba2 100644
--- a/packages/overlays/IconPackFilledAndroidOverlay/res/drawable/perm_group_calendar.xml
+++ b/packages/overlays/IconPackFilledAndroidOverlay/res/drawable/perm_group_calendar.xml
@@ -16,6 +16,7 @@
 -->
 <vector xmlns:android="http://schemas.android.com/apk/res/android"
     android:height="24dp"
+    android:tint="?android:attr/colorControlNormal"
     android:viewportHeight="24"
     android:viewportWidth="24"
     android:width="24dp" >
diff --git a/packages/overlays/IconPackFilledAndroidOverlay/res/drawable/perm_group_call_log.xml b/packages/overlays/IconPackFilledAndroidOverlay/res/drawable/perm_group_call_log.xml
index 8d70f48..590ced0 100644
--- a/packages/overlays/IconPackFilledAndroidOverlay/res/drawable/perm_group_call_log.xml
+++ b/packages/overlays/IconPackFilledAndroidOverlay/res/drawable/perm_group_call_log.xml
@@ -16,7 +16,7 @@
 -->
 <vector xmlns:android="http://schemas.android.com/apk/res/android"
     android:height="24dp"
-    android:tint="@android:color/black"
+    android:tint="?android:attr/colorControlNormal"
     android:viewportHeight="24"
     android:viewportWidth="24"
     android:width="24dp" >
diff --git a/packages/overlays/IconPackFilledAndroidOverlay/res/drawable/perm_group_camera.xml b/packages/overlays/IconPackFilledAndroidOverlay/res/drawable/perm_group_camera.xml
index 03075a6..b063e2b 100644
--- a/packages/overlays/IconPackFilledAndroidOverlay/res/drawable/perm_group_camera.xml
+++ b/packages/overlays/IconPackFilledAndroidOverlay/res/drawable/perm_group_camera.xml
@@ -16,7 +16,7 @@
 -->
 <vector xmlns:android="http://schemas.android.com/apk/res/android"
     android:height="24dp"
-    android:tint="@android:color/black"
+    android:tint="?android:attr/colorControlNormal"
     android:viewportHeight="24"
     android:viewportWidth="24"
     android:width="24dp" >
diff --git a/packages/overlays/IconPackFilledAndroidOverlay/res/drawable/perm_group_contacts.xml b/packages/overlays/IconPackFilledAndroidOverlay/res/drawable/perm_group_contacts.xml
index 50cd633..54cfeec 100644
--- a/packages/overlays/IconPackFilledAndroidOverlay/res/drawable/perm_group_contacts.xml
+++ b/packages/overlays/IconPackFilledAndroidOverlay/res/drawable/perm_group_contacts.xml
@@ -16,7 +16,7 @@
 -->
 <vector xmlns:android="http://schemas.android.com/apk/res/android"
     android:height="24dp"
-    android:tint="@android:color/black"
+    android:tint="?android:attr/colorControlNormal"
     android:viewportHeight="24"
     android:viewportWidth="24"
     android:width="24dp" >
diff --git a/packages/overlays/IconPackFilledAndroidOverlay/res/drawable/perm_group_location.xml b/packages/overlays/IconPackFilledAndroidOverlay/res/drawable/perm_group_location.xml
index ebd9e61..3815921 100644
--- a/packages/overlays/IconPackFilledAndroidOverlay/res/drawable/perm_group_location.xml
+++ b/packages/overlays/IconPackFilledAndroidOverlay/res/drawable/perm_group_location.xml
@@ -16,7 +16,7 @@
 -->
 <vector xmlns:android="http://schemas.android.com/apk/res/android"
     android:height="24dp"
-    android:tint="@android:color/black"
+    android:tint="?android:attr/colorControlNormal"
     android:viewportHeight="24"
     android:viewportWidth="24"
     android:width="24dp" >
diff --git a/packages/overlays/IconPackFilledAndroidOverlay/res/drawable/perm_group_microphone.xml b/packages/overlays/IconPackFilledAndroidOverlay/res/drawable/perm_group_microphone.xml
index 39acc9c..e6493bc 100644
--- a/packages/overlays/IconPackFilledAndroidOverlay/res/drawable/perm_group_microphone.xml
+++ b/packages/overlays/IconPackFilledAndroidOverlay/res/drawable/perm_group_microphone.xml
@@ -16,7 +16,7 @@
 -->
 <vector xmlns:android="http://schemas.android.com/apk/res/android"
     android:height="24dp"
-    android:tint="@android:color/black"
+    android:tint="?android:attr/colorControlNormal"
     android:viewportHeight="24"
     android:viewportWidth="24"
     android:width="24dp" >
diff --git a/packages/overlays/IconPackFilledAndroidOverlay/res/drawable/perm_group_phone_calls.xml b/packages/overlays/IconPackFilledAndroidOverlay/res/drawable/perm_group_phone_calls.xml
index 2b6e32a..ae84541 100644
--- a/packages/overlays/IconPackFilledAndroidOverlay/res/drawable/perm_group_phone_calls.xml
+++ b/packages/overlays/IconPackFilledAndroidOverlay/res/drawable/perm_group_phone_calls.xml
@@ -16,7 +16,7 @@
 -->
 <vector xmlns:android="http://schemas.android.com/apk/res/android"
     android:height="24dp"
-    android:tint="@android:color/black"
+    android:tint="?android:attr/colorControlNormal"
     android:viewportHeight="24"
     android:viewportWidth="24"
     android:width="24dp" >
diff --git a/packages/overlays/IconPackFilledAndroidOverlay/res/drawable/perm_group_sensors.xml b/packages/overlays/IconPackFilledAndroidOverlay/res/drawable/perm_group_sensors.xml
index 2128e79..88f0c54 100644
--- a/packages/overlays/IconPackFilledAndroidOverlay/res/drawable/perm_group_sensors.xml
+++ b/packages/overlays/IconPackFilledAndroidOverlay/res/drawable/perm_group_sensors.xml
@@ -16,7 +16,7 @@
 -->
 <vector xmlns:android="http://schemas.android.com/apk/res/android"
     android:height="24dp"
-    android:tint="@android:color/black"
+    android:tint="?android:attr/colorControlNormal"
     android:viewportHeight="24"
     android:viewportWidth="24"
     android:width="24dp" >
diff --git a/packages/overlays/IconPackFilledAndroidOverlay/res/drawable/perm_group_sms.xml b/packages/overlays/IconPackFilledAndroidOverlay/res/drawable/perm_group_sms.xml
index eef9e62..7a320e0 100644
--- a/packages/overlays/IconPackFilledAndroidOverlay/res/drawable/perm_group_sms.xml
+++ b/packages/overlays/IconPackFilledAndroidOverlay/res/drawable/perm_group_sms.xml
@@ -16,7 +16,7 @@
 -->
 <vector xmlns:android="http://schemas.android.com/apk/res/android"
     android:height="24dp"
-    android:tint="@android:color/black"
+    android:tint="?android:attr/colorControlNormal"
     android:viewportHeight="24"
     android:viewportWidth="24"
     android:width="24dp" >
diff --git a/packages/overlays/IconPackFilledAndroidOverlay/res/drawable/perm_group_storage.xml b/packages/overlays/IconPackFilledAndroidOverlay/res/drawable/perm_group_storage.xml
index 3a863a3..0ad7e6d 100644
--- a/packages/overlays/IconPackFilledAndroidOverlay/res/drawable/perm_group_storage.xml
+++ b/packages/overlays/IconPackFilledAndroidOverlay/res/drawable/perm_group_storage.xml
@@ -16,7 +16,7 @@
 -->
 <vector xmlns:android="http://schemas.android.com/apk/res/android"
     android:height="24dp"
-    android:tint="@android:color/black"
+    android:tint="?android:attr/colorControlNormal"
     android:viewportHeight="24"
     android:viewportWidth="24"
     android:width="24dp" >
diff --git a/packages/overlays/IconPackFilledAndroidOverlay/res/drawable/perm_group_visual.xml b/packages/overlays/IconPackFilledAndroidOverlay/res/drawable/perm_group_visual.xml
index 57c7ae9..d5bdb87 100644
--- a/packages/overlays/IconPackFilledAndroidOverlay/res/drawable/perm_group_visual.xml
+++ b/packages/overlays/IconPackFilledAndroidOverlay/res/drawable/perm_group_visual.xml
@@ -16,7 +16,7 @@
 -->
 <vector xmlns:android="http://schemas.android.com/apk/res/android"
     android:height="24dp"
-    android:tint="@android:color/black"
+    android:tint="?android:attr/colorControlNormal"
     android:viewportHeight="24"
     android:viewportWidth="24"
     android:width="24dp" >
diff --git a/packages/overlays/IconPackFilledAndroidOverlay/res/values/config.xml b/packages/overlays/IconPackFilledAndroidOverlay/res/values/config.xml
index 6b59b62..f1d8c73 100644
--- a/packages/overlays/IconPackFilledAndroidOverlay/res/values/config.xml
+++ b/packages/overlays/IconPackFilledAndroidOverlay/res/values/config.xml
@@ -33,4 +33,12 @@
         M 9,11 C 9,11.55 8.55,12 8,12 H 7 V 13 C 7,13.55 6.55,14 6,14 5.45,14 5,13.55 5,13 V 12 H 4 C 3.45,12 3,11.55 3,11 3,10.45 3.45,10.005 4,10 H 5 V 9 C 5,8.45 5.45,8 6,8 6.55,8 7,8.45 7,9 V 10 H 8 C 8.55,10 9,10.45 9,11 Z
     </string>
     <bool name="config_batterymeterDualTone">true</bool>
+    <!-- X path for SignalDrawable as defined on a 24x24 canvas. -->
+    <string name="config_signalXPath" translatable="false">
+        M 21.7,20.28 L 19.92,18.5 L 21.7,16.72 C 22.1,16.32 22.1,15.68 21.71,15.29 C 21.32,14.9 20.68,14.9 20.28,15.3 L 18.5,17.08 L 16.72,15.3 C 16.32,14.9 15.68,14.9 15.29,15.29 C 14.9,15.68 14.9,16.32 15.3,16.72 L 17.08,18.5 L 15.3,20.28 C 14.9,20.68 14.9,21.32 15.29,21.71 C 15.68,22.1 16.32,22.1 16.72,21.7 L 18.5,19.92 L 20.28,21.7 C 20.68,22.1 21.32,22.1 21.71,21.71 C 22.1,21.32 22.1,20.68 21.7,20.28
+    </string>
+    <!-- config_signalCutout{Height,Width}Fraction define fraction of the 24x24 canvas that
+         should be cut out to display config_signalXPath.-->
+    <item name="config_signalCutoutWidthFraction" format="float" type="dimen">11</item>
+    <item name="config_signalCutoutHeightFraction" format="float" type="dimen">11</item>
 </resources>
diff --git a/packages/overlays/IconPackFilledLauncherOverlay/res/drawable/ic_setting.xml b/packages/overlays/IconPackFilledLauncherOverlay/res/drawable/ic_setting.xml
index 30e8660..b3625ac 100644
--- a/packages/overlays/IconPackFilledLauncherOverlay/res/drawable/ic_setting.xml
+++ b/packages/overlays/IconPackFilledLauncherOverlay/res/drawable/ic_setting.xml
@@ -16,6 +16,7 @@
 -->
 <vector xmlns:android="http://schemas.android.com/apk/res/android"
     android:height="24dp"
+    android:tint="?android:attr/textColorPrimary"
     android:viewportHeight="24"
     android:viewportWidth="24"
     android:width="24dp" >
diff --git a/packages/overlays/IconPackFilledSettingsOverlay/res/drawable/ic_arrow_back.xml b/packages/overlays/IconPackFilledSettingsOverlay/res/drawable/ic_arrow_back.xml
index b4f2a9d..deb77c8 100644
--- a/packages/overlays/IconPackFilledSettingsOverlay/res/drawable/ic_arrow_back.xml
+++ b/packages/overlays/IconPackFilledSettingsOverlay/res/drawable/ic_arrow_back.xml
@@ -15,6 +15,7 @@
    limitations under the License.
 -->
 <vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:autoMirrored="true"
     android:height="24dp"
     android:tint="?android:attr/colorControlNormal"
     android:viewportHeight="24"
diff --git a/packages/overlays/IconPackFilledSettingsOverlay/res/drawable/ic_battery_saver_accent_24dp.xml b/packages/overlays/IconPackFilledSettingsOverlay/res/drawable/ic_battery_saver_accent_24dp.xml
deleted file mode 100644
index 4ddeae6..0000000
--- a/packages/overlays/IconPackFilledSettingsOverlay/res/drawable/ic_battery_saver_accent_24dp.xml
+++ /dev/null
@@ -1,26 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-   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.
--->
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
-    android:height="24dp"
-    android:tint="?android:attr/colorAccent"
-    android:viewportHeight="24"
-    android:viewportWidth="24"
-    android:width="24dp" >
-    <path
-        android:fillColor="@android:color/white"
-        android:pathData="M10,2v2H8.33C7.6,4,7,4.6,7,5.33v15.33C7,21.4,7.6,22,8.33,22h7.33C16.4,22,17,21.4,17,20.67V5.33C17,4.6,16.4,4,15.67,4 H14V2H10z M15,13c0,0.55-0.45,1-1,1h-1v1c0,0.55-0.45,1-1,1s-1-0.45-1-1v-1h-1c-0.55,0-1-0.45-1-1s0.45-1,1-1h1v-1 c0-0.55,0.45-1,1-1s1,0.45,1,1v1h1C14.55,12,15,12.45,15,13z" />
-</vector>
\ No newline at end of file
diff --git a/packages/overlays/IconPackFilledSettingsOverlay/res/drawable/ic_cellular_off.xml b/packages/overlays/IconPackFilledSettingsOverlay/res/drawable/ic_cellular_off.xml
index 32ce0f5..466ae50 100644
--- a/packages/overlays/IconPackFilledSettingsOverlay/res/drawable/ic_cellular_off.xml
+++ b/packages/overlays/IconPackFilledSettingsOverlay/res/drawable/ic_cellular_off.xml
@@ -15,6 +15,7 @@
    limitations under the License.
 -->
 <vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:autoMirrored="true"
     android:height="24dp"
     android:tint="?android:attr/colorAccent"
     android:viewportHeight="24"
diff --git a/packages/overlays/IconPackFilledSettingsOverlay/res/drawable/ic_chevron_right_24dp.xml b/packages/overlays/IconPackFilledSettingsOverlay/res/drawable/ic_chevron_right_24dp.xml
index e1a8b1f..b5b514a 100644
--- a/packages/overlays/IconPackFilledSettingsOverlay/res/drawable/ic_chevron_right_24dp.xml
+++ b/packages/overlays/IconPackFilledSettingsOverlay/res/drawable/ic_chevron_right_24dp.xml
@@ -15,6 +15,7 @@
    limitations under the License.
 -->
 <vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:autoMirrored="true"
     android:height="24dp"
     android:tint="?android:attr/colorControlNormal"
     android:viewportHeight="24"
diff --git a/packages/overlays/IconPackFilledSettingsOverlay/res/drawable/ic_content_copy_grey600_24dp.xml b/packages/overlays/IconPackFilledSettingsOverlay/res/drawable/ic_content_copy_grey600_24dp.xml
index be607a3..e479f50 100644
--- a/packages/overlays/IconPackFilledSettingsOverlay/res/drawable/ic_content_copy_grey600_24dp.xml
+++ b/packages/overlays/IconPackFilledSettingsOverlay/res/drawable/ic_content_copy_grey600_24dp.xml
@@ -16,7 +16,7 @@
 -->
 <vector xmlns:android="http://schemas.android.com/apk/res/android"
     android:height="24dp"
-    android:tint="#757575"
+    android:tint="@*android:color/material_grey_600"
     android:viewportHeight="24"
     android:viewportWidth="24"
     android:width="24dp" >
diff --git a/packages/overlays/IconPackFilledSettingsOverlay/res/drawable/ic_data_saver.xml b/packages/overlays/IconPackFilledSettingsOverlay/res/drawable/ic_data_saver.xml
index 2718efa..5c85eb3 100644
--- a/packages/overlays/IconPackFilledSettingsOverlay/res/drawable/ic_data_saver.xml
+++ b/packages/overlays/IconPackFilledSettingsOverlay/res/drawable/ic_data_saver.xml
@@ -15,6 +15,7 @@
    limitations under the License.
 -->
 <vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:autoMirrored="true"
     android:height="24dp"
     android:tint="?android:attr/colorControlNormal"
     android:viewportHeight="24"
diff --git a/packages/overlays/IconPackFilledSettingsOverlay/res/drawable/ic_devices_other.xml b/packages/overlays/IconPackFilledSettingsOverlay/res/drawable/ic_devices_other.xml
index 21368fe..a451ef8 100644
--- a/packages/overlays/IconPackFilledSettingsOverlay/res/drawable/ic_devices_other.xml
+++ b/packages/overlays/IconPackFilledSettingsOverlay/res/drawable/ic_devices_other.xml
@@ -15,6 +15,7 @@
    limitations under the License.
 -->
 <vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:autoMirrored="true"
     android:height="24dp"
     android:viewportHeight="24"
     android:viewportWidth="24"
diff --git a/packages/overlays/IconPackFilledSettingsOverlay/res/drawable/ic_eject_24dp.xml b/packages/overlays/IconPackFilledSettingsOverlay/res/drawable/ic_eject_24dp.xml
index 5a9511a..7af9246 100644
--- a/packages/overlays/IconPackFilledSettingsOverlay/res/drawable/ic_eject_24dp.xml
+++ b/packages/overlays/IconPackFilledSettingsOverlay/res/drawable/ic_eject_24dp.xml
@@ -16,6 +16,7 @@
 -->
 <vector xmlns:android="http://schemas.android.com/apk/res/android"
     android:height="24dp"
+    android:tint="?android:attr/colorControlNormal"
     android:viewportHeight="24"
     android:viewportWidth="24"
     android:width="24dp" >
diff --git a/packages/overlays/IconPackFilledSettingsOverlay/res/drawable/ic_battery_status_bad_24dp.xml b/packages/overlays/IconPackFilledSettingsOverlay/res/drawable/ic_find_in_page_24px.xml
similarity index 69%
copy from packages/overlays/IconPackFilledSettingsOverlay/res/drawable/ic_battery_status_bad_24dp.xml
copy to packages/overlays/IconPackFilledSettingsOverlay/res/drawable/ic_find_in_page_24px.xml
index 22e183c..dd35dae 100644
--- a/packages/overlays/IconPackFilledSettingsOverlay/res/drawable/ic_battery_status_bad_24dp.xml
+++ b/packages/overlays/IconPackFilledSettingsOverlay/res/drawable/ic_find_in_page_24px.xml
@@ -16,10 +16,12 @@
 -->
 <vector xmlns:android="http://schemas.android.com/apk/res/android"
     android:height="24dp"
+    android:tint="?android:attr/colorControlNormal"
     android:viewportHeight="24"
     android:viewportWidth="24"
     android:width="24dp" >
+    <path android:pathData="M0 0h24v24H0z" />
     <path
         android:fillColor="@android:color/white"
-        android:pathData="M10,2v2H8.33C7.6,4,7,4.6,7,5.33v15.33C7,21.4,7.6,22,8.33,22h7.33C16.4,22,17,21.4,17,20.67V5.33C17,4.6,16.4,4,15.67,4 H14V2H10z M15,13c0,0.55-0.45,1-1,1h-1v1c0,0.55-0.45,1-1,1s-1-0.45-1-1v-1h-1c-0.55,0-1-0.45-1-1s0.45-1,1-1h1v-1 c0-0.55,0.45-1,1-1s1,0.45,1,1v1h1C14.55,12,15,12.45,15,13z" />
+        android:pathData="M20 19.59V8l-6-6H6c-1.1 0-1.99 0.9 -1.99 2L4 20c0 1.1 0.89 2 1.99 2H18c0.45 0 0.85-0.15 1.19-0.4l-4.43-4.43c-0.8 0.52 -1.74 0.83 -2.76 0.83 -2.76 0-5-2.24-5-5s2.24-5 5-5 5 2.24 5 5c0 1.02-0.31 1.96-0.83 2.75L20 19.59zM9 13c0 1.66 1.34 3 3 3s3-1.34 3-3-1.34-3-3-3-3 1.34-3 3z" />
 </vector>
\ No newline at end of file
diff --git a/packages/overlays/IconPackFilledSettingsOverlay/res/drawable/ic_help_actionbar.xml b/packages/overlays/IconPackFilledSettingsOverlay/res/drawable/ic_help_actionbar.xml
index ed6d553..4d6d9dd 100644
--- a/packages/overlays/IconPackFilledSettingsOverlay/res/drawable/ic_help_actionbar.xml
+++ b/packages/overlays/IconPackFilledSettingsOverlay/res/drawable/ic_help_actionbar.xml
@@ -15,6 +15,7 @@
    limitations under the License.
 -->
 <vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:autoMirrored="true"
     android:height="24dp"
     android:tint="?android:attr/colorControlNormal"
     android:viewportHeight="24"
diff --git a/packages/overlays/IconPackFilledSettingsOverlay/res/drawable/ic_network_cell.xml b/packages/overlays/IconPackFilledSettingsOverlay/res/drawable/ic_network_cell.xml
index 2e9433b..d62758e 100644
--- a/packages/overlays/IconPackFilledSettingsOverlay/res/drawable/ic_network_cell.xml
+++ b/packages/overlays/IconPackFilledSettingsOverlay/res/drawable/ic_network_cell.xml
@@ -15,6 +15,7 @@
    limitations under the License.
 -->
 <vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:autoMirrored="true"
     android:height="24dp"
     android:tint="?android:attr/colorControlNormal"
     android:viewportHeight="24"
diff --git a/packages/overlays/IconPackFilledSettingsOverlay/res/drawable/ic_notifications_off_24dp.xml b/packages/overlays/IconPackFilledSettingsOverlay/res/drawable/ic_notifications_off_24dp.xml
index 9944bb5..c6cd015 100644
--- a/packages/overlays/IconPackFilledSettingsOverlay/res/drawable/ic_notifications_off_24dp.xml
+++ b/packages/overlays/IconPackFilledSettingsOverlay/res/drawable/ic_notifications_off_24dp.xml
@@ -15,6 +15,7 @@
    limitations under the License.
 -->
 <vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:autoMirrored="true"
     android:height="24dp"
     android:tint="?android:attr/colorControlNormal"
     android:viewportHeight="24"
diff --git a/packages/overlays/IconPackFilledSettingsOverlay/res/drawable/ic_scan_24dp.xml b/packages/overlays/IconPackFilledSettingsOverlay/res/drawable/ic_scan_24dp.xml
new file mode 100644
index 0000000..146e20f
--- /dev/null
+++ b/packages/overlays/IconPackFilledSettingsOverlay/res/drawable/ic_scan_24dp.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+   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.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:height="24dp"
+    android:tint="?android:attr/colorAccent"
+    android:viewportHeight="24"
+    android:viewportWidth="24"
+    android:width="24dp" >
+    <path
+        android:fillColor="@android:color/white"
+        android:pathData="M4,9 L8,9 C8.55228475,9 9,8.55228475 9,8 L9,4 C9,3.44771525 8.55228475,3 8,3 L4,3 C3.44771525,3 3,3.44771525 3,4 L3,8 C3,8.55228475 3.44771525,9 4,9 Z M5,5 L7,5 L7,7 L5,7 L5,5 Z M15,4 L15,8 C15,8.55228475 15.4477153,9 16,9 L20,9 C20.5522847,9 21,8.55228475 21,8 L21,4 C21,3.44771525 20.5522847,3 20,3 L16,3 C15.4477153,3 15,3.44771525 15,4 Z M19,7 L17,7 L17,5 L19,5 L19,7 Z M4,21 L8,21 C8.55228475,21 9,20.5522847 9,20 L9,16 C9,15.4477153 8.55228475,15 8,15 L4,15 C3.44771525,15 3,15.4477153 3,16 L3,20 C3,20.5522847 3.44771525,21 4,21 Z M5,17 L7,17 L7,19 L5,19 L5,17 Z M7.4,11 L8.6,11 C8.8209139,11 9,11.1790861 9,11.4 L9,12.6 C9,12.8209139 8.8209139,13 8.6,13 L7.4,13 C7.1790861,13 7,12.8209139 7,12.6 L7,11.4 C7,11.1790861 7.1790861,11 7.4,11 Z M4.6,13 L3.4,13 C3.1790861,13 3,12.8209139 3,12.6 L3,11.4 C3,11.1790861 3.1790861,11 3.4,11 L4.6,11 C4.8209139,11 5,11.1790861 5,11.4 L5,12.6 C5,12.8209139 4.8209139,13 4.6,13 L4.6,13 Z M11.6,9 C11.2686292,9 11,8.73137085 11,8.4 L11,3.6 C11,3.26862915 11.2686292,3 11.6,3 L12.4,3 C12.7313708,3 13,3.26862915 13,3.6 L13,8.4 C13,8.73137085 12.7313708,9 12.4,9 L11.6,9 Z M17,15 L20.5,15 C20.7761424,15 21,15.2238576 21,15.5 L21,16.5 C21,16.7761424 20.7761424,17 20.5,17 L17,17 L17,20.5 C17,20.7761424 16.7761424,21 16.5,21 L15.5,21 C15.2238576,21 15,20.7761424 15,20.5 L15,17 L11.5,17 C11.2238576,17 11,16.7761424 11,16.5 L11,15.5 C11,15.2238576 11.2238576,15 11.5,15 L15,15 L15,11.5 C15,11.2238576 15.2238576,11 15.5,11 L16.5,11 C16.7761424,11 17,11.2238576 17,11.5 L17,15 Z"
+        android:strokeWidth="1" />
+</vector>
\ No newline at end of file
diff --git a/packages/overlays/IconPackFilledSettingsOverlay/res/drawable/ic_settings_disable.xml b/packages/overlays/IconPackFilledSettingsOverlay/res/drawable/ic_settings_disable.xml
new file mode 100644
index 0000000..b816e4e
--- /dev/null
+++ b/packages/overlays/IconPackFilledSettingsOverlay/res/drawable/ic_settings_disable.xml
@@ -0,0 +1,36 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+   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.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:height="24dp"
+    android:tint="?android:attr/colorControlNormal"
+    android:viewportHeight="24"
+    android:viewportWidth="24"
+    android:width="24dp" >
+    <group
+        android:scaleX="-1"
+        android:translateX="-12.000000"
+        android:translateY="-12.000000" >
+        <path
+            android:fillType="evenOdd"
+            android:pathData="M 0 0 H 24 V 24 H 0 V 0 Z"
+            android:strokeWidth="1" />
+    </group>
+    <path
+        android:fillColor="@android:color/white"
+        android:pathData="M12.11,2 C10.33,2 8.67,2.46 7.22,3.28 L8.7,4.76 C9.74,4.28 10.89,4 12.11,4 C16.52,4 20.11,7.59 20.11,12 C20.11,13.22 19.83,14.37 19.35,15.41 L20.83,16.89 C21.65,15.44 22.11,13.78 22.11,12 C22.11,6.48 17.63,2 12.11,2 Z M18.23,17.13 L6.98,5.87 L4.12750442,3.01750442 C3.73635677,2.62635677 3.10252735,2.62523693 2.71,3.015 C2.31926097,3.40298735 2.31703029,4.0342698 2.70501764,4.42500883 C2.70584509,4.42584216 2.70667402,4.42667402 2.70750442,4.42750442 L4.19,5.91 C2.88,7.59 2.11,9.71 2.11,12 C2.11,17.52 6.59,22 12.11,22 C14.4,22 16.52,21.23 18.2,19.92 L19.685,21.405 C20.0743607,21.7943607 20.7056393,21.7943607 21.095,21.405 C21.4843607,21.0156393 21.4843607,20.3843607 21.095,19.995 L18.23,17.13 Z M12.11,20 C7.7,20 4.11,16.41 4.11,12 C4.11,10.26 4.67,8.65 5.62,7.34 L16.77,18.49 C15.46,19.44 13.85,20 12.11,20 Z M8.7,4.76 L7.22,3.28 L8.7,4.76 Z"
+        android:strokeWidth="1" />
+</vector>
\ No newline at end of file
diff --git a/packages/overlays/IconPackFilledSettingsOverlay/res/drawable/ic_settings_enable.xml b/packages/overlays/IconPackFilledSettingsOverlay/res/drawable/ic_settings_enable.xml
new file mode 100644
index 0000000..d0b6209
--- /dev/null
+++ b/packages/overlays/IconPackFilledSettingsOverlay/res/drawable/ic_settings_enable.xml
@@ -0,0 +1,36 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+   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.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:height="24dp"
+    android:tint="?android:attr/colorControlNormal"
+    android:viewportHeight="24"
+    android:viewportWidth="24"
+    android:width="24dp" >
+    <group
+        android:scaleX="-1"
+        android:translateX="-12.000000"
+        android:translateY="-12.000000" >
+        <path
+            android:fillType="evenOdd"
+            android:pathData="M 0 0 H 24 V 24 H 0 V 0 Z"
+            android:strokeWidth="1" />
+    </group>
+    <path
+        android:fillColor="@android:color/white"
+        android:pathData="M13.0016705,11.5012475 L15.3917467,11.5012475 C15.9314188,11.5012475 16.206996,12.1426752 15.8165949,12.5140281 L12.4292913,15.822445 C12.1961989,16.0553846 11.8138355,16.0598858 11.5761501,15.8314475 C11.5738536,15.8280716 11.5704089,15.8258209 11.5681124,15.822445 L8.17851232,12.5117775 C7.79729714,12.1392993 8.06713319,11.5012475 8.60565705,11.5012475 L11.002341,11.5012475 L11.002341,2.99966471 C11.002341,2.44756514 11.4499062,2 12.0020057,2 C12.5541053,2 13.0016705,2.44756514 13.0016705,2.99966471 L13.0016705,11.5012475 Z M15,2.46 L15,4.59 C17.93,5.78 20,8.65 20,12 C20,16.41 16.41,20 12,20 C7.59,20 4,16.41 4,12 C4,8.65 6.07,5.78 9,4.59 L9,2.46 C4.94,3.74 2,7.53 2,12 C2,17.52 6.48,22 12,22 C17.52,22 22,17.52 22,12 C22,7.53 19.06,3.74 15,2.46 Z"
+        android:strokeWidth="1" />
+</vector>
\ No newline at end of file
diff --git a/packages/overlays/IconPackFilledSettingsOverlay/res/drawable/ic_settings_language.xml b/packages/overlays/IconPackFilledSettingsOverlay/res/drawable/ic_settings_language.xml
new file mode 100644
index 0000000..e23b9b6
--- /dev/null
+++ b/packages/overlays/IconPackFilledSettingsOverlay/res/drawable/ic_settings_language.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+   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.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:height="24dp"
+    android:tint="?android:attr/colorControlNormal"
+    android:viewportHeight="24"
+    android:viewportWidth="24"
+    android:width="24dp" >
+    <path
+        android:fillColor="@android:color/white"
+        android:pathData="M11.99,2C6.47,2,2,6.48,2,12c0,5.52,4.47,10,9.99,10C17.52,22,22,17.52,22,12C22,6.48,17.52,2,11.99,2z M18.92,8h-2.95 c-0.31-1.24-0.78-2.43-1.38-3.56C16.41,5.07,17.95,6.33,18.92,8z M12,4.04c0.83,1.2,1.48,2.53,1.91,3.96h-3.82 C10.52,6.57,11.17,5.24,12,4.04z M4.26,14C4.1,13.36,4,12.69,4,12s0.1-1.36,0.26-2h3.38c-0.08,0.66-0.14,1.32-0.14,2 s0.06,1.34,0.14,2H4.26z M5.08,16h2.95c0.32,1.25,0.78,2.45,1.38,3.56C7.58,18.94,6.05,17.67,5.08,16z M8.03,8H5.08 c0.97-1.67,2.5-2.94,4.33-3.56C8.81,5.57,8.34,6.76,8.03,8z M12,19.96c-0.83-1.2-1.48-2.53-1.91-3.96h3.82 C13.48,17.43,12.83,18.76,12,19.96z M14.34,14H9.66c-0.09-0.66-0.16-1.32-0.16-2s0.07-1.35,0.16-2h4.68c0.09,0.65,0.16,1.32,0.16,2 S14.43,13.34,14.34,14z M14.59,19.56c0.6-1.11,1.06-2.31,1.38-3.56h2.95C17.95,17.67,16.41,18.93,14.59,19.56z M16.36,14 c0.08-0.66,0.14-1.32,0.14-2s-0.06-1.34-0.14-2h3.38C19.9,10.64,20,11.31,20,12s-0.1,1.36-0.26,2H16.36z" />
+</vector>
\ No newline at end of file
diff --git a/packages/overlays/IconPackFilledSettingsOverlay/res/drawable/ic_delete_accent.xml b/packages/overlays/IconPackFilledSettingsOverlay/res/drawable/ic_settings_multiuser.xml
similarity index 70%
copy from packages/overlays/IconPackFilledSettingsOverlay/res/drawable/ic_delete_accent.xml
copy to packages/overlays/IconPackFilledSettingsOverlay/res/drawable/ic_settings_multiuser.xml
index e65987e..accc694 100644
--- a/packages/overlays/IconPackFilledSettingsOverlay/res/drawable/ic_delete_accent.xml
+++ b/packages/overlays/IconPackFilledSettingsOverlay/res/drawable/ic_settings_multiuser.xml
@@ -16,14 +16,14 @@
 -->
 <vector xmlns:android="http://schemas.android.com/apk/res/android"
     android:height="24dp"
-    android:tint="?android:attr/colorAccent"
+    android:tint="?android:attr/colorControlNormal"
     android:viewportHeight="24"
     android:viewportWidth="24"
     android:width="24dp" >
     <path
         android:fillColor="@android:color/white"
-        android:pathData="M18,4h-2.5l-0.71-0.71C14.61,3.11,14.35,3,14.09,3H9.9C9.64,3,9.38,3.11,9.2,3.29L8.49,4h-2.5c-0.55,0-1,0.45-1,1 s0.45,1,1,1h12c0.55,0,1-0.45,1-1C19,4.45,18.55,4,18,4z" />
+        android:pathData="M 12 4 C 14.2091389993 4 16 5.79086100068 16 8 C 16 10.2091389993 14.2091389993 12 12 12 C 9.79086100068 12 8 10.2091389993 8 8 C 8 5.79086100068 9.79086100068 4 12 4 Z" />
     <path
         android:fillColor="@android:color/white"
-        android:pathData="M6,19c0,1.1,0.9,2,2,2h8c1.1,0,2-0.9,2-2V7H6V19z" />
+        android:pathData="M12,13.5c-2.67,0-8,1.34-8,4v2C4,19.77,4.22,20,4.5,20h15c0.27,0,0.5-0.23,0.5-0.5v-2C20,14.84,14.67,13.5,12,13.5z" />
 </vector>
\ No newline at end of file
diff --git a/packages/overlays/IconPackFilledSettingsOverlay/res/drawable/ic_settings_wireless_white.xml b/packages/overlays/IconPackFilledSettingsOverlay/res/drawable/ic_settings_wireless_white.xml
deleted file mode 100644
index 03e142e..0000000
--- a/packages/overlays/IconPackFilledSettingsOverlay/res/drawable/ic_settings_wireless_white.xml
+++ /dev/null
@@ -1,31 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-   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.
--->
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
-    android:height="24dp"
-    android:viewportHeight="24"
-    android:viewportWidth="24"
-    android:width="24dp" >
-    <path
-        android:fillColor="@android:color/white"
-        android:pathData="M11.29,19.29c0.39,0.39,1.03,0.4,1.42,0L14,18c0.47-0.47,0.38-1.28-0.22-1.58C13.25,16.15,12.64,16,12,16 c-0.64,0-1.24,0.15-1.77,0.41c-0.59,0.29-0.69,1.11-0.22,1.58L11.29,19.29z" />
-    <path
-        android:fillColor="@android:color/white"
-        android:pathData="M17.6,14.39l0.71-0.71c0.42-0.42,0.39-1.12-0.08-1.5C16.52,10.82,14.35,10,12,10c-2.34,0-4.5,0.81-6.21,2.17 c-0.47,0.37-0.51,1.07-0.09,1.49l0.71,0.71c0.35,0.36,0.92,0.39,1.32,0.08C8.91,13.54,10.39,13,12,13c1.61,0,3.1,0.55,4.29,1.47 C16.69,14.78,17.25,14.75,17.6,14.39z" />
-    <path
-        android:fillColor="@android:color/white"
-        android:pathData="M21.83,10.16l0.71-0.71c0.42-0.42,0.38-1.09-0.06-1.48C19.68,5.5,16.01,4,12,4C8.01,4,4.36,5.49,1.56,7.94 C1.12,8.33,1.08,9,1.49,9.41l0.71,0.71c0.37,0.37,0.96,0.4,1.35,0.06C5.81,8.2,8.77,7,12,7c3.25,0,6.22,1.22,8.49,3.22 C20.88,10.56,21.47,10.53,21.83,10.16z" />
-</vector>
\ No newline at end of file
diff --git a/packages/overlays/IconPackFilledSettingsOverlay/res/drawable/ic_battery_status_bad_24dp.xml b/packages/overlays/IconPackFilledSettingsOverlay/res/drawable/ic_sync_problem_24dp.xml
similarity index 68%
copy from packages/overlays/IconPackFilledSettingsOverlay/res/drawable/ic_battery_status_bad_24dp.xml
copy to packages/overlays/IconPackFilledSettingsOverlay/res/drawable/ic_sync_problem_24dp.xml
index 22e183c..f2dd9e8 100644
--- a/packages/overlays/IconPackFilledSettingsOverlay/res/drawable/ic_battery_status_bad_24dp.xml
+++ b/packages/overlays/IconPackFilledSettingsOverlay/res/drawable/ic_sync_problem_24dp.xml
@@ -16,10 +16,12 @@
 -->
 <vector xmlns:android="http://schemas.android.com/apk/res/android"
     android:height="24dp"
+    android:tint="?android:attr/colorControlNormal"
     android:viewportHeight="24"
     android:viewportWidth="24"
     android:width="24dp" >
+    <path android:pathData="M0 0h24v24H0z" />
     <path
         android:fillColor="@android:color/white"
-        android:pathData="M10,2v2H8.33C7.6,4,7,4.6,7,5.33v15.33C7,21.4,7.6,22,8.33,22h7.33C16.4,22,17,21.4,17,20.67V5.33C17,4.6,16.4,4,15.67,4 H14V2H10z M15,13c0,0.55-0.45,1-1,1h-1v1c0,0.55-0.45,1-1,1s-1-0.45-1-1v-1h-1c-0.55,0-1-0.45-1-1s0.45-1,1-1h1v-1 c0-0.55,0.45-1,1-1s1,0.45,1,1v1h1C14.55,12,15,12.45,15,13z" />
+        android:pathData="M3 12c0 2.21 0.91 4.2 2.36 5.64L3 20h6v-6l-2.24 2.24C5.68 15.15 5 13.66 5 12c0-2.61 1.67-4.83 4-5.65V4.26C5.55 5.15 3 8.27 3 12zm8 5h2v-2h-2v2zM21 4h-6v6l2.24-2.24C18.32 8.85 19 10.34 19 12c0 2.61-1.67 4.83-4 5.65v2.09c3.45-0.89 6-4.01 6-7.74 0-2.21-0.91-4.2-2.36-5.64L21 4zm-10 9h2V7h-2v6z" />
 </vector>
\ No newline at end of file
diff --git a/packages/overlays/IconPackFilledSystemUIOverlay/res/drawable/ic_arrow_back.xml b/packages/overlays/IconPackFilledSystemUIOverlay/res/drawable/ic_arrow_back.xml
index b4f2a9d..deb77c8 100644
--- a/packages/overlays/IconPackFilledSystemUIOverlay/res/drawable/ic_arrow_back.xml
+++ b/packages/overlays/IconPackFilledSystemUIOverlay/res/drawable/ic_arrow_back.xml
@@ -15,6 +15,7 @@
    limitations under the License.
 -->
 <vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:autoMirrored="true"
     android:height="24dp"
     android:tint="?android:attr/colorControlNormal"
     android:viewportHeight="24"
diff --git a/packages/overlays/IconPackFilledSystemUIOverlay/res/drawable/ic_brightness_thumb.xml b/packages/overlays/IconPackFilledSystemUIOverlay/res/drawable/ic_brightness_thumb.xml
index e82e9a3..1b881ea 100644
--- a/packages/overlays/IconPackFilledSystemUIOverlay/res/drawable/ic_brightness_thumb.xml
+++ b/packages/overlays/IconPackFilledSystemUIOverlay/res/drawable/ic_brightness_thumb.xml
@@ -23,6 +23,6 @@
         android:fillColor="?android:attr/colorControlActivated"
         android:pathData="M4,15.3V19c0,0.55,0.45,1,1,1h3.69l2.6,2.6c0.39,0.39,1.02,0.39,1.41,0l2.6-2.6H19c0.55,0,1-0.45,1-1v-3.69l2.6-2.6 c0.39-0.39,0.39-1.02,0-1.41L20,8.69V5c0-0.55-0.45-1-1-1h-3.69l-2.6-2.6c-0.39-0.39-1.02-0.39-1.41,0L8.69,4H5C4.45,4,4,4.45,4,5 v3.69l-2.6,2.6c-0.39,0.39-0.39,1.02,0,1.41L4,15.3z M12,7c2.76,0,5,2.24,5,5s-2.24,5-5,5s-5-2.24-5-5S9.24,7,12,7z" />
     <path
-        android:fillColor="?android:attr/colorPrimary"
+        android:fillColor="?android:attr/colorBackgroundFloating"
         android:pathData="M 12 7 C 14.7614237492 7 17 9.23857625085 17 12 C 17 14.7614237492 14.7614237492 17 12 17 C 9.23857625085 17 7 14.7614237492 7 12 C 7 9.23857625085 9.23857625085 7 12 7 Z" />
 </vector>
\ No newline at end of file
diff --git a/packages/overlays/IconPackFilledSystemUIOverlay/res/drawable/ic_camera.xml b/packages/overlays/IconPackFilledSystemUIOverlay/res/drawable/ic_camera.xml
index ae3e7e2..fac551c 100644
--- a/packages/overlays/IconPackFilledSystemUIOverlay/res/drawable/ic_camera.xml
+++ b/packages/overlays/IconPackFilledSystemUIOverlay/res/drawable/ic_camera.xml
@@ -15,10 +15,10 @@
    limitations under the License.
 -->
 <vector xmlns:android="http://schemas.android.com/apk/res/android"
-    android:height="24dp"
+    android:height="17dp"
     android:viewportHeight="24"
     android:viewportWidth="24"
-    android:width="24dp" >
+    android:width="17dp" >
     <path
         android:fillColor="@android:color/white"
         android:pathData="M 12 8.8 C 13.7673111995 8.8 15.2 10.2326888005 15.2 12 C 15.2 13.7673111995 13.7673111995 15.2 12 15.2 C 10.2326888005 15.2 8.8 13.7673111995 8.8 12 C 8.8 10.2326888005 10.2326888005 8.8 12 8.8 Z" />
diff --git a/packages/overlays/IconPackFilledSystemUIOverlay/res/drawable/ic_cast_connected.xml b/packages/overlays/IconPackFilledSystemUIOverlay/res/drawable/ic_cast_connected.xml
index f5056f2..bbe2cff 100644
--- a/packages/overlays/IconPackFilledSystemUIOverlay/res/drawable/ic_cast_connected.xml
+++ b/packages/overlays/IconPackFilledSystemUIOverlay/res/drawable/ic_cast_connected.xml
@@ -15,10 +15,10 @@
    limitations under the License.
 -->
 <vector xmlns:android="http://schemas.android.com/apk/res/android"
-    android:height="17dp"
+    android:height="24dp"
     android:viewportHeight="24"
     android:viewportWidth="24"
-    android:width="17dp" >
+    android:width="24dp" >
     <path
         android:fillColor="@android:color/white"
         android:pathData="M2.07,10.05C1.5,10,1.02,10.45,1,11.03c-0.01,0.52,0.34,0.96,0.85,1.01c4.26,0.43,7.68,3.82,8.1,8.08 C10,20.62,10.43,21,10.94,21c0.59,0,1.06-0.51,1-1.1C11.42,14.69,7.28,10.56,2.07,10.05z" />
diff --git a/packages/overlays/IconPackFilledSystemUIOverlay/res/drawable/ic_data_saver.xml b/packages/overlays/IconPackFilledSystemUIOverlay/res/drawable/ic_data_saver.xml
index 3d4cf5e..28b8ba1 100644
--- a/packages/overlays/IconPackFilledSystemUIOverlay/res/drawable/ic_data_saver.xml
+++ b/packages/overlays/IconPackFilledSystemUIOverlay/res/drawable/ic_data_saver.xml
@@ -15,10 +15,10 @@
    limitations under the License.
 -->
 <vector xmlns:android="http://schemas.android.com/apk/res/android"
-    android:height="18dp "
+    android:height="18dp"
     android:viewportHeight="24"
     android:viewportWidth="24"
-    android:width="18dp " >
+    android:width="18dp" >
     <path
         android:fillColor="@android:color/white"
         android:pathData="M11,11H9c-0.55,0-1,0.45-1,1s0.45,1,1,1h2v2c0,0.55,0.45,1,1,1s1-0.45,1-1v-2h2c0.55,0,1-0.45,1-1s-0.45-1-1-1h-2V9 c0-0.55-0.45-1-1-1s-1,0.45-1,1V11z" />
diff --git a/packages/overlays/IconPackFilledSystemUIOverlay/res/drawable/ic_qs_bluetooth_connecting.xml b/packages/overlays/IconPackFilledSystemUIOverlay/res/drawable/ic_qs_bluetooth_connecting.xml
index f661673..59a18ba 100644
--- a/packages/overlays/IconPackFilledSystemUIOverlay/res/drawable/ic_qs_bluetooth_connecting.xml
+++ b/packages/overlays/IconPackFilledSystemUIOverlay/res/drawable/ic_qs_bluetooth_connecting.xml
@@ -16,6 +16,7 @@
 -->
 <vector xmlns:android="http://schemas.android.com/apk/res/android"
     android:height="24dp"
+    android:tint="?android:attr/colorControlNormal"
     android:viewportHeight="24"
     android:viewportWidth="24"
     android:width="24dp" >
diff --git a/packages/overlays/IconPackFilledSystemUIOverlay/res/drawable/ic_volume_alarm_mute.xml b/packages/overlays/IconPackFilledSystemUIOverlay/res/drawable/ic_volume_alarm_mute.xml
index 8640a79..e498f803 100644
--- a/packages/overlays/IconPackFilledSystemUIOverlay/res/drawable/ic_volume_alarm_mute.xml
+++ b/packages/overlays/IconPackFilledSystemUIOverlay/res/drawable/ic_volume_alarm_mute.xml
@@ -16,6 +16,7 @@
 -->
 <vector xmlns:android="http://schemas.android.com/apk/res/android"
     android:height="24dp"
+    android:tint="?android:attr/colorControlNormal"
     android:viewportHeight="24"
     android:viewportWidth="24"
     android:width="24dp" >
diff --git a/packages/overlays/IconPackFilledSettingsOverlay/res/drawable/ic_battery_status_bad_24dp.xml b/packages/overlays/IconPackFilledSystemUIOverlay/res/drawable/ic_volume_odi_captions.xml
similarity index 61%
copy from packages/overlays/IconPackFilledSettingsOverlay/res/drawable/ic_battery_status_bad_24dp.xml
copy to packages/overlays/IconPackFilledSystemUIOverlay/res/drawable/ic_volume_odi_captions.xml
index 22e183c..42ef41c 100644
--- a/packages/overlays/IconPackFilledSettingsOverlay/res/drawable/ic_battery_status_bad_24dp.xml
+++ b/packages/overlays/IconPackFilledSystemUIOverlay/res/drawable/ic_volume_odi_captions.xml
@@ -19,7 +19,13 @@
     android:viewportHeight="24"
     android:viewportWidth="24"
     android:width="24dp" >
-    <path
-        android:fillColor="@android:color/white"
-        android:pathData="M10,2v2H8.33C7.6,4,7,4.6,7,5.33v15.33C7,21.4,7.6,22,8.33,22h7.33C16.4,22,17,21.4,17,20.67V5.33C17,4.6,16.4,4,15.67,4 H14V2H10z M15,13c0,0.55-0.45,1-1,1h-1v1c0,0.55-0.45,1-1,1s-1-0.45-1-1v-1h-1c-0.55,0-1-0.45-1-1s0.45-1,1-1h1v-1 c0-0.55,0.45-1,1-1s1,0.45,1,1v1h1C14.55,12,15,12.45,15,13z" />
+    <group
+        android:translateX="2.000000"
+        android:translateY="4.000000" >
+        <path
+            android:fillColor="@android:color/white"
+            android:fillType="evenOdd"
+            android:pathData="M8,8 L16,8 L16,6 L8,6 L8,8 Z M14,12 L16,12 L16,10 L14,10 L14,12 Z M4,12 L12,12 L12,10 L4,10 L4,12 Z M4,8 L6,8 L6,6 L4,6 L4,8 Z M18,0 L2,0 C0.9,0 0,0.9 0,2 L0,14 C0,15.1 0.9,16 2,16 L18,16 C19.1,16 20,15.1 20,14 L20,2 C20,0.9 19.1,0 18,0 L18,0 Z"
+            android:strokeWidth="1" />
+    </group>
 </vector>
\ No newline at end of file
diff --git a/packages/overlays/IconPackFilledSystemUIOverlay/res/drawable/ic_volume_odi_captions_disabled.xml b/packages/overlays/IconPackFilledSystemUIOverlay/res/drawable/ic_volume_odi_captions_disabled.xml
new file mode 100644
index 0000000..f164ba8
--- /dev/null
+++ b/packages/overlays/IconPackFilledSystemUIOverlay/res/drawable/ic_volume_odi_captions_disabled.xml
@@ -0,0 +1,29 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+   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.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:height="24dp"
+    android:viewportHeight="24"
+    android:viewportWidth="24"
+    android:width="24dp" >
+    <group android:translateY="2.000000" >
+        <path
+            android:fillColor="@android:color/white"
+            android:fillType="evenOdd"
+            android:pathData="M6,14 L13.17,14 L11.17,12 L6,12 L6,14 Z M6,8 L6,10 L8,10 L8,8.83 L7.17,8 L6,8 Z M1.293,0.7085 C1.68545692,0.318530482 2.3194559,0.319620835 2.71056916,0.71093794 L20.4851837,18.4948164 C20.8744727,18.8843082 20.8743905,19.5156095 20.485,19.905 C20.0956393,20.2943607 19.4643607,20.2943607 19.075,19.905 L17.17,18 L4,18 C2.9,18 2,17.1 2,16 L2,4 C2,3.663 2.092,3.35 2.241,3.071 L1.29096704,2.12154004 C1.29014848,2.12072198 1.28933135,2.11990248 1.28851564,2.11908157 C0.900232614,1.7283219 0.902240332,1.09678302 1.293,0.7085 Z M6.82,2 L20,2 C21.1,2 22,2.9 22,4 L22,16 C22,16.342 21.905,16.659 21.753,16.94 L18,13.187 L18,12 L16.814,12 L14.815,10 L18,10 L18,8 L12.816,8 L8.819,4 L6.82,2 Z"
+            android:strokeWidth="1" />
+    </group>
+</vector>
\ No newline at end of file
diff --git a/packages/overlays/IconPackFilledSettingsOverlay/res/drawable/ic_battery_status_bad_24dp.xml b/packages/overlays/IconPackRoundedAndroidOverlay/res/drawable/ic_battery_80_24dp.xml
similarity index 73%
rename from packages/overlays/IconPackFilledSettingsOverlay/res/drawable/ic_battery_status_bad_24dp.xml
rename to packages/overlays/IconPackRoundedAndroidOverlay/res/drawable/ic_battery_80_24dp.xml
index 22e183c..c19ca31 100644
--- a/packages/overlays/IconPackFilledSettingsOverlay/res/drawable/ic_battery_status_bad_24dp.xml
+++ b/packages/overlays/IconPackRoundedAndroidOverlay/res/drawable/ic_battery_80_24dp.xml
@@ -21,5 +21,5 @@
     android:width="24dp" >
     <path
         android:fillColor="@android:color/white"
-        android:pathData="M10,2v2H8.33C7.6,4,7,4.6,7,5.33v15.33C7,21.4,7.6,22,8.33,22h7.33C16.4,22,17,21.4,17,20.67V5.33C17,4.6,16.4,4,15.67,4 H14V2H10z M15,13c0,0.55-0.45,1-1,1h-1v1c0,0.55-0.45,1-1,1s-1-0.45-1-1v-1h-1c-0.55,0-1-0.45-1-1s0.45-1,1-1h1v-1 c0-0.55,0.45-1,1-1s1,0.45,1,1v1h1C14.55,12,15,12.45,15,13z" />
+        android:pathData="M13,2.49h-2c-0.55,0-1,0.45-1,1V4H7C6.45,4,6,4.45,6,5v16c0,0.55,0.45,1,1,1h10c0.55,0,1-0.45,1-1V5c0-0.55-0.45-1-1-1h-3 V3.49C14,2.94,13.55,2.49,13,2.49z M16.5,9.01h-9V5.5h9V9.01z" />
 </vector>
\ No newline at end of file
diff --git a/packages/overlays/IconPackRoundedAndroidOverlay/res/drawable/ic_file_copy.xml b/packages/overlays/IconPackRoundedAndroidOverlay/res/drawable/ic_file_copy.xml
index 97945f0..1feaab1 100644
--- a/packages/overlays/IconPackRoundedAndroidOverlay/res/drawable/ic_file_copy.xml
+++ b/packages/overlays/IconPackRoundedAndroidOverlay/res/drawable/ic_file_copy.xml
@@ -16,7 +16,7 @@
 -->
 <vector xmlns:android="http://schemas.android.com/apk/res/android"
     android:height="24dp"
-    android:tint="#FF737373"
+    android:tint="@*android:color/material_grey_600"
     android:viewportHeight="24"
     android:viewportWidth="24"
     android:width="24dp" >
diff --git a/packages/overlays/IconPackRoundedAndroidOverlay/res/drawable/ic_lock.xml b/packages/overlays/IconPackRoundedAndroidOverlay/res/drawable/ic_lock.xml
index ac8e478..d0b85e7 100644
--- a/packages/overlays/IconPackRoundedAndroidOverlay/res/drawable/ic_lock.xml
+++ b/packages/overlays/IconPackRoundedAndroidOverlay/res/drawable/ic_lock.xml
@@ -16,7 +16,6 @@
 -->
 <vector xmlns:android="http://schemas.android.com/apk/res/android"
     android:height="32dp"
-    android:tint="?android:attr/textColor"
     android:viewportHeight="24"
     android:viewportWidth="24"
     android:width="32dp" >
diff --git a/packages/overlays/IconPackRoundedAndroidOverlay/res/drawable/ic_lock_open.xml b/packages/overlays/IconPackRoundedAndroidOverlay/res/drawable/ic_lock_open.xml
index 345d6b1..6f19afe 100644
--- a/packages/overlays/IconPackRoundedAndroidOverlay/res/drawable/ic_lock_open.xml
+++ b/packages/overlays/IconPackRoundedAndroidOverlay/res/drawable/ic_lock_open.xml
@@ -16,7 +16,6 @@
 -->
 <vector xmlns:android="http://schemas.android.com/apk/res/android"
     android:height="32dp"
-    android:tint="?android:attr/textColor"
     android:viewportHeight="24"
     android:viewportWidth="24"
     android:width="32dp" >
diff --git a/packages/overlays/IconPackRoundedAndroidOverlay/res/drawable/ic_lockscreen_ime.xml b/packages/overlays/IconPackRoundedAndroidOverlay/res/drawable/ic_lockscreen_ime.xml
index 16f0868..fae8445 100644
--- a/packages/overlays/IconPackRoundedAndroidOverlay/res/drawable/ic_lockscreen_ime.xml
+++ b/packages/overlays/IconPackRoundedAndroidOverlay/res/drawable/ic_lockscreen_ime.xml
@@ -16,6 +16,7 @@
 -->
 <vector xmlns:android="http://schemas.android.com/apk/res/android"
     android:height="24dp"
+    android:tint="?android:attr/colorControlNormal"
     android:viewportHeight="24"
     android:viewportWidth="24"
     android:width="24dp" >
diff --git a/packages/overlays/IconPackRoundedAndroidOverlay/res/drawable/ic_mode_edit.xml b/packages/overlays/IconPackRoundedAndroidOverlay/res/drawable/ic_mode_edit.xml
index 5db3b12..c44a8d6 100644
--- a/packages/overlays/IconPackRoundedAndroidOverlay/res/drawable/ic_mode_edit.xml
+++ b/packages/overlays/IconPackRoundedAndroidOverlay/res/drawable/ic_mode_edit.xml
@@ -16,10 +16,17 @@
 -->
 <vector xmlns:android="http://schemas.android.com/apk/res/android"
     android:height="24dp"
+    android:tint="?android:attr/colorControlNormal"
     android:viewportHeight="24"
     android:viewportWidth="24"
     android:width="24dp" >
-    <path
-        android:fillColor="@android:color/white"
-        android:pathData="M20.08,5.08l-1.17-1.17c-0.39-0.39-0.9-0.58-1.41-0.58c-0.51,0-1.02,0.2-1.41,0.59L3.29,16.71C3.11,16.89,3,17.15,3,17.41 l0,2.59c0,0.55,0.45,1,1,1c0,0,0,0,0,0L6.59,21c0.26,0,0.52-0.11,0.71-0.29l10.68-10.68l0,0l1.06-1.06l0,0l1.05-1.06 C20.87,7.13,20.87,5.86,20.08,5.08z M6.38,19.5l-1.88,0l0-1.88L15.03,7.09l1.88,1.88L6.38,19.5z M19.02,6.85l-1.06,1.06l-1.88-1.88 l1.05-1.05c0.13-0.13,0.28-0.15,0.35-0.15c0.08,0,0.23,0.02,0.35,0.15l1.17,1.17c0.13,0.13,0.15,0.28,0.15,0.35 C19.17,6.57,19.15,6.72,19.02,6.85z" />
+    <group
+        android:translateX="3.000000"
+        android:translateY="3.000000" >
+        <path
+            android:fillColor="@android:color/white"
+            android:fillType="evenOdd"
+            android:pathData="M14.971,4.992 L13.092,3.115 L14.499,1.707 L16.38,3.583 L14.971,4.992 Z M3.38,16.588 L1.501,16.592 L1.502,14.708 L12.031,4.176 L13.91,6.054 L3.38,16.588 Z M17.794,2.874 L15.205,0.292 C15.01,0.097 14.755,0 14.499,0 C14.243,0 13.987,0.098 13.792,0.293 L0.295,13.794 C0.108,13.981 0.002,14.236 0.002,14.5 L-1.42108547e-14,17.594 C-1.42108547e-14,17.87 0.224,18.094 0.5,18.094 L0.501,18.094 L3.589,18.088 C3.854,18.087 4.107,17.982 4.294,17.795 L17.795,4.289 C18.185,3.898 18.185,3.264 17.794,2.874 L17.794,2.874 Z"
+            android:strokeWidth="1" />
+    </group>
 </vector>
\ No newline at end of file
diff --git a/packages/overlays/IconPackRoundedAndroidOverlay/res/drawable/ic_notifications_alerted.xml b/packages/overlays/IconPackRoundedAndroidOverlay/res/drawable/ic_notifications_alerted.xml
new file mode 100644
index 0000000..752dab5
--- /dev/null
+++ b/packages/overlays/IconPackRoundedAndroidOverlay/res/drawable/ic_notifications_alerted.xml
@@ -0,0 +1,34 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+   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.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:height="24dp"
+    android:viewportHeight="24"
+    android:viewportWidth="24"
+    android:width="24dp" >
+    <path
+        android:fillColor="@android:color/white"
+        android:pathData="M14,20h-4c0,1.1,0.9,2,2,2S14,21.1,14,20z" />
+    <path
+        android:fillColor="@android:color/white"
+        android:pathData="M12,2.5c-0.69,0-1.25,0.56-1.25,1.25v0.77C8.04,5.11,6,7.51,6,10.4V17H4.75C4.34,17,4,17.34,4,17.75s0.34,0.75,0.75,0.75 h14.5c0.41,0,0.75-0.34,0.75-0.75S19.66,17,19.25,17H18v-6.6c0-2.88-2.04-5.29-4.75-5.87V3.75C13.25,3.06,12.69,2.5,12,2.5z M16.5,10.4V17h-9v-6.6c0-2.48,2.02-4.5,4.5-4.5S16.5,7.91,16.5,10.4z" />
+    <path
+        android:fillColor="@android:color/white"
+        android:pathData="M5.85,3.01C3.72,4.82,2.5,7.46,2.5,10.25C2.5,10.66,2.84,11,3.25,11S4,10.66,4,10.25c0-2.35,1.03-4.57,2.82-6.1 C7.14,3.88,7.17,3.41,6.91,3.1C6.64,2.78,6.17,2.74,5.85,3.01z" />
+    <path
+        android:fillColor="@android:color/white"
+        android:pathData="M18.15,3.01c-0.32-0.27-0.79-0.23-1.06,0.08c-0.27,0.32-0.23,0.79,0.08,1.06C18.97,5.68,20,7.9,20,10.25 c0,0.41,0.34,0.75,0.75,0.75s0.75-0.34,0.75-0.75C21.5,7.46,20.28,4.82,18.15,3.01z" />
+</vector>
\ No newline at end of file
diff --git a/packages/overlays/IconPackRoundedAndroidOverlay/res/drawable/ic_phone.xml b/packages/overlays/IconPackRoundedAndroidOverlay/res/drawable/ic_phone.xml
index 2115392..c6e8f57 100644
--- a/packages/overlays/IconPackRoundedAndroidOverlay/res/drawable/ic_phone.xml
+++ b/packages/overlays/IconPackRoundedAndroidOverlay/res/drawable/ic_phone.xml
@@ -15,7 +15,9 @@
    limitations under the License.
 -->
 <vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:autoMirrored="true"
     android:height="24dp"
+    android:tint="?android:attr/colorControlNormal"
     android:viewportHeight="24"
     android:viewportWidth="24"
     android:width="24dp" >
diff --git a/packages/overlays/IconPackRoundedAndroidOverlay/res/drawable/ic_qs_battery_saver.xml b/packages/overlays/IconPackRoundedAndroidOverlay/res/drawable/ic_qs_battery_saver.xml
index db4d302..ca37d58 100644
--- a/packages/overlays/IconPackRoundedAndroidOverlay/res/drawable/ic_qs_battery_saver.xml
+++ b/packages/overlays/IconPackRoundedAndroidOverlay/res/drawable/ic_qs_battery_saver.xml
@@ -15,7 +15,9 @@
    limitations under the License.
 -->
 <vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:autoMirrored="true"
     android:height="24dp"
+    android:tint="?android:attr/colorControlNormal"
     android:viewportHeight="24"
     android:viewportWidth="24"
     android:width="24dp" >
diff --git a/packages/overlays/IconPackRoundedAndroidOverlay/res/drawable/ic_qs_bluetooth.xml b/packages/overlays/IconPackRoundedAndroidOverlay/res/drawable/ic_qs_bluetooth.xml
index 3d270b3..5e1a5f2 100644
--- a/packages/overlays/IconPackRoundedAndroidOverlay/res/drawable/ic_qs_bluetooth.xml
+++ b/packages/overlays/IconPackRoundedAndroidOverlay/res/drawable/ic_qs_bluetooth.xml
@@ -16,6 +16,7 @@
 -->
 <vector xmlns:android="http://schemas.android.com/apk/res/android"
     android:height="24dp"
+    android:tint="?android:attr/colorControlNormal"
     android:viewportHeight="24"
     android:viewportWidth="24"
     android:width="24dp" >
diff --git a/packages/overlays/IconPackFilledSettingsOverlay/res/drawable/ic_delete_accent.xml b/packages/overlays/IconPackRoundedAndroidOverlay/res/drawable/ic_qs_ui_mode_night.xml
similarity index 64%
copy from packages/overlays/IconPackFilledSettingsOverlay/res/drawable/ic_delete_accent.xml
copy to packages/overlays/IconPackRoundedAndroidOverlay/res/drawable/ic_qs_ui_mode_night.xml
index e65987e..3cf7541 100644
--- a/packages/overlays/IconPackFilledSettingsOverlay/res/drawable/ic_delete_accent.xml
+++ b/packages/overlays/IconPackRoundedAndroidOverlay/res/drawable/ic_qs_ui_mode_night.xml
@@ -16,14 +16,12 @@
 -->
 <vector xmlns:android="http://schemas.android.com/apk/res/android"
     android:height="24dp"
-    android:tint="?android:attr/colorAccent"
     android:viewportHeight="24"
     android:viewportWidth="24"
     android:width="24dp" >
     <path
         android:fillColor="@android:color/white"
-        android:pathData="M18,4h-2.5l-0.71-0.71C14.61,3.11,14.35,3,14.09,3H9.9C9.64,3,9.38,3.11,9.2,3.29L8.49,4h-2.5c-0.55,0-1,0.45-1,1 s0.45,1,1,1h12c0.55,0,1-0.45,1-1C19,4.45,18.55,4,18,4z" />
-    <path
-        android:fillColor="@android:color/white"
-        android:pathData="M6,19c0,1.1,0.9,2,2,2h8c1.1,0,2-0.9,2-2V7H6V19z" />
-</vector>
\ No newline at end of file
+        android:fillType="evenOdd"
+        android:pathData="M12,20.5 L12,3.5 C16.687,3.5 20.5,7.313 20.5,12 C20.5,16.687 16.687,20.5 12,20.5 M12,2 C10.619,2 9.304,2.279 8.107,2.786 C7.51,3.039 6.941,3.349 6.409,3.708 C6.143,3.888 5.886,4.08 5.639,4.283 C4.651,5.099 3.822,6.1 3.207,7.233 C2.899,7.8 2.645,8.4 2.449,9.026 C2.255,9.652 2.12,10.305 2.052,10.978 C2.018,11.313 2,11.654 2,12 C2,17.522 6.478,22 12,22 C17.522,22 22,17.522 22,12 C22,6.478 17.522,2 12,2"
+        android:strokeWidth="1" />
+</vector>
diff --git a/packages/overlays/IconPackRoundedAndroidOverlay/res/drawable/perm_group_activity_recognition.xml b/packages/overlays/IconPackRoundedAndroidOverlay/res/drawable/perm_group_activity_recognition.xml
index b470603..6697047 100644
--- a/packages/overlays/IconPackRoundedAndroidOverlay/res/drawable/perm_group_activity_recognition.xml
+++ b/packages/overlays/IconPackRoundedAndroidOverlay/res/drawable/perm_group_activity_recognition.xml
@@ -16,7 +16,7 @@
 -->
 <vector xmlns:android="http://schemas.android.com/apk/res/android"
     android:height="24dp"
-    android:tint="@android:color/black"
+    android:tint="?android:attr/colorControlNormal"
     android:viewportHeight="24"
     android:viewportWidth="24"
     android:width="24dp" >
diff --git a/packages/overlays/IconPackRoundedAndroidOverlay/res/drawable/perm_group_aural.xml b/packages/overlays/IconPackRoundedAndroidOverlay/res/drawable/perm_group_aural.xml
new file mode 100644
index 0000000..8cd240d
--- /dev/null
+++ b/packages/overlays/IconPackRoundedAndroidOverlay/res/drawable/perm_group_aural.xml
@@ -0,0 +1,40 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+   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.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:height="24dp"
+    android:tint="?android:attr/colorControlNormal"
+    android:viewportHeight="24"
+    android:viewportWidth="24"
+    android:width="24dp" >
+    <group
+        android:translateX="2.000000"
+        android:translateY="2.000000" >
+        <path
+            android:fillColor="@android:color/white"
+            android:pathData="M18,0 L6,0 C4.9,0 4,0.9 4,2 L4,14 C4,15.1 4.9,16 6,16 L18,16 C19.1,16 20,15.1 20,14 L20,2 C20,0.9 19.1,0 18,0 Z M18.5,14 C18.5,14.28 18.28,14.5 18,14.5 L6,14.5 C5.72,14.5 5.5,14.28 5.5,14 L5.5,2 C5.5,1.72 5.72,1.5 6,1.5 L18,1.5 C18.28,1.5 18.5,1.72 18.5,2 L18.5,14 Z"
+            android:strokeWidth="1" />
+        <path
+            android:fillColor="@android:color/white"
+            android:fillType="evenOdd"
+            android:pathData="M15.86,3.10740288 C15.7704,3.02963963 15.6528,2.990758 15.5352,3.00186703 L13.0152,3.27959295 C12.8024,3.30736554 12.64,3.48511013 12.64,3.69618182 L12.64,9.056292 C12.2536,8.75079349 11.772,8.55638535 11.24,8.55638535 C10.0024,8.55638535 9,9.55064413 9,10.7781927 C9,12.0057412 10.0024,13 11.24,13 C12.4776,13 13.48,12.0057412 13.48,10.7781927 L13.48,5.01241596 L15.6248,4.77912619 C15.8376,4.7513536 16,4.57360901 16,4.36253732 L16,3.41845591 C16,3.30181102 15.9496,3.18516614 15.86,3.10740288 Z"
+            android:strokeWidth="1" />
+        <path
+            android:fillColor="@android:color/white"
+            android:pathData="M15.25,18 L3.25,18 C2.56,18 2,17.44 2,16.75 L2,4.75 C2,4.34 1.66,4 1.25,4 C0.84,4 0.5,4.34 0.5,4.75 L0.5,16.75 C0.5,18.27 1.73,19.5 3.25,19.5 L15.25,19.5 C15.66,19.5 16,19.16 16,18.75 C16,18.34 15.66,18 15.25,18 Z"
+            android:strokeWidth="1" />
+    </group>
+</vector>
\ No newline at end of file
diff --git a/packages/overlays/IconPackRoundedAndroidOverlay/res/drawable/perm_group_calendar.xml b/packages/overlays/IconPackRoundedAndroidOverlay/res/drawable/perm_group_calendar.xml
index e9dddd0..4e61af0 100644
--- a/packages/overlays/IconPackRoundedAndroidOverlay/res/drawable/perm_group_calendar.xml
+++ b/packages/overlays/IconPackRoundedAndroidOverlay/res/drawable/perm_group_calendar.xml
@@ -16,6 +16,7 @@
 -->
 <vector xmlns:android="http://schemas.android.com/apk/res/android"
     android:height="24dp"
+    android:tint="?android:attr/colorControlNormal"
     android:viewportHeight="24"
     android:viewportWidth="24"
     android:width="24dp" >
diff --git a/packages/overlays/IconPackRoundedAndroidOverlay/res/drawable/perm_group_call_log.xml b/packages/overlays/IconPackRoundedAndroidOverlay/res/drawable/perm_group_call_log.xml
index 2d6a6b9..8d3c43c 100644
--- a/packages/overlays/IconPackRoundedAndroidOverlay/res/drawable/perm_group_call_log.xml
+++ b/packages/overlays/IconPackRoundedAndroidOverlay/res/drawable/perm_group_call_log.xml
@@ -16,7 +16,7 @@
 -->
 <vector xmlns:android="http://schemas.android.com/apk/res/android"
     android:height="24dp"
-    android:tint="@android:color/black"
+    android:tint="?android:attr/colorControlNormal"
     android:viewportHeight="24"
     android:viewportWidth="24"
     android:width="24dp" >
diff --git a/packages/overlays/IconPackRoundedAndroidOverlay/res/drawable/perm_group_camera.xml b/packages/overlays/IconPackRoundedAndroidOverlay/res/drawable/perm_group_camera.xml
index e3498c3..7d42ff7 100644
--- a/packages/overlays/IconPackRoundedAndroidOverlay/res/drawable/perm_group_camera.xml
+++ b/packages/overlays/IconPackRoundedAndroidOverlay/res/drawable/perm_group_camera.xml
@@ -16,7 +16,7 @@
 -->
 <vector xmlns:android="http://schemas.android.com/apk/res/android"
     android:height="24dp"
-    android:tint="@android:color/black"
+    android:tint="?android:attr/colorControlNormal"
     android:viewportHeight="24"
     android:viewportWidth="24"
     android:width="24dp" >
diff --git a/packages/overlays/IconPackRoundedAndroidOverlay/res/drawable/perm_group_contacts.xml b/packages/overlays/IconPackRoundedAndroidOverlay/res/drawable/perm_group_contacts.xml
index 987ed18..5d68581 100644
--- a/packages/overlays/IconPackRoundedAndroidOverlay/res/drawable/perm_group_contacts.xml
+++ b/packages/overlays/IconPackRoundedAndroidOverlay/res/drawable/perm_group_contacts.xml
@@ -16,7 +16,7 @@
 -->
 <vector xmlns:android="http://schemas.android.com/apk/res/android"
     android:height="24dp"
-    android:tint="@android:color/black"
+    android:tint="?android:attr/colorControlNormal"
     android:viewportHeight="24"
     android:viewportWidth="24"
     android:width="24dp" >
diff --git a/packages/overlays/IconPackRoundedAndroidOverlay/res/drawable/perm_group_location.xml b/packages/overlays/IconPackRoundedAndroidOverlay/res/drawable/perm_group_location.xml
index 2da48d85..5dce9cb 100644
--- a/packages/overlays/IconPackRoundedAndroidOverlay/res/drawable/perm_group_location.xml
+++ b/packages/overlays/IconPackRoundedAndroidOverlay/res/drawable/perm_group_location.xml
@@ -16,7 +16,7 @@
 -->
 <vector xmlns:android="http://schemas.android.com/apk/res/android"
     android:height="24dp"
-    android:tint="@android:color/black"
+    android:tint="?android:attr/colorControlNormal"
     android:viewportHeight="24"
     android:viewportWidth="24"
     android:width="24dp" >
diff --git a/packages/overlays/IconPackRoundedAndroidOverlay/res/drawable/perm_group_microphone.xml b/packages/overlays/IconPackRoundedAndroidOverlay/res/drawable/perm_group_microphone.xml
index ddf14df..b45e832 100644
--- a/packages/overlays/IconPackRoundedAndroidOverlay/res/drawable/perm_group_microphone.xml
+++ b/packages/overlays/IconPackRoundedAndroidOverlay/res/drawable/perm_group_microphone.xml
@@ -16,7 +16,7 @@
 -->
 <vector xmlns:android="http://schemas.android.com/apk/res/android"
     android:height="24dp"
-    android:tint="@android:color/black"
+    android:tint="?android:attr/colorControlNormal"
     android:viewportHeight="24"
     android:viewportWidth="24"
     android:width="24dp" >
diff --git a/packages/overlays/IconPackRoundedAndroidOverlay/res/drawable/perm_group_phone_calls.xml b/packages/overlays/IconPackRoundedAndroidOverlay/res/drawable/perm_group_phone_calls.xml
index 516ee36..fe45a97 100644
--- a/packages/overlays/IconPackRoundedAndroidOverlay/res/drawable/perm_group_phone_calls.xml
+++ b/packages/overlays/IconPackRoundedAndroidOverlay/res/drawable/perm_group_phone_calls.xml
@@ -16,7 +16,7 @@
 -->
 <vector xmlns:android="http://schemas.android.com/apk/res/android"
     android:height="24dp"
-    android:tint="@android:color/black"
+    android:tint="?android:attr/colorControlNormal"
     android:viewportHeight="24"
     android:viewportWidth="24"
     android:width="24dp" >
diff --git a/packages/overlays/IconPackRoundedAndroidOverlay/res/drawable/perm_group_sensors.xml b/packages/overlays/IconPackRoundedAndroidOverlay/res/drawable/perm_group_sensors.xml
index 65a193d..c84cb0e 100644
--- a/packages/overlays/IconPackRoundedAndroidOverlay/res/drawable/perm_group_sensors.xml
+++ b/packages/overlays/IconPackRoundedAndroidOverlay/res/drawable/perm_group_sensors.xml
@@ -16,7 +16,7 @@
 -->
 <vector xmlns:android="http://schemas.android.com/apk/res/android"
     android:height="24dp"
-    android:tint="@android:color/black"
+    android:tint="?android:attr/colorControlNormal"
     android:viewportHeight="24"
     android:viewportWidth="24"
     android:width="24dp" >
diff --git a/packages/overlays/IconPackRoundedAndroidOverlay/res/drawable/perm_group_sms.xml b/packages/overlays/IconPackRoundedAndroidOverlay/res/drawable/perm_group_sms.xml
index b5509d1..96b70f7 100644
--- a/packages/overlays/IconPackRoundedAndroidOverlay/res/drawable/perm_group_sms.xml
+++ b/packages/overlays/IconPackRoundedAndroidOverlay/res/drawable/perm_group_sms.xml
@@ -16,7 +16,7 @@
 -->
 <vector xmlns:android="http://schemas.android.com/apk/res/android"
     android:height="24dp"
-    android:tint="@android:color/black"
+    android:tint="?android:attr/colorControlNormal"
     android:viewportHeight="24"
     android:viewportWidth="24"
     android:width="24dp" >
diff --git a/packages/overlays/IconPackRoundedAndroidOverlay/res/drawable/perm_group_storage.xml b/packages/overlays/IconPackRoundedAndroidOverlay/res/drawable/perm_group_storage.xml
index 9b17e55..9240bb4 100644
--- a/packages/overlays/IconPackRoundedAndroidOverlay/res/drawable/perm_group_storage.xml
+++ b/packages/overlays/IconPackRoundedAndroidOverlay/res/drawable/perm_group_storage.xml
@@ -16,7 +16,7 @@
 -->
 <vector xmlns:android="http://schemas.android.com/apk/res/android"
     android:height="24dp"
-    android:tint="@android:color/black"
+    android:tint="?android:attr/colorControlNormal"
     android:viewportHeight="24"
     android:viewportWidth="24"
     android:width="24dp" >
diff --git a/packages/overlays/IconPackRoundedAndroidOverlay/res/drawable/perm_group_visual.xml b/packages/overlays/IconPackRoundedAndroidOverlay/res/drawable/perm_group_visual.xml
index 350bb4b..2cd1bc0f 100644
--- a/packages/overlays/IconPackRoundedAndroidOverlay/res/drawable/perm_group_visual.xml
+++ b/packages/overlays/IconPackRoundedAndroidOverlay/res/drawable/perm_group_visual.xml
@@ -16,7 +16,7 @@
 -->
 <vector xmlns:android="http://schemas.android.com/apk/res/android"
     android:height="24dp"
-    android:tint="@android:color/black"
+    android:tint="?android:attr/colorControlNormal"
     android:viewportHeight="24"
     android:viewportWidth="24"
     android:width="24dp" >
diff --git a/packages/overlays/IconPackRoundedAndroidOverlay/res/values/config.xml b/packages/overlays/IconPackRoundedAndroidOverlay/res/values/config.xml
index ebcac82..b7bfaad 100644
--- a/packages/overlays/IconPackRoundedAndroidOverlay/res/values/config.xml
+++ b/packages/overlays/IconPackRoundedAndroidOverlay/res/values/config.xml
@@ -30,4 +30,12 @@
     <string name="config_batterymeterPowersavePath" translatable="false">
         M 3.75,11.25 H 5.25 V 12.75 C 5.25,13.16 5.59,13.5 6,13.5 6.41,13.5 6.75,13.16 6.75,12.75 V 11.25 H 8.25 C 8.66,11.25 9,10.91 9,10.5 9,10.09 8.66,9.7499 8.25,9.7499 H 6.75 V 8.2499 C 6.75,7.8399 6.41,7.4999 6,7.4999 5.59,7.4999 5.2794,7.841 5.25,8.2499 V 9.7499 H 3.75 C 3.34,9.7499 3,10.09 3,10.5 3,10.91 3.3401,11.25 3.75,11.25 Z
     </string>
+    <!-- X path for SignalDrawable as defined on a 24x24 canvas. -->
+    <string name="config_signalXPath" translatable="false">
+        M 20.72,16.22 L 19,17.94 L 17.28,16.22 C 16.99,15.93 16.51,15.93 16.22,16.22 C 15.93,16.51 15.93,16.99 16.22,17.28 L 17.94,19 L 16.22,20.72 C 15.93,21.01 15.93,21.49 16.22,21.78 C 16.37,21.93 16.56,22 16.75,22 C 16.94,22 17.13,21.93 17.28,21.78 L 19,20.06 L 20.72,21.78 C 20.87,21.93 21.06,22 21.25,22 C 21.44,22 21.63,21.93 21.78,21.78 C 22.07,21.49 22.07,21.01 21.78,20.72 L 20.06,19 L 21.78,17.28 C 22.07,16.99 22.07,16.51 21.78,16.22 C 21.49,15.93 21.01,15.93 20.72,16.22 Z
+    </string>
+    <!-- config_signalCutout{Height,Width}Fraction define fraction of the 24x24 canvas that
+         should be cut out to display config_signalXPath.-->
+    <item name="config_signalCutoutWidthFraction" format="float" type="dimen">10</item>
+    <item name="config_signalCutoutHeightFraction" format="float" type="dimen">10</item>
 </resources>
diff --git a/packages/overlays/IconPackRoundedLauncherOverlay/res/drawable/ic_setting.xml b/packages/overlays/IconPackRoundedLauncherOverlay/res/drawable/ic_setting.xml
index 86cb525..70621ae 100644
--- a/packages/overlays/IconPackRoundedLauncherOverlay/res/drawable/ic_setting.xml
+++ b/packages/overlays/IconPackRoundedLauncherOverlay/res/drawable/ic_setting.xml
@@ -16,6 +16,7 @@
 -->
 <vector xmlns:android="http://schemas.android.com/apk/res/android"
     android:height="24dp"
+    android:tint="?android:attr/textColorPrimary"
     android:viewportHeight="24"
     android:viewportWidth="24"
     android:width="24dp" >
diff --git a/packages/overlays/IconPackRoundedSettingsOverlay/res/drawable/ic_arrow_back.xml b/packages/overlays/IconPackRoundedSettingsOverlay/res/drawable/ic_arrow_back.xml
index 03f06e9..34f79b4 100644
--- a/packages/overlays/IconPackRoundedSettingsOverlay/res/drawable/ic_arrow_back.xml
+++ b/packages/overlays/IconPackRoundedSettingsOverlay/res/drawable/ic_arrow_back.xml
@@ -15,6 +15,7 @@
    limitations under the License.
 -->
 <vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:autoMirrored="true"
     android:height="24dp"
     android:tint="?android:attr/colorControlNormal"
     android:viewportHeight="24"
diff --git a/packages/overlays/IconPackRoundedSettingsOverlay/res/drawable/ic_battery_saver_accent_24dp.xml b/packages/overlays/IconPackRoundedSettingsOverlay/res/drawable/ic_battery_saver_accent_24dp.xml
deleted file mode 100644
index 9b39a94..0000000
--- a/packages/overlays/IconPackRoundedSettingsOverlay/res/drawable/ic_battery_saver_accent_24dp.xml
+++ /dev/null
@@ -1,29 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-   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.
--->
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
-    android:height="24dp"
-    android:tint="?android:attr/colorAccent"
-    android:viewportHeight="24"
-    android:viewportWidth="24"
-    android:width="24dp" >
-    <path
-        android:fillColor="@android:color/white"
-        android:pathData="M9.74,13.75h1.5v1.5c0,0.41,0.34,0.75,0.75,0.75s0.75-0.34,0.75-0.75v-1.5h1.5c0.41,0,0.75-0.34,0.75-0.75 s-0.34-0.75-0.75-0.75h-1.5v-1.5c0-0.41-0.34-0.75-0.75-0.75s-0.75,0.34-0.75,0.75v1.5h-1.5c-0.41,0-0.75,0.34-0.75,0.75 S9.33,13.75,9.74,13.75z" />
-    <path
-        android:fillColor="@android:color/white"
-        android:pathData="M17,4h-3V3.49c0-0.55-0.45-1-1-1h-2c-0.55,0-1,0.45-1,1V4H7C6.45,4,6,4.45,6,5v16c0,0.55,0.45,1,1,1h10c0.55,0,1-0.45,1-1 V5C18,4.45,17.55,4,17,4z M16.5,20.5h-9v-15h9V20.5z" />
-</vector>
\ No newline at end of file
diff --git a/packages/overlays/IconPackRoundedSettingsOverlay/res/drawable/ic_battery_status_bad_24dp.xml b/packages/overlays/IconPackRoundedSettingsOverlay/res/drawable/ic_battery_status_bad_24dp.xml
deleted file mode 100644
index db4d302..0000000
--- a/packages/overlays/IconPackRoundedSettingsOverlay/res/drawable/ic_battery_status_bad_24dp.xml
+++ /dev/null
@@ -1,28 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-   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.
--->
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
-    android:height="24dp"
-    android:viewportHeight="24"
-    android:viewportWidth="24"
-    android:width="24dp" >
-    <path
-        android:fillColor="@android:color/white"
-        android:pathData="M9.74,13.75h1.5v1.5c0,0.41,0.34,0.75,0.75,0.75s0.75-0.34,0.75-0.75v-1.5h1.5c0.41,0,0.75-0.34,0.75-0.75 s-0.34-0.75-0.75-0.75h-1.5v-1.5c0-0.41-0.34-0.75-0.75-0.75s-0.75,0.34-0.75,0.75v1.5h-1.5c-0.41,0-0.75,0.34-0.75,0.75 S9.33,13.75,9.74,13.75z" />
-    <path
-        android:fillColor="@android:color/white"
-        android:pathData="M17,4h-3V3.49c0-0.55-0.45-1-1-1h-2c-0.55,0-1,0.45-1,1V4H7C6.45,4,6,4.45,6,5v16c0,0.55,0.45,1,1,1h10c0.55,0,1-0.45,1-1 V5C18,4.45,17.55,4,17,4z M16.5,20.5h-9v-15h9V20.5z" />
-</vector>
\ No newline at end of file
diff --git a/packages/overlays/IconPackRoundedSettingsOverlay/res/drawable/ic_cellular_off.xml b/packages/overlays/IconPackRoundedSettingsOverlay/res/drawable/ic_cellular_off.xml
index 710387c..34d40ec 100644
--- a/packages/overlays/IconPackRoundedSettingsOverlay/res/drawable/ic_cellular_off.xml
+++ b/packages/overlays/IconPackRoundedSettingsOverlay/res/drawable/ic_cellular_off.xml
@@ -15,6 +15,7 @@
    limitations under the License.
 -->
 <vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:autoMirrored="true"
     android:height="24dp"
     android:tint="?android:attr/colorAccent"
     android:viewportHeight="24"
diff --git a/packages/overlays/IconPackRoundedSettingsOverlay/res/drawable/ic_chevron_right_24dp.xml b/packages/overlays/IconPackRoundedSettingsOverlay/res/drawable/ic_chevron_right_24dp.xml
index 7df03ad..1e86983 100644
--- a/packages/overlays/IconPackRoundedSettingsOverlay/res/drawable/ic_chevron_right_24dp.xml
+++ b/packages/overlays/IconPackRoundedSettingsOverlay/res/drawable/ic_chevron_right_24dp.xml
@@ -15,6 +15,7 @@
    limitations under the License.
 -->
 <vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:autoMirrored="true"
     android:height="24dp"
     android:tint="?android:attr/colorControlNormal"
     android:viewportHeight="24"
diff --git a/packages/overlays/IconPackRoundedSettingsOverlay/res/drawable/ic_content_copy_grey600_24dp.xml b/packages/overlays/IconPackRoundedSettingsOverlay/res/drawable/ic_content_copy_grey600_24dp.xml
index b3f6421..1feaab1 100644
--- a/packages/overlays/IconPackRoundedSettingsOverlay/res/drawable/ic_content_copy_grey600_24dp.xml
+++ b/packages/overlays/IconPackRoundedSettingsOverlay/res/drawable/ic_content_copy_grey600_24dp.xml
@@ -16,7 +16,7 @@
 -->
 <vector xmlns:android="http://schemas.android.com/apk/res/android"
     android:height="24dp"
-    android:tint="#757575"
+    android:tint="@*android:color/material_grey_600"
     android:viewportHeight="24"
     android:viewportWidth="24"
     android:width="24dp" >
diff --git a/packages/overlays/IconPackRoundedSettingsOverlay/res/drawable/ic_data_saver.xml b/packages/overlays/IconPackRoundedSettingsOverlay/res/drawable/ic_data_saver.xml
index 9acb62d..ba3c580 100644
--- a/packages/overlays/IconPackRoundedSettingsOverlay/res/drawable/ic_data_saver.xml
+++ b/packages/overlays/IconPackRoundedSettingsOverlay/res/drawable/ic_data_saver.xml
@@ -15,18 +15,19 @@
    limitations under the License.
 -->
 <vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:autoMirrored="true"
     android:height="24dp"
     android:tint="?android:attr/colorControlNormal"
     android:viewportHeight="24"
     android:viewportWidth="24"
     android:width="24dp" >
-    <path
-        android:fillColor="@android:color/white"
-        android:pathData="M3.36,7A10,10,0,0,0,20.27,17.64L18.1,16.39A7.5,7.5,0,1,1,11.25,4.56V2.05A10,10,0,0,0,3.36,7Z" />
-    <path
-        android:fillColor="@android:color/white"
-        android:pathData="M21,16.35a10,10,0,0,0-8.27-14.3V4.56a7.48,7.48,0,0,1,6.1,10.54Z" />
-    <path
-        android:fillColor="@android:color/white"
-        android:pathData="M8,12a0.76 0.76 ,0,0,0,0.75 0.75 h2.5v2.5a0.75 0.75 ,0,0,0,1.5,0v-2.5h2.5a0.75 0.75 ,0,0,0,0-1.5h-2.5V8.75a0.75 0.75 ,0,0,0-1.5,0v2.5H8.75A0.76 0.76 ,0,0,0,8,12Z" />
+    <group
+        android:translateX="2.000000"
+        android:translateY="2.000000" >
+        <path
+            android:fillColor="@android:color/white"
+            android:fillType="evenOdd"
+            android:pathData="M17.5000671,10 C17.5000671,6.198 14.6680671,3.064 11.0000671,2.574 L11.0000671,0.05 C16.0500671,0.55 20.0000671,4.82 20.0000671,10 C20.0000671,11.45 19.6800671,12.83 19.1200671,14.07 L16.9560671,12.796 C17.3040671,11.932 17.5000671,10.989 17.5000671,10 Z M10.0000671,17.5 C12.3900671,17.5 14.5140671,16.378 15.8870671,14.637 C16.6270671,15.073 18.0500671,15.91 18.0500671,15.91 C15.9790671,18.732 12.4710671,20.427 8.60106711,19.906 C4.22106711,19.316 0.68406711,15.774 0.0940671101,11.394 C-0.68693289,5.591 3.49306711,0.594 9.00006711,0.05 L9.00006711,2.574 C5.33206711,3.064 2.50006711,6.198 2.50006711,10 C2.50006711,14.142 5.85806711,17.5 10.0000671,17.5 Z M6,10 C6.00538581,9.58803794 6.33803794,9.25538581 6.75,9.25 L9.25,9.25 L9.25,6.75 C9.25,6.33578644 9.58578644,6 10,6 C10.4142136,6 10.75,6.33578644 10.75,6.75 L10.75,9.25 L13.25,9.25 C13.6642136,9.25 14,9.58578644 14,10 C14,10.4142136 13.6642136,10.75 13.25,10.75 L10.75,10.75 L10.75,13.25 C10.75,13.6642136 10.4142136,14 10,14 C9.58578644,14 9.25,13.6642136 9.25,13.25 L9.25,10.75 L6.75,10.75 C6.33803794,10.7446142 6.00538581,10.4119621 6,10 Z"
+            android:strokeWidth="1" />
+    </group>
 </vector>
\ No newline at end of file
diff --git a/packages/overlays/IconPackRoundedSettingsOverlay/res/drawable/ic_delete_accent.xml b/packages/overlays/IconPackRoundedSettingsOverlay/res/drawable/ic_delete_accent.xml
deleted file mode 100644
index d30eb7c..0000000
--- a/packages/overlays/IconPackRoundedSettingsOverlay/res/drawable/ic_delete_accent.xml
+++ /dev/null
@@ -1,32 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-   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.
--->
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
-    android:height="24dp"
-    android:tint="?android:attr/colorAccent"
-    android:viewportHeight="24"
-    android:viewportWidth="24"
-    android:width="24dp" >
-    <path
-        android:fillColor="@android:color/white"
-        android:pathData="M20,4h-1h-4c0-0.55-0.45-1-1-1h-4C9.45,3,9,3.45,9,4H5H4C3.59,4,3.25,4.34,3.25,4.75S3.59,5.5,4,5.5h1V18 c0,1.66,1.34,3,3,3h8c1.66,0,3-1.34,3-3V5.5h1c0.41,0,0.75-0.34,0.75-0.75S20.41,4,20,4z M17.5,18c0,0.83-0.67,1.5-1.5,1.5H8 c-0.83,0-1.5-0.67-1.5-1.5V5.5h11V18z" />
-    <path
-        android:fillColor="@android:color/white"
-        android:pathData="M14.25,8c-0.41,0-0.75,0.34-0.75,0.75v7.5c0,0.41,0.34,0.75,0.75,0.75S15,16.66,15,16.25v-7.5C15,8.34,14.66,8,14.25,8z" />
-    <path
-        android:fillColor="@android:color/white"
-        android:pathData="M9.75,8C9.34,8,9,8.34,9,8.75v7.5C9,16.66,9.34,17,9.75,17s0.75-0.34,0.75-0.75v-7.5C10.5,8.34,10.16,8,9.75,8z" />
-</vector>
\ No newline at end of file
diff --git a/packages/overlays/IconPackRoundedSettingsOverlay/res/drawable/ic_devices_other.xml b/packages/overlays/IconPackRoundedSettingsOverlay/res/drawable/ic_devices_other.xml
index 9283216..463525d 100644
--- a/packages/overlays/IconPackRoundedSettingsOverlay/res/drawable/ic_devices_other.xml
+++ b/packages/overlays/IconPackRoundedSettingsOverlay/res/drawable/ic_devices_other.xml
@@ -15,6 +15,7 @@
    limitations under the License.
 -->
 <vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:autoMirrored="true"
     android:height="24dp"
     android:viewportHeight="24"
     android:viewportWidth="24"
diff --git a/packages/overlays/IconPackRoundedSettingsOverlay/res/drawable/ic_eject_24dp.xml b/packages/overlays/IconPackRoundedSettingsOverlay/res/drawable/ic_eject_24dp.xml
index 4e37a88..0d4bd9b 100644
--- a/packages/overlays/IconPackRoundedSettingsOverlay/res/drawable/ic_eject_24dp.xml
+++ b/packages/overlays/IconPackRoundedSettingsOverlay/res/drawable/ic_eject_24dp.xml
@@ -16,6 +16,7 @@
 -->
 <vector xmlns:android="http://schemas.android.com/apk/res/android"
     android:height="24dp"
+    android:tint="?android:attr/colorControlNormal"
     android:viewportHeight="24"
     android:viewportWidth="24"
     android:width="24dp" >
diff --git a/packages/overlays/IconPackRoundedSettingsOverlay/res/drawable/ic_find_in_page_24px.xml b/packages/overlays/IconPackRoundedSettingsOverlay/res/drawable/ic_find_in_page_24px.xml
new file mode 100644
index 0000000..36d5c7c
--- /dev/null
+++ b/packages/overlays/IconPackRoundedSettingsOverlay/res/drawable/ic_find_in_page_24px.xml
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+   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.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:height="24dp"
+    android:tint="?android:attr/colorControlNormal"
+    android:viewportHeight="24"
+    android:viewportWidth="24"
+    android:width="24dp" >
+    <group
+        android:translateX="4.000000"
+        android:translateY="2.000000" >
+        <path
+            android:fillColor="@android:color/white"
+            android:fillType="evenOdd"
+            android:pathData="M8.0001,15.25 C6.2081,15.25 4.7501,13.792 4.7501,12 C4.7501,10.208 6.2081,8.75 8.0001,8.75 C9.7921,8.75 11.2501,10.208 11.2501,12 C11.2501,13.792 9.7921,15.25 8.0001,15.25 L8.0001,15.25 Z M1.5001,18.5 L1.5001,1.5 L9.3791,1.5 L14.5001,6.621 L14.5001,17.439 L11.8371,14.776 C12.5921,13.735 12.9531,12.393 12.6341,10.949 C12.2191,9.075 10.6391,7.595 8.7411,7.307 C5.5431,6.82 2.8181,9.547 3.3071,12.745 C3.5971,14.642 5.0781,16.221 6.9521,16.634 C8.3941,16.952 9.7361,16.592 10.7761,15.837 L13.4391,18.5 L1.5001,18.5 Z M10.0001,0 L1.5001,0 C0.6721,0 0.0001,0.672 0.0001,1.5 L0.0001,18.5 C0.0001,19.328 0.6721,20 1.5001,20 L14.5001,20 C15.3281,20 16.0001,19.328 16.0001,18.5 L16.0001,6 L10.0001,0 Z"
+            android:strokeWidth="1" />
+    </group>
+</vector>
\ No newline at end of file
diff --git a/packages/overlays/IconPackRoundedSettingsOverlay/res/drawable/ic_help_actionbar.xml b/packages/overlays/IconPackRoundedSettingsOverlay/res/drawable/ic_help_actionbar.xml
index e0a6f95..c7d672e 100644
--- a/packages/overlays/IconPackRoundedSettingsOverlay/res/drawable/ic_help_actionbar.xml
+++ b/packages/overlays/IconPackRoundedSettingsOverlay/res/drawable/ic_help_actionbar.xml
@@ -15,6 +15,7 @@
    limitations under the License.
 -->
 <vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:autoMirrored="true"
     android:height="24dp"
     android:tint="?android:attr/colorControlNormal"
     android:viewportHeight="24"
diff --git a/packages/overlays/IconPackRoundedSettingsOverlay/res/drawable/ic_network_cell.xml b/packages/overlays/IconPackRoundedSettingsOverlay/res/drawable/ic_network_cell.xml
index 10e0f2f..fbe5ef0 100644
--- a/packages/overlays/IconPackRoundedSettingsOverlay/res/drawable/ic_network_cell.xml
+++ b/packages/overlays/IconPackRoundedSettingsOverlay/res/drawable/ic_network_cell.xml
@@ -15,6 +15,7 @@
    limitations under the License.
 -->
 <vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:autoMirrored="true"
     android:height="24dp"
     android:tint="?android:attr/colorControlNormal"
     android:viewportHeight="24"
diff --git a/packages/overlays/IconPackRoundedSettingsOverlay/res/drawable/ic_notifications_off_24dp.xml b/packages/overlays/IconPackRoundedSettingsOverlay/res/drawable/ic_notifications_off_24dp.xml
index 81f18fb..56a67c9 100644
--- a/packages/overlays/IconPackRoundedSettingsOverlay/res/drawable/ic_notifications_off_24dp.xml
+++ b/packages/overlays/IconPackRoundedSettingsOverlay/res/drawable/ic_notifications_off_24dp.xml
@@ -15,6 +15,7 @@
    limitations under the License.
 -->
 <vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:autoMirrored="true"
     android:height="24dp"
     android:tint="?android:attr/colorControlNormal"
     android:viewportHeight="24"
diff --git a/packages/overlays/IconPackRoundedSettingsOverlay/res/drawable/ic_scan_24dp.xml b/packages/overlays/IconPackRoundedSettingsOverlay/res/drawable/ic_scan_24dp.xml
new file mode 100644
index 0000000..3d79f79
--- /dev/null
+++ b/packages/overlays/IconPackRoundedSettingsOverlay/res/drawable/ic_scan_24dp.xml
@@ -0,0 +1,55 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+   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.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:height="24dp"
+    android:tint="?android:attr/colorAccent"
+    android:viewportHeight="24"
+    android:viewportWidth="24"
+    android:width="24dp" >
+    <group
+        android:translateX="3.000000"
+        android:translateY="3.000000" >
+        <path
+            android:fillColor="@android:color/white"
+            android:pathData="M4.5,1.5 L4.5,4.5 L1.5,4.5 L1.5,1.5 L4.5,1.5 L4.5,1.5 Z M5,0 L1,0 C0.44771525,0 0,0.44771525 0,1 L0,5 C0,5.55228475 0.44771525,6 1,6 L5,6 C5.55228475,6 6,5.55228475 6,5 L6,1 C6,0.44771525 5.55228475,0 5,0 Z"
+            android:strokeWidth="1" />
+        <path
+            android:fillColor="@android:color/white"
+            android:pathData="M16.5,1.5 L16.5,4.5 L13.5,4.5 L13.5,1.5 L16.5,1.5 L16.5,1.5 Z M17,0 L13,0 C12.4477153,0 12,0.44771525 12,1 L12,5 C12,5.55228475 12.4477153,6 13,6 L17,6 C17.5522847,6 18,5.55228475 18,5 L18,1 C18,0.44771525 17.5522847,0 17,0 Z"
+            android:strokeWidth="1" />
+        <path
+            android:fillColor="@android:color/white"
+            android:pathData="M4.5,13.5 L4.5,16.5 L1.5,16.5 L1.5,13.5 L4.5,13.5 L4.5,13.5 Z M5,12 L1,12 C0.44771525,12 0,12.4477153 0,13 L0,17 C0,17.5522847 0.44771525,18 1,18 L5,18 C5.55228475,18 6,17.5522847 6,17 L6,13 C6,12.4477153 5.55228475,12 5,12 Z"
+            android:strokeWidth="1" />
+        <path
+            android:fillColor="@android:color/white"
+            android:pathData="M13.75,12.25 L17.25,12.25 C17.6619621,12.2553858 17.9946142,12.5880379 18,13 C17.9946142,13.4119621 17.6619621,13.7446142 17.25,13.75 L13.75,13.75 L13.75,17.25 C13.75,17.6642136 13.4142136,18 13,18 C12.5857864,18 12.25,17.6642136 12.25,17.25 L12.25,13.75 L8.74999997,13.75 C8.33578642,13.75 8,13.4142136 8,13 C8,12.5857864 8.33578642,12.25 8.74999997,12.25 L12.25,12.25 L12.25,8.75 C12.2553858,8.33803794 12.5880379,8.00538581 13,8 C13.4119621,8.00538581 13.7446142,8.33803794 13.75,8.75 L13.75,12.25 Z"
+            android:strokeWidth="1" />
+        <path
+            android:fillColor="@android:color/white"
+            android:pathData="M1.6,8 L0.4,8 C0.1790861,8 0,8.1790861 0,8.4 L0,9.6 C0,9.8209139 0.1790861,10 0.4,10 L1.6,10 C1.8209139,10 2,9.8209139 2,9.6 L2,8.4 C2,8.1790861 1.8209139,8 1.6,8 L1.6,8 Z"
+            android:strokeWidth="1" />
+        <path
+            android:fillColor="@android:color/white"
+            android:pathData="M9,0 C8.58803794,0.00538581231 8.25538581,0.338037936 8.25,0.75 L8.25,5.75 C8.25000002,6.16421355 8.58578645,6.49999997 9,6.49999997 C9.41421355,6.49999997 9.74999998,6.16421355 9.75,5.75 L9.75,0.75 C9.74461419,0.338037936 9.41196206,0.00538581231 9,0 L9,0 Z"
+            android:strokeWidth="1" />
+        <path
+            android:fillColor="@android:color/white"
+            android:pathData="M5.6,8 L4.4,8 C4.1790861,8 4,8.1790861 4,8.4 L4,9.6 C4,9.8209139 4.1790861,10 4.4,10 L5.6,10 C5.8209139,10 6,9.8209139 6,9.6 L6,8.4 C6,8.1790861 5.8209139,8 5.6,8 Z"
+            android:strokeWidth="1" />
+    </group>
+</vector>
\ No newline at end of file
diff --git a/packages/overlays/IconPackRoundedSettingsOverlay/res/drawable/ic_settings_data_usage.xml b/packages/overlays/IconPackRoundedSettingsOverlay/res/drawable/ic_settings_data_usage.xml
index b9c131b..855e4bb 100644
--- a/packages/overlays/IconPackRoundedSettingsOverlay/res/drawable/ic_settings_data_usage.xml
+++ b/packages/overlays/IconPackRoundedSettingsOverlay/res/drawable/ic_settings_data_usage.xml
@@ -22,8 +22,7 @@
     android:width="24dp" >
     <path
         android:fillColor="@android:color/white"
-        android:pathData="M12,20c-4.4,0-8-3.6-8-8c0-4.2,3.2-7.6,7.2-8V2C5.7,2.4,1.6,7.3,2,12.8c0.4,5.5,5.3,9.6,10.8,9.2c4.9-0.4,8.8-4.3,9.2-9.2 h-2C19.6,16.8,16.2,20,12,20z" />
-    <path
-        android:fillColor="@android:color/white"
-        android:pathData="M20,11.2h2c-0.4-4.9-4.3-8.9-9.2-9.2v2C16.6,4.4,19.6,7.4,20,11.2z" />
+        android:fillType="evenOdd"
+        android:pathData="M19.5000671,12 C19.5000671,8.198 16.6680671,5.064 13.0000671,4.574 L13.0000671,2.05 C18.0500671,2.55 22.0000671,6.82 22.0000671,12 C22.0000671,13.45 21.6800671,14.83 21.1200671,16.07 L18.9560671,14.796 C19.3040671,13.932 19.5000671,12.989 19.5000671,12 Z M12.0000671,19.5 C14.3900671,19.5 16.5140671,18.378 17.8870671,16.637 C18.6270671,17.073 20.0500671,17.91 20.0500671,17.91 C17.9790671,20.732 14.4710671,22.427 10.6010671,21.906 C6.22106711,21.316 2.68406711,17.774 2.09406711,13.394 C1.31306711,7.591 5.49306711,2.594 11.0000671,2.05 L11.0000671,4.574 C7.33206711,5.064 4.50006711,8.198 4.50006711,12 C4.50006711,16.142 7.85806711,19.5 12.0000671,19.5 Z"
+        android:strokeWidth="1" />
 </vector>
\ No newline at end of file
diff --git a/packages/overlays/IconPackRoundedSettingsOverlay/res/drawable/ic_settings_disable.xml b/packages/overlays/IconPackRoundedSettingsOverlay/res/drawable/ic_settings_disable.xml
new file mode 100644
index 0000000..0572fb7
--- /dev/null
+++ b/packages/overlays/IconPackRoundedSettingsOverlay/res/drawable/ic_settings_disable.xml
@@ -0,0 +1,37 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+   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.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:height="24dp"
+    android:tint="?android:attr/colorControlNormal"
+    android:viewportHeight="24"
+    android:viewportWidth="24"
+    android:width="24dp" >
+    <group
+        android:translateX="1.000000"
+        android:translateY="2.000000" >
+        <path
+            android:fillColor="@android:color/white"
+            android:fillType="evenOdd"
+            android:pathData="M11,18.5 C6.313,18.5 2.5,14.687 2.5,10 C2.5,8.182 3.078,6.498 4.055,5.114 L15.887,16.945 C14.503,17.922 12.818,18.5 11,18.5 M20.031,18.969 L2.032,0.971 C1.739,0.678 1.264,0.678 0.971,0.971 C0.678,1.264 0.678,1.738 0.971,2.031 L2.983,4.043 C1.742,5.707 1,7.765 1,10 C1,15.522 5.477,20 11,20 C13.236,20 15.293,19.258 16.957,18.017 L18.971,20.029 C19.117,20.176 19.309,20.249 19.501,20.249 C19.693,20.249 19.885,20.176 20.031,20.029 C20.324,19.736 20.324,19.262 20.031,18.969"
+            android:strokeWidth="1" />
+        <path
+            android:fillColor="@android:color/white"
+            android:fillType="evenOdd"
+            android:pathData="M11,1.5 C15.687,1.5 19.5,5.313 19.5,10 C19.5,11.782 18.946,13.436 18.006,14.804 L19.078,15.877 C20.281,14.226 21,12.199 21,10 C21,4.478 16.522,0 11,0 C8.801,0 6.774,0.719 5.124,1.922 L6.196,2.994 C7.564,2.054 9.218,1.5 11,1.5"
+            android:strokeWidth="1" />
+    </group>
+</vector>
\ No newline at end of file
diff --git a/packages/overlays/IconPackRoundedSettingsOverlay/res/drawable/ic_settings_enable.xml b/packages/overlays/IconPackRoundedSettingsOverlay/res/drawable/ic_settings_enable.xml
new file mode 100644
index 0000000..ec608cd
--- /dev/null
+++ b/packages/overlays/IconPackRoundedSettingsOverlay/res/drawable/ic_settings_enable.xml
@@ -0,0 +1,37 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+   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.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:height="24dp"
+    android:tint="?android:attr/colorControlNormal"
+    android:viewportHeight="24"
+    android:viewportWidth="24"
+    android:width="24dp" >
+    <group
+        android:translateX="2.000000"
+        android:translateY="2.000000" >
+        <path
+            android:fillColor="@android:color/white"
+            android:fillType="evenOdd"
+            android:pathData="M12.2502,0.2637 L12.2502,1.8127 C15.8472,2.8017 18.5002,6.0927 18.5002,9.9997 C18.5002,14.6867 14.6872,18.4997 10.0002,18.4997 C5.3132,18.4997 1.5002,14.6867 1.5002,9.9997 C1.5002,6.0927 4.1532,2.8017 7.7502,1.8127 L7.7502,0.2637 C3.3122,1.2847 0.0002,5.2517 0.0002,9.9997 C0.0002,15.5227 4.4772,19.9997 10.0002,19.9997 C15.5222,19.9997 20.0002,15.5227 20.0002,9.9997 C20.0002,5.2517 16.6872,1.2847 12.2502,0.2637"
+            android:strokeWidth="1" />
+        <path
+            android:fillColor="@android:color/white"
+            android:fillType="evenOdd"
+            android:pathData="M15.0304,9.9697 C14.7374,9.6767 14.2624,9.6767 13.9694,9.9697 L10.7504,13.1897 L10.7504,0.7387 C10.7504,0.3307 10.4144,-0.0003 10.0004,-0.0003 C9.5864,-0.0003 9.2504,0.3307 9.2504,0.7387 L9.2504,13.1897 L6.0304,9.9697 C5.7374,9.6767 5.2624,9.6767 4.9694,9.9697 C4.6764,10.2627 4.6764,10.7377 4.9694,11.0307 L9.4694,15.5307 C9.6164,15.6767 9.8074,15.7497 10.0004,15.7497 C10.1924,15.7497 10.3844,15.6767 10.5304,15.5307 L15.0304,11.0307 C15.3234,10.7377 15.3234,10.2627 15.0304,9.9697"
+            android:strokeWidth="1" />
+    </group>
+</vector>
\ No newline at end of file
diff --git a/packages/overlays/IconPackRoundedSettingsOverlay/res/drawable/ic_settings_language.xml b/packages/overlays/IconPackRoundedSettingsOverlay/res/drawable/ic_settings_language.xml
new file mode 100644
index 0000000..730942b
--- /dev/null
+++ b/packages/overlays/IconPackRoundedSettingsOverlay/res/drawable/ic_settings_language.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+   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.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:height="24dp"
+    android:tint="?android:attr/colorControlNormal"
+    android:viewportHeight="24"
+    android:viewportWidth="24"
+    android:width="24dp" >
+    <path
+        android:fillColor="@android:color/white"
+        android:pathData="M12,22c5.52,0,10-4.48,10-10c0-5.52-4.48-10-10-10C6.48,2,2,6.48,2,12C2,17.52,6.48,22,12,22z M4.5,16h3.14 c0.4,1.41,1.01,2.8,1.84,4.12C7.34,19.45,5.55,17.95,4.5,16z M3.5,12c0-0.87,0.13-1.71,0.38-2.5H7.3c-0.29,1.66-0.3,3.34-0.01,5 H3.88C3.63,13.71,3.5,12.87,3.5,12z M20.5,12c0,0.87-0.13,1.71-0.38,2.5h-3.42c0.29-1.66,0.28-3.34-0.01-5h3.43 C20.37,10.29,20.5,11.13,20.5,12z M15.2,14.5H8.8c-0.33-1.66-0.32-3.34,0.01-5h6.39C15.53,11.16,15.53,12.84,15.2,14.5z M11.55,20.48c-1.08-1.43-1.86-2.94-2.36-4.48h5.62c-0.5,1.54-1.28,3.05-2.36,4.48c-0.15,0.01-0.3,0.02-0.45,0.02 S11.7,20.49,11.55,20.48z M14.51,20.12c0.83-1.32,1.44-2.71,1.84-4.12h3.14C18.45,17.95,16.66,19.45,14.51,20.12z M19.5,8h-3.15 c-0.4-1.41-1.01-2.79-1.84-4.12C16.66,4.54,18.45,6.04,19.5,8z M12.45,3.52C13.52,4.96,14.3,6.46,14.8,8H9.2 c0.5-1.54,1.28-3.04,2.35-4.48C11.7,3.51,11.85,3.5,12,3.5S12.3,3.51,12.45,3.52z M9.49,3.88C8.67,5.21,8.06,6.59,7.65,8H4.5 C5.55,6.04,7.34,4.54,9.49,3.88z" />
+</vector>
\ No newline at end of file
diff --git a/packages/overlays/IconPackFilledSettingsOverlay/res/drawable/ic_delete_accent.xml b/packages/overlays/IconPackRoundedSettingsOverlay/res/drawable/ic_settings_multiuser.xml
similarity index 68%
copy from packages/overlays/IconPackFilledSettingsOverlay/res/drawable/ic_delete_accent.xml
copy to packages/overlays/IconPackRoundedSettingsOverlay/res/drawable/ic_settings_multiuser.xml
index e65987e..83d9d2a 100644
--- a/packages/overlays/IconPackFilledSettingsOverlay/res/drawable/ic_delete_accent.xml
+++ b/packages/overlays/IconPackRoundedSettingsOverlay/res/drawable/ic_settings_multiuser.xml
@@ -16,14 +16,14 @@
 -->
 <vector xmlns:android="http://schemas.android.com/apk/res/android"
     android:height="24dp"
-    android:tint="?android:attr/colorAccent"
+    android:tint="?android:attr/colorControlNormal"
     android:viewportHeight="24"
     android:viewportWidth="24"
     android:width="24dp" >
     <path
         android:fillColor="@android:color/white"
-        android:pathData="M18,4h-2.5l-0.71-0.71C14.61,3.11,14.35,3,14.09,3H9.9C9.64,3,9.38,3.11,9.2,3.29L8.49,4h-2.5c-0.55,0-1,0.45-1,1 s0.45,1,1,1h12c0.55,0,1-0.45,1-1C19,4.45,18.55,4,18,4z" />
+        android:pathData="M4,19c0,0.55,0.45,1,1,1h14c0.55,0,1-0.45,1-1v-3c0-1.66-1.34-3-3-3H7c-1.66,0-3,1.34-3,3V19z M5.5,16 c0-0.83,0.67-1.5,1.5-1.5h10c0.83,0,1.5,0.67,1.5,1.5v2.5h-13V16z" />
     <path
         android:fillColor="@android:color/white"
-        android:pathData="M6,19c0,1.1,0.9,2,2,2h8c1.1,0,2-0.9,2-2V7H6V19z" />
+        android:pathData="M8,8c0,2.21,1.79,4,4,4s4-1.79,4-4c0-2.21-1.79-4-4-4S8,5.79,8,8z M12,5.5c1.38,0,2.5,1.12,2.5,2.5 c0,1.38-1.12,2.5-2.5,2.5S9.5,9.38,9.5,8C9.5,6.62,10.62,5.5,12,5.5z" />
 </vector>
\ No newline at end of file
diff --git a/packages/overlays/IconPackRoundedSettingsOverlay/res/drawable/ic_settings_wireless_white.xml b/packages/overlays/IconPackRoundedSettingsOverlay/res/drawable/ic_settings_wireless_white.xml
deleted file mode 100644
index 0a1c305..0000000
--- a/packages/overlays/IconPackRoundedSettingsOverlay/res/drawable/ic_settings_wireless_white.xml
+++ /dev/null
@@ -1,34 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-   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.
--->
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
-    android:height="24dp"
-    android:viewportHeight="24"
-    android:viewportWidth="24"
-    android:width="24dp" >
-    <path
-        android:fillColor="@android:color/white"
-        android:pathData="M12,2.75C7.95,2.69,4.05,4.3,1.22,7.2C0.96,7.5,0.97,7.95,1.24,8.23C1.53,8.53,2,8.54,2.3,8.25c2.55-2.61,6.05-4.06,9.7-4 c3.65-0.06,7.17,1.4,9.72,4.02c0.28,0.27,0.73,0.28,1.03,0.01c0.31-0.28,0.33-0.75,0.05-1.06C19.96,4.32,16.06,2.69,12,2.75z" />
-    <path
-        android:fillColor="@android:color/white"
-        android:pathData="M15.78,14.82c0.05,0.06,0.1,0.11,0.17,0.15c0.34,0.23,0.81,0.14,1.04-0.21s0.14-0.81-0.21-1.04 c-2.64-2.64-6.91-2.64-9.55,0c-0.27,0.29-0.27,0.73,0,1.02c0.28,0.3,0.76,0.32,1.06,0.04h0.03c0,0,0,0,0.01-0.01 c2.05-2.05,5.37-2.04,7.42,0.01C15.75,14.8,15.76,14.81,15.78,14.82z" />
-    <path
-        android:fillColor="@android:color/white"
-        android:pathData="M 12 17 C 12.8284271247 17 13.5 17.6715728753 13.5 18.5 C 13.5 19.3284271247 12.8284271247 20 12 20 C 11.1715728753 20 10.5 19.3284271247 10.5 18.5 C 10.5 17.6715728753 11.1715728753 17 12 17 Z" />
-    <path
-        android:fillColor="@android:color/white"
-        android:pathData="M20.03,11.79c0.3-0.29,0.3-0.77,0.01-1.06h-0.01c-2.12-2.18-5.01-3.44-8.04-3.5c-3.04,0.06-5.93,1.32-8.05,3.5 c-0.29,0.3-0.28,0.77,0.01,1.06c0.3,0.29,0.77,0.28,1.06-0.01c1.85-1.88,4.36-2.96,7-3c2.62,0.05,5.11,1.13,6.95,3 C19.25,12.07,19.73,12.08,20.03,11.79z" />
-</vector>
\ No newline at end of file
diff --git a/packages/overlays/IconPackRoundedSettingsOverlay/res/drawable/ic_sync_problem_24dp.xml b/packages/overlays/IconPackRoundedSettingsOverlay/res/drawable/ic_sync_problem_24dp.xml
new file mode 100644
index 0000000..e9a07cc
--- /dev/null
+++ b/packages/overlays/IconPackRoundedSettingsOverlay/res/drawable/ic_sync_problem_24dp.xml
@@ -0,0 +1,37 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+   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.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:height="24dp"
+    android:tint="?android:attr/colorControlNormal"
+    android:viewportHeight="24"
+    android:viewportWidth="24"
+    android:width="24dp" >
+    <group
+        android:translateX="3.000000"
+        android:translateY="3.000000" >
+        <path
+            android:fillColor="@android:color/white"
+            android:fillType="evenOdd"
+            android:pathData="M16.7178,12.626 C17.2378,11.522 17.5288,10.291 17.5288,9 C17.5288,6.119 16.1088,3.539 13.8488,2 L15.7588,2 C16.1578,2 16.4988,1.659 16.4988,1.25 C16.4988,0.84 16.1578,0.5 15.7488,0.5 L10.7488,0.5 C10.3388,0.5 9.9988,0.84 9.9988,1.25 L9.9988,6.25 C9.9988,6.659 10.3388,7 10.7488,7 C11.1578,7 11.4988,6.659 11.4988,6.25 L11.4988,2.47 C14.1978,3.489 16.0188,6.039 16.0188,9 C16.0188,9.785 15.8828,10.542 15.6438,11.252 C15.0498,10.788 14.3108,10.5 13.4988,10.5 C11.5658,10.5 9.9988,12.066 9.9988,14 C9.9988,15.933 11.5658,17.5 13.4988,17.5 C15.4318,17.5 16.9988,15.933 16.9988,14 C16.9988,13.512 16.8978,13.048 16.7178,12.626 L16.7178,12.626 Z M13.4988,16.5 C13.2228,16.5 12.9988,16.275 12.9988,16 C12.9988,15.723 13.2228,15.5 13.4988,15.5 C13.7748,15.5 13.9988,15.723 13.9988,16 C13.9988,16.275 13.7748,16.5 13.4988,16.5 L13.4988,16.5 Z M13.9988,14 C13.9988,14.275 13.7748,14.5 13.4988,14.5 C13.2228,14.5 12.9988,14.275 12.9988,14 L12.9988,12 C12.9988,11.723 13.2228,11.5 13.4988,11.5 C13.7748,11.5 13.9988,11.723 13.9988,12 L13.9988,14 Z"
+            android:strokeWidth="1" />
+        <path
+            android:fillColor="@android:color/white"
+            android:fillType="evenOdd"
+            android:pathData="M7.0811,0.7197 C3.1901,1.6097 0.4801,5.0097 0.4801,8.9997 C0.4801,11.8797 1.9011,14.4587 4.1611,15.9987 L2.2511,15.9987 C1.8411,15.9987 1.5011,16.3397 1.5011,16.7497 C1.5011,17.1577 1.8411,17.4997 2.2511,17.4997 L7.2511,17.4997 C7.6621,17.4997 8.0011,17.1577 8.0011,16.7497 L8.0011,11.7487 C8.0011,11.3397 7.6621,10.9997 7.2511,10.9997 C6.8411,10.9997 6.5021,11.3397 6.5021,11.7487 L6.5021,15.5287 C3.8011,14.5107 1.9811,11.9587 1.9811,8.9997 C1.9811,5.7197 4.2111,2.9097 7.4211,2.1807 C7.8221,2.0907 8.0811,1.6797 7.9801,1.2797 C7.9041,0.9347 7.5961,0.7017 7.2491,0.7017 C7.1941,0.7017 7.1381,0.7067 7.0811,0.7197"
+            android:strokeWidth="1" />
+    </group>
+</vector>
\ No newline at end of file
diff --git a/packages/overlays/IconPackRoundedSystemUIOverlay/res/drawable/ic_arrow_back.xml b/packages/overlays/IconPackRoundedSystemUIOverlay/res/drawable/ic_arrow_back.xml
index 03f06e9..34f79b4 100644
--- a/packages/overlays/IconPackRoundedSystemUIOverlay/res/drawable/ic_arrow_back.xml
+++ b/packages/overlays/IconPackRoundedSystemUIOverlay/res/drawable/ic_arrow_back.xml
@@ -15,6 +15,7 @@
    limitations under the License.
 -->
 <vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:autoMirrored="true"
     android:height="24dp"
     android:tint="?android:attr/colorControlNormal"
     android:viewportHeight="24"
diff --git a/packages/overlays/IconPackRoundedSystemUIOverlay/res/drawable/ic_brightness_thumb.xml b/packages/overlays/IconPackRoundedSystemUIOverlay/res/drawable/ic_brightness_thumb.xml
index 697d1c2..62fcd4c 100644
--- a/packages/overlays/IconPackRoundedSystemUIOverlay/res/drawable/ic_brightness_thumb.xml
+++ b/packages/overlays/IconPackRoundedSystemUIOverlay/res/drawable/ic_brightness_thumb.xml
@@ -20,7 +20,7 @@
     android:viewportWidth="24"
     android:width="24dp" >
     <path
-        android:fillColor="?android:attr/colorPrimary"
+        android:fillColor="?android:attr/colorBackgroundFloating"
         android:pathData="M 12 0 L 12 0 Q 24 0 24 12 L 24 12 Q 24 24 12 24 L 12 24 Q 0 24 0 12 L 0 12 Q 0 0 12 0 Z" />
     <path
         android:fillColor="?android:attr/colorControlActivated"
diff --git a/packages/overlays/IconPackRoundedSystemUIOverlay/res/drawable/ic_camera.xml b/packages/overlays/IconPackRoundedSystemUIOverlay/res/drawable/ic_camera.xml
index 294e181..142e078 100644
--- a/packages/overlays/IconPackRoundedSystemUIOverlay/res/drawable/ic_camera.xml
+++ b/packages/overlays/IconPackRoundedSystemUIOverlay/res/drawable/ic_camera.xml
@@ -15,10 +15,10 @@
    limitations under the License.
 -->
 <vector xmlns:android="http://schemas.android.com/apk/res/android"
-    android:height="24dp"
+    android:height="17dp"
     android:viewportHeight="24"
     android:viewportWidth="24"
-    android:width="24dp" >
+    android:width="17dp" >
     <path
         android:fillColor="@android:color/white"
         android:pathData="M22,7c0-1.1-0.9-2-2-2h-3l-1.41-1.41C15.21,3.21,14.7,3,14.17,3H9.83C9.3,3,8.79,3.21,8.41,3.59L7,5H4C2.9,5,2,5.9,2,7v12 c0,1.1,0.9,2,2,2h16c1.1,0,2-0.9,2-2V7z M20.5,19c0,0.28-0.22,0.5-0.5,0.5H4c-0.28,0-0.5-0.22-0.5-0.5V7c0-0.28,0.22-0.5,0.5-0.5 h3.62l1.85-1.85C9.57,4.55,9.69,4.5,9.83,4.5h4.34c0.13,0,0.26,0.05,0.35,0.15l1.85,1.85H20c0.28,0,0.5,0.22,0.5,0.5V19z" />
diff --git a/packages/overlays/IconPackRoundedSystemUIOverlay/res/drawable/ic_cast_connected.xml b/packages/overlays/IconPackRoundedSystemUIOverlay/res/drawable/ic_cast_connected.xml
index 14d88e7..f282166 100644
--- a/packages/overlays/IconPackRoundedSystemUIOverlay/res/drawable/ic_cast_connected.xml
+++ b/packages/overlays/IconPackRoundedSystemUIOverlay/res/drawable/ic_cast_connected.xml
@@ -15,10 +15,10 @@
    limitations under the License.
 -->
 <vector xmlns:android="http://schemas.android.com/apk/res/android"
-    android:height="17dp"
+    android:height="24dp"
     android:viewportHeight="24"
     android:viewportWidth="24"
-    android:width="17dp" >
+    android:width="24dp" >
     <path
         android:fillColor="@android:color/white"
         android:pathData="M20.5,4h-17C3.49,4,3.48,4,3.47,4C2.64,4.02,1.98,4.7,2,5.53v3.18c0,0.41,0.34,0.75,0.75,0.75S3.5,9.12,3.5,8.71 c0-1.96,0-3.21,0-3.21l17,0.03V18.5h-7.35c-0.41,0-0.75,0.34-0.75,0.75S12.74,20,13.15,20h7.35c0.01,0,0.02,0,0.03,0 c0.83-0.02,1.49-0.7,1.47-1.53V5.53c0-0.01,0-0.02,0-0.03C22,4.67,21.33,4,20.5,4z" />
diff --git a/packages/overlays/IconPackRoundedSystemUIOverlay/res/drawable/ic_data_saver.xml b/packages/overlays/IconPackRoundedSystemUIOverlay/res/drawable/ic_data_saver.xml
index ee11b84..cdc3bfb 100644
--- a/packages/overlays/IconPackRoundedSystemUIOverlay/res/drawable/ic_data_saver.xml
+++ b/packages/overlays/IconPackRoundedSystemUIOverlay/res/drawable/ic_data_saver.xml
@@ -15,17 +15,17 @@
    limitations under the License.
 -->
 <vector xmlns:android="http://schemas.android.com/apk/res/android"
-    android:height="18dp "
+    android:height="18dp"
     android:viewportHeight="24"
     android:viewportWidth="24"
-    android:width="18dp " >
-    <path
-        android:fillColor="@android:color/white"
-        android:pathData="M3.36,7A10,10,0,0,0,20.27,17.64L18.1,16.39A7.5,7.5,0,1,1,11.25,4.56V2.05A10,10,0,0,0,3.36,7Z" />
-    <path
-        android:fillColor="@android:color/white"
-        android:pathData="M21,16.35a10,10,0,0,0-8.27-14.3V4.56a7.48,7.48,0,0,1,6.1,10.54Z" />
-    <path
-        android:fillColor="@android:color/white"
-        android:pathData="M8,12a0.76 0.76 ,0,0,0,0.75 0.75 h2.5v2.5a0.75 0.75 ,0,0,0,1.5,0v-2.5h2.5a0.75 0.75 ,0,0,0,0-1.5h-2.5V8.75a0.75 0.75 ,0,0,0-1.5,0v2.5H8.75A0.76 0.76 ,0,0,0,8,12Z" />
+    android:width="18dp" >
+    <group
+        android:translateX="2.000000"
+        android:translateY="2.000000" >
+        <path
+            android:fillColor="@android:color/white"
+            android:fillType="evenOdd"
+            android:pathData="M17.5000671,10 C17.5000671,6.198 14.6680671,3.064 11.0000671,2.574 L11.0000671,0.05 C16.0500671,0.55 20.0000671,4.82 20.0000671,10 C20.0000671,11.45 19.6800671,12.83 19.1200671,14.07 L16.9560671,12.796 C17.3040671,11.932 17.5000671,10.989 17.5000671,10 Z M10.0000671,17.5 C12.3900671,17.5 14.5140671,16.378 15.8870671,14.637 C16.6270671,15.073 18.0500671,15.91 18.0500671,15.91 C15.9790671,18.732 12.4710671,20.427 8.60106711,19.906 C4.22106711,19.316 0.68406711,15.774 0.0940671101,11.394 C-0.68693289,5.591 3.49306711,0.594 9.00006711,0.05 L9.00006711,2.574 C5.33206711,3.064 2.50006711,6.198 2.50006711,10 C2.50006711,14.142 5.85806711,17.5 10.0000671,17.5 Z M6,10 C6.00538581,9.58803794 6.33803794,9.25538581 6.75,9.25 L9.25,9.25 L9.25,6.75 C9.25,6.33578644 9.58578644,6 10,6 C10.4142136,6 10.75,6.33578644 10.75,6.75 L10.75,9.25 L13.25,9.25 C13.6642136,9.25 14,9.58578644 14,10 C14,10.4142136 13.6642136,10.75 13.25,10.75 L10.75,10.75 L10.75,13.25 C10.75,13.6642136 10.4142136,14 10,14 C9.58578644,14 9.25,13.6642136 9.25,13.25 L9.25,10.75 L6.75,10.75 C6.33803794,10.7446142 6.00538581,10.4119621 6,10 Z"
+            android:strokeWidth="1" />
+    </group>
 </vector>
\ No newline at end of file
diff --git a/packages/overlays/IconPackRoundedSystemUIOverlay/res/drawable/ic_data_saver_off.xml b/packages/overlays/IconPackRoundedSystemUIOverlay/res/drawable/ic_data_saver_off.xml
index 3d620a1..7dab949 100644
--- a/packages/overlays/IconPackRoundedSystemUIOverlay/res/drawable/ic_data_saver_off.xml
+++ b/packages/overlays/IconPackRoundedSystemUIOverlay/res/drawable/ic_data_saver_off.xml
@@ -21,8 +21,7 @@
     android:width="24dp" >
     <path
         android:fillColor="@android:color/white"
-        android:pathData="M3.36,7A10,10,0,0,0,20.27,17.64L18.1,16.39A7.5,7.5,0,1,1,11.25,4.56V2.05A10,10,0,0,0,3.36,7Z" />
-    <path
-        android:fillColor="@android:color/white"
-        android:pathData="M21,16.35a10,10,0,0,0-8.27-14.3V4.56a7.48,7.48,0,0,1,6.1,10.54Z" />
+        android:fillType="evenOdd"
+        android:pathData="M19.5000671,12 C19.5000671,8.198 16.6680671,5.064 13.0000671,4.574 L13.0000671,2.05 C18.0500671,2.55 22.0000671,6.82 22.0000671,12 C22.0000671,13.45 21.6800671,14.83 21.1200671,16.07 L18.9560671,14.796 C19.3040671,13.932 19.5000671,12.989 19.5000671,12 Z M12.0000671,19.5 C14.3900671,19.5 16.5140671,18.378 17.8870671,16.637 C18.6270671,17.073 20.0500671,17.91 20.0500671,17.91 C17.9790671,20.732 14.4710671,22.427 10.6010671,21.906 C6.22106711,21.316 2.68406711,17.774 2.09406711,13.394 C1.31306711,7.591 5.49306711,2.594 11.0000671,2.05 L11.0000671,4.574 C7.33206711,5.064 4.50006711,8.198 4.50006711,12 C4.50006711,16.142 7.85806711,19.5 12.0000671,19.5 Z"
+        android:strokeWidth="1" />
 </vector>
\ No newline at end of file
diff --git a/packages/overlays/IconPackRoundedSystemUIOverlay/res/drawable/ic_qs_bluetooth_connecting.xml b/packages/overlays/IconPackRoundedSystemUIOverlay/res/drawable/ic_qs_bluetooth_connecting.xml
index f2284bc..85c2bcd 100644
--- a/packages/overlays/IconPackRoundedSystemUIOverlay/res/drawable/ic_qs_bluetooth_connecting.xml
+++ b/packages/overlays/IconPackRoundedSystemUIOverlay/res/drawable/ic_qs_bluetooth_connecting.xml
@@ -16,6 +16,7 @@
 -->
 <vector xmlns:android="http://schemas.android.com/apk/res/android"
     android:height="24dp"
+    android:tint="?android:attr/colorControlNormal"
     android:viewportHeight="24"
     android:viewportWidth="24"
     android:width="24dp" >
diff --git a/packages/overlays/IconPackRoundedSystemUIOverlay/res/drawable/ic_volume_alarm_mute.xml b/packages/overlays/IconPackRoundedSystemUIOverlay/res/drawable/ic_volume_alarm_mute.xml
index 15201e9..3a26cba 100644
--- a/packages/overlays/IconPackRoundedSystemUIOverlay/res/drawable/ic_volume_alarm_mute.xml
+++ b/packages/overlays/IconPackRoundedSystemUIOverlay/res/drawable/ic_volume_alarm_mute.xml
@@ -16,6 +16,7 @@
 -->
 <vector xmlns:android="http://schemas.android.com/apk/res/android"
     android:height="24dp"
+    android:tint="?android:attr/colorControlNormal"
     android:viewportHeight="24"
     android:viewportWidth="24"
     android:width="24dp" >
diff --git a/packages/overlays/IconPackRoundedSystemUIOverlay/res/drawable/ic_volume_odi_captions.xml b/packages/overlays/IconPackRoundedSystemUIOverlay/res/drawable/ic_volume_odi_captions.xml
new file mode 100644
index 0000000..ad79132
--- /dev/null
+++ b/packages/overlays/IconPackRoundedSystemUIOverlay/res/drawable/ic_volume_odi_captions.xml
@@ -0,0 +1,51 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+   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.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:height="24dp"
+    android:viewportHeight="24"
+    android:viewportWidth="24"
+    android:width="24dp" >
+    <group
+        android:translateX="2.000000"
+        android:translateY="4.000000" >
+        <path
+            android:fillColor="@android:color/white"
+            android:fillType="evenOdd"
+            android:pathData="M18.0001,0 L2.0001,0 C0.8961,0 0.0001,0.896 0.0001,2 L0.0001,14 C0.0001,15.104 0.8961,16 2.0001,16 L18.0001,16 C19.1041,16 20.0001,15.104 20.0001,14 L20.0001,2 C20.0001,0.896 19.1041,0 18.0001,0 M18.0001,1.5 C18.2751,1.5 18.5001,1.725 18.5001,2 L18.5001,14 C18.5001,14.275 18.2751,14.5 18.0001,14.5 L2.0001,14.5 C1.7251,14.5 1.5001,14.275 1.5001,14 L1.5001,2 C1.5001,1.725 1.7251,1.5 2.0001,1.5 L18.0001,1.5"
+            android:strokeWidth="1" />
+        <path
+            android:fillColor="@android:color/white"
+            android:fillType="evenOdd"
+            android:pathData="M3.5001,11.5 L13.5001,11.5 C13.7761,11.5 14.0001,11.724 14.0001,12 L14.0001,12.5 C14.0001,12.776 13.7761,13 13.5001,13 L3.5001,13 C3.2241,13 3.0001,12.776 3.0001,12.5 L3.0001,12 C3.0001,11.724 3.2241,11.5 3.5001,11.5"
+            android:strokeWidth="1" />
+        <path
+            android:fillColor="@android:color/white"
+            android:fillType="evenOdd"
+            android:pathData="M3.5001,8.5 L4.0001,8.5 C4.2761,8.5 4.5001,8.724 4.5001,9 L4.5001,9.5 C4.5001,9.776 4.2761,10 4.0001,10 L3.5001,10 C3.2241,10 3.0001,9.776 3.0001,9.5 L3.0001,9 C3.0001,8.724 3.2241,8.5 3.5001,8.5"
+            android:strokeWidth="1" />
+        <path
+            android:fillColor="@android:color/white"
+            android:fillType="evenOdd"
+            android:pathData="M16.0001,11.5 L16.5001,11.5 C16.7761,11.5 17.0001,11.724 17.0001,12 L17.0001,12.5 C17.0001,12.776 16.7761,13 16.5001,13 L16.0001,13 C15.7241,13 15.5001,12.776 15.5001,12.5 L15.5001,12 C15.5001,11.724 15.7241,11.5 16.0001,11.5"
+            android:strokeWidth="1" />
+        <path
+            android:fillColor="@android:color/white"
+            android:fillType="evenOdd"
+            android:pathData="M6.5001,8.5 L16.5001,8.5 C16.7761,8.5 17.0001,8.724 17.0001,9 L17.0001,9.5 C17.0001,9.776 16.7761,10 16.5001,10 L6.5001,10 C6.2241,10 6.0001,9.776 6.0001,9.5 L6.0001,9 C6.0001,8.724 6.2241,8.5 6.5001,8.5"
+            android:strokeWidth="1" />
+    </group>
+</vector>
\ No newline at end of file
diff --git a/packages/overlays/IconPackRoundedSystemUIOverlay/res/drawable/ic_volume_odi_captions_disabled.xml b/packages/overlays/IconPackRoundedSystemUIOverlay/res/drawable/ic_volume_odi_captions_disabled.xml
new file mode 100644
index 0000000..2ea41f2
--- /dev/null
+++ b/packages/overlays/IconPackRoundedSystemUIOverlay/res/drawable/ic_volume_odi_captions_disabled.xml
@@ -0,0 +1,61 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+   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.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:height="24dp"
+    android:viewportHeight="24"
+    android:viewportWidth="24"
+    android:width="24dp" >
+    <group
+        android:translateX="1.750150"
+        android:translateY="2.750000" >
+        <path
+            android:fillColor="@android:color/white"
+            android:fillType="evenOdd"
+            android:pathData="M3.74975,9.74875 L4.24975,9.74875 C4.52575,9.74875 4.74975,9.97275 4.74975,10.24875 L4.74975,10.74875 C4.74975,11.02475 4.52575,11.24875 4.24975,11.24875 L3.74975,11.24875 C3.47375,11.24875 3.24975,11.02475 3.24975,10.74875 L3.24975,10.24875 C3.24975,9.97275 3.47375,9.74875 3.74975,9.74875"
+            android:strokeWidth="1" />
+        <path
+            android:fillColor="@android:color/white"
+            android:fillType="evenOdd"
+            android:pathData="M18.24975,2.74875 C18.52475,2.74875 18.74975,2.97375 18.74975,3.24875 L18.74975,15.24875 C18.74975,15.33875 18.71975,15.41875 18.67775,15.49275 L19.74675,16.56175 C20.05675,16.20975 20.24975,15.75475 20.24975,15.24875 L20.24975,3.24875 C20.24975,2.14475 19.35375,1.24875 18.24975,1.24875 L4.43375,1.24875 L5.93375,2.74875 L18.24975,2.74875 Z"
+            android:strokeWidth="1" />
+        <path
+            android:fillColor="@android:color/white"
+            android:fillType="evenOdd"
+            android:pathData="M17.24975,13.74875 L17.24975,13.24875 C17.24975,12.97275 17.02575,12.74875 16.74975,12.74875 L16.24975,12.74875 C16.15875,12.74875 16.07875,12.77875 16.00575,12.82075 L17.17775,13.99275 C17.21975,13.91975 17.24975,13.83875 17.24975,13.74875"
+            android:strokeWidth="1" />
+        <path
+            android:fillColor="@android:color/white"
+            android:fillType="evenOdd"
+            android:pathData="M16.74975,11.24875 C17.02575,11.24875 17.24975,11.02475 17.24975,10.74875 L17.24975,10.24875 C17.24975,9.97275 17.02575,9.74875 16.74975,9.74875 L12.93375,9.74875 L14.43375,11.24875 L16.74975,11.24875 Z"
+            android:strokeWidth="1" />
+        <path
+            android:fillColor="@android:color/white"
+            android:fillType="evenOdd"
+            android:pathData="M2.24975,15.74875 C1.97475,15.74875 1.74975,15.52375 1.74975,15.24875 L1.74975,3.24875 C1.74975,3.12675 1.79875,3.01875 1.87175,2.93275 L8.68875,9.74875 L6.74975,9.74875 C6.47375,9.74875 6.24975,9.97275 6.24975,10.24875 L6.24975,10.74875 C6.24975,11.02475 6.47375,11.24875 6.74975,11.24875 L10.18875,11.24875 L11.68875,12.74875 L3.74975,12.74875 C3.47375,12.74875 3.24975,12.97275 3.24975,13.24875 L3.24975,13.74875 C3.24975,14.02475 3.47375,14.24875 3.74975,14.24875 L13.18875,14.24875 L14.68975,15.74875 L2.24975,15.74875 Z M19.27975,18.21775 L1.27975,0.21975 C0.98675,-0.07325 0.51275,-0.07325 0.21975,0.21975 C-0.07325,0.51275 -0.07325,0.98675 0.21975,1.27975 L0.80775,1.86775 C0.46375,2.22775 0.24975,2.71175 0.24975,3.24875 L0.24975,15.24875 C0.24975,16.35275 1.14575,17.24875 2.24975,17.24875 L16.18975,17.24875 L18.21975,19.27775 C18.51275,19.57075 18.98675,19.57075 19.27975,19.27775 C19.57275,18.98475 19.57275,18.51075 19.27975,18.21775 L19.27975,18.21775 Z"
+            android:strokeWidth="1" />
+        <path
+            android:fillColor="@android:color/white"
+            android:fillType="evenOdd"
+            android:pathData="M2.24975,15.74875 C1.97475,15.74875 1.74975,15.52375 1.74975,15.24875 L1.74975,3.24875 C1.74975,3.12675 1.79875,3.01875 1.87175,2.93275 L0.80775,1.86775 C0.46375,2.22775 0.24975,2.71175 0.24975,3.24875 L0.24975,15.24875 C0.24975,16.35275 1.14575,17.24875 2.24975,17.24875 L16.18975,17.24875 L14.68975,15.74875 L2.24975,15.74875 Z"
+            android:strokeWidth="1" />
+        <path
+            android:fillColor="@android:color/white"
+            android:fillType="evenOdd"
+            android:pathData="M18.24975,2.74875 C18.52475,2.74875 18.74975,2.97375 18.74975,3.24875 L18.74975,15.24875 C18.74975,15.33875 18.71975,15.41875 18.67775,15.49275 L19.74675,16.56175 C20.05675,16.20975 20.24975,15.75475 20.24975,15.24875 L20.24975,3.24875 C20.24975,2.14475 19.35375,1.24875 18.24975,1.24875 L4.43375,1.24875 L5.93375,2.74875 L18.24975,2.74875 Z"
+            android:strokeWidth="1" />
+    </group>
+</vector>
\ No newline at end of file
diff --git a/proto/src/wifi.proto b/proto/src/wifi.proto
index f9a2ca2..8ad2489 100644
--- a/proto/src/wifi.proto
+++ b/proto/src/wifi.proto
@@ -551,6 +551,30 @@
 
   // Histogram of the EAP method type of all installed Passpoint profiles for R2
   repeated PasspointProfileTypeCount installed_passpoint_profile_type_for_r2 = 148;
+
+  // Histogram of Tx link speed at 2G
+  repeated Int32Count tx_link_speed_count_2g = 149;
+
+  // Histogram of Tx link speed at 5G low band
+  repeated Int32Count tx_link_speed_count_5g_low = 150;
+
+  // Histogram of Tx link speed at 5G middle band
+  repeated Int32Count tx_link_speed_count_5g_mid = 151;
+
+  // Histogram of Tx link speed at 5G high band
+  repeated Int32Count tx_link_speed_count_5g_high = 152;
+
+  // Histogram of Rx link speed at 2G
+  repeated Int32Count rx_link_speed_count_2g = 153;
+
+  // Histogram of Rx link speed at 5G low band
+  repeated Int32Count rx_link_speed_count_5g_low = 154;
+
+  // Histogram of Rx link speed at 5G middle band
+  repeated Int32Count rx_link_speed_count_5g_mid = 155;
+
+  // Histogram of Rx link speed at 5G high band
+  repeated Int32Count rx_link_speed_count_5g_high = 156;
 }
 
 // Information that gets logged for every WiFi connection.
@@ -827,6 +851,7 @@
   optional int64 rssi_sum_of_squares_dbm_sq = 4;
 }
 
+
 // Number of occurrences of Soft AP session durations
 message SoftApDurationBucket {
   // Bucket covers duration : [duration_sec, duration_sec + bucket_size_sec)
diff --git a/services/accessibility/TEST_MAPPING b/services/accessibility/TEST_MAPPING
index 45c5245..d90c3bd 100644
--- a/services/accessibility/TEST_MAPPING
+++ b/services/accessibility/TEST_MAPPING
@@ -52,9 +52,6 @@
         },
         {
           "exclude-annotation": "androidx.test.filters.FlakyTest"
-        },
-        {
-          "exclude-filter": "android.view.textclassifier.TextClassifierTest#testSuggetsConversationActions_deduplicate"
         }
       ]
     },
@@ -66,9 +63,6 @@
         },
         {
           "exclude-annotation": "androidx.test.filters.FlakyTest"
-        },
-        {
-          "exclude-filter": "android.view.textclassifier.TextClassifierTest#testSuggetsConversationActions_deduplicate"
         }
       ]
     }
diff --git a/services/backup/java/com/android/server/backup/UserBackupManagerService.java b/services/backup/java/com/android/server/backup/UserBackupManagerService.java
index c0af99c..2554433 100644
--- a/services/backup/java/com/android/server/backup/UserBackupManagerService.java
+++ b/services/backup/java/com/android/server/backup/UserBackupManagerService.java
@@ -166,6 +166,52 @@
 
 /** System service that performs backup/restore operations. */
 public class UserBackupManagerService {
+    /** Wrapper over {@link PowerManager.WakeLock} to prevent double-free exceptions on release()
+     * after quit().
+     * */
+    public static class BackupWakeLock {
+        private final PowerManager.WakeLock mPowerManagerWakeLock;
+        private boolean mHasQuit = false;
+
+        public BackupWakeLock(PowerManager.WakeLock powerManagerWakeLock) {
+            mPowerManagerWakeLock = powerManagerWakeLock;
+        }
+
+        /** Acquires the {@link PowerManager.WakeLock} if hasn't been quit. */
+        public synchronized void acquire() {
+            if (mHasQuit) {
+                Slog.v(TAG, "Ignore wakelock acquire after quit:" + mPowerManagerWakeLock.getTag());
+                return;
+            }
+            mPowerManagerWakeLock.acquire();
+        }
+
+        /** Releases the {@link PowerManager.WakeLock} if hasn't been quit. */
+        public synchronized void release() {
+            if (mHasQuit) {
+                Slog.v(TAG, "Ignore wakelock release after quit:" + mPowerManagerWakeLock.getTag());
+                return;
+            }
+            mPowerManagerWakeLock.release();
+        }
+
+        /**
+         * Returns true if the {@link PowerManager.WakeLock} has been acquired but not yet released.
+         */
+        public synchronized boolean isHeld() {
+            return mPowerManagerWakeLock.isHeld();
+        }
+
+        /** Release the {@link PowerManager.WakeLock} till it isn't held. */
+        public synchronized void quit() {
+            while (mPowerManagerWakeLock.isHeld()) {
+                Slog.v(TAG, "Releasing wakelock:" + mPowerManagerWakeLock.getTag());
+                mPowerManagerWakeLock.release();
+            }
+            mHasQuit = true;
+        }
+    }
+
     // Persistently track the need to do a full init.
     private static final String INIT_SENTINEL_FILE_NAME = "_need_init_";
 
@@ -252,7 +298,6 @@
     private final @UserIdInt int mUserId;
     private final BackupAgentTimeoutParameters mAgentTimeoutParameters;
     private final TransportManager mTransportManager;
-    private final HandlerThread mUserBackupThread;
 
     private final Context mContext;
     private final PackageManager mPackageManager;
@@ -263,7 +308,7 @@
     private final AlarmManager mAlarmManager;
     private final IStorageManager mStorageManager;
     private final BackupManagerConstants mConstants;
-    private final PowerManager.WakeLock mWakelock;
+    private final BackupWakeLock mWakelock;
     private final BackupHandler mBackupHandler;
 
     private final IBackupManager mBackupManagerBinder;
@@ -367,6 +412,9 @@
     private long mCurrentToken = 0;
     @Nullable private File mAncestralSerialNumberFile;
 
+    private final ContentObserver mSetupObserver;
+    private final BroadcastReceiver mRunBackupReceiver;
+    private final BroadcastReceiver mRunInitReceiver;
 
     /**
      * Creates an instance of {@link UserBackupManagerService} and initializes state for it. This
@@ -484,8 +532,7 @@
         mAgentTimeoutParameters.start();
 
         checkNotNull(userBackupThread, "userBackupThread cannot be null");
-        mUserBackupThread = userBackupThread;
-        mBackupHandler = new BackupHandler(this, userBackupThread.getLooper());
+        mBackupHandler = new BackupHandler(this, userBackupThread);
 
         // Set up our bookkeeping
         final ContentResolver resolver = context.getContentResolver();
@@ -493,11 +540,11 @@
         mAutoRestore = Settings.Secure.getIntForUser(resolver,
                 Settings.Secure.BACKUP_AUTO_RESTORE, 1, userId) != 0;
 
-        ContentObserver setupObserver = new SetupObserver(this, mBackupHandler);
+        mSetupObserver = new SetupObserver(this, mBackupHandler);
         resolver.registerContentObserver(
                 Settings.Secure.getUriFor(Settings.Secure.USER_SETUP_COMPLETE),
                 /* notifyForDescendents */ false,
-                setupObserver,
+                mSetupObserver,
                 mUserId);
 
         mBaseStateDir = checkNotNull(baseStateDir, "baseStateDir cannot be null");
@@ -516,21 +563,21 @@
         mBackupPasswordManager = new BackupPasswordManager(mContext, mBaseStateDir, mRng);
 
         // Receivers for scheduled backups and transport initialization operations.
-        BroadcastReceiver runBackupReceiver = new RunBackupReceiver(this);
+        mRunBackupReceiver = new RunBackupReceiver(this);
         IntentFilter filter = new IntentFilter();
         filter.addAction(RUN_BACKUP_ACTION);
         context.registerReceiverAsUser(
-                runBackupReceiver,
+                mRunBackupReceiver,
                 UserHandle.of(userId),
                 filter,
                 android.Manifest.permission.BACKUP,
                 /* scheduler */ null);
 
-        BroadcastReceiver runInitReceiver = new RunInitializeReceiver(this);
+        mRunInitReceiver = new RunInitializeReceiver(this);
         filter = new IntentFilter();
         filter.addAction(RUN_INITIALIZE_ACTION);
         context.registerReceiverAsUser(
-                runInitReceiver,
+                mRunInitReceiver,
                 UserHandle.of(userId),
                 filter,
                 android.Manifest.permission.BACKUP,
@@ -585,7 +632,10 @@
         mBackupHandler.postDelayed(this::parseLeftoverJournals, INITIALIZATION_DELAY_MILLIS);
 
         // Power management
-        mWakelock = mPowerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "*backup*-" + userId);
+        mWakelock = new BackupWakeLock(
+                mPowerManager.newWakeLock(
+                        PowerManager.PARTIAL_WAKE_LOCK,
+                        "*backup*-" + userId + "-" + userBackupThread.getThreadId()));
 
         // Set up the various sorts of package tracking we do
         mFullBackupScheduleFile = new File(mBaseStateDir, "fb-schedule");
@@ -599,7 +649,13 @@
 
     /** Cleans up state when the user of this service is stopped. */
     void tearDownService() {
-        mUserBackupThread.quit();
+        mAgentTimeoutParameters.stop();
+        mConstants.stop();
+        mContext.getContentResolver().unregisterContentObserver(mSetupObserver);
+        mContext.unregisterReceiver(mRunBackupReceiver);
+        mContext.unregisterReceiver(mRunInitReceiver);
+        mContext.unregisterReceiver(mPackageTrackingReceiver);
+        mBackupHandler.stop();
     }
 
     public @UserIdInt int getUserId() {
@@ -659,7 +715,7 @@
         mSetupComplete = setupComplete;
     }
 
-    public PowerManager.WakeLock getWakelock() {
+    public BackupWakeLock getWakelock() {
         return mWakelock;
     }
 
@@ -670,7 +726,7 @@
     @VisibleForTesting
     public void setWorkSource(@Nullable WorkSource workSource) {
         // TODO: This is for testing, unfortunately WakeLock is final and WorkSource is not exposed
-        mWakelock.setWorkSource(workSource);
+        mWakelock.mPowerManagerWakeLock.setWorkSource(workSource);
     }
 
     public Handler getBackupHandler() {
@@ -747,7 +803,7 @@
 
     @VisibleForTesting
     BroadcastReceiver getPackageTrackingReceiver() {
-        return mBroadcastReceiver;
+        return mPackageTrackingReceiver;
     }
 
     @Nullable
@@ -874,7 +930,7 @@
         filter.addAction(Intent.ACTION_PACKAGE_CHANGED);
         filter.addDataScheme("package");
         mContext.registerReceiverAsUser(
-                mBroadcastReceiver,
+                mPackageTrackingReceiver,
                 UserHandle.of(mUserId),
                 filter,
                 /* broadcastPermission */ null,
@@ -885,7 +941,7 @@
         sdFilter.addAction(Intent.ACTION_EXTERNAL_APPLICATIONS_AVAILABLE);
         sdFilter.addAction(Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE);
         mContext.registerReceiverAsUser(
-                mBroadcastReceiver,
+                mPackageTrackingReceiver,
                 UserHandle.of(mUserId),
                 sdFilter,
                 /* broadcastPermission */ null,
@@ -1158,7 +1214,7 @@
      * A {@link BroadcastReceiver} tracking changes to packages and sd cards in order to update our
      * internal bookkeeping.
      */
-    private BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() {
+    private BroadcastReceiver mPackageTrackingReceiver = new BroadcastReceiver() {
         public void onReceive(Context context, Intent intent) {
             if (MORE_DEBUG) {
                 Slog.d(TAG, "Received broadcast " + intent);
diff --git a/services/backup/java/com/android/server/backup/internal/BackupHandler.java b/services/backup/java/com/android/server/backup/internal/BackupHandler.java
index ba153bf..059b1b9 100644
--- a/services/backup/java/com/android/server/backup/internal/BackupHandler.java
+++ b/services/backup/java/com/android/server/backup/internal/BackupHandler.java
@@ -23,7 +23,7 @@
 import android.app.backup.RestoreSet;
 import android.content.Intent;
 import android.os.Handler;
-import android.os.Looper;
+import android.os.HandlerThread;
 import android.os.Message;
 import android.os.RemoteException;
 import android.os.UserHandle;
@@ -83,19 +83,47 @@
     // backup task state machine tick
     public static final int MSG_BACKUP_RESTORE_STEP = 20;
     public static final int MSG_OP_COMPLETE = 21;
+    // Release the wakelock. This is used to ensure we don't hold it after
+    // a user is removed. This will also terminate the looper thread.
+    public static final int MSG_STOP = 22;
 
     private final UserBackupManagerService backupManagerService;
     private final BackupAgentTimeoutParameters mAgentTimeoutParameters;
 
-    public BackupHandler(UserBackupManagerService backupManagerService, Looper looper) {
-        super(looper);
+    private final HandlerThread mBackupThread;
+    private volatile boolean mIsStopping = false;
+
+    public BackupHandler(
+            UserBackupManagerService backupManagerService, HandlerThread backupThread) {
+        super(backupThread.getLooper());
+        mBackupThread = backupThread;
         this.backupManagerService = backupManagerService;
         mAgentTimeoutParameters = Preconditions.checkNotNull(
                 backupManagerService.getAgentTimeoutParameters(),
                 "Timeout parameters cannot be null");
     }
 
+    /**
+     * Put the BackupHandler into a stopping state where the remaining messages on the queue will be
+     * silently dropped and the {@link WakeLock} held by the {@link UserBackupManagerService} will
+     * then be released.
+     */
+    public void stop() {
+        mIsStopping = true;
+        sendMessage(obtainMessage(BackupHandler.MSG_STOP));
+    }
+
     public void handleMessage(Message msg) {
+        if (msg.what == MSG_STOP) {
+            Slog.v(TAG, "Stopping backup handler");
+            backupManagerService.getWakelock().quit();
+            mBackupThread.quitSafely();
+        }
+
+        if (mIsStopping) {
+            // If we're finishing all other types of messages should be ignored
+            return;
+        }
 
         TransportManager transportManager = backupManagerService.getTransportManager();
         switch (msg.what) {
diff --git a/services/backup/java/com/android/server/backup/internal/RunInitializeReceiver.java b/services/backup/java/com/android/server/backup/internal/RunInitializeReceiver.java
index 97711e3..96d61e5 100644
--- a/services/backup/java/com/android/server/backup/internal/RunInitializeReceiver.java
+++ b/services/backup/java/com/android/server/backup/internal/RunInitializeReceiver.java
@@ -23,7 +23,6 @@
 import android.content.BroadcastReceiver;
 import android.content.Context;
 import android.content.Intent;
-import android.os.PowerManager;
 import android.util.Slog;
 
 import com.android.server.backup.UserBackupManagerService;
@@ -57,7 +56,8 @@
 
                 mUserBackupManagerService.clearPendingInits();
 
-                PowerManager.WakeLock wakelock = mUserBackupManagerService.getWakelock();
+                UserBackupManagerService.BackupWakeLock wakelock =
+                        mUserBackupManagerService.getWakelock();
                 wakelock.acquire();
                 OnTaskFinishedListener listener = caller -> wakelock.release();
 
diff --git a/services/backup/java/com/android/server/backup/restore/ActiveRestoreSession.java b/services/backup/java/com/android/server/backup/restore/ActiveRestoreSession.java
index 10304c3..5a57cdc 100644
--- a/services/backup/java/com/android/server/backup/restore/ActiveRestoreSession.java
+++ b/services/backup/java/com/android/server/backup/restore/ActiveRestoreSession.java
@@ -34,7 +34,6 @@
 import android.os.Binder;
 import android.os.Handler;
 import android.os.Message;
-import android.os.PowerManager;
 import android.util.Slog;
 
 import com.android.server.backup.TransportManager;
@@ -110,7 +109,7 @@
             // comes in.
             mBackupManagerService.getBackupHandler().removeMessages(MSG_RESTORE_SESSION_TIMEOUT);
 
-            PowerManager.WakeLock wakelock = mBackupManagerService.getWakelock();
+            UserBackupManagerService.BackupWakeLock wakelock = mBackupManagerService.getWakelock();
             wakelock.acquire();
 
             // Prevent lambda from leaking 'this'
@@ -392,7 +391,7 @@
         Handler backupHandler = mBackupManagerService.getBackupHandler();
         backupHandler.removeMessages(MSG_RESTORE_SESSION_TIMEOUT);
 
-        PowerManager.WakeLock wakelock = mBackupManagerService.getWakelock();
+        UserBackupManagerService.BackupWakeLock wakelock = mBackupManagerService.getWakelock();
         wakelock.acquire();
         if (MORE_DEBUG) {
             Slog.d(TAG, callerLogString);
diff --git a/services/core/java/com/android/server/GraphicsStatsService.java b/services/core/java/com/android/server/GraphicsStatsService.java
index 70569db..4639d75 100644
--- a/services/core/java/com/android/server/GraphicsStatsService.java
+++ b/services/core/java/com/android/server/GraphicsStatsService.java
@@ -191,7 +191,7 @@
             if (!file.getFileDescriptor().valid()) {
                 throw new IllegalStateException("Invalid file descriptor");
             }
-            return ParcelFileDescriptor.dup(file.getFileDescriptor());
+            return new ParcelFileDescriptor(file.getFileDescriptor());
         } catch (IOException ex) {
             throw new IllegalStateException("Failed to get PFD from memory file", ex);
         }
diff --git a/services/core/java/com/android/server/LocationManagerService.java b/services/core/java/com/android/server/LocationManagerService.java
index 8a639c5..90e4670 100644
--- a/services/core/java/com/android/server/LocationManagerService.java
+++ b/services/core/java/com/android/server/LocationManagerService.java
@@ -466,7 +466,7 @@
         // the user being changed will cause a reload of all user specific settings, which causes
         // provider initialization, and propagates changes until a steady state is reached
         mCurrentUserId = UserHandle.USER_NULL;
-        onUserChangedLocked(UserHandle.USER_SYSTEM);
+        onUserChangedLocked(ActivityManager.getCurrentUser());
 
         // initialize in-memory settings values
         onBackgroundThrottleWhitelistChangedLocked();
diff --git a/services/core/java/com/android/server/MmsServiceBroker.java b/services/core/java/com/android/server/MmsServiceBroker.java
index b6fa157..c0f10a3 100644
--- a/services/core/java/com/android/server/MmsServiceBroker.java
+++ b/services/core/java/com/android/server/MmsServiceBroker.java
@@ -37,6 +37,7 @@
 import android.os.UserHandle;
 import android.service.carrier.CarrierMessagingService;
 import android.telephony.SmsManager;
+import android.telephony.SubscriptionManager;
 import android.telephony.TelephonyManager;
 import android.util.Slog;
 
@@ -331,7 +332,7 @@
         @Override
         public void sendMessage(int subId, String callingPkg, Uri contentUri,
                 String locationUrl, Bundle configOverrides, PendingIntent sentIntent)
-                        throws RemoteException {
+                throws RemoteException {
             Slog.d(TAG, "sendMessage() by " + callingPkg);
             mContext.enforceCallingPermission(Manifest.permission.SEND_SMS, "Send MMS message");
             if (getAppOpsManager().noteOp(AppOpsManager.OP_SEND_SMS, Binder.getCallingUid(),
@@ -341,7 +342,8 @@
             }
             contentUri = adjustUriForUserAndGrantPermission(contentUri,
                     CarrierMessagingService.SERVICE_INTERFACE,
-                    Intent.FLAG_GRANT_READ_URI_PERMISSION);
+                    Intent.FLAG_GRANT_READ_URI_PERMISSION,
+                    subId);
             getServiceGuarded().sendMessage(subId, callingPkg, contentUri, locationUrl,
                     configOverrides, sentIntent);
         }
@@ -360,7 +362,8 @@
             }
             contentUri = adjustUriForUserAndGrantPermission(contentUri,
                     CarrierMessagingService.SERVICE_INTERFACE,
-                    Intent.FLAG_GRANT_READ_URI_PERMISSION | Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
+                    Intent.FLAG_GRANT_READ_URI_PERMISSION | Intent.FLAG_GRANT_WRITE_URI_PERMISSION,
+                    subId);
 
             getServiceGuarded().downloadMessage(subId, callingPkg, locationUrl, contentUri,
                     configOverrides, downloadedIntent);
@@ -388,7 +391,7 @@
         @Override
         public Uri importMultimediaMessage(String callingPkg, Uri contentUri,
                 String messageId, long timestampSecs, boolean seen, boolean read)
-                        throws RemoteException {
+                throws RemoteException {
             if (getAppOpsManager().noteOp(AppOpsManager.OP_WRITE_SMS, Binder.getCallingUid(),
                     callingPkg) != AppOpsManager.MODE_ALLOWED) {
                 // Silently fail AppOps failure due to not being the default SMS app
@@ -496,12 +499,12 @@
          * even if the caller is not in the primary user.
          *
          * @param contentUri The Uri to adjust
-         * @param action The intent action used to find the associated carrier app
+         * @param action     The intent action used to find the associated carrier app
          * @param permission The permission to add
          * @return The adjusted Uri containing the calling userId.
          */
         private Uri adjustUriForUserAndGrantPermission(Uri contentUri, String action,
-                int permission) {
+                int permission, int subId) {
             final Intent grantIntent = new Intent();
             grantIntent.setData(contentUri);
             grantIntent.setFlags(permission);
@@ -521,9 +524,10 @@
                 // Grant permission for the carrier app.
                 Intent intent = new Intent(action);
                 TelephonyManager telephonyManager =
-                    (TelephonyManager) mContext.getSystemService(Context.TELEPHONY_SERVICE);
-                List<String> carrierPackages = telephonyManager.getCarrierPackageNamesForIntent(
-                        intent);
+                        (TelephonyManager) mContext.getSystemService(Context.TELEPHONY_SERVICE);
+                List<String> carrierPackages =
+                        telephonyManager.getCarrierPackageNamesForIntentAndPhone(
+                                intent, SubscriptionManager.getPhoneId(subId));
                 if (carrierPackages != null && carrierPackages.size() == 1) {
                     LocalServices.getService(UriGrantsManagerInternal.class)
                             .grantUriPermissionFromIntent(callingUid, carrierPackages.get(0),
diff --git a/services/core/java/com/android/server/TelephonyRegistry.java b/services/core/java/com/android/server/TelephonyRegistry.java
index 8638432..f7e825e 100644
--- a/services/core/java/com/android/server/TelephonyRegistry.java
+++ b/services/core/java/com/android/server/TelephonyRegistry.java
@@ -1261,23 +1261,21 @@
         }
     }
 
-    public void notifyPhysicalChannelConfiguration(List<PhysicalChannelConfig> configs) {
-        notifyPhysicalChannelConfigurationForSubscriber(SubscriptionManager.DEFAULT_SUBSCRIPTION_ID,
-                configs);
-    }
-
-    public void notifyPhysicalChannelConfigurationForSubscriber(int subId,
+    /**
+     * Notify physical channel configuration according to subscripton ID and phone ID
+     */
+    public void notifyPhysicalChannelConfigurationForSubscriber(int phoneId, int subId,
             List<PhysicalChannelConfig> configs) {
         if (!checkNotifyPermission("notifyPhysicalChannelConfiguration()")) {
             return;
         }
 
         if (VDBG) {
-            log("notifyPhysicalChannelConfiguration: subId=" + subId + " configs=" + configs);
+            log("notifyPhysicalChannelConfiguration: subId=" + subId + " phoneId=" + phoneId
+                    + " configs=" + configs);
         }
 
         synchronized (mRecords) {
-            int phoneId = SubscriptionManager.getPhoneId(subId);
             if (validatePhoneId(phoneId)) {
                 mPhysicalChannelConfigs.set(phoneId, configs);
                 for (Record r : mRecords) {
diff --git a/services/core/java/com/android/server/VibratorService.java b/services/core/java/com/android/server/VibratorService.java
index 6eb9f0c..9936d73 100644
--- a/services/core/java/com/android/server/VibratorService.java
+++ b/services/core/java/com/android/server/VibratorService.java
@@ -16,6 +16,7 @@
 
 package com.android.server;
 
+import android.annotation.Nullable;
 import android.app.ActivityManager;
 import android.app.AppOpsManager;
 import android.app.IUidObserver;
@@ -193,7 +194,7 @@
         // with other system events, any duration calculations should be done use startTime so as
         // not to be affected by discontinuities created by RTC adjustments.
         public final long startTimeDebug;
-        public final int usageHint;
+        public final AudioAttributes attrs;
         public final int uid;
         public final String opPkg;
         public final String reason;
@@ -206,12 +207,12 @@
         public VibrationEffect originalEffect;
 
         private Vibration(IBinder token, VibrationEffect effect,
-                int usageHint, int uid, String opPkg, String reason) {
+                AudioAttributes attrs, int uid, String opPkg, String reason) {
             this.token = token;
             this.effect = effect;
             this.startTime = SystemClock.elapsedRealtime();
             this.startTimeDebug = System.currentTimeMillis();
-            this.usageHint = usageHint;
+            this.attrs = attrs;
             this.uid = uid;
             this.opPkg = opPkg;
             this.reason = reason;
@@ -231,7 +232,7 @@
         }
 
         public boolean isHapticFeedback() {
-            if (VibratorService.this.isHapticFeedback(usageHint)) {
+            if (VibratorService.this.isHapticFeedback(attrs.getUsage())) {
                 return true;
             }
             if (effect instanceof VibrationEffect.Prebaked) {
@@ -256,15 +257,15 @@
         }
 
         public boolean isNotification() {
-            return VibratorService.this.isNotification(usageHint);
+            return VibratorService.this.isNotification(attrs.getUsage());
         }
 
         public boolean isRingtone() {
-            return VibratorService.this.isRingtone(usageHint);
+            return VibratorService.this.isRingtone(attrs.getUsage());
         }
 
         public boolean isAlarm() {
-            return VibratorService.this.isAlarm(usageHint);
+            return VibratorService.this.isAlarm(attrs.getUsage());
         }
 
         public boolean isFromSystem() {
@@ -273,7 +274,7 @@
 
         public VibrationInfo toInfo() {
             return new VibrationInfo(
-                    startTimeDebug, effect, originalEffect, usageHint, uid, opPkg, reason);
+                    startTimeDebug, effect, originalEffect, attrs, uid, opPkg, reason);
         }
     }
 
@@ -281,18 +282,18 @@
         private final long mStartTimeDebug;
         private final VibrationEffect mEffect;
         private final VibrationEffect mOriginalEffect;
-        private final int mUsageHint;
+        private final AudioAttributes mAttrs;
         private final int mUid;
         private final String mOpPkg;
         private final String mReason;
 
         public VibrationInfo(long startTimeDebug, VibrationEffect effect,
-                VibrationEffect originalEffect, int usageHint, int uid,
+                VibrationEffect originalEffect, AudioAttributes attrs, int uid,
                 String opPkg, String reason) {
             mStartTimeDebug = startTimeDebug;
             mEffect = effect;
             mOriginalEffect = originalEffect;
-            mUsageHint = usageHint;
+            mAttrs = attrs;
             mUid = uid;
             mOpPkg = opPkg;
             mReason = reason;
@@ -307,8 +308,8 @@
                     .append(mEffect)
                     .append(", originalEffect: ")
                     .append(mOriginalEffect)
-                    .append(", usageHint: ")
-                    .append(mUsageHint)
+                    .append(", attrs: ")
+                    .append(mAttrs)
                     .append(", uid: ")
                     .append(mUid)
                     .append(", opPkg: ")
@@ -549,12 +550,11 @@
     }
 
     @Override // Binder call
-    public void vibrate(int uid, String opPkg, VibrationEffect effect, int usageHint, String reason,
-            IBinder token) {
+    public void vibrate(int uid, String opPkg, VibrationEffect effect,
+            @Nullable AudioAttributes attrs, String reason, IBinder token) {
         Trace.traceBegin(Trace.TRACE_TAG_VIBRATOR, "vibrate, reason = " + reason);
         try {
-            if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.VIBRATE)
-                    != PackageManager.PERMISSION_GRANTED) {
+            if (!hasPermission(android.Manifest.permission.VIBRATE)) {
                 throw new SecurityException("Requires VIBRATE permission");
             }
             if (token == null) {
@@ -566,6 +566,22 @@
                 return;
             }
 
+            if (attrs == null) {
+                attrs = new AudioAttributes.Builder()
+                        .setUsage(AudioAttributes.USAGE_UNKNOWN)
+                        .build();
+            }
+
+            if (shouldBypassDnd(attrs)) {
+                if (!(hasPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS)
+                        || hasPermission(android.Manifest.permission.MODIFY_PHONE_STATE)
+                        || hasPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING))) {
+                    final int flags = attrs.getAllFlags()
+                            & ~AudioAttributes.FLAG_BYPASS_INTERRUPTION_POLICY;
+                    attrs = new AudioAttributes.Builder(attrs).replaceFlags(flags).build();
+                }
+            }
+
             // If our current vibration is longer than the new vibration and is the same amplitude,
             // then just let the current one finish.
             synchronized (mLock) {
@@ -608,13 +624,13 @@
                     return;
                 }
 
-                Vibration vib = new Vibration(token, effect, usageHint, uid, opPkg, reason);
+                Vibration vib = new Vibration(token, effect, attrs, uid, opPkg, reason);
                 if (mProcStatesCache.get(uid, ActivityManager.PROCESS_STATE_IMPORTANT_FOREGROUND)
                         > ActivityManager.PROCESS_STATE_IMPORTANT_FOREGROUND
                         && !vib.isNotification() && !vib.isRingtone() && !vib.isAlarm()) {
                     Slog.e(TAG, "Ignoring incoming vibration as process with"
-                            + " uid = " + uid + " is background,"
-                            + " usage = " + AudioAttributes.usageToString(vib.usageHint));
+                            + " uid= " + uid + " is background,"
+                            + " attrs= " + vib.attrs);
                     return;
                 }
                 linkVibration(vib);
@@ -632,6 +648,11 @@
         }
     }
 
+    private boolean hasPermission(String permission) {
+        return mContext.checkCallingOrSelfPermission(permission)
+                == PackageManager.PERMISSION_GRANTED;
+    }
+
     private static boolean isRepeatingVibration(VibrationEffect effect) {
         return effect.getDuration() == Long.MAX_VALUE;
     }
@@ -760,14 +781,14 @@
             if (vib.effect instanceof VibrationEffect.OneShot) {
                 Trace.asyncTraceBegin(Trace.TRACE_TAG_VIBRATOR, "vibration", 0);
                 VibrationEffect.OneShot oneShot = (VibrationEffect.OneShot) vib.effect;
-                doVibratorOn(oneShot.getDuration(), oneShot.getAmplitude(), vib.uid, vib.usageHint);
+                doVibratorOn(oneShot.getDuration(), oneShot.getAmplitude(), vib.uid, vib.attrs);
                 mH.postDelayed(mVibrationEndRunnable, oneShot.getDuration());
             } else if (vib.effect instanceof VibrationEffect.Waveform) {
                 // mThread better be null here. doCancelVibrate should always be
                 // called before startNextVibrationLocked or startVibrationLocked.
                 Trace.asyncTraceBegin(Trace.TRACE_TAG_VIBRATOR, "vibration", 0);
                 VibrationEffect.Waveform waveform = (VibrationEffect.Waveform) vib.effect;
-                mThread = new VibrateThread(waveform, vib.uid, vib.usageHint);
+                mThread = new VibrateThread(waveform, vib.uid, vib.attrs);
                 mThread.start();
             } else if (vib.effect instanceof VibrationEffect.Prebaked) {
                 Trace.asyncTraceBegin(Trace.TRACE_TAG_VIBRATOR, "vibration", 0);
@@ -788,13 +809,14 @@
             return true;
         }
 
-        if (vib.usageHint == AudioAttributes.USAGE_NOTIFICATION_RINGTONE) {
+        if (vib.attrs.getUsage() == AudioAttributes.USAGE_NOTIFICATION_RINGTONE) {
             return true;
         }
 
-        if (vib.usageHint == AudioAttributes.USAGE_ALARM ||
-                vib.usageHint == AudioAttributes.USAGE_ASSISTANCE_ACCESSIBILITY ||
-                vib.usageHint == AudioAttributes.USAGE_NOTIFICATION_COMMUNICATION_REQUEST) {
+        if (vib.attrs.getUsage() == AudioAttributes.USAGE_ALARM
+                || vib.attrs.getUsage() == AudioAttributes.USAGE_ASSISTANCE_ACCESSIBILITY
+                || vib.attrs.getUsage()
+                    == AudioAttributes.USAGE_NOTIFICATION_COMMUNICATION_REQUEST) {
             return true;
         }
 
@@ -887,12 +909,24 @@
         }
     }
 
+    private static boolean shouldBypassDnd(AudioAttributes attrs) {
+        return (attrs.getAllFlags() & AudioAttributes.FLAG_BYPASS_INTERRUPTION_POLICY) != 0;
+    }
+
     private int getAppOpMode(Vibration vib) {
         int mode = mAppOps.checkAudioOpNoThrow(AppOpsManager.OP_VIBRATE,
-                vib.usageHint, vib.uid, vib.opPkg);
+                vib.attrs.getUsage(), vib.uid, vib.opPkg);
         if (mode == AppOpsManager.MODE_ALLOWED) {
             mode = mAppOps.startOpNoThrow(AppOpsManager.OP_VIBRATE, vib.uid, vib.opPkg);
         }
+
+        if (mode == AppOpsManager.MODE_IGNORED && shouldBypassDnd(vib.attrs)) {
+            // If we're just ignoring the vibration op then this is set by DND and we should ignore
+            // if we're asked to bypass. AppOps won't be able to record this operation, so make
+            // sure we at least note it in the logs for debugging.
+            Slog.d(TAG, "Bypassing DND for vibration: " + vib);
+            mode = AppOpsManager.MODE_ALLOWED;
+        }
         return mode;
     }
 
@@ -1032,7 +1066,7 @@
         return vibratorExists();
     }
 
-    private void doVibratorOn(long millis, int amplitude, int uid, int usageHint) {
+    private void doVibratorOn(long millis, int amplitude, int uid, AudioAttributes attrs) {
         Trace.traceBegin(Trace.TRACE_TAG_VIBRATOR, "doVibratorOn");
         try {
             synchronized (mInputDeviceVibrators) {
@@ -1046,10 +1080,8 @@
                 noteVibratorOnLocked(uid, millis);
                 final int vibratorCount = mInputDeviceVibrators.size();
                 if (vibratorCount != 0) {
-                    final AudioAttributes attributes =
-                            new AudioAttributes.Builder().setUsage(usageHint).build();
                     for (int i = 0; i < vibratorCount; i++) {
-                        mInputDeviceVibrators.get(i).vibrate(millis, attributes);
+                        mInputDeviceVibrators.get(i).vibrate(millis, attrs);
                     }
                 } else {
                     // Note: ordering is important here! Many haptic drivers will reset their
@@ -1118,7 +1150,7 @@
                 Slog.w(TAG, "Failed to play prebaked effect, no fallback");
                 return 0;
             }
-            Vibration fallbackVib = new Vibration(vib.token, effect, vib.usageHint, vib.uid,
+            Vibration fallbackVib = new Vibration(vib.token, effect, vib.attrs, vib.uid,
                     vib.opPkg, vib.reason + " (fallback)");
             final int intensity = getCurrentIntensityLocked(fallbackVib);
             linkVibration(fallbackVib);
@@ -1156,6 +1188,7 @@
     private static boolean isNotification(int usageHint) {
         switch (usageHint) {
             case AudioAttributes.USAGE_NOTIFICATION:
+            case AudioAttributes.USAGE_NOTIFICATION_EVENT:
             case AudioAttributes.USAGE_NOTIFICATION_COMMUNICATION_REQUEST:
             case AudioAttributes.USAGE_NOTIFICATION_COMMUNICATION_INSTANT:
             case AudioAttributes.USAGE_NOTIFICATION_COMMUNICATION_DELAYED:
@@ -1213,14 +1246,14 @@
     private class VibrateThread extends Thread {
         private final VibrationEffect.Waveform mWaveform;
         private final int mUid;
-        private final int mUsageHint;
+        private final AudioAttributes mAttrs;
 
         private boolean mForceStop;
 
-        VibrateThread(VibrationEffect.Waveform waveform, int uid, int usageHint) {
+        VibrateThread(VibrationEffect.Waveform waveform, int uid, AudioAttributes attrs) {
             mWaveform = waveform;
             mUid = uid;
-            mUsageHint = usageHint;
+            mAttrs = attrs;
             mTmpWorkSource.set(uid);
             mWakeLock.setWorkSource(mTmpWorkSource);
         }
@@ -1295,7 +1328,7 @@
                                     // appropriate intervals.
                                     onDuration = getTotalOnDuration(timings, amplitudes, index - 1,
                                             repeat);
-                                    doVibratorOn(onDuration, amplitude, mUid, mUsageHint);
+                                    doVibratorOn(onDuration, amplitude, mUid, mAttrs);
                                 } else {
                                     doVibratorSetAmplitude(amplitude);
                                 }
@@ -1612,8 +1645,9 @@
 
                 VibrationEffect effect =
                         VibrationEffect.createOneShot(duration, VibrationEffect.DEFAULT_AMPLITUDE);
-                vibrate(Binder.getCallingUid(), description, effect, AudioAttributes.USAGE_UNKNOWN,
-                        "Shell Command", mToken);
+                AudioAttributes attrs = createAudioAttributes(commonOptions);
+                vibrate(Binder.getCallingUid(), description, effect, attrs, "Shell Command",
+                        mToken);
                 return 0;
             } finally {
                 Trace.traceEnd(Trace.TRACE_TAG_VIBRATOR);
@@ -1672,8 +1706,9 @@
                             amplitudesList.stream().mapToInt(Integer::intValue).toArray();
                     effect = VibrationEffect.createWaveform(timings, amplitudes, repeat);
                 }
-                vibrate(Binder.getCallingUid(), description, effect, AudioAttributes.USAGE_UNKNOWN,
-                        "Shell Command", mToken);
+                AudioAttributes attrs = createAudioAttributes(commonOptions);
+                vibrate(Binder.getCallingUid(), description, effect, attrs, "Shell Command",
+                        mToken);
                 return 0;
             } finally {
                 Trace.traceEnd(Trace.TRACE_TAG_VIBRATOR);
@@ -1703,14 +1738,25 @@
 
                 VibrationEffect effect =
                         VibrationEffect.get(id, false);
-                vibrate(Binder.getCallingUid(), description, effect, AudioAttributes.USAGE_UNKNOWN,
-                        "Shell Command", mToken);
+                AudioAttributes attrs = createAudioAttributes(commonOptions);
+                vibrate(Binder.getCallingUid(), description, effect, attrs, "Shell Command",
+                        mToken);
                 return 0;
             } finally {
                 Trace.traceEnd(Trace.TRACE_TAG_VIBRATOR);
             }
         }
 
+        private AudioAttributes createAudioAttributes(CommonOptions commonOptions) {
+            final int flags = commonOptions.force
+                    ? AudioAttributes.FLAG_BYPASS_INTERRUPTION_POLICY
+                    : 0;
+            return new AudioAttributes.Builder()
+                    .setUsage(AudioAttributes.USAGE_UNKNOWN)
+                    .setFlags(flags)
+                    .build();
+        }
+
         @Override
         public void onHelp() {
             try (PrintWriter pw = getOutPrintWriter();) {
diff --git a/services/core/java/com/android/server/Watchdog.java b/services/core/java/com/android/server/Watchdog.java
index 1046e82..19ad32e 100644
--- a/services/core/java/com/android/server/Watchdog.java
+++ b/services/core/java/com/android/server/Watchdog.java
@@ -112,6 +112,7 @@
             "android.hardware.media.c2@1.0::IComponentStore",
             "android.hardware.media.omx@1.0::IOmx",
             "android.hardware.media.omx@1.0::IOmxStore",
+            "android.hardware.power.stats@1.0::IPowerStats",
             "android.hardware.sensors@1.0::ISensors",
             "android.hardware.vr@1.0::IVr",
             "android.system.suspend@1.0::ISystemSuspend"
diff --git a/services/core/java/com/android/server/WiredAccessoryManager.java b/services/core/java/com/android/server/WiredAccessoryManager.java
index 9bbc315..8e5c73bf 100644
--- a/services/core/java/com/android/server/WiredAccessoryManager.java
+++ b/services/core/java/com/android/server/WiredAccessoryManager.java
@@ -16,33 +16,33 @@
 
 package com.android.server;
 
+import static com.android.server.input.InputManagerService.SW_HEADPHONE_INSERT;
+import static com.android.server.input.InputManagerService.SW_HEADPHONE_INSERT_BIT;
+import static com.android.server.input.InputManagerService.SW_LINEOUT_INSERT;
+import static com.android.server.input.InputManagerService.SW_LINEOUT_INSERT_BIT;
+import static com.android.server.input.InputManagerService.SW_MICROPHONE_INSERT;
+import static com.android.server.input.InputManagerService.SW_MICROPHONE_INSERT_BIT;
+
 import android.content.Context;
+import android.media.AudioManager;
 import android.os.Handler;
 import android.os.Looper;
 import android.os.Message;
 import android.os.PowerManager;
 import android.os.PowerManager.WakeLock;
 import android.os.UEventObserver;
+import android.util.Log;
 import android.util.Pair;
 import android.util.Slog;
-import android.media.AudioManager;
-import android.util.Log;
 import android.view.InputDevice;
 
 import com.android.internal.R;
 import com.android.server.input.InputManagerService;
 import com.android.server.input.InputManagerService.WiredAccessoryCallbacks;
 
-import static com.android.server.input.InputManagerService.SW_HEADPHONE_INSERT;
-import static com.android.server.input.InputManagerService.SW_MICROPHONE_INSERT;
-import static com.android.server.input.InputManagerService.SW_LINEOUT_INSERT;
-import static com.android.server.input.InputManagerService.SW_HEADPHONE_INSERT_BIT;
-import static com.android.server.input.InputManagerService.SW_MICROPHONE_INSERT_BIT;
-import static com.android.server.input.InputManagerService.SW_LINEOUT_INSERT_BIT;
-
 import java.io.File;
-import java.io.FileReader;
 import java.io.FileNotFoundException;
+import java.io.FileReader;
 import java.io.IOException;
 import java.util.ArrayList;
 import java.util.List;
@@ -538,7 +538,7 @@
             synchronized (mLock) {
                 int mask = maskAndState.first;
                 int state = maskAndState.second;
-                updateLocked(name, mHeadsetState | (mask & state) & ~(mask & ~state));
+                updateLocked(name, mHeadsetState & ~(mask & ~state) | (mask & state));
                 return;
             }
         }
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index e462c7d..cc5932e 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -5267,7 +5267,7 @@
             storageManager.commitChanges();
         } catch (Exception e) {
             PowerManager pm = (PowerManager)
-                     mInjector.getContext().getSystemService(Context.POWER_SERVICE);
+                     mContext.getSystemService(Context.POWER_SERVICE);
             pm.reboot("Checkpoint commit failed");
         }
 
@@ -8475,32 +8475,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
@@ -17979,11 +17953,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/ActivityManagerShellCommand.java b/services/core/java/com/android/server/am/ActivityManagerShellCommand.java
index 6db9702..4017fc3 100644
--- a/services/core/java/com/android/server/am/ActivityManagerShellCommand.java
+++ b/services/core/java/com/android/server/am/ActivityManagerShellCommand.java
@@ -513,12 +513,12 @@
                 options.setLockTaskEnabled(true);
             }
             if (mWaitOption) {
-                result = mInternal.startActivityAndWait(null, null, intent, mimeType,
+                result = mInternal.startActivityAndWait(null, SHELL_PACKAGE_NAME, intent, mimeType,
                         null, null, 0, mStartFlags, profilerInfo,
                         options != null ? options.toBundle() : null, mUserId);
                 res = result.result;
             } else {
-                res = mInternal.startActivityAsUser(null, null, intent, mimeType,
+                res = mInternal.startActivityAsUser(null, SHELL_PACKAGE_NAME, intent, mimeType,
                         null, null, 0, mStartFlags, profilerInfo,
                         options != null ? options.toBundle() : null, mUserId);
             }
diff --git a/services/core/java/com/android/server/am/BatteryStatsService.java b/services/core/java/com/android/server/am/BatteryStatsService.java
index e2b59b4..c2f4529 100644
--- a/services/core/java/com/android/server/am/BatteryStatsService.java
+++ b/services/core/java/com/android/server/am/BatteryStatsService.java
@@ -108,7 +108,7 @@
                     .replaceWith("?");
     private ByteBuffer mUtf8BufferStat = ByteBuffer.allocateDirect(MAX_LOW_POWER_STATS_SIZE);
     private CharBuffer mUtf16BufferStat = CharBuffer.allocate(MAX_LOW_POWER_STATS_SIZE);
-    private static final int MAX_LOW_POWER_STATS_SIZE = 2048;
+    private static final int MAX_LOW_POWER_STATS_SIZE = 4096;
 
     /**
      * Replaces the information in the given rpmStats with up-to-date information.
diff --git a/services/core/java/com/android/server/am/OomAdjuster.java b/services/core/java/com/android/server/am/OomAdjuster.java
index bcfe71b8..dbf8acf 100644
--- a/services/core/java/com/android/server/am/OomAdjuster.java
+++ b/services/core/java/com/android/server/am/OomAdjuster.java
@@ -34,6 +34,7 @@
 import static android.os.Process.THREAD_GROUP_DEFAULT;
 import static android.os.Process.THREAD_GROUP_RESTRICTED;
 import static android.os.Process.THREAD_GROUP_TOP_APP;
+import static android.os.Process.THREAD_PRIORITY_DISPLAY;
 import static android.os.Process.setProcessGroup;
 import static android.os.Process.setThreadPriority;
 import static android.os.Process.setThreadScheduler;
@@ -1803,7 +1804,6 @@
                                 if (app.renderThreadTid != 0) {
                                     setThreadScheduler(app.renderThreadTid,
                                             SCHED_OTHER, 0);
-                                    setThreadPriority(app.renderThreadTid, -4);
                                 }
                             } catch (IllegalArgumentException e) {
                                 Slog.w(TAG,
@@ -1815,9 +1815,10 @@
                         } else {
                             // Reset priority for top app UI and render threads
                             setThreadPriority(app.pid, 0);
-                            if (app.renderThreadTid != 0) {
-                                setThreadPriority(app.renderThreadTid, 0);
-                            }
+                        }
+
+                        if (app.renderThreadTid != 0) {
+                            setThreadPriority(app.renderThreadTid, THREAD_PRIORITY_DISPLAY);
                         }
                     }
                 } catch (Exception e) {
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/am/TEST_MAPPING b/services/core/java/com/android/server/am/TEST_MAPPING
index 884e7a5..21d4925 100644
--- a/services/core/java/com/android/server/am/TEST_MAPPING
+++ b/services/core/java/com/android/server/am/TEST_MAPPING
@@ -14,15 +14,6 @@
         },
         {
           "exclude-annotation": "androidx.test.filters.FlakyTest"
-        },
-        {
-          "exclude-filter": "android.app.cts.AlarmManagerTest#testSetRepeating"
-        },
-        {
-          "exclude-filter": "android.app.cts.SystemFeaturesTest#testLocationFeatures"
-        },
-        {
-          "exclude-filter": "android.app.cts.SystemFeaturesTest#testSensorFeatures"
         }
       ]
     },
diff --git a/services/core/java/com/android/server/attention/AttentionManagerService.java b/services/core/java/com/android/server/attention/AttentionManagerService.java
index 1b45eb4..087c84f 100644
--- a/services/core/java/com/android/server/attention/AttentionManagerService.java
+++ b/services/core/java/com/android/server/attention/AttentionManagerService.java
@@ -375,7 +375,7 @@
 
     private void dumpInternal(IndentingPrintWriter ipw) {
         ipw.println("Attention Manager Service (dumpsys attention) state:\n");
-
+        ipw.println("isServiceEnabled=" + isServiceEnabled());
         ipw.println("AttentionServicePackageName=" + getServiceConfigPackage(mContext));
         ipw.println("Resolved component:");
         if (mComponentName != null) {
diff --git a/services/core/java/com/android/server/biometrics/AuthenticationClient.java b/services/core/java/com/android/server/biometrics/AuthenticationClient.java
index b899d02..4a9ccde 100644
--- a/services/core/java/com/android/server/biometrics/AuthenticationClient.java
+++ b/services/core/java/com/android/server/biometrics/AuthenticationClient.java
@@ -46,6 +46,7 @@
     // authentication while the device is already locked out. In that case, the client is created
     // but not started yet. The user shouldn't receive the error haptics in this case.
     private boolean mStarted;
+    private long mStartTimeMs;
 
     /**
      * This method is called when authentication starts.
@@ -75,6 +76,10 @@
         mRequireConfirmation = requireConfirmation;
     }
 
+    protected long getStartTimeMs() {
+        return mStartTimeMs;
+    }
+
     @Override
     public void binderDied() {
         super.binderDied();
@@ -228,6 +233,7 @@
         mStarted = true;
         onStart();
         try {
+            mStartTimeMs = System.currentTimeMillis();
             final int result = getDaemonWrapper().authenticate(mOpId, getGroupId());
             if (result != 0) {
                 Slog.w(getLogTag(), "startAuthentication failed, result=" + result);
diff --git a/services/core/java/com/android/server/biometrics/BiometricService.java b/services/core/java/com/android/server/biometrics/BiometricService.java
index db17f83..af2f24f 100644
--- a/services/core/java/com/android/server/biometrics/BiometricService.java
+++ b/services/core/java/com/android/server/biometrics/BiometricService.java
@@ -170,6 +170,8 @@
         // the authentication.
         byte[] mTokenEscrow;
 
+        // Timestamp when authentication started
+        private long mStartTimeMs;
         // Timestamp when hardware authentication occurred
         private long mAuthenticatedTimeMs;
 
@@ -519,8 +521,8 @@
             List<EnabledOnKeyguardCallback> callbacks = mEnabledOnKeyguardCallbacks;
             for (int i = 0; i < callbacks.size(); i++) {
                 callbacks.get(i).notify(BiometricSourceType.FACE,
-                        mFaceEnabledOnKeyguard.getOrDefault(userId,
-                                DEFAULT_KEYGUARD_ENABLED));
+                        mFaceEnabledOnKeyguard.getOrDefault(userId, DEFAULT_KEYGUARD_ENABLED),
+                        userId);
             }
         }
     }
@@ -538,9 +540,9 @@
             }
         }
 
-        void notify(BiometricSourceType sourceType, boolean enabled) {
+        void notify(BiometricSourceType sourceType, boolean enabled, int userId) {
             try {
-                mCallback.onChanged(sourceType, enabled);
+                mCallback.onChanged(sourceType, enabled, userId);
             } catch (DeadObjectException e) {
                 Slog.w(TAG, "Death while invoking notify", e);
                 mEnabledOnKeyguardCallbacks.remove(this);
@@ -766,10 +768,16 @@
         }
 
         @Override // Binder call
-        public int canAuthenticate(String opPackageName) {
-            checkPermission();
+        public int canAuthenticate(String opPackageName, int userId) {
+            Slog.d(TAG, "canAuthenticate: User=" + userId
+                    + ", Caller=" + UserHandle.getCallingUserId());
 
-            final int userId = UserHandle.getCallingUserId();
+            if (userId != UserHandle.getCallingUserId()) {
+                checkInternalPermission();
+            } else {
+                checkPermission();
+            }
+
             final long ident = Binder.clearCallingIdentity();
             int error;
             try {
@@ -781,6 +789,23 @@
             return error;
         }
 
+        @Override
+        public boolean hasEnrolledBiometrics(int userId) {
+            checkInternalPermission();
+
+            final long ident = Binder.clearCallingIdentity();
+            try {
+                for (int i = 0; i < mAuthenticators.size(); i++) {
+                    if (mAuthenticators.get(i).mAuthenticator.hasEnrolledTemplates(userId)) {
+                        return true;
+                    }
+                }
+            } finally {
+                Binder.restoreCallingIdentity(ident);
+            }
+            return false;
+        }
+
         @Override // Binder call
         public void registerEnabledOnKeyguardCallback(IBiometricEnabledOnKeyguardCallback callback)
                 throws RemoteException {
@@ -788,7 +813,8 @@
             mEnabledOnKeyguardCallbacks.add(new EnabledOnKeyguardCallback(callback));
             try {
                 callback.onChanged(BiometricSourceType.FACE,
-                        mSettingObserver.getFaceEnabledOnKeyguard());
+                        mSettingObserver.getFaceEnabledOnKeyguard(),
+                        UserHandle.getCallingUserId());
             } catch (RemoteException e) {
                 Slog.w(TAG, "Remote exception", e);
             }
@@ -965,6 +991,11 @@
             }
         }
 
+        Slog.d(TAG, "checkAndGetBiometricModality: user=" + userId
+                + " isHardwareDetected=" + isHardwareDetected
+                + " hasTemplatesEnrolled=" + hasTemplatesEnrolled
+                + " enabledForApps=" + enabledForApps);
+
         // Check error conditions
         if (!isHardwareDetected) {
             return new Pair<>(TYPE_NONE, BiometricConstants.BIOMETRIC_ERROR_HW_UNAVAILABLE);
@@ -1065,6 +1096,9 @@
                     latency,
                     Utils.isDebugEnabled(getContext(), mCurrentAuthSession.mUserId));
         } else {
+
+            final long latency = System.currentTimeMillis() - mCurrentAuthSession.mStartTimeMs;
+
             int error = reason == BiometricPrompt.DISMISSED_REASON_NEGATIVE
                     ? BiometricConstants.BIOMETRIC_ERROR_NEGATIVE_BUTTON
                     : reason == BiometricPrompt.DISMISSED_REASON_USER_CANCEL
@@ -1076,7 +1110,8 @@
                         + ", IsCrypto: " + mCurrentAuthSession.isCrypto()
                         + ", Action: " + BiometricsProtoEnums.ACTION_AUTHENTICATE
                         + ", Client: " + BiometricsProtoEnums.CLIENT_BIOMETRIC_PROMPT
-                        + ", Error: " + error);
+                        + ", Error: " + error
+                        + ", Latency: " + latency);
             }
             // Auth canceled
             StatsLog.write(StatsLog.BIOMETRIC_ERROR_OCCURRED,
@@ -1087,7 +1122,8 @@
                     BiometricsProtoEnums.CLIENT_BIOMETRIC_PROMPT,
                     error,
                     0 /* vendorCode */,
-                    Utils.isDebugEnabled(getContext(), mCurrentAuthSession.mUserId));
+                    Utils.isDebugEnabled(getContext(), mCurrentAuthSession.mUserId),
+                    latency);
         }
     }
 
@@ -1411,6 +1447,9 @@
                     && mCurrentAuthSession.mState == STATE_AUTH_PAUSED;
 
             mCurrentAuthSession = mPendingAuthSession;
+
+            // Time starts when lower layers are ready to start the client.
+            mCurrentAuthSession.mStartTimeMs = System.currentTimeMillis();
             mPendingAuthSession = null;
 
             mCurrentAuthSession.mState = STATE_AUTH_STARTED;
diff --git a/services/core/java/com/android/server/biometrics/BiometricServiceBase.java b/services/core/java/com/android/server/biometrics/BiometricServiceBase.java
index d3c62be..f3f9754 100644
--- a/services/core/java/com/android/server/biometrics/BiometricServiceBase.java
+++ b/services/core/java/com/android/server/biometrics/BiometricServiceBase.java
@@ -282,10 +282,10 @@
         public EnrollClientImpl(Context context, DaemonWrapper daemon, long halDeviceId,
                 IBinder token, ServiceListener listener, int userId, int groupId,
                 byte[] cryptoToken, boolean restricted, String owner,
-                final int[] disabledFeatures) {
+                final int[] disabledFeatures, int timeoutSec) {
             super(context, getConstants(), daemon, halDeviceId, token, listener,
                     userId, groupId, cryptoToken, restricted, owner, getBiometricUtils(),
-                    disabledFeatures);
+                    disabledFeatures, timeoutSec);
         }
 
         @Override
@@ -497,9 +497,9 @@
         }
     }
 
-    private final class BiometricTaskStackListener extends TaskStackListener {
+    private final Runnable mOnTaskStackChangedRunnable = new Runnable() {
         @Override
-        public void onTaskStackChanged() {
+        public void run() {
             try {
                 if (!(mCurrentClient instanceof AuthenticationClient)) {
                     return;
@@ -514,8 +514,8 @@
                     final String topPackage = runningTasks.get(0).topActivity.getPackageName();
                     if (!topPackage.contentEquals(currentClient)
                             && !mCurrentClient.isAlreadyDone()) {
-                        Slog.e(getTag(), "Stopping background authentication, top: " + topPackage
-                                + " currentClient: " + currentClient);
+                        Slog.e(getTag(), "Stopping background authentication, top: "
+                                + topPackage + " currentClient: " + currentClient);
                         mCurrentClient.stop(false /* initiatedByClient */);
                     }
                 }
@@ -523,6 +523,13 @@
                 Slog.e(getTag(), "Unable to get running tasks", e);
             }
         }
+    };
+
+    private final class BiometricTaskStackListener extends TaskStackListener {
+        @Override
+        public void onTaskStackChanged() {
+            mHandler.post(mOnTaskStackChangedRunnable);
+        }
     }
 
     private final class ResetClientStateRunnable implements Runnable {
@@ -658,8 +665,12 @@
         mMetricsLogger.count(getConstants().tagHalDied(), 1);
         mHALDeathCount++;
         mCurrentUserId = UserHandle.USER_NULL;
-        handleError(getHalDeviceId(), BiometricConstants.BIOMETRIC_ERROR_HW_UNAVAILABLE,
-                0 /*vendorCode */);
+
+        // All client lifecycle must be managed on the handler.
+        mHandler.post(() -> {
+            handleError(getHalDeviceId(), BiometricConstants.BIOMETRIC_ERROR_HW_UNAVAILABLE,
+                    0 /*vendorCode */);
+        });
 
         StatsLog.write(StatsLog.BIOMETRIC_SYSTEM_HEALTH_ISSUE_DETECTED, statsModality(),
                 BiometricsProtoEnums.ISSUE_HAL_DEATH);
@@ -713,8 +724,6 @@
             // already generated a new authenticator id when the new biometric is enrolled.
             if (identifier instanceof Fingerprint) {
                 updateActiveGroup(((Fingerprint)identifier).getGroupId(), null);
-            } else {
-                updateActiveGroup(mCurrentUserId, null);
             }
         }
     }
@@ -903,8 +912,12 @@
     }
 
     protected void setActiveUserInternal(int userId) {
-        // Do not put on handler, since it should finish before returning to caller.
-        updateActiveGroup(userId, null /* clientPackage */);
+        mHandler.post(() -> {
+            if (DEBUG) {
+                Slog.d(getTag(), "setActiveUser(" + userId + ")");
+            }
+            updateActiveGroup(userId, null /* clientPackage */);
+        });
     }
 
     protected void removeInternal(RemovalClient client) {
@@ -1090,6 +1103,8 @@
         if (DEBUG) Slog.v(getTag(), "starting client "
                 + mCurrentClient.getClass().getSuperclass().getSimpleName()
                 + "(" + mCurrentClient.getOwnerString() + ")"
+                + " targetUserId: " + mCurrentClient.getTargetUserId()
+                + " currentUserId: " + mCurrentUserId
                 + " cookie: " + cookie + "/" + mCurrentClient.getCookie());
         if (cookie != mCurrentClient.getCookie()) {
             Slog.e(getTag(), "Mismatched cookie");
diff --git a/services/core/java/com/android/server/biometrics/EnrollClient.java b/services/core/java/com/android/server/biometrics/EnrollClient.java
index 854528f..7ebb7c0 100644
--- a/services/core/java/com/android/server/biometrics/EnrollClient.java
+++ b/services/core/java/com/android/server/biometrics/EnrollClient.java
@@ -31,11 +31,11 @@
  * A class to keep track of the enrollment state for a given client.
  */
 public abstract class EnrollClient extends ClientMonitor {
-    private static final long MS_PER_SEC = 1000;
-    private static final int ENROLLMENT_TIMEOUT_MS = 60 * 1000; // 1 minute
     private final byte[] mCryptoToken;
     private final BiometricUtils mBiometricUtils;
     private final int[] mDisabledFeatures;
+    private final int mTimeoutSec;
+
     private long mEnrollmentStartTimeMs;
 
     public abstract boolean shouldVibrate();
@@ -44,12 +44,13 @@
             BiometricServiceBase.DaemonWrapper daemon, long halDeviceId, IBinder token,
             BiometricServiceBase.ServiceListener listener, int userId, int groupId,
             byte[] cryptoToken, boolean restricted, String owner, BiometricUtils utils,
-            final int[] disabledFeatures) {
+            final int[] disabledFeatures, int timeoutSec) {
         super(context, constants, daemon, halDeviceId, token, listener, userId, groupId, restricted,
                 owner, 0 /* cookie */);
         mBiometricUtils = utils;
         mCryptoToken = Arrays.copyOf(cryptoToken, cryptoToken.length);
         mDisabledFeatures = Arrays.copyOf(disabledFeatures, disabledFeatures.length);
+        mTimeoutSec = timeoutSec;
     }
 
     @Override
@@ -94,14 +95,13 @@
     @Override
     public int start() {
         mEnrollmentStartTimeMs = System.currentTimeMillis();
-        final int timeout = (int) (ENROLLMENT_TIMEOUT_MS / MS_PER_SEC);
         try {
             final ArrayList<Integer> disabledFeatures = new ArrayList<>();
             for (int i = 0; i < mDisabledFeatures.length; i++) {
                 disabledFeatures.add(mDisabledFeatures[i]);
             }
 
-            final int result = getDaemonWrapper().enroll(mCryptoToken, getGroupId(), timeout,
+            final int result = getDaemonWrapper().enroll(mCryptoToken, getGroupId(), mTimeoutSec,
                     disabledFeatures);
             if (result != 0) {
                 Slog.w(getLogTag(), "startEnroll failed, result=" + result);
diff --git a/services/core/java/com/android/server/biometrics/LoggableMonitor.java b/services/core/java/com/android/server/biometrics/LoggableMonitor.java
index 9c04088..ecf3864 100644
--- a/services/core/java/com/android/server/biometrics/LoggableMonitor.java
+++ b/services/core/java/com/android/server/biometrics/LoggableMonitor.java
@@ -33,6 +33,10 @@
 
     private long mFirstAcquireTimeMs;
 
+    protected long getFirstAcquireTimeMs() {
+        return mFirstAcquireTimeMs;
+    }
+
     /**
      * Only valid for AuthenticationClient.
      * @return true if the client is authenticating for a crypto operation.
@@ -89,11 +93,15 @@
                 statsAction(),
                 statsClient(),
                 acquiredInfo,
-                0 /* vendorCode */, // Don't log vendorCode for now
+                vendorCode,
                 Utils.isDebugEnabled(context, targetUserId));
     }
 
     protected final void logOnError(Context context, int error, int vendorCode, int targetUserId) {
+
+        final long latency = mFirstAcquireTimeMs != 0
+                ? (System.currentTimeMillis() - mFirstAcquireTimeMs) : -1;
+
         if (DEBUG) {
             Slog.v(TAG, "Error! Modality: " + statsModality()
                     + ", User: " + targetUserId
@@ -101,7 +109,10 @@
                     + ", Action: " + statsAction()
                     + ", Client: " + statsClient()
                     + ", Error: " + error
-                    + ", VendorCode: " + vendorCode);
+                    + ", VendorCode: " + vendorCode
+                    + ", Latency: " + latency);
+        } else {
+            Slog.v(TAG, "Error latency: " + latency);
         }
         StatsLog.write(StatsLog.BIOMETRIC_ERROR_OCCURRED,
                 statsModality(),
@@ -111,7 +122,8 @@
                 statsClient(),
                 error,
                 vendorCode,
-                Utils.isDebugEnabled(context, targetUserId));
+                Utils.isDebugEnabled(context, targetUserId),
+                latency);
     }
 
     protected final void logOnAuthenticated(Context context, boolean authenticated,
diff --git a/services/core/java/com/android/server/biometrics/Utils.java b/services/core/java/com/android/server/biometrics/Utils.java
index 5544bed..4fa29ac 100644
--- a/services/core/java/com/android/server/biometrics/Utils.java
+++ b/services/core/java/com/android/server/biometrics/Utils.java
@@ -18,10 +18,15 @@
 
 import android.content.Context;
 import android.os.Build;
+import android.os.UserHandle;
 import android.provider.Settings;
 
 public class Utils {
     public static boolean isDebugEnabled(Context context, int targetUserId) {
+        if (targetUserId == UserHandle.USER_NULL) {
+            return false;
+        }
+
         if (!(Build.IS_ENG || Build.IS_USERDEBUG)) {
             return false;
         }
diff --git a/services/core/java/com/android/server/biometrics/face/FaceService.java b/services/core/java/com/android/server/biometrics/face/FaceService.java
index 463a499..ee49f58 100644
--- a/services/core/java/com/android/server/biometrics/face/FaceService.java
+++ b/services/core/java/com/android/server/biometrics/face/FaceService.java
@@ -54,7 +54,6 @@
 import android.os.UserHandle;
 import android.os.UserManager;
 import android.util.Slog;
-import android.util.proto.ProtoOutputStream;
 
 import com.android.internal.R;
 import com.android.internal.annotations.GuardedBy;
@@ -64,6 +63,7 @@
 import com.android.server.biometrics.AuthenticationClient;
 import com.android.server.biometrics.BiometricServiceBase;
 import com.android.server.biometrics.BiometricUtils;
+import com.android.server.biometrics.ClientMonitor;
 import com.android.server.biometrics.Constants;
 import com.android.server.biometrics.EnumerateClient;
 import com.android.server.biometrics.RemovalClient;
@@ -79,7 +79,9 @@
 import java.io.PrintWriter;
 import java.util.ArrayList;
 import java.util.Arrays;
+import java.util.HashMap;
 import java.util.List;
+import java.util.Map;
 
 /**
  * A service to manage multiple clients that want to access the face HAL API.
@@ -97,6 +99,107 @@
             "com.android.server.biometrics.face.ACTION_LOCKOUT_RESET";
     private static final int CHALLENGE_TIMEOUT_SEC = 600; // 10 minutes
 
+    private static final String NOTIFICATION_TAG = "FaceService";
+    private static final int NOTIFICATION_ID = 1;
+
+    /**
+     * Events for bugreports.
+     */
+    public static final class AuthenticationEvent {
+        private long mStartTime;
+        private long mLatency;
+        // Only valid if mError is 0
+        private boolean mAuthenticated;
+        private int mError;
+        // Only valid if mError is ERROR_VENDOR
+        private int mVendorError;
+
+        AuthenticationEvent(long startTime, long latency, boolean authenticated, int error,
+                int vendorError) {
+            mStartTime = startTime;
+            mLatency = latency;
+            mAuthenticated = authenticated;
+            mError = error;
+            mVendorError = vendorError;
+        }
+
+        public String toString(Context context) {
+            return "Start: " + mStartTime
+                    + "\tLatency: " + mLatency
+                    + "\tAuthenticated: " + mAuthenticated
+                    + "\tError: " + mError
+                    + "\tVendorCode: " + mVendorError
+                    + "\t" + FaceManager.getErrorString(context, mError, mVendorError);
+        }
+    }
+
+    /**
+     * Keep a short historical buffer of stats, with an aggregated usage time.
+     */
+    private class UsageStats {
+        static final int EVENT_LOG_SIZE = 100;
+
+        Context mContext;
+        List<AuthenticationEvent> mAuthenticationEvents;
+
+        int acceptCount;
+        int rejectCount;
+        Map<Integer, Integer> mErrorCount;
+
+        long acceptLatency;
+        long rejectLatency;
+        Map<Integer, Long> mErrorLatency;
+
+        UsageStats(Context context) {
+            mAuthenticationEvents = new ArrayList<>();
+            mErrorCount = new HashMap<>();
+            mErrorLatency = new HashMap<>();
+            mContext = context;
+        }
+
+        void addEvent(AuthenticationEvent event) {
+            if (mAuthenticationEvents.size() >= EVENT_LOG_SIZE) {
+                mAuthenticationEvents.remove(0);
+            }
+            mAuthenticationEvents.add(event);
+
+            if (event.mAuthenticated) {
+                acceptCount++;
+                acceptLatency += event.mLatency;
+            } else if (event.mError == 0) {
+                rejectCount++;
+                rejectLatency += event.mLatency;
+            } else {
+                mErrorCount.put(event.mError, mErrorCount.getOrDefault(event.mError, 0) + 1);
+                mErrorLatency.put(event.mError,
+                        mErrorLatency.getOrDefault(event.mError, 0l) + event.mLatency);
+            }
+        }
+
+        void print(PrintWriter pw) {
+            pw.println("Events since last reboot: " + mAuthenticationEvents.size());
+            for (int i = 0; i < mAuthenticationEvents.size(); i++) {
+                pw.println(mAuthenticationEvents.get(i).toString(mContext));
+            }
+
+            // Dump aggregated usage stats
+            // TODO: Remove or combine with json dump in a future release
+            pw.println("Accept\tCount: " + acceptCount + "\tLatency: " + acceptLatency
+                    + "\tAverage: " + (acceptCount > 0 ? acceptLatency / acceptCount : 0));
+            pw.println("Reject\tCount: " + rejectCount + "\tLatency: " + rejectLatency
+                    + "\tAverage: " + (rejectCount > 0 ? rejectLatency / rejectCount : 0));
+
+            for (Integer key : mErrorCount.keySet()) {
+                final int count = mErrorCount.get(key);
+                pw.println("Error" + key + "\tCount: " + count
+                        + "\tLatency: " + mErrorLatency.getOrDefault(key, 0l)
+                        + "\tAverage: " + (count > 0 ? mErrorLatency.getOrDefault(key, 0l) / count
+                        : 0)
+                        + "\t" + FaceManager.getErrorString(mContext, key, 0 /* vendorCode */));
+            }
+        }
+    }
+
     private final class FaceAuthClient extends AuthenticationClientImpl {
         private int mLastAcquire;
 
@@ -120,7 +223,8 @@
 
         @Override
         public boolean wasUserDetected() {
-            return mLastAcquire != FaceManager.FACE_ACQUIRED_NOT_DETECTED;
+            return mLastAcquire != FaceManager.FACE_ACQUIRED_NOT_DETECTED
+                    && mLastAcquire != FaceManager.FACE_ACQUIRED_SENSOR_DIRTY;
         }
 
         @Override
@@ -128,6 +232,13 @@
                 boolean authenticated, ArrayList<Byte> token) {
             final boolean result = super.onAuthenticated(identifier, authenticated, token);
 
+            mUsageStats.addEvent(new AuthenticationEvent(
+                    getStartTimeMs(),
+                    System.currentTimeMillis() - getStartTimeMs() /* latency */,
+                    authenticated,
+                    0 /* error */,
+                    0 /* vendorError */));
+
             // For face, the authentication lifecycle ends either when
             // 1) Authenticated == true
             // 2) Error occurred
@@ -138,6 +249,18 @@
         }
 
         @Override
+        public boolean onError(long deviceId, int error, int vendorCode) {
+            mUsageStats.addEvent(new AuthenticationEvent(
+                    getStartTimeMs(),
+                    System.currentTimeMillis() - getStartTimeMs() /* latency */,
+                    false /* authenticated */,
+                    error,
+                    vendorCode));
+
+            return super.onError(deviceId, error, vendorCode);
+        }
+
+        @Override
         public int[] getAcquireIgnorelist() {
             if (isBiometricPrompt()) {
                 return mBiometricPromptIgnoreList;
@@ -177,13 +300,11 @@
                         0 /* requestCode */, intent, 0 /* flags */, null /* options */,
                         UserHandle.CURRENT);
 
-                final String id = "FaceService";
+                final String channelName = "FaceEnrollNotificationChannel";
 
-                NotificationManager nm =
-                        getContext().getSystemService(NotificationManager.class);
-                NotificationChannel channel = new NotificationChannel(id, name,
+                NotificationChannel channel = new NotificationChannel(channelName, name,
                         NotificationManager.IMPORTANCE_HIGH);
-                Notification notification = new Notification.Builder(getContext(), id)
+                Notification notification = new Notification.Builder(getContext(), channelName)
                         .setSmallIcon(R.drawable.ic_lock)
                         .setContentTitle(title)
                         .setContentText(content)
@@ -193,10 +314,12 @@
                         .setAutoCancel(true)
                         .setCategory(Notification.CATEGORY_SYSTEM)
                         .setContentIntent(pendingIntent)
+                        .setVisibility(Notification.VISIBILITY_SECRET)
                         .build();
 
-                nm.createNotificationChannel(channel);
-                nm.notifyAsUser(null /* tag */, 0 /* id */, notification, UserHandle.CURRENT);
+                mNotificationManager.createNotificationChannel(channel);
+                mNotificationManager.notifyAsUser(NOTIFICATION_TAG, NOTIFICATION_ID, notification,
+                        UserHandle.CURRENT);
             }
 
             return super.onAcquired(acquireInfo, vendorCode);
@@ -207,6 +330,7 @@
      * Receives the incoming binder calls from FaceManager.
      */
     private final class FaceServiceWrapper extends IFaceService.Stub {
+        private static final int ENROLL_TIMEOUT_SEC = 75;
 
         /**
          * The following methods contain common code which is shared in biometrics/common.
@@ -221,19 +345,36 @@
         @Override // Binder call
         public int revokeChallenge(IBinder token) {
             checkPermission(MANAGE_BIOMETRIC);
-            return startRevokeChallenge(token);
+            mHandler.post(() -> {
+                // TODO(b/137106905): Schedule binder calls in FaceService to avoid deadlocks.
+                if (getCurrentClient() == null) {
+                    // if we aren't handling any other HIDL calls (mCurrentClient == null), revoke
+                    // the challenge right away.
+                    startRevokeChallenge(token);
+                } else {
+                    // postpone revoking the challenge until we finish processing the current HIDL
+                    // call.
+                    mRevokeChallengePending = true;
+                }
+            });
+            return Status.OK;
         }
 
         @Override // Binder call
-        public void enroll(final IBinder token, final byte[] cryptoToken,
+        public void enroll(int userId, final IBinder token, final byte[] cryptoToken,
                 final IFaceServiceReceiver receiver, final String opPackageName,
                 final int[] disabledFeatures) {
             checkPermission(MANAGE_BIOMETRIC);
+            updateActiveGroup(userId, opPackageName);
+
+            mNotificationManager.cancelAsUser(NOTIFICATION_TAG, NOTIFICATION_ID,
+                    UserHandle.CURRENT);
 
             final boolean restricted = isRestricted();
             final EnrollClientImpl client = new EnrollClientImpl(getContext(), mDaemonWrapper,
                     mHalDeviceId, token, new ServiceListenerImpl(receiver), mCurrentUserId,
-                    0 /* groupId */, cryptoToken, restricted, opPackageName, disabledFeatures) {
+                    0 /* groupId */, cryptoToken, restricted, opPackageName, disabledFeatures,
+                    ENROLL_TIMEOUT_SEC) {
 
                 @Override
                 public int[] getAcquireIgnorelist() {
@@ -324,8 +465,9 @@
 
         @Override // Binder call
         public void remove(final IBinder token, final int faceId, final int userId,
-                final IFaceServiceReceiver receiver) {
+                final IFaceServiceReceiver receiver, final String opPackageName) {
             checkPermission(MANAGE_BIOMETRIC);
+            updateActiveGroup(userId, opPackageName);
 
             if (token == null) {
                 Slog.w(TAG, "remove(): token is null");
@@ -378,8 +520,6 @@
             try {
                 if (args.length > 1 && "--hal".equals(args[0])) {
                     dumpHal(fd, Arrays.copyOfRange(args, 1, args.length, args.getClass()));
-                } else if (args.length > 0 && "--proto".equals(args[0])) {
-                    dumpProto(fd);
                 } else {
                     dumpInternal(pw);
                 }
@@ -475,24 +615,32 @@
         public void resetLockout(byte[] token) {
             checkPermission(MANAGE_BIOMETRIC);
 
-            if (!FaceService.this.hasEnrolledBiometrics(mCurrentUserId)) {
-                Slog.w(TAG, "Ignoring lockout reset, no templates enrolled");
-                return;
-            }
+            mHandler.post(() -> {
+                if (!FaceService.this.hasEnrolledBiometrics(mCurrentUserId)) {
+                    Slog.w(TAG, "Ignoring lockout reset, no templates enrolled");
+                    return;
+                }
 
-            try {
-                mDaemonWrapper.resetLockout(token);
-            } catch (RemoteException e) {
-                Slog.e(getTag(), "Unable to reset lockout", e);
-            }
+                Slog.d(TAG, "Resetting lockout for user: " + mCurrentUserId);
+
+                try {
+                    mDaemonWrapper.resetLockout(token);
+                } catch (RemoteException e) {
+                    Slog.e(getTag(), "Unable to reset lockout", e);
+                }
+            });
         }
 
         @Override
-        public void setFeature(int feature, boolean enabled, final byte[] token,
-                IFaceServiceReceiver receiver) {
+        public void setFeature(int userId, int feature, boolean enabled, final byte[] token,
+                IFaceServiceReceiver receiver, final String opPackageName) {
             checkPermission(MANAGE_BIOMETRIC);
 
             mHandler.post(() -> {
+                if (DEBUG) {
+                    Slog.d(TAG, "setFeature for user(" + userId + ")");
+                }
+                updateActiveGroup(userId, opPackageName);
                 if (!FaceService.this.hasEnrolledBiometrics(mCurrentUserId)) {
                     Slog.e(TAG, "No enrolled biometrics while setting feature: " + feature);
                     return;
@@ -520,10 +668,15 @@
         }
 
         @Override
-        public void getFeature(int feature, IFaceServiceReceiver receiver) {
+        public void getFeature(int userId, int feature, IFaceServiceReceiver receiver,
+                final String opPackageName) {
             checkPermission(MANAGE_BIOMETRIC);
 
             mHandler.post(() -> {
+                if (DEBUG) {
+                    Slog.d(TAG, "getFeature for user(" + userId + ")");
+                }
+                updateActiveGroup(userId, opPackageName);
                 // This should ideally return tri-state, but the user isn't shown settings unless
                 // they are enrolled so it's fine for now.
                 if (!FaceService.this.hasEnrolledBiometrics(mCurrentUserId)) {
@@ -682,9 +835,13 @@
 
     @GuardedBy("this")
     private IBiometricsFace mDaemon;
+    private UsageStats mUsageStats;
+    private boolean mRevokeChallengePending = false;
     // One of the AuthenticationClient constants
     private int mCurrentUserLockoutMode;
 
+    private NotificationManager mNotificationManager;
+
     private int[] mBiometricPromptIgnoreList;
     private int[] mBiometricPromptIgnoreListVendor;
     private int[] mKeyguardIgnoreList;
@@ -704,6 +861,18 @@
                 final Face face = new Face(getBiometricUtils()
                         .getUniqueName(getContext(), userId), faceId, deviceId);
                 FaceService.super.handleEnrollResult(face, remaining);
+
+                // Enrollment changes the authenticatorId, so update it here.
+                IBiometricsFace daemon = getFaceDaemon();
+                if (remaining == 0 && daemon != null) {
+                    try {
+                        mAuthenticatorIds.put(userId,
+                                hasEnrolledBiometrics(userId) ? daemon.getAuthenticatorId().value
+                                        : 0L);
+                    } catch (RemoteException e) {
+                        Slog.e(TAG, "Unable to get authenticatorId", e);
+                    }
+                }
             });
         }
 
@@ -878,6 +1047,10 @@
     public FaceService(Context context) {
         super(context);
 
+        mUsageStats = new UsageStats(context);
+
+        mNotificationManager = getContext().getSystemService(NotificationManager.class);
+
         mBiometricPromptIgnoreList = getContext().getResources()
                 .getIntArray(R.array.config_face_acquire_biometricprompt_ignorelist);
         mBiometricPromptIgnoreListVendor = getContext().getResources()
@@ -893,10 +1066,22 @@
     }
 
     @Override
+    protected void removeClient(ClientMonitor client) {
+        super.removeClient(client);
+        if (mRevokeChallengePending) {
+            startRevokeChallenge(null);
+            mRevokeChallengePending = false;
+        }
+    }
+
+    @Override
     public void onStart() {
         super.onStart();
         publishBinderService(Context.FACE_SERVICE, new FaceServiceWrapper());
-        SystemServerInitThreadPool.get().submit(this::getFaceDaemon, TAG + ".onStart");
+        // Get the face daemon on FaceService's on thread so SystemServerInitThreadPool isn't
+        // blocked
+        SystemServerInitThreadPool.get().submit(() -> mHandler.post(this::getFaceDaemon),
+                TAG + ".onStart");
     }
 
     @Override
@@ -965,9 +1150,9 @@
 
                     daemon.setActiveUser(userId, faceDir.getAbsolutePath());
                     mCurrentUserId = userId;
+                    mAuthenticatorIds.put(userId,
+                            hasEnrolledBiometrics(userId) ? daemon.getAuthenticatorId().value : 0L);
                 }
-                mAuthenticatorIds.put(userId,
-                        hasEnrolledBiometrics(userId) ? daemon.getAuthenticatorId().value : 0L);
             } catch (RemoteException e) {
                 Slog.e(TAG, "Failed to setActiveUser():", e);
             }
@@ -1100,7 +1285,11 @@
             return 0;
         }
         try {
-            return daemon.revokeChallenge();
+            final int res = daemon.revokeChallenge();
+            if (res != Status.OK) {
+                Slog.e(TAG, "revokeChallenge returned " + res);
+            }
+            return res;
         } catch (RemoteException e) {
             Slog.e(TAG, "startRevokeChallenge failed", e);
         }
@@ -1142,51 +1331,9 @@
             Slog.e(TAG, "dump formatting failure", e);
         }
         pw.println(dump);
-        pw.println("HAL Deaths: " + mHALDeathCount);
-        mHALDeathCount = 0;
-    }
+        pw.println("HAL deaths since last reboot: " + mHALDeathCount);
 
-    private void dumpProto(FileDescriptor fd) {
-        final ProtoOutputStream proto = new ProtoOutputStream(fd);
-        for (UserInfo user : UserManager.get(getContext()).getUsers()) {
-            final int userId = user.getUserHandle().getIdentifier();
-
-            final long userToken = proto.start(FaceServiceDumpProto.USERS);
-
-            proto.write(FaceUserStatsProto.USER_ID, userId);
-            proto.write(FaceUserStatsProto.NUM_FACES,
-                    getBiometricUtils().getBiometricsForUser(getContext(), userId).size());
-
-            // Normal face authentications (e.g. lockscreen)
-            final PerformanceStats normal = mPerformanceMap.get(userId);
-            if (normal != null) {
-                final long countsToken = proto.start(FaceUserStatsProto.NORMAL);
-                proto.write(FaceActionStatsProto.ACCEPT, normal.accept);
-                proto.write(FaceActionStatsProto.REJECT, normal.reject);
-                proto.write(FaceActionStatsProto.ACQUIRE, normal.acquire);
-                proto.write(FaceActionStatsProto.LOCKOUT, normal.lockout);
-                proto.write(FaceActionStatsProto.LOCKOUT_PERMANENT, normal.lockout);
-                proto.end(countsToken);
-            }
-
-            // Statistics about secure face transactions (e.g. to unlock password
-            // storage, make secure purchases, etc.)
-            final PerformanceStats crypto = mCryptoPerformanceMap.get(userId);
-            if (crypto != null) {
-                final long countsToken = proto.start(FaceUserStatsProto.CRYPTO);
-                proto.write(FaceActionStatsProto.ACCEPT, crypto.accept);
-                proto.write(FaceActionStatsProto.REJECT, crypto.reject);
-                proto.write(FaceActionStatsProto.ACQUIRE, crypto.acquire);
-                proto.write(FaceActionStatsProto.LOCKOUT, crypto.lockout);
-                proto.write(FaceActionStatsProto.LOCKOUT_PERMANENT, crypto.lockout);
-                proto.end(countsToken);
-            }
-
-            proto.end(userToken);
-        }
-        proto.flush();
-        mPerformanceMap.clear();
-        mCryptoPerformanceMap.clear();
+        mUsageStats.print(pw);
     }
 
     private void dumpHal(FileDescriptor fd, String[] args) {
diff --git a/services/core/java/com/android/server/biometrics/fingerprint/FingerprintService.java b/services/core/java/com/android/server/biometrics/fingerprint/FingerprintService.java
index 24fd1b7..320e102 100644
--- a/services/core/java/com/android/server/biometrics/fingerprint/FingerprintService.java
+++ b/services/core/java/com/android/server/biometrics/fingerprint/FingerprintService.java
@@ -176,6 +176,7 @@
      * Receives the incoming binder calls from FingerprintManager.
      */
     private final class FingerprintServiceWrapper extends IFingerprintService.Stub {
+        private static final int ENROLL_TIMEOUT_SEC = 60;
 
         /**
          * The following methods contain common code which is shared in biometrics/common.
@@ -203,7 +204,8 @@
             final int groupId = userId; // default group for fingerprint enrollment
             final EnrollClientImpl client = new EnrollClientImpl(getContext(), mDaemonWrapper,
                     mHalDeviceId, token, new ServiceListenerImpl(receiver), mCurrentUserId, groupId,
-                    cryptoToken, restricted, opPackageName, new int[0] /* disabledFeatures */) {
+                    cryptoToken, restricted, opPackageName, new int[0] /* disabledFeatures */,
+                    ENROLL_TIMEOUT_SEC) {
                 @Override
                 public boolean shouldVibrate() {
                     return true;
@@ -1035,8 +1037,7 @@
             Slog.e(TAG, "dump formatting failure", e);
         }
         pw.println(dump);
-        pw.println("HAL Deaths: " + mHALDeathCount);
-        mHALDeathCount = 0;
+        pw.println("HAL deaths since last reboot: " + mHALDeathCount);
     }
 
     private void dumpProto(FileDescriptor fd) {
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/display/ColorFade.java b/services/core/java/com/android/server/display/ColorFade.java
index 36d9c0e..f613064 100644
--- a/services/core/java/com/android/server/display/ColorFade.java
+++ b/services/core/java/com/android/server/display/ColorFade.java
@@ -29,6 +29,7 @@
 import android.opengl.GLES20;
 import android.os.IBinder;
 import android.util.Slog;
+import android.view.Display;
 import android.view.DisplayInfo;
 import android.view.Surface;
 import android.view.Surface.OutOfResourcesException;
@@ -72,6 +73,9 @@
     // See code for details.
     private static final int DEJANK_FRAMES = 3;
 
+    private static final int EGL_GL_COLORSPACE_KHR = 0x309D;
+    private static final int EGL_GL_COLORSPACE_DISPLAY_P3_PASSTHROUGH_EXT = 0x3490;
+
     private final int mDisplayId;
 
     // Set to true when the animation context has been fully prepared.
@@ -93,6 +97,7 @@
     private EGLSurface mEglSurface;
     private boolean mSurfaceVisible;
     private float mSurfaceAlpha;
+    private boolean mIsWideColor;
 
     // Texture names.  We only use one texture, which contains the screenshot.
     private final int[] mTexNames = new int[1];
@@ -482,6 +487,8 @@
                     return false;
                 }
 
+                mIsWideColor = SurfaceControl.getActiveColorMode(token)
+                        == Display.COLOR_MODE_DISPLAY_P3;
                 SurfaceControl.screenshot(token, s);
                 st.updateTexImage();
                 st.getTransformMatrix(mTexMatrix);
@@ -608,8 +615,16 @@
     private boolean createEglSurface() {
         if (mEglSurface == null) {
             int[] eglSurfaceAttribList = new int[] {
+                    EGL14.EGL_NONE,
+                    EGL14.EGL_NONE,
                     EGL14.EGL_NONE
             };
+
+            // If the current display is in wide color, then so is the screenshot.
+            if (mIsWideColor) {
+                eglSurfaceAttribList[0] = EGL_GL_COLORSPACE_KHR;
+                eglSurfaceAttribList[1] = EGL_GL_COLORSPACE_DISPLAY_P3_PASSTHROUGH_EXT;
+            }
             // turn our SurfaceControl into a Surface
             mEglSurface = EGL14.eglCreateWindowSurface(mEglDisplay, mEglConfig, mSurface,
                     eglSurfaceAttribList, 0);
diff --git a/services/core/java/com/android/server/display/DisplayManagerService.java b/services/core/java/com/android/server/display/DisplayManagerService.java
index 99341d1..4f33ebb0 100644
--- a/services/core/java/com/android/server/display/DisplayManagerService.java
+++ b/services/core/java/com/android/server/display/DisplayManagerService.java
@@ -303,6 +303,8 @@
     private final Spline mMinimumBrightnessSpline;
     private final ColorSpace mWideColorSpace;
 
+    private SensorManager mSensorManager;
+
     public DisplayManagerService(Context context) {
         this(context, new Injector());
     }
@@ -430,7 +432,7 @@
         }
 
         mDisplayModeDirector.setListener(new AllowedDisplayModeObserver());
-        mDisplayModeDirector.start();
+        mDisplayModeDirector.start(mSensorManager);
 
         mHandler.sendEmptyMessage(MSG_REGISTER_ADDITIONAL_DISPLAY_ADAPTERS);
     }
@@ -2358,6 +2360,7 @@
                 };
                 mDisplayPowerController = new DisplayPowerController(
                         mContext, callbacks, handler, sensorManager, blanker);
+                mSensorManager = sensorManager;
             }
 
             mHandler.sendEmptyMessage(MSG_LOAD_BRIGHTNESS_CONFIGURATION);
diff --git a/services/core/java/com/android/server/display/DisplayModeDirector.java b/services/core/java/com/android/server/display/DisplayModeDirector.java
index 0940a2e..500a242 100644
--- a/services/core/java/com/android/server/display/DisplayModeDirector.java
+++ b/services/core/java/com/android/server/display/DisplayModeDirector.java
@@ -18,26 +18,44 @@
 
 import android.annotation.NonNull;
 import android.annotation.Nullable;
+import android.content.BroadcastReceiver;
 import android.content.ContentResolver;
 import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.content.res.Resources;
 import android.database.ContentObserver;
 import android.hardware.display.DisplayManager;
+import android.hardware.Sensor;
+import android.hardware.SensorEvent;
+import android.hardware.SensorEventListener;
+import android.hardware.SensorManager;
+
 import android.net.Uri;
 import android.os.Handler;
 import android.os.Looper;
 import android.os.Message;
 import android.os.UserHandle;
+import android.os.PowerManager;
+import android.os.SystemClock;
+import android.provider.DeviceConfig;
 import android.provider.Settings;
+import android.text.TextUtils;
+import android.util.Pair;
 import android.util.Slog;
 import android.util.SparseArray;
 import android.view.Display;
 import android.view.DisplayInfo;
 
+import com.android.internal.os.BackgroundThread;
 import com.android.internal.R;
+import com.android.server.display.whitebalance.DisplayWhiteBalanceFactory;
+import com.android.server.display.whitebalance.AmbientFilter;
 
 import java.io.PrintWriter;
 import java.util.ArrayList;
 import java.util.Arrays;
+import java.util.List;
 import java.util.Objects;
 
 /**
@@ -49,6 +67,9 @@
     private static final boolean DEBUG = false;
 
     private static final int MSG_ALLOWED_MODES_CHANGED = 1;
+    private static final int MSG_BRIGHTNESS_THRESHOLDS_CHANGED = 2;
+    private static final int MSG_DEFAULT_PEAK_REFRESH_RATE_CHANGED = 3;
+    private static final int MSG_REFRESH_RATE_IN_ZONE_CHANGED = 4;
 
     // Special ID used to indicate that given vote is to be applied globally, rather than to a
     // specific display.
@@ -74,8 +95,9 @@
     private final AppRequestObserver mAppRequestObserver;
     private final SettingsObserver mSettingsObserver;
     private final DisplayObserver mDisplayObserver;
+    private final BrightnessObserver mBrightnessObserver;
 
-
+    private final DeviceConfigDisplaySettings mDeviceConfigDisplaySettings;
     private Listener mListener;
 
     public DisplayModeDirector(@NonNull Context context, @NonNull Handler handler) {
@@ -87,6 +109,8 @@
         mAppRequestObserver = new AppRequestObserver();
         mSettingsObserver = new SettingsObserver(context, handler);
         mDisplayObserver = new DisplayObserver(context, handler);
+        mBrightnessObserver = new BrightnessObserver(context, handler);
+        mDeviceConfigDisplaySettings = new DeviceConfigDisplaySettings();
     }
 
     /**
@@ -96,15 +120,17 @@
      * This has to be deferred because the object may be constructed before the rest of the system
      * is ready.
      */
-    public void start() {
+    public void start(SensorManager sensorManager) {
         mSettingsObserver.observe();
         mDisplayObserver.observe();
         mSettingsObserver.observe();
+        mBrightnessObserver.observe(sensorManager);
         synchronized (mLock) {
             // We may have a listener already registered before the call to start, so go ahead and
             // notify them to pick up our newly initialized state.
             notifyAllowedModesChangedLocked();
         }
+
     }
 
     /**
@@ -315,6 +341,7 @@
             }
             mSettingsObserver.dumpLocked(pw);
             mAppRequestObserver.dumpLocked(pw);
+            mBrightnessObserver.dumpLocked(pw);
         }
     }
 
@@ -385,7 +412,7 @@
         void onAllowedDisplayModesChanged();
     }
 
-    private static final class DisplayModeDirectorHandler extends Handler {
+    private final class DisplayModeDirectorHandler extends Handler {
         DisplayModeDirectorHandler(Looper looper) {
             super(looper, null, true /*async*/);
         }
@@ -397,22 +424,65 @@
                     Listener listener = (Listener) msg.obj;
                     listener.onAllowedDisplayModesChanged();
                     break;
+
+                case MSG_BRIGHTNESS_THRESHOLDS_CHANGED:
+                    Pair<int[], int[]> thresholds = (Pair<int[], int[]>) msg.obj;
+
+                    if (thresholds != null) {
+                        mBrightnessObserver.onDeviceConfigThresholdsChanged(
+                                thresholds.first, thresholds.second);
+                    } else {
+                        mBrightnessObserver.onDeviceConfigThresholdsChanged(null, null);
+                    }
+                    break;
+
+                case MSG_DEFAULT_PEAK_REFRESH_RATE_CHANGED:
+                    Float defaultPeakRefreshRate = (Float) msg.obj;
+                    mSettingsObserver.onDeviceConfigDefaultPeakRefreshRateChanged(
+                            defaultPeakRefreshRate);
+                    break;
+
+                case MSG_REFRESH_RATE_IN_ZONE_CHANGED:
+                    int refreshRateInZone = msg.arg1;
+                    mBrightnessObserver.onDeviceConfigRefreshRateInZoneChanged(
+                            refreshRateInZone);
+                    break;
             }
         }
     }
 
     private static final class Vote {
-        public static final int PRIORITY_USER_SETTING = 0;
-        // We split the app request into two priorities in case we can satisfy one desire without
-        // the other.
-        public static final int PRIORITY_APP_REQUEST_REFRESH_RATE = 1;
-        public static final int PRIORITY_APP_REQUEST_SIZE = 2;
-        public static final int PRIORITY_LOW_POWER_MODE = 3;
+        // LOW_BRIGHTNESS votes for a single refresh rate like [60,60], [90,90] or null.
+        // If the higher voters result is a range, it will fix the rate to a single choice.
+        // It's used to avoid rate switch in certain conditions.
+        public static final int PRIORITY_LOW_BRIGHTNESS = 0;
+
+        // SETTING_MIN_REFRESH_RATE is used to propose a lower bound of display refresh rate.
+        // It votes [MIN_REFRESH_RATE, Float.POSITIVE_INFINITY]
+        public static final int PRIORITY_USER_SETTING_MIN_REFRESH_RATE = 1;
+
+        // We split the app request into different priorities in case we can satisfy one desire
+        // without the other.
+
+        // Application can specify preferred refresh rate with below attrs.
+        // @see android.view.WindowManager.LayoutParams#preferredRefreshRate
+        // @see android.view.WindowManager.LayoutParams#preferredDisplayModeId
+        // System also forces some apps like blacklisted app to run at a lower refresh rate.
+        // @see android.R.array#config_highRefreshRateBlacklist
+        public static final int PRIORITY_APP_REQUEST_REFRESH_RATE = 2;
+        public static final int PRIORITY_APP_REQUEST_SIZE = 3;
+
+        // SETTING_PEAK_REFRESH_RATE has a high priority and will restrict the bounds of the rest
+        // of low priority voters. It votes [0, max(PEAK, MIN)]
+        public static final int PRIORITY_USER_SETTING_PEAK_REFRESH_RATE = 4;
+
+        // LOW_POWER_MODE force display to [0, 60HZ] if Settings.Global.LOW_POWER_MODE is on.
+        public static final int PRIORITY_LOW_POWER_MODE = 5;
 
         // Whenever a new priority is added, remember to update MIN_PRIORITY and/or MAX_PRIORITY as
         // appropriate, as well as priorityToString.
 
-        public static final int MIN_PRIORITY = PRIORITY_USER_SETTING;
+        public static final int MIN_PRIORITY = PRIORITY_LOW_BRIGHTNESS;
         public static final int MAX_PRIORITY = PRIORITY_LOW_POWER_MODE;
 
         /**
@@ -456,12 +526,16 @@
 
         public static String priorityToString(int priority) {
             switch (priority) {
-                case PRIORITY_USER_SETTING:
-                    return "PRIORITY_USER_SETTING";
+                case PRIORITY_LOW_BRIGHTNESS:
+                    return "PRIORITY_LOW_BRIGHTNESS";
+                case PRIORITY_USER_SETTING_MIN_REFRESH_RATE:
+                    return "PRIORITY_USER_SETTING_MIN_REFRESH_RATE";
                 case PRIORITY_APP_REQUEST_REFRESH_RATE:
                     return "PRIORITY_APP_REQUEST_REFRESH_RATE";
                 case PRIORITY_APP_REQUEST_SIZE:
                     return "PRIORITY_APP_REQUEST_SIZE";
+                case PRIORITY_USER_SETTING_PEAK_REFRESH_RATE:
+                    return "PRIORITY_USER_SETTING_PEAK_REFRESH_RATE";
                 case PRIORITY_LOW_POWER_MODE:
                     return "PRIORITY_LOW_POWER_MODE";
                 default:
@@ -481,13 +555,15 @@
     }
 
     private final class SettingsObserver extends ContentObserver {
-        private final Uri mRefreshRateSetting =
+        private final Uri mPeakRefreshRateSetting =
                 Settings.System.getUriFor(Settings.System.PEAK_REFRESH_RATE);
+        private final Uri mMinRefreshRateSetting =
+                Settings.System.getUriFor(Settings.System.MIN_REFRESH_RATE);
         private final Uri mLowPowerModeSetting =
                 Settings.Global.getUriFor(Settings.Global.LOW_POWER_MODE);
 
         private final Context mContext;
-        private final float mDefaultPeakRefreshRate;
+        private float mDefaultPeakRefreshRate;
 
         SettingsObserver(@NonNull Context context, @NonNull Handler handler) {
             super(handler);
@@ -498,20 +574,44 @@
 
         public void observe() {
             final ContentResolver cr = mContext.getContentResolver();
-            cr.registerContentObserver(mRefreshRateSetting, false /*notifyDescendants*/, this,
+            cr.registerContentObserver(mPeakRefreshRateSetting, false /*notifyDescendants*/, this,
+                    UserHandle.USER_SYSTEM);
+            cr.registerContentObserver(mMinRefreshRateSetting, false /*notifyDescendants*/, this,
                     UserHandle.USER_SYSTEM);
             cr.registerContentObserver(mLowPowerModeSetting, false /*notifyDescendants*/, this,
                     UserHandle.USER_SYSTEM);
+
+            Float deviceConfigDefaultPeakRefresh =
+                    mDeviceConfigDisplaySettings.getDefaultPeakRefreshRate();
+            if (deviceConfigDefaultPeakRefresh != null) {
+                mDefaultPeakRefreshRate = deviceConfigDefaultPeakRefresh;
+            }
+
             synchronized (mLock) {
                 updateRefreshRateSettingLocked();
                 updateLowPowerModeSettingLocked();
             }
         }
 
+        public void onDeviceConfigDefaultPeakRefreshRateChanged(Float defaultPeakRefreshRate) {
+            if (defaultPeakRefreshRate == null) {
+                defaultPeakRefreshRate = (float) mContext.getResources().getInteger(
+                        R.integer.config_defaultPeakRefreshRate);
+            }
+
+            if (mDefaultPeakRefreshRate != defaultPeakRefreshRate) {
+                synchronized (mLock) {
+                    mDefaultPeakRefreshRate = defaultPeakRefreshRate;
+                    updateRefreshRateSettingLocked();
+                }
+            }
+        }
+
         @Override
         public void onChange(boolean selfChange, Uri uri, int userId) {
             synchronized (mLock) {
-                if (mRefreshRateSetting.equals(uri)) {
+                if (mPeakRefreshRateSetting.equals(uri)
+                        || mMinRefreshRateSetting.equals(uri)) {
                     updateRefreshRateSettingLocked();
                 } else if (mLowPowerModeSetting.equals(uri)) {
                     updateLowPowerModeSettingLocked();
@@ -529,13 +629,21 @@
                 vote = null;
             }
             updateVoteLocked(Vote.PRIORITY_LOW_POWER_MODE, vote);
+            mBrightnessObserver.onLowPowerModeEnabledLocked(inLowPowerMode);
         }
 
         private void updateRefreshRateSettingLocked() {
+            float minRefreshRate = Settings.System.getFloat(mContext.getContentResolver(),
+                    Settings.System.MIN_REFRESH_RATE, 0f);
             float peakRefreshRate = Settings.System.getFloat(mContext.getContentResolver(),
                     Settings.System.PEAK_REFRESH_RATE, mDefaultPeakRefreshRate);
-            Vote vote = Vote.forRefreshRates(0f, peakRefreshRate);
-            updateVoteLocked(Vote.PRIORITY_USER_SETTING, vote);
+
+            updateVoteLocked(Vote.PRIORITY_USER_SETTING_PEAK_REFRESH_RATE,
+                    Vote.forRefreshRates(0f, Math.max(minRefreshRate, peakRefreshRate)));
+            updateVoteLocked(Vote.PRIORITY_USER_SETTING_MIN_REFRESH_RATE,
+                    Vote.forRefreshRates(minRefreshRate, Float.POSITIVE_INFINITY));
+
+            mBrightnessObserver.onRefreshRateSettingChangedLocked(minRefreshRate, peakRefreshRate);
         }
 
         public void dumpLocked(PrintWriter pw) {
@@ -576,6 +684,7 @@
                 refreshRateVote = null;
                 sizeVote = null;
             }
+
             updateVoteLocked(displayId, Vote.PRIORITY_APP_REQUEST_REFRESH_RATE, refreshRateVote);
             updateVoteLocked(displayId, Vote.PRIORITY_APP_REQUEST_SIZE, sizeVote);
             return;
@@ -685,4 +794,491 @@
             }
         }
     }
+
+    /**
+     * This class manages brightness threshold for switching between 60 hz and higher refresh rate.
+     * See more information at the definition of
+     * {@link R.array#config_brightnessThresholdsOfPeakRefreshRate} and
+     * {@link R.array#config_ambientThresholdsOfPeakRefreshRate}.
+     */
+    private class BrightnessObserver extends ContentObserver {
+        private final Uri mDisplayBrightnessSetting =
+                Settings.System.getUriFor(Settings.System.SCREEN_BRIGHTNESS);
+
+        private final static int LIGHT_SENSOR_RATE_MS = 250;
+        private int[] mDisplayBrightnessThresholds;
+        private int[] mAmbientBrightnessThresholds;
+        // valid threshold if any item from the array >= 0
+        private boolean mShouldObserveDisplayChange;
+        private boolean mShouldObserveAmbientChange;
+
+        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;
+
+        private final Context mContext;
+        private final ScreenStateReceiver mScreenStateReceiver;
+
+        // Enable light sensor only when mShouldObserveAmbientChange is true, screen is on, peak
+        // refresh rate changeable and low power mode off. After initialization, these states will
+        // be updated from the same handler thread.
+        private boolean mScreenOn = false;
+        private boolean mRefreshRateChangeable = false;
+        private boolean mLowPowerModeEnabled = false;
+
+        private int mRefreshRateInZone;
+
+        BrightnessObserver(Context context, Handler handler) {
+            super(handler);
+            mContext = context;
+            mScreenStateReceiver = new ScreenStateReceiver(mContext);
+            mDisplayBrightnessThresholds = context.getResources().getIntArray(
+                    R.array.config_brightnessThresholdsOfPeakRefreshRate);
+            mAmbientBrightnessThresholds = context.getResources().getIntArray(
+                    R.array.config_ambientThresholdsOfPeakRefreshRate);
+
+            if (mDisplayBrightnessThresholds.length != mAmbientBrightnessThresholds.length) {
+                throw new RuntimeException("display brightness threshold array and ambient "
+                        + "brightness threshold array have different length");
+            }
+        }
+
+        public void observe(SensorManager sensorManager) {
+            mSensorManager = sensorManager;
+
+            // DeviceConfig is accessible after system ready.
+            int[] brightnessThresholds = mDeviceConfigDisplaySettings.getBrightnessThresholds();
+            int[] ambientThresholds = mDeviceConfigDisplaySettings.getAmbientThresholds();
+
+            if (brightnessThresholds != null && ambientThresholds != null
+                    && brightnessThresholds.length == ambientThresholds.length) {
+                mDisplayBrightnessThresholds = brightnessThresholds;
+                mAmbientBrightnessThresholds = ambientThresholds;
+            }
+
+            mRefreshRateInZone = mDeviceConfigDisplaySettings.getRefreshRateInZone();
+            restartObserver();
+            mDeviceConfigDisplaySettings.startListening();
+        }
+
+        public void onRefreshRateSettingChangedLocked(float min, float max) {
+            boolean changeable = (max - min > 1f && max > 60f);
+            if (mRefreshRateChangeable != changeable) {
+                mRefreshRateChangeable = changeable;
+                updateSensorStatus();
+                if (!changeable) {
+                    // Revoke previous vote from BrightnessObserver
+                    updateVoteLocked(Vote.PRIORITY_LOW_BRIGHTNESS, null);
+                }
+            }
+        }
+
+        public void onLowPowerModeEnabledLocked(boolean b) {
+            if (mLowPowerModeEnabled != b) {
+                mLowPowerModeEnabled = b;
+                updateSensorStatus();
+            }
+        }
+
+        public void onDeviceConfigThresholdsChanged(int[] brightnessThresholds,
+                int[] ambientThresholds) {
+            if (brightnessThresholds != null && ambientThresholds != null
+                    && brightnessThresholds.length == ambientThresholds.length) {
+                mDisplayBrightnessThresholds = brightnessThresholds;
+                mAmbientBrightnessThresholds = ambientThresholds;
+            } else {
+                // Invalid or empty. Use device default.
+                mDisplayBrightnessThresholds = mContext.getResources().getIntArray(
+                        R.array.config_brightnessThresholdsOfPeakRefreshRate);
+                mAmbientBrightnessThresholds = mContext.getResources().getIntArray(
+                        R.array.config_ambientThresholdsOfPeakRefreshRate);
+            }
+            restartObserver();
+        }
+
+        public void onDeviceConfigRefreshRateInZoneChanged(int refreshRate) {
+            if (refreshRate != mRefreshRateInZone) {
+                mRefreshRateInZone = refreshRate;
+                restartObserver();
+            }
+        }
+
+        public void dumpLocked(PrintWriter pw) {
+            pw.println("  BrightnessObserver");
+            pw.println("    mRefreshRateInZone: " + mRefreshRateInZone);
+
+            for (int d: mDisplayBrightnessThresholds) {
+                pw.println("    mDisplayBrightnessThreshold: " + d);
+            }
+
+            for (int d: mAmbientBrightnessThresholds) {
+                pw.println("    mAmbientBrightnessThreshold: " + d);
+            }
+        }
+
+        @Override
+        public void onChange(boolean selfChange, Uri uri, int userId) {
+            synchronized (mLock) {
+                if (mRefreshRateChangeable) {
+                    onBrightnessChangedLocked();
+                }
+            }
+        }
+
+        private void restartObserver() {
+            mShouldObserveDisplayChange = checkShouldObserve(mDisplayBrightnessThresholds);
+            mShouldObserveAmbientChange = checkShouldObserve(mAmbientBrightnessThresholds);
+
+            final ContentResolver cr = mContext.getContentResolver();
+            if (mShouldObserveDisplayChange) {
+                // Content Service does not check if an listener has already been registered.
+                // To ensure only one listener is registered, force an unregistration first.
+                cr.unregisterContentObserver(this);
+                cr.registerContentObserver(mDisplayBrightnessSetting,
+                        false /*notifyDescendants*/, this, UserHandle.USER_SYSTEM);
+            } else {
+                cr.unregisterContentObserver(this);
+            }
+
+            if (mShouldObserveAmbientChange) {
+                Resources resources = mContext.getResources();
+                String lightSensorType = resources.getString(
+                        com.android.internal.R.string.config_displayLightSensorType);
+
+                Sensor lightSensor = null;
+                if (!TextUtils.isEmpty(lightSensorType)) {
+                    List<Sensor> sensors = mSensorManager.getSensorList(Sensor.TYPE_ALL);
+                    for (int i = 0; i < sensors.size(); i++) {
+                        Sensor sensor = sensors.get(i);
+                        if (lightSensorType.equals(sensor.getStringType())) {
+                            lightSensor = sensor;
+                            break;
+                        }
+                    }
+                }
+
+                if (lightSensor == null) {
+                    lightSensor = mSensorManager.getDefaultSensor(Sensor.TYPE_LIGHT);
+                }
+
+                if (lightSensor != null) {
+                    final Resources res = mContext.getResources();
+
+                    mAmbientFilter = DisplayWhiteBalanceFactory.createBrightnessFilter(res);
+                    mLightSensor = lightSensor;
+
+                    // Intent.ACTION_SCREEN_ON is not sticky. Check current screen status.
+                    if (mContext.getSystemService(PowerManager.class).isInteractive()) {
+                        onScreenOn(true);
+                    }
+                    mScreenStateReceiver.register();
+                }
+            } else {
+                mAmbientFilter = null;
+                mLightSensor = null;
+                mScreenStateReceiver.unregister();
+            }
+
+            if (mRefreshRateChangeable) {
+                updateSensorStatus();
+                synchronized (mLock) {
+                    onBrightnessChangedLocked();
+                }
+            }
+        }
+
+        /**
+         * Checks to see if at least one value is positive, in which case it is necessary to listen
+         * to value changes.
+         */
+        private boolean checkShouldObserve(int[] a) {
+            if (mRefreshRateInZone <= 0) {
+                return false;
+            }
+
+            for (int d: a) {
+                if (d >= 0) {
+                    return true;
+                }
+            }
+
+            return false;
+        }
+
+        private boolean isInsideZone(int brightness, float lux) {
+            for (int i = 0; i < mDisplayBrightnessThresholds.length; i++) {
+                int disp = mDisplayBrightnessThresholds[i];
+                int ambi = mAmbientBrightnessThresholds[i];
+
+                if (disp >= 0 && ambi >= 0) {
+                    if (brightness <= disp && mAmbientLux <= ambi) {
+                        return true;
+                    }
+                } else if (disp >= 0) {
+                    if (brightness <= disp) {
+                        return true;
+                    }
+                } else if (ambi >= 0) {
+                    if (mAmbientLux <= ambi) {
+                        return true;
+                    }
+                }
+            }
+
+            return false;
+        }
+
+        private void onBrightnessChangedLocked() {
+            int brightness = Settings.System.getInt(mContext.getContentResolver(),
+                    Settings.System.SCREEN_BRIGHTNESS, -1);
+
+            Vote vote = null;
+            boolean insideZone = isInsideZone(brightness, mAmbientLux);
+            if (insideZone) {
+                vote = Vote.forRefreshRates(mRefreshRateInZone, mRefreshRateInZone);
+            }
+
+            if (DEBUG) {
+                Slog.d(TAG, "Display brightness " + brightness + ", ambient lux " +  mAmbientLux +
+                        ", Vote " + vote);
+            }
+            updateVoteLocked(Vote.PRIORITY_LOW_BRIGHTNESS, vote);
+        }
+
+        private void onScreenOn(boolean on) {
+            // Not check mShouldObserveAmbientChange because Screen status receiver is registered
+            // only when it is true.
+            if (mScreenOn != on) {
+                mScreenOn = on;
+                updateSensorStatus();
+            }
+        }
+
+        private void updateSensorStatus() {
+            if (mSensorManager == null || mLightSensorListener == null) {
+                return;
+            }
+
+            if (mShouldObserveAmbientChange && mScreenOn && !mLowPowerModeEnabled
+                    && mRefreshRateChangeable) {
+                mSensorManager.registerListener(mLightSensorListener,
+                        mLightSensor, LIGHT_SENSOR_RATE_MS * 1000, mHandler);
+            } else {
+                mLightSensorListener.removeCallbacks();
+                mSensorManager.unregisterListener(mLightSensorListener);
+            }
+        }
+
+        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) {
+                mLastSensorData = event.values[0];
+                if (DEBUG) {
+                    Slog.d(TAG, "On sensor changed: " + mLastSensorData);
+                }
+
+                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);
+                }
+            }
+
+            @Override
+            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 {
+            final Context mContext;
+            boolean mRegistered;
+
+            public ScreenStateReceiver(Context context) {
+                mContext = context;
+            }
+
+            @Override
+            public void onReceive(Context context, Intent intent) {
+                onScreenOn(Intent.ACTION_SCREEN_ON.equals(intent.getAction()));
+            }
+
+            public void register() {
+                if (!mRegistered) {
+                    IntentFilter filter = new IntentFilter();
+                    filter.addAction(Intent.ACTION_SCREEN_OFF);
+                    filter.addAction(Intent.ACTION_SCREEN_ON);
+                    filter.setPriority(IntentFilter.SYSTEM_HIGH_PRIORITY);
+                    mContext.registerReceiver(this, filter, null, mHandler);
+                    mRegistered = true;
+                }
+            }
+
+            public void unregister() {
+                if (mRegistered) {
+                    mContext.unregisterReceiver(this);
+                    mRegistered = false;
+                }
+            }
+        }
+    }
+
+    private class DeviceConfigDisplaySettings implements DeviceConfig.OnPropertiesChangedListener {
+        public DeviceConfigDisplaySettings() {
+        }
+
+        public void startListening() {
+            DeviceConfig.addOnPropertiesChangedListener(DeviceConfig.NAMESPACE_DISPLAY_MANAGER,
+                    BackgroundThread.getExecutor(), this);
+        }
+
+        /*
+         * Return null if no such property or wrong format (not comma separated integers).
+         */
+        public int[] getBrightnessThresholds() {
+            return getIntArrayProperty(
+                    DisplayManager.DeviceConfig.
+                            KEY_PEAK_REFRESH_RATE_DISPLAY_BRIGHTNESS_THRESHOLDS);
+        }
+
+        /*
+         * Return null if no such property or wrong format (not comma separated integers).
+         */
+        public int[] getAmbientThresholds() {
+            return getIntArrayProperty(
+                    DisplayManager.DeviceConfig.
+                            KEY_PEAK_REFRESH_RATE_AMBIENT_BRIGHTNESS_THRESHOLDS);
+        }
+
+        /*
+         * Return null if no such property
+         */
+        public Float getDefaultPeakRefreshRate() {
+            float defaultPeakRefreshRate = DeviceConfig.getFloat(
+                    DeviceConfig.NAMESPACE_DISPLAY_MANAGER,
+                    DisplayManager.DeviceConfig.KEY_PEAK_REFRESH_RATE_DEFAULT, -1);
+
+            if (defaultPeakRefreshRate == -1) {
+                return null;
+            }
+            return defaultPeakRefreshRate;
+        }
+
+        public int getRefreshRateInZone() {
+            int defaultRefreshRateInZone = mContext.getResources().getInteger(
+                    R.integer.config_defaultRefreshRateInZone);
+
+            int refreshRate = DeviceConfig.getInt(
+                    DeviceConfig.NAMESPACE_DISPLAY_MANAGER,
+                    DisplayManager.DeviceConfig.KEY_REFRESH_RATE_IN_ZONE,
+                    defaultRefreshRateInZone);
+
+            return refreshRate;
+        }
+
+        @Override
+        public void onPropertiesChanged(@NonNull DeviceConfig.Properties properties) {
+            int[] brightnessThresholds = getBrightnessThresholds();
+            int[] ambientThresholds = getAmbientThresholds();
+            Float defaultPeakRefreshRate = getDefaultPeakRefreshRate();
+            int refreshRateInZone = getRefreshRateInZone();
+
+            mHandler.obtainMessage(MSG_BRIGHTNESS_THRESHOLDS_CHANGED,
+                    new Pair<int[], int[]>(brightnessThresholds, ambientThresholds))
+                    .sendToTarget();
+            mHandler.obtainMessage(MSG_DEFAULT_PEAK_REFRESH_RATE_CHANGED,
+                    defaultPeakRefreshRate).sendToTarget();
+            mHandler.obtainMessage(MSG_REFRESH_RATE_IN_ZONE_CHANGED, refreshRateInZone,
+                    0).sendToTarget();
+        }
+
+        private int[] getIntArrayProperty(String prop) {
+            String strArray = DeviceConfig.getString(DeviceConfig.NAMESPACE_DISPLAY_MANAGER, prop,
+                    null);
+
+            if (strArray != null) {
+                return parseIntArray(strArray);
+            }
+
+            return null;
+        }
+
+        private int[] parseIntArray(@NonNull String strArray) {
+            String[] items = strArray.split(",");
+            int[] array = new int[items.length];
+
+            try {
+                for (int i = 0; i < array.length; i++) {
+                    array[i] = Integer.parseInt(items[i]);
+                }
+            } catch (NumberFormatException e) {
+                Slog.e(TAG, "Incorrect format for array: '" + strArray + "'", e);
+                array = null;
+            }
+
+            return array;
+        }
+    }
+
 }
diff --git a/services/core/java/com/android/server/display/LocalDisplayAdapter.java b/services/core/java/com/android/server/display/LocalDisplayAdapter.java
index 85fbdf6..b03dc3b 100644
--- a/services/core/java/com/android/server/display/LocalDisplayAdapter.java
+++ b/services/core/java/com/android/server/display/LocalDisplayAdapter.java
@@ -856,7 +856,7 @@
 
     private final class PhysicalDisplayEventReceiver extends DisplayEventReceiver {
         PhysicalDisplayEventReceiver(Looper looper) {
-            super(looper, VSYNC_SOURCE_APP);
+            super(looper, VSYNC_SOURCE_APP, CONFIG_CHANGED_EVENT_DISPATCH);
         }
 
         @Override
diff --git a/services/core/java/com/android/server/display/color/ColorDisplayService.java b/services/core/java/com/android/server/display/color/ColorDisplayService.java
index 64a9e00..7fb5b19 100644
--- a/services/core/java/com/android/server/display/color/ColorDisplayService.java
+++ b/services/core/java/com/android/server/display/color/ColorDisplayService.java
@@ -63,6 +63,8 @@
 import android.provider.Settings.System;
 import android.util.MathUtils;
 import android.util.Slog;
+import android.util.SparseIntArray;
+import android.view.Display;
 import android.view.SurfaceControl;
 import android.view.accessibility.AccessibilityManager;
 import android.view.animation.AnimationUtils;
@@ -171,6 +173,11 @@
 
     private NightDisplayAutoMode mNightDisplayAutoMode;
 
+    /**
+     * Map of color modes -> display composition colorspace
+     */
+    private SparseIntArray mColorModeCompositionColorSpaces = null;
+
     public ColorDisplayService(Context context) {
         super(context);
         mHandler = new TintHandler(DisplayThread.get().getLooper());
@@ -226,7 +233,7 @@
         }
     }
 
-    private void onUserChanged(int userHandle) {
+    @VisibleForTesting void onUserChanged(int userHandle) {
         final ContentResolver cr = getContext().getContentResolver();
 
         if (mCurrentUser != UserHandle.USER_NULL) {
@@ -267,6 +274,30 @@
         return Secure.getIntForUser(cr, Secure.USER_SETUP_COMPLETE, 0, userHandle) == 1;
     }
 
+    private void setUpDisplayCompositionColorSpaces(Resources res) {
+        mColorModeCompositionColorSpaces = null;
+
+        final int[] colorModes = res.getIntArray(R.array.config_displayCompositionColorModes);
+        if (colorModes == null) {
+            return;
+        }
+
+        final int[] compSpaces = res.getIntArray(R.array.config_displayCompositionColorSpaces);
+        if (compSpaces == null) {
+            return;
+        }
+
+        if (colorModes.length != compSpaces.length) {
+            Slog.e(TAG, "Number of composition color spaces doesn't match specified color modes");
+            return;
+        }
+
+        mColorModeCompositionColorSpaces = new SparseIntArray(colorModes.length);
+        for (int i = 0; i < colorModes.length; i++) {
+            mColorModeCompositionColorSpaces.put(colorModes[i], compSpaces[i]);
+        }
+    }
+
     private void setUp() {
         Slog.d(TAG, "setUp: currentUser=" + mCurrentUser);
 
@@ -359,6 +390,8 @@
         onAccessibilityInversionChanged();
         onAccessibilityDaltonizerChanged();
 
+        setUpDisplayCompositionColorSpaces(getContext().getResources());
+
         // Set the color mode, if valid, and immediately apply the updated tint matrix based on the
         // existing activated state. This ensures consistency of tint across the color mode change.
         onDisplayColorModeChanged(getColorModeInternal());
@@ -450,6 +483,14 @@
         }
     }
 
+    private int getCompositionColorSpace(int mode) {
+        if (mColorModeCompositionColorSpaces == null) {
+            return Display.COLOR_MODE_INVALID;
+        }
+
+        return mColorModeCompositionColorSpaces.get(mode, Display.COLOR_MODE_INVALID);
+    }
+
     private void onDisplayColorModeChanged(int mode) {
         if (mode == NOT_SET) {
             return;
@@ -465,12 +506,17 @@
                     .setMatrix(mNightDisplayTintController.getColorTemperatureSetting());
         }
 
+        // dtm.setColorMode() needs to be called before
+        // updateDisplayWhiteBalanceStatus(), this is because the latter calls
+        // DisplayTransformManager.needsLinearColorMatrix(), therefore it is dependent
+        // on the state of DisplayTransformManager.
+        final DisplayTransformManager dtm = getLocalService(DisplayTransformManager.class);
+        dtm.setColorMode(mode, mNightDisplayTintController.getMatrix(),
+                getCompositionColorSpace(mode));
+
         if (mDisplayWhiteBalanceTintController.isAvailable(getContext())) {
             updateDisplayWhiteBalanceStatus();
         }
-
-        final DisplayTransformManager dtm = getLocalService(DisplayTransformManager.class);
-        dtm.setColorMode(mode, mNightDisplayTintController.getMatrix());
     }
 
     private void onAccessibilityActivated() {
@@ -931,7 +977,7 @@
 
             if (mNightDisplayTintController.isActivatedStateNotSet()
                     || (mNightDisplayTintController.isActivated() != activate)) {
-                mNightDisplayTintController.setActivated(activate);
+                mNightDisplayTintController.setActivated(activate, activate ? start : end);
             }
 
             updateNextAlarm(mNightDisplayTintController.isActivated(), now);
@@ -1127,6 +1173,14 @@
 
         @Override
         public void setActivated(Boolean activated) {
+            setActivated(activated, LocalDateTime.now());
+        }
+
+        /**
+         * Use directly when it is important that the last activation time be exact (for example, an
+         * automatic change). Otherwise use {@link #setActivated(Boolean)}.
+         */
+        public void setActivated(Boolean activated, @NonNull LocalDateTime lastActivationTime) {
             if (activated == null) {
                 super.setActivated(null);
                 return;
@@ -1138,7 +1192,7 @@
                 // This is a true state change, so set this as the last activation time.
                 Secure.putStringForUser(getContext().getContentResolver(),
                         Secure.NIGHT_DISPLAY_LAST_ACTIVATED_TIME,
-                        LocalDateTime.now().toString(),
+                        lastActivationTime.toString(),
                         mCurrentUser);
             }
 
diff --git a/services/core/java/com/android/server/display/color/DisplayTransformManager.java b/services/core/java/com/android/server/display/color/DisplayTransformManager.java
index 5ff45a9..d5706a5 100644
--- a/services/core/java/com/android/server/display/color/DisplayTransformManager.java
+++ b/services/core/java/com/android/server/display/color/DisplayTransformManager.java
@@ -26,6 +26,7 @@
 import android.os.SystemProperties;
 import android.util.Slog;
 import android.util.SparseArray;
+import android.view.Display;
 
 import com.android.internal.annotations.GuardedBy;
 import com.android.internal.annotations.VisibleForTesting;
@@ -77,6 +78,8 @@
     @VisibleForTesting
     static final String PERSISTENT_PROPERTY_SATURATION = "persist.sys.sf.color_saturation";
     @VisibleForTesting
+    static final String PERSISTENT_PROPERTY_COMPOSITION_COLOR_MODE = "persist.sys.sf.color_mode";
+    @VisibleForTesting
     static final String PERSISTENT_PROPERTY_DISPLAY_COLOR = "persist.sys.sf.native_mode";
 
     private static final float COLOR_SATURATION_NATURAL = 1.0f;
@@ -251,23 +254,24 @@
     /**
      * Sets color mode and updates night display transform values.
      */
-    public boolean setColorMode(int colorMode, float[] nightDisplayMatrix) {
+    public boolean setColorMode(int colorMode, float[] nightDisplayMatrix,
+            int compositionColorMode) {
         if (colorMode == ColorDisplayManager.COLOR_MODE_NATURAL) {
             applySaturation(COLOR_SATURATION_NATURAL);
-            setDisplayColor(DISPLAY_COLOR_MANAGED);
+            setDisplayColor(DISPLAY_COLOR_MANAGED, compositionColorMode);
         } else if (colorMode == ColorDisplayManager.COLOR_MODE_BOOSTED) {
             applySaturation(COLOR_SATURATION_BOOSTED);
-            setDisplayColor(DISPLAY_COLOR_MANAGED);
+            setDisplayColor(DISPLAY_COLOR_MANAGED, compositionColorMode);
         } else if (colorMode == ColorDisplayManager.COLOR_MODE_SATURATED) {
             applySaturation(COLOR_SATURATION_NATURAL);
-            setDisplayColor(DISPLAY_COLOR_UNMANAGED);
+            setDisplayColor(DISPLAY_COLOR_UNMANAGED, compositionColorMode);
         } else if (colorMode == ColorDisplayManager.COLOR_MODE_AUTOMATIC) {
             applySaturation(COLOR_SATURATION_NATURAL);
-            setDisplayColor(DISPLAY_COLOR_ENHANCED);
+            setDisplayColor(DISPLAY_COLOR_ENHANCED, compositionColorMode);
         } else if (colorMode >= ColorDisplayManager.VENDOR_COLOR_MODE_RANGE_MIN
                 && colorMode <= ColorDisplayManager.VENDOR_COLOR_MODE_RANGE_MAX) {
             applySaturation(COLOR_SATURATION_NATURAL);
-            setDisplayColor(colorMode);
+            setDisplayColor(colorMode, compositionColorMode);
         }
 
         setColorMatrix(LEVEL_COLOR_MATRIX_NIGHT_DISPLAY, nightDisplayMatrix);
@@ -323,13 +327,21 @@
     /**
      * Toggles native mode on/off in SurfaceFlinger.
      */
-    private void setDisplayColor(int color) {
+    private void setDisplayColor(int color, int compositionColorMode) {
         SystemProperties.set(PERSISTENT_PROPERTY_DISPLAY_COLOR, Integer.toString(color));
+        if (compositionColorMode != Display.COLOR_MODE_INVALID) {
+            SystemProperties.set(PERSISTENT_PROPERTY_COMPOSITION_COLOR_MODE,
+                Integer.toString(compositionColorMode));
+        }
+
         final IBinder flinger = ServiceManager.getService(SURFACE_FLINGER);
         if (flinger != null) {
             final Parcel data = Parcel.obtain();
             data.writeInterfaceToken("android.ui.ISurfaceComposer");
             data.writeInt(color);
+            if (compositionColorMode != Display.COLOR_MODE_INVALID) {
+                data.writeInt(compositionColorMode);
+            }
             try {
                 flinger.transact(SURFACE_FLINGER_TRANSACTION_DISPLAY_COLOR, data, null, 0);
             } catch (RemoteException ex) {
diff --git a/services/core/java/com/android/server/display/whitebalance/AmbientFilter.java b/services/core/java/com/android/server/display/whitebalance/AmbientFilter.java
index 532bbed..3580897 100644
--- a/services/core/java/com/android/server/display/whitebalance/AmbientFilter.java
+++ b/services/core/java/com/android/server/display/whitebalance/AmbientFilter.java
@@ -18,6 +18,7 @@
 
 import android.util.Slog;
 
+import com.android.internal.annotations.VisibleForTesting;
 import com.android.server.display.utils.RollingBuffer;
 
 import java.io.PrintWriter;
@@ -35,7 +36,7 @@
  * - {@link WeightedMovingAverageAmbientFilter}
  *   A weighted average prioritising recent changes.
  */
-abstract class AmbientFilter {
+abstract public class AmbientFilter {
 
     protected static final boolean DEBUG = false; // Enable for verbose logs.
 
diff --git a/services/core/java/com/android/server/display/whitebalance/DisplayWhiteBalanceController.java b/services/core/java/com/android/server/display/whitebalance/DisplayWhiteBalanceController.java
index 0f86b47..02ec10e 100644
--- a/services/core/java/com/android/server/display/whitebalance/DisplayWhiteBalanceController.java
+++ b/services/core/java/com/android/server/display/whitebalance/DisplayWhiteBalanceController.java
@@ -20,6 +20,7 @@
 import android.util.Slog;
 import android.util.Spline;
 
+import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.util.Preconditions;
 import com.android.server.LocalServices;
 import com.android.server.display.color.ColorDisplayService.ColorDisplayServiceInternal;
@@ -53,18 +54,22 @@
     private Callbacks mCallbacks;
 
     private AmbientSensor.AmbientBrightnessSensor mBrightnessSensor;
-    private AmbientFilter mBrightnessFilter;
+
+    @VisibleForTesting
+    AmbientFilter mBrightnessFilter;
     private AmbientSensor.AmbientColorTemperatureSensor mColorTemperatureSensor;
-    private AmbientFilter mColorTemperatureFilter;
+
+    @VisibleForTesting
+    AmbientFilter mColorTemperatureFilter;
     private DisplayWhiteBalanceThrottler mThrottler;
 
-    // When the brightness drops below a certain threshold, it affects the color temperature
-    // accuracy, so we fall back to a fixed ambient color temperature.
-    private final float mLowLightAmbientBrightnessThreshold;
     private final float mLowLightAmbientColorTemperature;
+    private final float mHighLightAmbientColorTemperature;
 
     private float mAmbientColorTemperature;
-    private float mPendingAmbientColorTemperature;
+
+    @VisibleForTesting
+    float mPendingAmbientColorTemperature;
     private float mLastAmbientColorTemperature;
 
     private ColorDisplayServiceInternal mColorDisplayServiceInternal;
@@ -79,6 +84,17 @@
     // A piecewise linear relationship between ambient and display color temperatures.
     private Spline.LinearSpline mAmbientToDisplayColorTemperatureSpline;
 
+    // In very low or very high brightness conditions ambient EQ should to set to a default
+    // instead of using mAmbientToDisplayColorTemperatureSpline. However, setting ambient EQ
+    // based on thresholds can cause the display to rapidly change color temperature. To solve
+    // this, mLowLightAmbientBrightnessToBiasSpline and mHighLightAmbientBrightnessToBiasSpline
+    // are used to smoothly interpolate from ambient color temperature to the defaults.
+    // A piecewise linear relationship between low light brightness and low light bias.
+    private Spline.LinearSpline mLowLightAmbientBrightnessToBiasSpline;
+
+    // A piecewise linear relationship between high light brightness and high light bias.
+    private Spline.LinearSpline mHighLightAmbientBrightnessToBiasSpline;
+
     /**
      * @param brightnessSensor
      *      The sensor used to detect changes in the ambient brightness.
@@ -93,12 +109,22 @@
      * @param throttler
      *      The throttler used to determine whether the new display color temperature should be
      *      updated or not.
-     * @param lowLightAmbientBrightnessThreshold
-     *      The ambient brightness threshold beneath which we fall back to a fixed ambient color
-     *      temperature.
+     * @param lowLightAmbientBrightnesses
+     *      The ambient brightness used to map the ambient brightnesses to the biases used to
+     *      interpolate to lowLightAmbientColorTemperature.
+     * @param lowLightAmbientBiases
+     *      The biases used to map the ambient brightnesses to the biases used to interpolate to
+     *      lowLightAmbientColorTemperature.
      * @param lowLightAmbientColorTemperature
-     *      The ambient color temperature to which we fall back when the ambient brightness drops
-     *      beneath a certain threshold.
+     *      The ambient color temperature to which we interpolate to based on the low light curve.
+     * @param highLightAmbientBrightnesses
+     *      The ambient brightness used to map the ambient brightnesses to the biases used to
+     *      interpolate to highLightAmbientColorTemperature.
+     * @param highLightAmbientBiases
+     *      The biases used to map the ambient brightnesses to the biases used to interpolate to
+     *      highLightAmbientColorTemperature.
+     * @param highLightAmbientColorTemperature
+     *      The ambient color temperature to which we interpolate to based on the high light curve.
      * @param ambientColorTemperatures
      *      The ambient color tempeartures used to map the ambient color temperature to the display
      *      color temperature (or null if no mapping is necessary).
@@ -119,7 +145,10 @@
             @NonNull AmbientSensor.AmbientColorTemperatureSensor colorTemperatureSensor,
             @NonNull AmbientFilter colorTemperatureFilter,
             @NonNull DisplayWhiteBalanceThrottler throttler,
-            float lowLightAmbientBrightnessThreshold, float lowLightAmbientColorTemperature,
+            float[] lowLightAmbientBrightnesses, float[] lowLightAmbientBiases,
+            float lowLightAmbientColorTemperature,
+            float[] highLightAmbientBrightnesses, float[] highLightAmbientBiases,
+            float highLightAmbientColorTemperature,
             float[] ambientColorTemperatures, float[] displayColorTemperatures) {
         validateArguments(brightnessSensor, brightnessFilter, colorTemperatureSensor,
                 colorTemperatureFilter, throttler);
@@ -131,8 +160,8 @@
         mColorTemperatureSensor = colorTemperatureSensor;
         mColorTemperatureFilter = colorTemperatureFilter;
         mThrottler = throttler;
-        mLowLightAmbientBrightnessThreshold = lowLightAmbientBrightnessThreshold;
         mLowLightAmbientColorTemperature = lowLightAmbientColorTemperature;
+        mHighLightAmbientColorTemperature = highLightAmbientColorTemperature;
         mAmbientColorTemperature = -1.0f;
         mPendingAmbientColorTemperature = -1.0f;
         mLastAmbientColorTemperature = -1.0f;
@@ -140,9 +169,55 @@
         mAmbientColorTemperatureOverride = -1.0f;
 
         try {
+            mLowLightAmbientBrightnessToBiasSpline = new Spline.LinearSpline(
+                    lowLightAmbientBrightnesses, lowLightAmbientBiases);
+        } catch (Exception e) {
+            Slog.e(TAG, "failed to create low light ambient brightness to bias spline.", e);
+            mLowLightAmbientBrightnessToBiasSpline = null;
+        }
+        if (mLowLightAmbientBrightnessToBiasSpline != null) {
+            if (mLowLightAmbientBrightnessToBiasSpline.interpolate(0.0f) != 0.0f ||
+                    mLowLightAmbientBrightnessToBiasSpline.interpolate(Float.POSITIVE_INFINITY)
+                    != 1.0f) {
+                Slog.d(TAG, "invalid low light ambient brightness to bias spline, "
+                        + "bias must begin at 0.0 and end at 1.0.");
+                mLowLightAmbientBrightnessToBiasSpline = null;
+            }
+        }
+
+        try {
+            mHighLightAmbientBrightnessToBiasSpline = new Spline.LinearSpline(
+                    highLightAmbientBrightnesses, highLightAmbientBiases);
+        } catch (Exception e) {
+            Slog.e(TAG, "failed to create high light ambient brightness to bias spline.", e);
+            mHighLightAmbientBrightnessToBiasSpline = null;
+        }
+        if (mHighLightAmbientBrightnessToBiasSpline != null) {
+            if (mHighLightAmbientBrightnessToBiasSpline.interpolate(0.0f) != 0.0f ||
+                    mHighLightAmbientBrightnessToBiasSpline.interpolate(Float.POSITIVE_INFINITY)
+                    != 1.0f) {
+                Slog.d(TAG, "invalid high light ambient brightness to bias spline, "
+                        + "bias must begin at 0.0 and end at 1.0.");
+                mHighLightAmbientBrightnessToBiasSpline = null;
+            }
+        }
+
+        if (mLowLightAmbientBrightnessToBiasSpline != null &&
+                mHighLightAmbientBrightnessToBiasSpline != null) {
+            if (lowLightAmbientBrightnesses[lowLightAmbientBrightnesses.length - 1] >
+                    highLightAmbientBrightnesses[0]) {
+                Slog.d(TAG, "invalid low light and high light ambient brightness to bias spline "
+                        + "combination, defined domains must not intersect.");
+                mLowLightAmbientBrightnessToBiasSpline = null;
+                mHighLightAmbientBrightnessToBiasSpline = null;
+            }
+        }
+
+        try {
             mAmbientToDisplayColorTemperatureSpline = new Spline.LinearSpline(
                     ambientColorTemperatures, displayColorTemperatures);
         } catch (Exception e) {
+            Slog.e(TAG, "failed to create ambient to display color temperature spline.", e);
             mAmbientToDisplayColorTemperatureSpline = null;
         }
 
@@ -238,9 +313,8 @@
         mColorTemperatureSensor.dump(writer);
         mColorTemperatureFilter.dump(writer);
         mThrottler.dump(writer);
-        writer.println("  mLowLightAmbientBrightnessThreshold="
-                + mLowLightAmbientBrightnessThreshold);
         writer.println("  mLowLightAmbientColorTemperature=" + mLowLightAmbientColorTemperature);
+        writer.println("  mHighLightAmbientColorTemperature=" + mHighLightAmbientColorTemperature);
         writer.println("  mAmbientColorTemperature=" + mAmbientColorTemperature);
         writer.println("  mPendingAmbientColorTemperature=" + mPendingAmbientColorTemperature);
         writer.println("  mLastAmbientColorTemperature=" + mLastAmbientColorTemperature);
@@ -248,6 +322,10 @@
         writer.println("  mAmbientColorTemperatureOverride=" + mAmbientColorTemperatureOverride);
         writer.println("  mAmbientToDisplayColorTemperatureSpline="
                 + mAmbientToDisplayColorTemperatureSpline);
+        writer.println("  mLowLightAmbientBrightnessToBiasSpline="
+                + mLowLightAmbientBrightnessToBiasSpline);
+        writer.println("  mHighLightAmbientBrightnessToBiasSpline="
+                + mHighLightAmbientBrightnessToBiasSpline);
     }
 
     @Override // AmbientSensor.AmbientBrightnessSensor.Callbacks
@@ -276,15 +354,21 @@
                 mAmbientToDisplayColorTemperatureSpline.interpolate(ambientColorTemperature);
         }
 
-        final float ambientBrightness = mBrightnessFilter.getEstimate(time);
-        if (ambientBrightness < mLowLightAmbientBrightnessThreshold) {
-            if (mLoggingEnabled) {
-                Slog.d(TAG, "low light ambient brightness: " + ambientBrightness + " < "
-                        + mLowLightAmbientBrightnessThreshold
-                        + ", falling back to fixed ambient color temperature: "
-                        + ambientColorTemperature + " => " + mLowLightAmbientColorTemperature);
-            }
-            ambientColorTemperature = mLowLightAmbientColorTemperature;
+        float ambientBrightness = mBrightnessFilter.getEstimate(time);
+
+        if (ambientColorTemperature != -1.0f &&
+                mLowLightAmbientBrightnessToBiasSpline != null) {
+            float bias = mLowLightAmbientBrightnessToBiasSpline.interpolate(ambientBrightness);
+            ambientColorTemperature =
+                    bias * ambientColorTemperature + (1.0f - bias)
+                    * mLowLightAmbientColorTemperature;
+        }
+        if (ambientColorTemperature != -1.0f &&
+                mHighLightAmbientBrightnessToBiasSpline != null) {
+            float bias = mHighLightAmbientBrightnessToBiasSpline.interpolate(ambientBrightness);
+            ambientColorTemperature =
+                    (1.0f - bias) * ambientColorTemperature + bias
+                    * mHighLightAmbientColorTemperature;
         }
 
         if (mAmbientColorTemperatureOverride != -1.0f) {
diff --git a/services/core/java/com/android/server/display/whitebalance/DisplayWhiteBalanceFactory.java b/services/core/java/com/android/server/display/whitebalance/DisplayWhiteBalanceFactory.java
index 6ff2b09..bf0a1d1 100644
--- a/services/core/java/com/android/server/display/whitebalance/DisplayWhiteBalanceFactory.java
+++ b/services/core/java/com/android/server/display/whitebalance/DisplayWhiteBalanceFactory.java
@@ -63,19 +63,34 @@
                 createColorTemperatureSensor(handler, sensorManager, resources);
         final AmbientFilter colorTemperatureFilter = createColorTemperatureFilter(resources);
         final DisplayWhiteBalanceThrottler throttler = createThrottler(resources);
-        final float lowLightAmbientBrightnessThreshold = getFloat(resources,
-                com.android.internal.R.dimen
-                .config_displayWhiteBalanceLowLightAmbientBrightnessThreshold);
+        final float[] displayWhiteBalanceLowLightAmbientBrightnesses = getFloatArray(resources,
+                com.android.internal.R.array
+                .config_displayWhiteBalanceLowLightAmbientBrightnesses);
+        final float[] displayWhiteBalanceLowLightAmbientBiases = getFloatArray(resources,
+                com.android.internal.R.array
+                .config_displayWhiteBalanceLowLightAmbientBiases);
         final float lowLightAmbientColorTemperature = getFloat(resources,
                 com.android.internal.R.dimen
                 .config_displayWhiteBalanceLowLightAmbientColorTemperature);
+        final float[] displayWhiteBalanceHighLightAmbientBrightnesses = getFloatArray(resources,
+                com.android.internal.R.array
+                .config_displayWhiteBalanceHighLightAmbientBrightnesses);
+        final float[] displayWhiteBalanceHighLightAmbientBiases = getFloatArray(resources,
+                com.android.internal.R.array
+                .config_displayWhiteBalanceHighLightAmbientBiases);
+        final float highLightAmbientColorTemperature = getFloat(resources,
+                com.android.internal.R.dimen
+                .config_displayWhiteBalanceHighLightAmbientColorTemperature);
         final float[] ambientColorTemperatures = getFloatArray(resources,
                 com.android.internal.R.array.config_displayWhiteBalanceAmbientColorTemperatures);
         final float[] displayColorTempeartures = getFloatArray(resources,
                 com.android.internal.R.array.config_displayWhiteBalanceDisplayColorTemperatures);
         final DisplayWhiteBalanceController controller = new DisplayWhiteBalanceController(
                 brightnessSensor, brightnessFilter, colorTemperatureSensor, colorTemperatureFilter,
-                throttler, lowLightAmbientBrightnessThreshold, lowLightAmbientColorTemperature,
+                throttler, displayWhiteBalanceLowLightAmbientBrightnesses,
+                displayWhiteBalanceLowLightAmbientBiases, lowLightAmbientColorTemperature,
+                displayWhiteBalanceHighLightAmbientBrightnesses,
+                displayWhiteBalanceHighLightAmbientBiases, highLightAmbientColorTemperature,
                 ambientColorTemperatures, displayColorTempeartures);
         brightnessSensor.setCallbacks(controller);
         colorTemperatureSensor.setCallbacks(controller);
@@ -100,8 +115,7 @@
      * Creates a BrightnessFilter which functions as a weighted moving average buffer for recent
      * brightness values.
      */
-    @VisibleForTesting
-    static AmbientFilter createBrightnessFilter(Resources resources) {
+    public static AmbientFilter createBrightnessFilter(Resources resources) {
         final int horizon = resources.getInteger(
                 com.android.internal.R.integer.config_displayWhiteBalanceBrightnessFilterHorizon);
         final float intercept = getFloat(resources,
@@ -114,7 +128,6 @@
                 + "expected config_displayWhiteBalanceBrightnessFilterIntercept");
     }
 
-
     /**
      * Creates an ambient color sensor instance to redirect sensor data to callbacks.
      */
diff --git a/services/core/java/com/android/server/infra/AbstractPerUserSystemService.java b/services/core/java/com/android/server/infra/AbstractPerUserSystemService.java
index c52921e..16cf7ee 100644
--- a/services/core/java/com/android/server/infra/AbstractPerUserSystemService.java
+++ b/services/core/java/com/android/server/infra/AbstractPerUserSystemService.java
@@ -75,6 +75,14 @@
         mMaster = master;
         mLock = lock;
         mUserId = userId;
+        updateIsSetupComplete(userId);
+    }
+
+    /** Updates whether setup is complete for current user */
+    private void updateIsSetupComplete(@UserIdInt int userId) {
+        final String setupComplete = Settings.Secure.getStringForUser(
+                getContext().getContentResolver(), Settings.Secure.USER_SETUP_COMPLETE, userId);
+        mSetupComplete = "1".equals(setupComplete);
     }
 
     /**
@@ -143,9 +151,7 @@
                     + ", disabled=" + disabled + ", mDisabled=" + mDisabled);
         }
 
-        final String setupComplete = Settings.Secure.getStringForUser(
-                getContext().getContentResolver(), Settings.Secure.USER_SETUP_COMPLETE, mUserId);
-        mSetupComplete = "1".equals(setupComplete);
+        updateIsSetupComplete(mUserId);
         mDisabled = disabled;
 
         updateServiceInfoLocked();
diff --git a/services/core/java/com/android/server/locksettings/LockSettingsService.java b/services/core/java/com/android/server/locksettings/LockSettingsService.java
index 107e1fbb..9510db0 100644
--- a/services/core/java/com/android/server/locksettings/LockSettingsService.java
+++ b/services/core/java/com/android/server/locksettings/LockSettingsService.java
@@ -32,6 +32,7 @@
 import static com.android.internal.widget.LockPatternUtils.frpCredentialEnabled;
 import static com.android.internal.widget.LockPatternUtils.userOwnsFrpCredential;
 
+import android.annotation.IntDef;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.annotation.UserIdInt;
@@ -169,6 +170,20 @@
     private static final String SEPARATE_PROFILE_CHALLENGE_KEY = "lockscreen.profilechallenge";
     private static final int SYNTHETIC_PASSWORD_ENABLED_BY_DEFAULT = 1;
 
+    // No challenge provided
+    private static final int CHALLENGE_NONE = 0;
+    // Challenge was provided from the external caller (non-LockSettingsService)
+    private static final int CHALLENGE_FROM_CALLER = 1;
+    // Challenge was generated from within LockSettingsService, for resetLockout. When challenge
+    // type is set to internal, LSS will revokeChallenge after all profiles for that user are
+    // unlocked.
+    private static final int CHALLENGE_INTERNAL = 2;
+
+    @IntDef({CHALLENGE_NONE,
+            CHALLENGE_FROM_CALLER,
+            CHALLENGE_INTERNAL})
+    @interface ChallengeType {};
+
     // Order of holding lock: mSeparateChallengeLock -> mSpManager -> this
     // Do not call into ActivityManager while holding mSpManager lock.
     private final Object mSeparateChallengeLock = new Object();
@@ -276,6 +291,15 @@
         }
     }
 
+    private class PendingResetLockout {
+        final int mUserId;
+        final byte[] mHAT;
+        PendingResetLockout(int userId, byte[] hat) {
+            mUserId = userId;
+            mHAT = hat;
+        }
+    }
+
     /**
      * Tie managed profile to primary profile if it is in unified mode and not tied before.
      *
@@ -420,9 +444,9 @@
                     new PasswordSlotManager());
         }
 
-        public boolean hasEnrolledBiometrics() {
+        public boolean hasEnrolledBiometrics(int userId) {
             BiometricManager bm = mContext.getSystemService(BiometricManager.class);
-            return bm.canAuthenticate() == BiometricManager.BIOMETRIC_SUCCESS;
+            return bm.hasEnrolledBiometrics(userId);
         }
 
         public int binderGetCallingUid() {
@@ -584,7 +608,8 @@
                 // If boot took too long and the password in vold got expired, parent keystore will
                 // be still locked, we ignore this case since the user will be prompted to unlock
                 // the device after boot.
-                unlockChildProfile(userId, true /* ignoreUserNotAuthenticated */);
+                unlockChildProfile(userId, true /* ignoreUserNotAuthenticated */,
+                        CHALLENGE_NONE, 0 /* challenge */, null /* resetLockouts */);
             } catch (RemoteException e) {
                 Slog.e(TAG, "Failed to unlock child profile");
             }
@@ -1160,12 +1185,15 @@
         return decryptionResult;
     }
 
-    private void unlockChildProfile(int profileHandle, boolean ignoreUserNotAuthenticated)
+    private void unlockChildProfile(int profileHandle, boolean ignoreUserNotAuthenticated,
+            @ChallengeType int challengeType, long challenge,
+            @Nullable ArrayList<PendingResetLockout> resetLockouts)
             throws RemoteException {
         try {
             doVerifyCredential(getDecryptedPasswordForTiedProfile(profileHandle),
                     CREDENTIAL_TYPE_PASSWORD,
-                    false, 0 /* no challenge */, profileHandle, null /* progressCallback */);
+                    challengeType, challenge, profileHandle, null /* progressCallback */,
+                    resetLockouts);
         } catch (UnrecoverableKeyException | InvalidKeyException | KeyStoreException
                 | NoSuchAlgorithmException | NoSuchPaddingException
                 | InvalidAlgorithmParameterException | IllegalBlockSizeException
@@ -1180,6 +1208,10 @@
         }
     }
 
+    private void unlockUser(int userId, byte[] token, byte[] secret) {
+        unlockUser(userId, token, secret, CHALLENGE_NONE, 0 /* challenge */, null);
+    }
+
     /**
      * Unlock the user (both storage and user state) and its associated managed profiles
      * synchronously.
@@ -1188,7 +1220,9 @@
      * can end up calling into other system services to process user unlock request (via
      * {@link com.android.server.SystemServiceManager#unlockUser} </em>
      */
-    private void unlockUser(int userId, byte[] token, byte[] secret) {
+    private void unlockUser(int userId, byte[] token, byte[] secret,
+            @ChallengeType int challengeType, long challenge,
+            @Nullable ArrayList<PendingResetLockout> resetLockouts) {
         // TODO: make this method fully async so we can update UI with progress strings
         final boolean alreadyUnlocked = mUserManager.isUserUnlockingOrUnlocked(userId);
         final CountDownLatch latch = new CountDownLatch(1);
@@ -1230,7 +1264,10 @@
             // Unlock managed profile with unified lock
             if (tiedManagedProfileReadyToUnlock(profile)) {
                 try {
-                    unlockChildProfile(profile.id, false /* ignoreUserNotAuthenticated */);
+                    // Must pass the challenge on for resetLockout, so it's not over-written, which
+                    // causes LockSettingsService to revokeChallenge inappropriately.
+                    unlockChildProfile(profile.id, false /* ignoreUserNotAuthenticated */,
+                            challengeType, challenge, resetLockouts);
                 } catch (RemoteException e) {
                     Log.d(TAG, "Failed to unlock child profile", e);
                 }
@@ -1247,6 +1284,21 @@
             }
 
         }
+
+        if (resetLockouts != null && !resetLockouts.isEmpty()) {
+            mHandler.post(() -> {
+                final BiometricManager bm = mContext.getSystemService(BiometricManager.class);
+                final PackageManager pm = mContext.getPackageManager();
+                for (int i = 0; i < resetLockouts.size(); i++) {
+                    bm.setActiveUser(resetLockouts.get(i).mUserId);
+                    bm.resetLockout(resetLockouts.get(i).mHAT);
+                }
+                if (challengeType == CHALLENGE_INTERNAL
+                        && pm.hasSystemFeature(PackageManager.FEATURE_FACE)) {
+                    mContext.getSystemService(FaceManager.class).revokeChallenge();
+                }
+            });
+        }
     }
 
     private boolean tiedManagedProfileReadyToUnlock(UserInfo userInfo) {
@@ -1518,7 +1570,8 @@
             setUserKeyProtection(userId, credential, convertResponse(gkResponse));
             fixateNewestUserKeyAuth(userId);
             // Refresh the auth token
-            doVerifyCredential(credential, credentialType, true, 0, userId, null /* progressCallback */);
+            doVerifyCredential(credential, credentialType, CHALLENGE_FROM_CALLER, 0, userId,
+                    null /* progressCallback */);
             synchronizeUnifiedWorkChallengeForProfiles(userId, null);
             sendCredentialsOnChangeIfRequired(
                     credentialType, credential, userId, isLockTiedToParent);
@@ -1743,24 +1796,32 @@
     public VerifyCredentialResponse checkCredential(byte[] credential, int type, int userId,
             ICheckCredentialProgressCallback progressCallback) throws RemoteException {
         checkPasswordReadPermission(userId);
-        return doVerifyCredential(credential, type, false, 0, userId, progressCallback);
+        return doVerifyCredential(credential, type, CHALLENGE_NONE, 0, userId, progressCallback);
     }
 
     @Override
     public VerifyCredentialResponse verifyCredential(byte[] credential, int type, long challenge,
             int userId) throws RemoteException {
         checkPasswordReadPermission(userId);
-        return doVerifyCredential(credential, type, true, challenge, userId,
+        return doVerifyCredential(credential, type, CHALLENGE_FROM_CALLER, challenge, userId,
                 null /* progressCallback */);
     }
 
+    private VerifyCredentialResponse doVerifyCredential(byte[] credential, int credentialType,
+            @ChallengeType int challengeType, long challenge, int userId,
+            ICheckCredentialProgressCallback progressCallback) throws RemoteException {
+        return doVerifyCredential(credential, credentialType, challengeType, challenge, userId,
+                progressCallback, null /* resetLockouts */);
+    }
+
     /**
      * Verify user credential and unlock the user. Fix pattern bug by deprecating the old base zero
      * format.
      */
     private VerifyCredentialResponse doVerifyCredential(byte[] credential, int credentialType,
-            boolean hasChallenge, long challenge, int userId,
-            ICheckCredentialProgressCallback progressCallback) throws RemoteException {
+            @ChallengeType int challengeType, long challenge, int userId,
+            ICheckCredentialProgressCallback progressCallback,
+            @Nullable ArrayList<PendingResetLockout> resetLockouts) throws RemoteException {
         if (credential == null || credential.length == 0) {
             throw new IllegalArgumentException("Credential can't be null or empty");
         }
@@ -1770,8 +1831,8 @@
             return VerifyCredentialResponse.ERROR;
         }
         VerifyCredentialResponse response = null;
-        response = spBasedDoVerifyCredential(credential, credentialType, hasChallenge, challenge,
-                userId, progressCallback);
+        response = spBasedDoVerifyCredential(credential, credentialType, challengeType, challenge,
+                userId, progressCallback, resetLockouts);
         // The user employs synthetic password based credential.
         if (response != null) {
             if (response.getResponseCode() == VerifyCredentialResponse.RESPONSE_OK) {
@@ -1803,7 +1864,7 @@
         }
 
         response = verifyCredential(userId, storedHash, credentialToVerify,
-                hasChallenge, challenge, progressCallback);
+                challengeType, challenge, progressCallback);
 
         if (response.getResponseCode() == VerifyCredentialResponse.RESPONSE_OK) {
             mStrongAuth.reportSuccessfulStrongAuthUnlock(userId);
@@ -1829,7 +1890,7 @@
         final VerifyCredentialResponse parentResponse = doVerifyCredential(
                 credential,
                 type,
-                true /* hasChallenge */,
+                CHALLENGE_FROM_CALLER,
                 challenge,
                 parentProfileId,
                 null /* progressCallback */);
@@ -1842,7 +1903,7 @@
             // Unlock work profile, and work profile with unified lock must use password only
             return doVerifyCredential(getDecryptedPasswordForTiedProfile(userId),
                     CREDENTIAL_TYPE_PASSWORD,
-                    true,
+                    CHALLENGE_FROM_CALLER,
                     challenge,
                     userId, null /* progressCallback */);
         } catch (UnrecoverableKeyException | InvalidKeyException | KeyStoreException
@@ -1860,7 +1921,7 @@
      * hash to GK.
      */
     private VerifyCredentialResponse verifyCredential(int userId, CredentialHash storedHash,
-            byte[] credential, boolean hasChallenge, long challenge,
+            byte[] credential, @ChallengeType int challengeType, long challenge,
             ICheckCredentialProgressCallback progressCallback) throws RemoteException {
         if ((storedHash == null || storedHash.hash.length == 0)
                     && (credential == null || credential.length == 0)) {
@@ -1903,7 +1964,7 @@
                                 : DevicePolicyManager.PASSWORD_QUALITY_ALPHANUMERIC
                                 /* TODO(roosa): keep the same password quality */,
                         userId, false, /* isLockTiedToParent= */ false);
-                if (!hasChallenge) {
+                if (challengeType == CHALLENGE_NONE) {
                     notifyActivePasswordMetricsAvailable(storedHash.type, credential, userId);
                     // Use credentials to create recoverable keystore snapshot.
                     sendCredentialsOnUnlockIfRequired(storedHash.type, credential, userId);
@@ -2491,9 +2552,14 @@
     }
 
     private VerifyCredentialResponse spBasedDoVerifyCredential(byte[] userCredential,
-            @CredentialType int credentialType, boolean hasChallenge, long challenge, int userId,
-            ICheckCredentialProgressCallback progressCallback) throws RemoteException {
-        if (DEBUG) Slog.d(TAG, "spBasedDoVerifyCredential: user=" + userId);
+            @CredentialType int credentialType, @ChallengeType int challengeType, long challenge,
+            int userId, ICheckCredentialProgressCallback progressCallback,
+            @Nullable ArrayList<PendingResetLockout> resetLockouts) throws RemoteException {
+
+        final boolean hasEnrolledBiometrics = mInjector.hasEnrolledBiometrics(userId);
+
+        Slog.d(TAG, "spBasedDoVerifyCredential: user=" + userId + " challengeType=" + challengeType
+                + " hasEnrolledBiometrics=" + hasEnrolledBiometrics);
         if (credentialType == CREDENTIAL_TYPE_NONE) {
             userCredential = null;
         }
@@ -2502,8 +2568,11 @@
         // TODO: When lockout is handled under the HAL for all biometrics (fingerprint),
         // we need to generate challenge for each one, have it signed by GK and reset lockout
         // for each modality.
-        if (!hasChallenge && pm.hasSystemFeature(PackageManager.FEATURE_FACE)
-                && mInjector.hasEnrolledBiometrics()) {
+        if (challengeType == CHALLENGE_NONE && pm.hasSystemFeature(PackageManager.FEATURE_FACE)
+                && hasEnrolledBiometrics) {
+            // If there are multiple profiles in the same account, ensure we only generate the
+            // challenge once.
+            challengeType = CHALLENGE_INTERNAL;
             challenge = mContext.getSystemService(FaceManager.class).generateChallenge();
         }
 
@@ -2545,21 +2614,18 @@
         if (response.getResponseCode() == VerifyCredentialResponse.RESPONSE_OK) {
             notifyActivePasswordMetricsAvailable(credentialType, userCredential, userId);
             unlockKeystore(authResult.authToken.deriveKeyStorePassword(), userId);
-            // Reset lockout only if user has enrolled templates
-            if (mInjector.hasEnrolledBiometrics()) {
-                BiometricManager bm = mContext.getSystemService(BiometricManager.class);
-                Slog.i(TAG, "Resetting lockout, length: "
-                        + authResult.gkResponse.getPayload().length);
-                bm.resetLockout(authResult.gkResponse.getPayload());
 
-                if (!hasChallenge && pm.hasSystemFeature(PackageManager.FEATURE_FACE)) {
-                    mContext.getSystemService(FaceManager.class).revokeChallenge();
+            // Do resetLockout / revokeChallenge when all profiles are unlocked
+            if (hasEnrolledBiometrics) {
+                if (resetLockouts == null) {
+                    resetLockouts = new ArrayList<>();
                 }
+                resetLockouts.add(new PendingResetLockout(userId, response.getPayload()));
             }
 
             final byte[] secret = authResult.authToken.deriveDiskEncryptionKey();
             Slog.i(TAG, "Unlocking user " + userId + " with secret only, length " + secret.length);
-            unlockUser(userId, null, secret);
+            unlockUser(userId, null, secret, challengeType, challenge, resetLockouts);
 
             activateEscrowTokens(authResult.authToken, userId);
 
diff --git a/services/core/java/com/android/server/locksettings/LockSettingsStorage.java b/services/core/java/com/android/server/locksettings/LockSettingsStorage.java
index f0e431e..84ae7c7 100644
--- a/services/core/java/com/android/server/locksettings/LockSettingsStorage.java
+++ b/services/core/java/com/android/server/locksettings/LockSettingsStorage.java
@@ -48,6 +48,8 @@
 import java.io.File;
 import java.io.IOException;
 import java.io.RandomAccessFile;
+import java.nio.channels.FileChannel;
+import java.nio.file.StandardOpenOption;
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.List;
@@ -390,6 +392,17 @@
         return stored;
     }
 
+    private void fsyncDirectory(File directory) {
+        try {
+            try (FileChannel file = FileChannel.open(directory.toPath(),
+                    StandardOpenOption.READ)) {
+                file.force(true);
+            }
+        } catch (IOException e) {
+            Slog.e(TAG, "Error syncing directory: " + directory, e);
+        }
+    }
+
     private void writeFile(String name, byte[] hash) {
         synchronized (mFileWriteLock) {
             RandomAccessFile raf = null;
@@ -406,6 +419,7 @@
                     raf.write(hash, 0, hash.length);
                 }
                 raf.close();
+                fsyncDirectory((new File(name)).getAbsoluteFile().getParentFile());
             } catch (IOException e) {
                 Slog.e(TAG, "Error writing to file " + e);
             } finally {
diff --git a/services/core/java/com/android/server/locksettings/recoverablekeystore/PlatformKeyManager.java b/services/core/java/com/android/server/locksettings/recoverablekeystore/PlatformKeyManager.java
index c54bfc0..0ad6c2a 100644
--- a/services/core/java/com/android/server/locksettings/recoverablekeystore/PlatformKeyManager.java
+++ b/services/core/java/com/android/server/locksettings/recoverablekeystore/PlatformKeyManager.java
@@ -19,6 +19,7 @@
 import android.app.KeyguardManager;
 import android.content.Context;
 import android.os.RemoteException;
+import android.os.UserHandle;
 import android.security.GateKeeper;
 import android.security.keystore.AndroidKeyStoreSecretKey;
 import android.security.keystore.KeyPermanentlyInvalidatedException;
@@ -437,25 +438,31 @@
         // so it may live in memory for some time.
         SecretKey secretKey = generateAesKey();
 
-        long secureUserId = getGateKeeperService().getSecureUserId(userId);
-        // TODO(b/124095438): Propagate this failure instead of silently failing.
-        if (secureUserId == GateKeeper.INVALID_SECURE_USER_ID) {
-            Log.e(TAG, "No SID available for user " + userId);
-            return;
-        }
-
-        // Store decryption key first since it is more likely to fail.
-        mKeyStore.setEntry(
-                decryptAlias,
-                new KeyStore.SecretKeyEntry(secretKey),
+        KeyProtection.Builder decryptionKeyProtection =
                 new KeyProtection.Builder(KeyProperties.PURPOSE_DECRYPT)
                     .setUserAuthenticationRequired(true)
                     .setUserAuthenticationValidityDurationSeconds(
                             USER_AUTHENTICATION_VALIDITY_DURATION_SECONDS)
                     .setBlockModes(KeyProperties.BLOCK_MODE_GCM)
-                    .setEncryptionPaddings(KeyProperties.ENCRYPTION_PADDING_NONE)
+                    .setEncryptionPaddings(KeyProperties.ENCRYPTION_PADDING_NONE);
+        if (userId != UserHandle.USER_SYSTEM) {
+            // Bind decryption key to secondary profile lock screen secret.
+            long secureUserId = getGateKeeperService().getSecureUserId(userId);
+            // TODO(b/124095438): Propagate this failure instead of silently failing.
+            if (secureUserId == GateKeeper.INVALID_SECURE_USER_ID) {
+                Log.e(TAG, "No SID available for user " + userId);
+                return;
+            }
+            decryptionKeyProtection
                     .setBoundToSpecificSecureUserId(secureUserId)
-                    .build());
+                    // Ignore caller uid which always belongs to the primary profile.
+                    .setCriticalToDeviceEncryption(true);
+        }
+        // Store decryption key first since it is more likely to fail.
+        mKeyStore.setEntry(
+                decryptAlias,
+                new KeyStore.SecretKeyEntry(secretKey),
+                decryptionKeyProtection.build());
         mKeyStore.setEntry(
                 encryptAlias,
                 new KeyStore.SecretKeyEntry(secretKey),
diff --git a/services/core/java/com/android/server/net/NetworkPolicyManagerService.java b/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
index 6c34e13..d3346cd 100644
--- a/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
+++ b/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
@@ -232,7 +232,6 @@
 import com.android.server.SystemConfig;
 
 import libcore.io.IoUtils;
-import libcore.util.EmptyArray;
 
 import org.xmlpull.v1.XmlPullParser;
 import org.xmlpull.v1.XmlSerializer;
@@ -540,7 +539,7 @@
     private final SparseArray<String> mSubIdToSubscriberId = new SparseArray<>();
     /** Set of all merged subscriberId as of last update */
     @GuardedBy("mNetworkPoliciesSecondLock")
-    private String[] mMergedSubscriberIds = EmptyArray.STRING;
+    private List<String[]> mMergedSubscriberIds = new ArrayList<>();
 
     /**
      * Indicates the uids restricted by admin from accessing metered data. It's a mapping from
@@ -1801,7 +1800,7 @@
         final SubscriptionManager sm = mContext.getSystemService(SubscriptionManager.class);
 
         final int[] subIds = ArrayUtils.defeatNullable(sm.getActiveSubscriptionIdList());
-        final String[] mergedSubscriberIds = ArrayUtils.defeatNullable(tm.getMergedSubscriberIds());
+        final List<String[]> mergedSubscriberIdsList = new ArrayList();
 
         final SparseArray<String> subIdToSubscriberId = new SparseArray<>(subIds.length);
         for (int subId : subIds) {
@@ -1811,6 +1810,10 @@
             } else {
                 Slog.wtf(TAG, "Missing subscriberId for subId " + subId);
             }
+
+            String[] mergedSubscriberId = ArrayUtils.defeatNullable(
+                    tm.createForSubscriptionId(subId).getMergedSubscriberIdsFromGroup());
+            mergedSubscriberIdsList.add(mergedSubscriberId);
         }
 
         synchronized (mNetworkPoliciesSecondLock) {
@@ -1820,7 +1823,7 @@
                         subIdToSubscriberId.valueAt(i));
             }
 
-            mMergedSubscriberIds = mergedSubscriberIds;
+            mMergedSubscriberIds = mergedSubscriberIdsList;
         }
 
         Trace.traceEnd(TRACE_TAG_NETWORK);
@@ -3373,8 +3376,10 @@
                 fout.decreaseIndent();
 
                 fout.println();
-                fout.println("Merged subscriptions: "
-                        + Arrays.toString(NetworkIdentity.scrubSubscriberId(mMergedSubscriberIds)));
+                for (String[] mergedSubscribers : mMergedSubscriberIds) {
+                    fout.println("Merged subscriptions: " + Arrays.toString(
+                            NetworkIdentity.scrubSubscriberId(mergedSubscribers)));
+                }
 
                 fout.println();
                 fout.println("Policy for UIDs:");
diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java
index f12c689..cc2df50 100644
--- a/services/core/java/com/android/server/notification/NotificationManagerService.java
+++ b/services/core/java/com/android/server/notification/NotificationManagerService.java
@@ -397,7 +397,7 @@
 
     // for enabling and disabling notification pulse behavior
     boolean mScreenOn = true;
-    protected boolean mInCall = false;
+    protected boolean mInCallStateOffHook = false;
     boolean mNotificationPulseEnabled;
 
     private Uri mInCallNotificationUri;
@@ -1306,7 +1306,7 @@
                 mScreenOn = false;
                 updateNotificationPulse();
             } else if (action.equals(TelephonyManager.ACTION_PHONE_STATE_CHANGED)) {
-                mInCall = TelephonyManager.EXTRA_STATE_OFFHOOK
+                mInCallStateOffHook = TelephonyManager.EXTRA_STATE_OFFHOOK
                         .equals(intent.getStringExtra(TelephonyManager.EXTRA_STATE));
                 updateNotificationPulse();
             } else if (action.equals(Intent.ACTION_USER_STOPPED)) {
@@ -5724,7 +5724,7 @@
                     }
                     if (DBG) Slog.v(TAG, "Interrupting!");
                     if (hasValidSound) {
-                        if (mInCall) {
+                        if (isInCall()) {
                             playInCallNotification();
                             beep = true;
                         } else {
@@ -5738,7 +5738,7 @@
                     final boolean ringerModeSilent =
                             mAudioManager.getRingerModeInternal()
                                     == AudioManager.RINGER_MODE_SILENT;
-                    if (!mInCall && hasValidVibrate && !ringerModeSilent) {
+                    if (!isInCall() && hasValidVibrate && !ringerModeSilent) {
                         buzz = playVibration(record, vibration, hasValidSound);
                         if(buzz) {
                             mVibrateNotificationKey = key;
@@ -5826,7 +5826,7 @@
             return false;
         }
         // not if in call or the screen's on
-        if (mInCall || mScreenOn) {
+        if (isInCall() || mScreenOn) {
             return false;
         }
 
@@ -6927,7 +6927,7 @@
         }
 
         // Don't flash while we are in a call or screen is on
-        if (ledNotification == null || mInCall || mScreenOn) {
+        if (ledNotification == null || isInCall() || mScreenOn) {
             mNotificationLight.turnOff();
         } else {
             NotificationRecord.Light light = ledNotification.getLight();
@@ -7395,6 +7395,18 @@
         }
     }
 
+    private boolean isInCall() {
+        if (mInCallStateOffHook) {
+            return true;
+        }
+        int audioMode = mAudioManager.getMode();
+        if (audioMode == AudioManager.MODE_IN_CALL
+                || audioMode == AudioManager.MODE_IN_COMMUNICATION) {
+            return true;
+        }
+        return false;
+    }
+
     public class NotificationAssistants extends ManagedServices {
         static final String TAG_ENABLED_NOTIFICATION_ASSISTANTS = "enabled_assistants";
 
diff --git a/services/core/java/com/android/server/notification/NotificationRecord.java b/services/core/java/com/android/server/notification/NotificationRecord.java
index c2e559a..3c2169a 100644
--- a/services/core/java/com/android/server/notification/NotificationRecord.java
+++ b/services/core/java/com/android/server/notification/NotificationRecord.java
@@ -34,11 +34,8 @@
 import android.content.Context;
 import android.content.Intent;
 import android.content.pm.PackageManager;
-import android.content.pm.PackageManager.NameNotFoundException;
 import android.content.pm.PackageManagerInternal;
-import android.content.res.Resources;
 import android.graphics.Bitmap;
-import android.graphics.drawable.Icon;
 import android.media.AudioAttributes;
 import android.media.AudioSystem;
 import android.metrics.LogMaker;
@@ -453,16 +450,11 @@
 
     void dump(PrintWriter pw, String prefix, Context baseContext, boolean redact) {
         final Notification notification = sbn.getNotification();
-        final Icon icon = notification.getSmallIcon();
-        String iconStr = String.valueOf(icon);
-        if (icon != null && icon.getType() == Icon.TYPE_RESOURCE) {
-            iconStr += " / " + idDebugString(baseContext, icon.getResPackage(), icon.getResId());
-        }
         pw.println(prefix + this);
         prefix = prefix + "  ";
         pw.println(prefix + "uid=" + sbn.getUid() + " userId=" + sbn.getUserId());
         pw.println(prefix + "opPkg=" + sbn.getOpPkg());
-        pw.println(prefix + "icon=" + iconStr);
+        pw.println(prefix + "icon=" + notification.getSmallIcon());
         pw.println(prefix + "flags=0x" + Integer.toHexString(notification.flags));
         pw.println(prefix + "pri=" + notification.priority);
         pw.println(prefix + "key=" + sbn.getKey());
@@ -592,28 +584,6 @@
         pw.println(prefix + "mAdjustments=" + mAdjustments);
     }
 
-
-    static String idDebugString(Context baseContext, String packageName, int id) {
-        Context c;
-
-        if (packageName != null) {
-            try {
-                c = baseContext.createPackageContext(packageName, 0);
-            } catch (NameNotFoundException e) {
-                c = baseContext;
-            }
-        } else {
-            c = baseContext;
-        }
-
-        Resources r = c.getResources();
-        try {
-            return r.getResourceName(id);
-        } catch (Resources.NotFoundException e) {
-            return "<name unknown>";
-        }
-    }
-
     @Override
     public final String toString() {
         return String.format(
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..20a4c75
--- /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);
+        }
+    }
+
+    private static void startIdmapService() {
+        SystemProperties.set("ctl.start", IDMAP_DAEMON);
+    }
+
+    private 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/pm/PackageInstallerService.java b/services/core/java/com/android/server/pm/PackageInstallerService.java
index 0032e9a..e75f545 100644
--- a/services/core/java/com/android/server/pm/PackageInstallerService.java
+++ b/services/core/java/com/android/server/pm/PackageInstallerService.java
@@ -505,6 +505,11 @@
             params.installFlags &= ~PackageManager.INSTALL_REQUEST_DOWNGRADE;
         }
 
+        if (callingUid != Process.SYSTEM_UID) {
+            // Only system_server can use INSTALL_DISABLE_VERIFICATION.
+            params.installFlags &= ~PackageManager.INSTALL_DISABLE_VERIFICATION;
+        }
+
         boolean isApex = (params.installFlags & PackageManager.INSTALL_APEX) != 0;
         if (params.isStaged || isApex) {
             mContext.enforceCallingOrSelfPermission(Manifest.permission.INSTALL_PACKAGES, TAG);
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index 94d262b..86fb00d 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -17041,11 +17041,6 @@
                     commitPackagesLocked(commitRequest);
                     success = true;
                 } finally {
-                    for (PrepareResult result : prepareResults.values()) {
-                        if (result.freezer != null) {
-                            result.freezer.close();
-                        }
-                    }
                     Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
                 }
             }
@@ -19871,6 +19866,9 @@
             }
         };
 
+        final AppOpsManager appOpsManager = mContext.getSystemService(AppOpsManager.class);
+        final int uid = UserHandle.getUid(userId, ps.pkg.applicationInfo.uid);
+
         final int permissionCount = ps.pkg.requestedPermissions.size();
         for (int i = 0; i < permissionCount; i++) {
             final String permName = ps.pkg.requestedPermissions.get(i);
@@ -19930,6 +19928,14 @@
             if ((oldFlags & FLAG_PERMISSION_GRANTED_BY_DEFAULT) != 0) {
                 mPermissionManager.grantRuntimePermission(permName, packageName, false,
                         Process.SYSTEM_UID, userId, delayingPermCallback);
+                // Allow app op later as we are holding mPackages
+                // PermissionPolicyService will handle the app op for foreground/background
+                // permissions.
+                String appOp = AppOpsManager.permissionToOp(permName);
+                if (appOp != null) {
+                    mHandler.post(() -> appOpsManager.setUidMode(appOp, uid,
+                            AppOpsManager.MODE_ALLOWED));
+                }
             // If permission review is enabled the permissions for a legacy apps
             // are represented as constantly granted runtime ones, so don't revoke.
             } else if ((flags & FLAG_PERMISSION_REVIEW_REQUIRED) == 0) {
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/policy/PhoneWindowManager.java b/services/core/java/com/android/server/policy/PhoneWindowManager.java
index 0c43d81..21b13fe 100644
--- a/services/core/java/com/android/server/policy/PhoneWindowManager.java
+++ b/services/core/java/com/android/server/policy/PhoneWindowManager.java
@@ -2517,14 +2517,21 @@
 
     @Override
     public Animation createHiddenByKeyguardExit(boolean onWallpaper,
-            boolean goingToNotificationShade) {
+            boolean goingToNotificationShade, boolean subtleAnimation) {
         if (goingToNotificationShade) {
             return AnimationUtils.loadAnimation(mContext, R.anim.lock_screen_behind_enter_fade_in);
         }
 
-        AnimationSet set = (AnimationSet) AnimationUtils.loadAnimation(mContext, onWallpaper ?
-                    R.anim.lock_screen_behind_enter_wallpaper :
-                    R.anim.lock_screen_behind_enter);
+        final int resource;
+        if (subtleAnimation) {
+            resource = R.anim.lock_screen_behind_enter_subtle;
+        } else if (onWallpaper) {
+            resource = R.anim.lock_screen_behind_enter_wallpaper;
+        } else  {
+            resource = R.anim.lock_screen_behind_enter;
+        }
+
+        AnimationSet set = (AnimationSet) AnimationUtils.loadAnimation(mContext, resource);
 
         // TODO: Use XML interpolators when we have log interpolators available in XML.
         final List<Animation> animations = set.getAnimations();
diff --git a/services/core/java/com/android/server/policy/WindowManagerPolicy.java b/services/core/java/com/android/server/policy/WindowManagerPolicy.java
index b196754..6d9c710 100644
--- a/services/core/java/com/android/server/policy/WindowManagerPolicy.java
+++ b/services/core/java/com/android/server/policy/WindowManagerPolicy.java
@@ -980,7 +980,7 @@
      * Create and return an animation to re-display a window that was force hidden by Keyguard.
      */
     public Animation createHiddenByKeyguardExit(boolean onWallpaper,
-            boolean goingToNotificationShade);
+            boolean goingToNotificationShade, boolean subtleAnimation);
 
     /**
      * Create and return an animation to let the wallpaper disappear after being shown behind
diff --git a/services/core/java/com/android/server/power/AttentionDetector.java b/services/core/java/com/android/server/power/AttentionDetector.java
index ed11fd4..4e9b724 100644
--- a/services/core/java/com/android/server/power/AttentionDetector.java
+++ b/services/core/java/com/android/server/power/AttentionDetector.java
@@ -40,6 +40,7 @@
 
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.server.LocalServices;
+import com.android.server.wm.WindowManagerInternal;
 
 import java.io.PrintWriter;
 import java.util.concurrent.atomic.AtomicBoolean;
@@ -102,6 +103,9 @@
     protected AttentionManagerInternal mAttentionManager;
 
     @VisibleForTesting
+    protected WindowManagerInternal mWindowManager;
+
+    @VisibleForTesting
     protected PackageManager mPackageManager;
 
     @VisibleForTesting
@@ -142,6 +146,7 @@
         mPackageManager = context.getPackageManager();
         mContentResolver = context.getContentResolver();
         mAttentionManager = LocalServices.getService(AttentionManagerInternal.class);
+        mWindowManager = LocalServices.getService(WindowManagerInternal.class);
         mMaximumExtensionMillis = context.getResources().getInteger(
                 com.android.internal.R.integer.config_attentionMaximumExtension);
         mMaxAttentionApiTimeoutMillis = context.getResources().getInteger(
@@ -156,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);
@@ -165,14 +170,10 @@
     }
 
     public long updateUserActivity(long nextScreenDimming) {
-        if (nextScreenDimming == mLastActedOnNextScreenDimming) {
-            return nextScreenDimming;
-        }
-        if (!mIsSettingEnabled) {
-            return nextScreenDimming;
-        }
-
-        if (!isAttentionServiceSupported()) {
+        if (nextScreenDimming == mLastActedOnNextScreenDimming
+                || !mIsSettingEnabled
+                || !isAttentionServiceSupported()
+                || mWindowManager.isKeyguardShowingAndNotOccluded()) {
             return nextScreenDimming;
         }
 
@@ -297,6 +298,7 @@
 
     public void dump(PrintWriter pw) {
         pw.println("AttentionDetector:");
+        pw.println(" mIsSettingEnabled=" + mIsSettingEnabled);
         pw.println(" mMaximumExtensionMillis=" + mMaximumExtensionMillis);
         pw.println(" mMaxAttentionApiTimeoutMillis=" + mMaxAttentionApiTimeoutMillis);
         pw.println(" mLastUserActivityTime(excludingAttention)=" + mLastUserActivityTime);
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/role/RoleManagerService.java b/services/core/java/com/android/server/role/RoleManagerService.java
index c6a1867..d66803b 100644
--- a/services/core/java/com/android/server/role/RoleManagerService.java
+++ b/services/core/java/com/android/server/role/RoleManagerService.java
@@ -225,9 +225,10 @@
             //TODO gradually add more role migrations statements here for remaining roles
             // Make sure to implement LegacyRoleResolutionPolicy#getRoleHolders
             // for a given role before adding a migration statement for it here
-            migrateRoleIfNecessary(RoleManager.ROLE_SMS, userId);
             migrateRoleIfNecessary(RoleManager.ROLE_ASSISTANT, userId);
+            migrateRoleIfNecessary(RoleManager.ROLE_BROWSER, userId);
             migrateRoleIfNecessary(RoleManager.ROLE_DIALER, userId);
+            migrateRoleIfNecessary(RoleManager.ROLE_SMS, userId);
             migrateRoleIfNecessary(RoleManager.ROLE_EMERGENCY, userId);
 
             // Some vital packages state has changed since last role grant
diff --git a/services/core/java/com/android/server/rollback/RollbackManagerServiceImpl.java b/services/core/java/com/android/server/rollback/RollbackManagerServiceImpl.java
index e107c9a..08c1bb5 100644
--- a/services/core/java/com/android/server/rollback/RollbackManagerServiceImpl.java
+++ b/services/core/java/com/android/server/rollback/RollbackManagerServiceImpl.java
@@ -86,9 +86,9 @@
 
     private static final String TAG = "RollbackManager";
 
-    // Rollbacks expire after 48 hours.
+    // Rollbacks expire after 14 days.
     private static final long DEFAULT_ROLLBACK_LIFETIME_DURATION_MILLIS =
-            TimeUnit.HOURS.toMillis(48);
+            TimeUnit.DAYS.toMillis(14);
 
     // Lock used to synchronize accesses to in-memory rollback data
     // structures. By convention, methods with the suffix "Locked" require
@@ -1289,7 +1289,8 @@
 
 
     private boolean packageVersionsEqual(VersionedPackage a, VersionedPackage b) {
-        return a.getPackageName().equals(b.getPackageName())
+        return a != null && b != null
+            && a.getPackageName().equals(b.getPackageName())
             && a.getLongVersionCode() == b.getLongVersionCode();
     }
 
diff --git a/services/core/java/com/android/server/slice/PinnedSliceState.java b/services/core/java/com/android/server/slice/PinnedSliceState.java
index e139ab8..4970862 100644
--- a/services/core/java/com/android/server/slice/PinnedSliceState.java
+++ b/services/core/java/com/android/server/slice/PinnedSliceState.java
@@ -188,7 +188,7 @@
             b.putParcelable(SliceProvider.EXTRA_BIND_URI, mUri);
             try {
                 client.call(SliceProvider.METHOD_PIN, null, b);
-            } catch (RemoteException e) {
+            } catch (Exception e) {
                 Log.w(TAG, "Unable to contact " + mUri, e);
             }
         }
@@ -201,7 +201,7 @@
             b.putParcelable(SliceProvider.EXTRA_BIND_URI, mUri);
             try {
                 client.call(SliceProvider.METHOD_UNPIN, null, b);
-            } catch (RemoteException e) {
+            } catch (Exception e) {
                 Log.w(TAG, "Unable to contact " + mUri, e);
             }
         }
diff --git a/services/core/java/com/android/server/statusbar/StatusBarShellCommand.java b/services/core/java/com/android/server/statusbar/StatusBarShellCommand.java
index b121298..d7f86cd 100644
--- a/services/core/java/com/android/server/statusbar/StatusBarShellCommand.java
+++ b/services/core/java/com/android/server/statusbar/StatusBarShellCommand.java
@@ -161,7 +161,15 @@
                 case "statusbar-expansion":
                     info.setStatusBarExpansionDisabled(true);
                     break;
-
+                case "system-icons":
+                    info.setSystemIconsDisabled(true);
+                    break;
+                case "clock":
+                    info.setClockDisabled(true);
+                    break;
+                case "notification-icons":
+                    info.setNotificationIconsDisabled(true);
+                    break;
                 default:
                     break;
             }
@@ -221,6 +229,9 @@
         pw.println("        recents             - disable recents/overview");
         pw.println("        notification-peek   - disable notification peeking");
         pw.println("        statusbar-expansion - disable status bar expansion");
+        pw.println("        system-icons        - disable system icons appearing in status bar");
+        pw.println("        clock               - disable clock appearing in status bar");
+        pw.println("        notification-icons  - disable notification icons from status bar");
         pw.println("");
     }
 
diff --git a/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java b/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java
index 9908b36..b0f1e5d 100644
--- a/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java
+++ b/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java
@@ -1172,8 +1172,16 @@
                 return false;
             }
             final int displayId = display.getDisplayId();
-            return displayId == DEFAULT_DISPLAY
-                    || mWindowManagerInternal.shouldShowSystemDecorOnDisplay(displayId);
+            if (displayId == DEFAULT_DISPLAY) {
+                return true;
+            }
+
+            final long ident = Binder.clearCallingIdentity();
+            try {
+                return mWindowManagerInternal.shouldShowSystemDecorOnDisplay(displayId);
+            } finally {
+                Binder.restoreCallingIdentity(ident);
+            }
         }
 
         void forEachDisplayConnector(Consumer<DisplayConnector> action) {
diff --git a/services/core/java/com/android/server/wm/AccessibilityController.java b/services/core/java/com/android/server/wm/AccessibilityController.java
index b6a5be8..4cfc1d1 100644
--- a/services/core/java/com/android/server/wm/AccessibilityController.java
+++ b/services/core/java/com/android/server/wm/AccessibilityController.java
@@ -1065,8 +1065,6 @@
 
         private final long mRecurringAccessibilityEventsIntervalMillis;
 
-        private int mTempLayer = 0;
-
         public WindowsForAccessibilityObserver(WindowManagerService windowManagerService,
                 WindowsForAccessibilityCallback callback) {
             mContext = windowManagerService.mContext;
@@ -1091,7 +1089,7 @@
         }
 
         /**
-         * Check if windows have changed, and send them to the accessibilty subsystem if they have.
+         * Check if windows have changed, and send them to the accessibility subsystem if they have.
          *
          * @param forceSend Send the windows the accessibility even if they haven't changed.
          */
@@ -1108,8 +1106,7 @@
                 // the window manager is still looking for where to put it.
                 // We will do the work when we get a focus change callback.
                 // TODO(b/112273690): Support multiple displays
-                // TODO(b/129098348): Support embedded displays
-                if (mService.getDefaultDisplayContentLocked().mCurrentFocus == null) {
+                if (!isCurrentFocusWindowOnDefaultDisplay()) {
                     return;
                 }
 
@@ -1395,21 +1392,35 @@
         }
 
         private void populateVisibleWindowsOnScreenLocked(SparseArray<WindowState> outWindows) {
+            final List<WindowState> tempWindowStatesList = new ArrayList<>();
             final DisplayContent dc = mService.getDefaultDisplayContentLocked();
-            mTempLayer = 0;
             dc.forAllWindows((w) -> {
                 if (w.isVisibleLw()) {
-                    outWindows.put(mTempLayer++, w);
+                    tempWindowStatesList.add(w);
                 }
             }, false /* traverseTopToBottom */);
+            // Insert the re-parented windows in another display on top of their parents in
+            // default display.
             mService.mRoot.forAllWindows(w -> {
-                final WindowState win = findRootDisplayParentWindow(w);
-                if (win != null && win.getDisplayContent().isDefaultDisplay && w.isVisibleLw()) {
-                    // TODO(b/129098348): insert windows on child displays into outWindows based on
-                    // root-display-parent window.
-                    outWindows.put(mTempLayer++, w);
+                final WindowState parentWindow = findRootDisplayParentWindow(w);
+                if (parentWindow == null) {
+                    return;
                 }
-            }, false /* traverseTopToBottom */);
+
+                // TODO: Use Region instead to get rid of this complicated logic.
+                // Check the tap exclude region of the parent window. If the tap exclude region
+                // is empty, it means there is another can-receive-pointer-event view on top of
+                // the region. Hence, we don't count the window as visible.
+                if (w.isVisibleLw() && parentWindow.getDisplayContent().isDefaultDisplay
+                        && parentWindow.hasTapExcludeRegion()
+                        && tempWindowStatesList.contains(parentWindow)) {
+                    tempWindowStatesList.add(
+                            tempWindowStatesList.lastIndexOf(parentWindow) + 1, w);
+                }
+            }, true /* traverseTopToBottom */);
+            for (int i = 0; i < tempWindowStatesList.size(); i++) {
+                outWindows.put(i, tempWindowStatesList.get(i));
+            }
         }
 
         private WindowState findRootDisplayParentWindow(WindowState win) {
@@ -1425,6 +1436,23 @@
             return displayParentWindow;
         }
 
+        private boolean isCurrentFocusWindowOnDefaultDisplay() {
+            final WindowState focusedWindow =
+                    mService.mRoot.getTopFocusedDisplayContent().mCurrentFocus;
+            if (focusedWindow == null) {
+                return false;
+            }
+
+            final WindowState rootDisplayParentWindow = findRootDisplayParentWindow(focusedWindow);
+            if (!focusedWindow.isDefaultDisplay()
+                    && (rootDisplayParentWindow == null
+                    || !rootDisplayParentWindow.isDefaultDisplay())) {
+                return false;
+            }
+
+            return true;
+        }
+
         private class MyHandler extends Handler {
             public static final int MESSAGE_COMPUTE_CHANGED_WINDOWS = 1;
 
diff --git a/services/core/java/com/android/server/wm/ActivityRecord.java b/services/core/java/com/android/server/wm/ActivityRecord.java
index 371a943..6491360 100644
--- a/services/core/java/com/android/server/wm/ActivityRecord.java
+++ b/services/core/java/com/android/server/wm/ActivityRecord.java
@@ -921,8 +921,9 @@
         return ResolverActivity.class.getName().equals(className);
     }
 
-    boolean isResolverActivity() {
-        return isResolverActivity(mActivityComponent.getClassName());
+    boolean isResolverOrDelegateActivity() {
+        return isResolverActivity(mActivityComponent.getClassName()) || Objects.equals(
+                mActivityComponent, mAtmService.mStackSupervisor.getSystemChooserActivity());
     }
 
     boolean isResolverOrChildActivity() {
@@ -1251,7 +1252,8 @@
                 && intent.getType() == null;
     }
 
-    private boolean canLaunchHomeActivity(int uid, ActivityRecord sourceRecord) {
+    @VisibleForTesting
+    boolean canLaunchHomeActivity(int uid, ActivityRecord sourceRecord) {
         if (uid == Process.myUid() || uid == 0) {
             // System process can launch home activity.
             return true;
@@ -1261,8 +1263,8 @@
         if (recentTasks != null && recentTasks.isCallerRecents(uid)) {
             return true;
         }
-        // Resolver activity can launch home activity.
-        return sourceRecord != null && sourceRecord.isResolverActivity();
+        // Resolver or system chooser activity can launch home activity.
+        return sourceRecord != null && sourceRecord.isResolverOrDelegateActivity();
     }
 
     /**
@@ -1281,7 +1283,7 @@
             ActivityOptions options, ActivityRecord sourceRecord) {
         int activityType = ACTIVITY_TYPE_UNDEFINED;
         if ((!componentSpecified || canLaunchHomeActivity(launchedFromUid, sourceRecord))
-                && isHomeIntent(intent) && !isResolverActivity()) {
+                && isHomeIntent(intent) && !isResolverOrDelegateActivity()) {
             // This sure looks like a home activity!
             activityType = ACTIVITY_TYPE_HOME;
 
@@ -3165,7 +3167,7 @@
 
     boolean ensureActivityConfiguration(int globalChanges, boolean preserveWindow) {
         return ensureActivityConfiguration(globalChanges, preserveWindow,
-                false /* ignoreStopState */);
+                false /* ignoreVisibility */);
     }
 
     /**
@@ -3175,15 +3177,15 @@
      * @param globalChanges The changes to the global configuration.
      * @param preserveWindow If the activity window should be preserved on screen if the activity
      *                       is relaunched.
-     * @param ignoreStopState If we should try to relaunch the activity even if it is in the stopped
-     *                        state. This is useful for the case where we know the activity will be
-     *                        visible soon and we want to ensure its configuration before we make it
-     *                        visible.
+     * @param ignoreVisibility If we should try to relaunch the activity even if it is invisible
+     *                         (stopped state). This is useful for the case where we know the
+     *                         activity will be visible soon and we want to ensure its configuration
+     *                         before we make it visible.
      * @return False if the activity was relaunched and true if it wasn't relaunched because we
      *         can't or the app handles the specific configuration that is changing.
      */
     boolean ensureActivityConfiguration(int globalChanges, boolean preserveWindow,
-            boolean ignoreStopState) {
+            boolean ignoreVisibility) {
         final ActivityStack stack = getActivityStack();
         if (stack.mConfigWillChange) {
             if (DEBUG_SWITCH || DEBUG_CONFIGURATION) Slog.v(TAG_CONFIGURATION,
@@ -3199,15 +3201,9 @@
             return true;
         }
 
-        if (!ignoreStopState && (mState == STOPPING || mState == STOPPED)) {
+        if (!ignoreVisibility && (mState == STOPPING || mState == STOPPED || !shouldBeVisible())) {
             if (DEBUG_SWITCH || DEBUG_CONFIGURATION) Slog.v(TAG_CONFIGURATION,
-                    "Skipping config check stopped or stopping: " + this);
-            return true;
-        }
-
-        if (!shouldBeVisible()) {
-            if (DEBUG_SWITCH || DEBUG_CONFIGURATION) Slog.v(TAG_CONFIGURATION,
-                    "Skipping config check invisible stack: " + this);
+                    "Skipping config check invisible: " + this);
             return true;
         }
 
diff --git a/services/core/java/com/android/server/wm/ActivityStack.java b/services/core/java/com/android/server/wm/ActivityStack.java
index 6bed462..c5c53d8 100644
--- a/services/core/java/com/android/server/wm/ActivityStack.java
+++ b/services/core/java/com/android/server/wm/ActivityStack.java
@@ -40,6 +40,7 @@
 import static android.view.WindowManager.TRANSIT_ACTIVITY_OPEN;
 import static android.view.WindowManager.TRANSIT_CRASHING_ACTIVITY_CLOSE;
 import static android.view.WindowManager.TRANSIT_NONE;
+import static android.view.WindowManager.TRANSIT_SHOW_SINGLE_TASK_DISPLAY;
 import static android.view.WindowManager.TRANSIT_TASK_CLOSE;
 import static android.view.WindowManager.TRANSIT_TASK_OPEN;
 import static android.view.WindowManager.TRANSIT_TASK_OPEN_BEHIND;
@@ -163,6 +164,8 @@
 import com.android.server.am.EventLogTags;
 import com.android.server.am.PendingIntentRecord;
 
+import com.google.android.collect.Sets;
+
 import java.io.FileDescriptor;
 import java.io.PrintWriter;
 import java.lang.ref.WeakReference;
@@ -1879,8 +1882,7 @@
         mRootActivityContainer.ensureActivitiesVisible(resuming, 0, !PRESERVE_WINDOWS);
     }
 
-    private void addToStopping(ActivityRecord r, boolean scheduleIdle, boolean idleDelayed,
-            String reason) {
+    void addToStopping(ActivityRecord r, boolean scheduleIdle, boolean idleDelayed, String reason) {
         if (!mStackSupervisor.mStoppingActivities.contains(r)) {
             EventLog.writeEvent(EventLogTags.AM_ADD_TO_STOPPING, r.mUserId,
                     System.identityHashCode(r), r.shortComponentName, reason);
@@ -2175,7 +2177,7 @@
                         // sure it matches the current configuration.
                         if (r != starting && notifyClients) {
                             r.ensureActivityConfiguration(0 /* globalChanges */, preserveWindows,
-                                    true /* ignoreStopState */);
+                                    true /* ignoreVisibility */);
                         }
 
                         if (!r.attachedToProcess()) {
@@ -3138,8 +3140,10 @@
             boolean newTask, boolean keepCurTransition, ActivityOptions options) {
         TaskRecord rTask = r.getTaskRecord();
         final int taskId = rTask.taskId;
+        final boolean allowMoveToFront = options == null || !options.getAvoidMoveToFront();
         // mLaunchTaskBehind tasks get placed at the back of the task stack.
-        if (!r.mLaunchTaskBehind && (taskForIdLocked(taskId) == null || newTask)) {
+        if (!r.mLaunchTaskBehind && allowMoveToFront
+                && (taskForIdLocked(taskId) == null || newTask)) {
             // Last activity in task had been removed or ActivityManagerService is reusing task.
             // Insert or replace.
             // Might not even be in.
@@ -3198,7 +3202,9 @@
 
         task.setFrontOfTask();
 
-        if (!isHomeOrRecentsStack() || numActivities() > 0) {
+        // The transition animation and starting window are not needed if {@code allowMoveToFront}
+        // is false, because the activity won't be visible.
+        if ((!isHomeOrRecentsStack() || numActivities() > 0) && allowMoveToFront) {
             final DisplayContent dc = getDisplay().mDisplayContent;
             if (DEBUG_TRANSITION) Slog.v(TAG_TRANSITION,
                     "Prepare open transition: starting " + r);
@@ -3210,6 +3216,8 @@
                 if (newTask) {
                     if (r.mLaunchTaskBehind) {
                         transit = TRANSIT_TASK_OPEN_BEHIND;
+                    } else if (getDisplay().isSingleTaskInstance()) {
+                        transit = TRANSIT_SHOW_SINGLE_TASK_DISPLAY;
                     } else {
                         // If a new task is being launched, then mark the existing top activity as
                         // supporting picture-in-picture while pausing only if the starting activity
@@ -4019,6 +4027,14 @@
                 }
                 getDisplay().mDisplayContent.prepareAppTransition(transit, false);
 
+                // When finishing the activity pre-emptively take the snapshot before the app window
+                // is marked as hidden and any configuration changes take place
+                if (mWindowManager.mTaskSnapshotController != null) {
+                    final ArraySet<Task> tasks = Sets.newArraySet(task.mTask);
+                    mWindowManager.mTaskSnapshotController.snapshotTasks(tasks);
+                    mWindowManager.mTaskSnapshotController.addSkipClosingAppSnapshotTasks(tasks);
+                }
+
                 // Tell window manager to prepare for this one to be removed.
                 r.setVisibility(false);
 
@@ -5635,13 +5651,20 @@
     void animateResizePinnedStack(Rect sourceHintBounds, Rect toBounds, int animationDuration,
             boolean fromFullscreen) {
         if (!inPinnedWindowingMode()) return;
-        if (skipResizeAnimation(toBounds == null /* toFullscreen */)) {
-            mService.moveTasksToFullscreenStack(mStackId, true /* onTop */);
-        } else {
-            if (getTaskStack() == null) return;
-            getTaskStack().animateResizePinnedStack(toBounds, sourceHintBounds,
-                    animationDuration, fromFullscreen);
+        if (toBounds == null /* toFullscreen */) {
+            final Configuration parentConfig = getParent().getConfiguration();
+            final ActivityRecord top = topRunningNonOverlayTaskActivity();
+            if (top != null && !top.isConfigurationCompatible(parentConfig)) {
+                // The final orientation of this activity will change after moving to full screen.
+                // Start freezing screen here to prevent showing a temporary full screen window.
+                top.startFreezingScreenLocked(top.app, CONFIG_SCREEN_LAYOUT);
+                mService.moveTasksToFullscreenStack(mStackId, true /* onTop */);
+                return;
+            }
         }
+        if (getTaskStack() == null) return;
+        getTaskStack().animateResizePinnedStack(toBounds, sourceHintBounds,
+                animationDuration, fromFullscreen);
     }
 
     /**
@@ -5657,15 +5680,6 @@
         stack.getAnimationOrCurrentBounds(outBounds);
     }
 
-    private boolean skipResizeAnimation(boolean toFullscreen) {
-        if (!toFullscreen) {
-            return false;
-        }
-        final Configuration parentConfig = getParent().getConfiguration();
-        final ActivityRecord top = topRunningNonOverlayTaskActivity();
-        return top != null && !top.isConfigurationCompatible(parentConfig);
-    }
-
     void setPictureInPictureAspectRatio(float aspectRatio) {
         if (getTaskStack() == null) return;
         getTaskStack().setPictureInPictureAspectRatio(aspectRatio);
diff --git a/services/core/java/com/android/server/wm/ActivityStackSupervisor.java b/services/core/java/com/android/server/wm/ActivityStackSupervisor.java
index 19916bc..3550ebf 100644
--- a/services/core/java/com/android/server/wm/ActivityStackSupervisor.java
+++ b/services/core/java/com/android/server/wm/ActivityStackSupervisor.java
@@ -130,6 +130,7 @@
 import android.util.SparseArray;
 import android.util.SparseIntArray;
 
+import com.android.internal.R;
 import com.android.internal.annotations.GuardedBy;
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.content.ReferrerIntent;
@@ -323,6 +324,12 @@
     boolean mUserLeaving = false;
 
     /**
+     * The system chooser activity which worked as a delegate of
+     * {@link com.android.internal.app.ResolverActivity}.
+     */
+    private ComponentName mSystemChooserActivity;
+
+    /**
      * We don't want to allow the device to go to sleep while in the process
      * of launching an activity.  This is primarily to allow alarm intent
      * receivers to launch an activity and get that to run before the device
@@ -469,6 +476,14 @@
         return mKeyguardController;
     }
 
+    ComponentName getSystemChooserActivity() {
+        if (mSystemChooserActivity == null) {
+            mSystemChooserActivity = ComponentName.unflattenFromString(
+                    mService.mContext.getResources().getString(R.string.config_chooserActivity));
+        }
+        return mSystemChooserActivity;
+    }
+
     void setRecentTasks(RecentTasks recentTasks) {
         mRecentTasks = recentTasks;
         mRecentTasks.registerCallback(this);
diff --git a/services/core/java/com/android/server/wm/ActivityStarter.java b/services/core/java/com/android/server/wm/ActivityStarter.java
index 0a88eef..5a1eed8 100644
--- a/services/core/java/com/android/server/wm/ActivityStarter.java
+++ b/services/core/java/com/android/server/wm/ActivityStarter.java
@@ -187,6 +187,7 @@
     private boolean mNoAnimation;
     private boolean mKeepCurTransition;
     private boolean mAvoidMoveToFront;
+    private boolean mFrozeTaskList;
 
     // We must track when we deliver the new intent since multiple code paths invoke
     // {@link #deliverNewIntent}. This is due to early returns in the code path. This flag is used
@@ -483,6 +484,7 @@
         mNoAnimation = starter.mNoAnimation;
         mKeepCurTransition = starter.mKeepCurTransition;
         mAvoidMoveToFront = starter.mAvoidMoveToFront;
+        mFrozeTaskList = starter.mFrozeTaskList;
 
         mVoiceSession = starter.mVoiceSession;
         mVoiceInteractor = starter.mVoiceInteractor;
@@ -1093,6 +1095,14 @@
 
     void postStartActivityProcessing(ActivityRecord r, int result,
             ActivityStack startedActivityStack) {
+        if (!ActivityManager.isStartResultSuccessful(result)) {
+            if (mFrozeTaskList) {
+                // If we specifically froze the task list as part of starting an activity, then
+                // reset the frozen list state if it failed to start. This is normally otherwise
+                // called when the freeze-timeout has elapsed.
+                mSupervisor.mRecentTasks.resetFreezeTaskListReorderingOnTimeout();
+            }
+        }
         if (ActivityManager.isStartResultFatalError(result)) {
             return;
         }
@@ -1485,6 +1495,14 @@
                 mLaunchParams.hasPreferredDisplay() ? mLaunchParams.mPreferredDisplayId
                         : DEFAULT_DISPLAY;
 
+        // If requested, freeze the task list
+        if (mOptions != null && mOptions.freezeRecentTasksReordering()
+                && mSupervisor.mRecentTasks.isCallerRecents(r.launchedFromUid)
+                && !mSupervisor.mRecentTasks.isFreezeTaskListReorderingSet()) {
+            mFrozeTaskList = true;
+            mSupervisor.mRecentTasks.setFreezeTaskListReordering();
+        }
+
         // Do not start home activity if it cannot be launched on preferred display. We are not
         // doing this in ActivityStackSupervisor#canPlaceEntityOnDisplay because it might
         // fallback to launch on other displays.
@@ -1775,6 +1793,7 @@
         mNoAnimation = false;
         mKeepCurTransition = false;
         mAvoidMoveToFront = false;
+        mFrozeTaskList = false;
 
         mVoiceSession = null;
         mVoiceInteractor = null;
@@ -1979,8 +1998,8 @@
             // Also put noDisplay activities in the source task. These by itself can be placed
             // in any task/stack, however it could launch other activities like ResolverActivity,
             // and we want those to stay in the original task.
-            if ((mStartActivity.isResolverActivity() || mStartActivity.noDisplay) && mSourceRecord != null
-                    && mSourceRecord.inFreeformWindowingMode())  {
+            if ((mStartActivity.isResolverOrDelegateActivity() || mStartActivity.noDisplay)
+                    && mSourceRecord != null && mSourceRecord.inFreeformWindowingMode()) {
                 mAddingToTask = true;
             }
         }
@@ -2307,12 +2326,12 @@
         // isLockTaskModeViolation fails below.
 
         if (mReuseTask == null) {
+            final boolean toTop = !mLaunchTaskBehind && !mAvoidMoveToFront;
             final TaskRecord task = mTargetStack.createTaskRecord(
                     mSupervisor.getNextTaskIdForUserLocked(mStartActivity.mUserId),
                     mNewTaskInfo != null ? mNewTaskInfo : mStartActivity.info,
                     mNewTaskIntent != null ? mNewTaskIntent : mIntent, mVoiceSession,
-                    mVoiceInteractor, !mLaunchTaskBehind /* toTop */, mStartActivity, mSourceRecord,
-                    mOptions);
+                    mVoiceInteractor, toTop, mStartActivity, mSourceRecord, mOptions);
             addOrReparentStartingActivity(task, "setTaskFromReuseOrCreateNewTask - mReuseTask");
             updateBounds(mStartActivity.getTaskRecord(), mLaunchParams.mBounds);
 
diff --git a/services/core/java/com/android/server/wm/ActivityTaskManagerInternal.java b/services/core/java/com/android/server/wm/ActivityTaskManagerInternal.java
index 5459ede..ab35652 100644
--- a/services/core/java/com/android/server/wm/ActivityTaskManagerInternal.java
+++ b/services/core/java/com/android/server/wm/ActivityTaskManagerInternal.java
@@ -34,7 +34,6 @@
 import android.os.RemoteException;
 import android.os.SystemClock;
 import android.service.voice.IVoiceInteractionSession;
-import android.util.Pair;
 import android.util.SparseIntArray;
 import android.util.proto.ProtoOutputStream;
 
@@ -189,6 +188,13 @@
     public abstract void notifyDockedStackMinimizedChanged(boolean minimized);
 
     /**
+     * Notify listeners that contents are drawn for the first time on a single task display.
+     *
+     * @param displayId An ID of the display on which contents are drawn.
+     */
+    public abstract void notifySingleTaskDisplayDrawn(int displayId);
+
+    /**
      * Start activity {@code intents} as if {@code packageName} on user {@code userId} did it.
      *
      * - DO NOT call it with the calling UID cleared.
diff --git a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
index e2421d6..747837b 100644
--- a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
+++ b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
@@ -1451,22 +1451,34 @@
                 .execute();
     }
 
+    /**
+     * Start the recents activity to perform the recents animation.
+     *
+     * @param intent The intent to start the recents activity.
+     * @param recentsAnimationRunner Pass {@code null} to only preload the activity.
+     */
     @Override
-    public void startRecentsActivity(Intent intent, IAssistDataReceiver assistDataReceiver,
-            IRecentsAnimationRunner recentsAnimationRunner) {
+    public void startRecentsActivity(Intent intent, @Deprecated IAssistDataReceiver unused,
+            @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, callingPid);
-                anim.startRecentsActivity(intent, recentsAnimationRunner, recentsComponent,
-                        recentsUid, assistDataReceiver);
+                        getActivityStartController(), mWindowManager, intent, recentsComponent,
+                        recentsUid, caller);
+                if (recentsAnimationRunner == null) {
+                    anim.preloadRecentsActivity();
+                } else {
+                    anim.startRecentsActivity(recentsAnimationRunner);
+                }
             }
         } finally {
             Binder.restoreCallingIdentity(origId);
@@ -4640,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) {
@@ -4660,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 {
@@ -4677,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) {
@@ -4988,6 +5000,9 @@
      *  - the cmd arg isn't the flattened component name of an existing activity:
      *    dump all activity whose component contains the cmd as a substring
      *  - A hex number of the ActivityRecord object instance.
+     * <p>
+     * The caller should not hold lock when calling this method because it will wait for the
+     * activities to complete the dump.
      *
      *  @param dumpVisibleStacksOnly dump activity with {@param name} only if in a visible stack
      *  @param dumpFocusedStackOnly dump activity with {@param name} only if in the focused stack
@@ -5040,29 +5055,28 @@
     private void dumpActivity(String prefix, FileDescriptor fd, PrintWriter pw,
             final ActivityRecord r, String[] args, boolean dumpAll) {
         String innerPrefix = prefix + "  ";
+        IApplicationThread appThread = null;
         synchronized (mGlobalLock) {
             pw.print(prefix); pw.print("ACTIVITY "); pw.print(r.shortComponentName);
             pw.print(" "); pw.print(Integer.toHexString(System.identityHashCode(r)));
             pw.print(" pid=");
-            if (r.hasProcess()) pw.println(r.app.getPid());
-            else pw.println("(not running)");
+            if (r.hasProcess()) {
+                pw.println(r.app.getPid());
+                appThread = r.app.getThread();
+            } else {
+                pw.println("(not running)");
+            }
             if (dumpAll) {
                 r.dump(pw, innerPrefix);
             }
         }
-        if (r.attachedToProcess()) {
+        if (appThread != null) {
             // flush anything that is already in the PrintWriter since the thread is going
             // to write to the file descriptor directly
             pw.flush();
-            try {
-                TransferPipe tp = new TransferPipe();
-                try {
-                    r.app.getThread().dumpActivity(tp.getWriteFd(),
-                            r.appToken, innerPrefix, args);
-                    tp.go(fd);
-                } finally {
-                    tp.kill();
-                }
+            try (TransferPipe tp = new TransferPipe()) {
+                appThread.dumpActivity(tp.getWriteFd(), r.appToken, innerPrefix, args);
+                tp.go(fd);
             } catch (IOException e) {
                 pw.println(innerPrefix + "Failure while dumping the activity: " + e);
             } catch (RemoteException e) {
@@ -6100,7 +6114,8 @@
         }
 
         @Override
-        public void notifyAppTransitionStarting(SparseIntArray reasons, long timestamp) {
+        public void notifyAppTransitionStarting(SparseIntArray reasons,
+                long timestamp) {
             synchronized (mGlobalLock) {
                 mStackSupervisor.getActivityMetricsLogger().notifyTransitionStarting(
                         reasons, timestamp);
@@ -6108,6 +6123,11 @@
         }
 
         @Override
+        public void notifySingleTaskDisplayDrawn(int displayId) {
+            mTaskChangeNotificationController.notifySingleTaskDisplayDrawn(displayId);
+        }
+
+        @Override
         public void notifyAppTransitionFinished() {
             synchronized (mGlobalLock) {
                 mStackSupervisor.notifyAppTransitionDone();
@@ -7165,10 +7185,8 @@
         public boolean dumpActivity(FileDescriptor fd, PrintWriter pw, String name,
                 String[] args, int opti, boolean dumpAll, boolean dumpVisibleStacksOnly,
                 boolean dumpFocusedStackOnly) {
-            synchronized (mGlobalLock) {
-                return ActivityTaskManagerService.this.dumpActivity(fd, pw, name, args, opti,
-                        dumpAll, dumpVisibleStacksOnly, dumpFocusedStackOnly);
-            }
+            return ActivityTaskManagerService.this.dumpActivity(fd, pw, name, args, opti, dumpAll,
+                    dumpVisibleStacksOnly, dumpFocusedStackOnly);
         }
 
         @Override
diff --git a/services/core/java/com/android/server/wm/AppTransition.java b/services/core/java/com/android/server/wm/AppTransition.java
index e6a83de..557a609 100644
--- a/services/core/java/com/android/server/wm/AppTransition.java
+++ b/services/core/java/com/android/server/wm/AppTransition.java
@@ -23,12 +23,14 @@
 import static android.view.WindowManager.TRANSIT_CRASHING_ACTIVITY_CLOSE;
 import static android.view.WindowManager.TRANSIT_DOCK_TASK_FROM_RECENTS;
 import static android.view.WindowManager.TRANSIT_FLAG_KEYGUARD_GOING_AWAY_NO_ANIMATION;
+import static android.view.WindowManager.TRANSIT_FLAG_KEYGUARD_GOING_AWAY_SUBTLE_ANIMATION;
 import static android.view.WindowManager.TRANSIT_FLAG_KEYGUARD_GOING_AWAY_TO_SHADE;
 import static android.view.WindowManager.TRANSIT_KEYGUARD_GOING_AWAY;
 import static android.view.WindowManager.TRANSIT_KEYGUARD_GOING_AWAY_ON_WALLPAPER;
 import static android.view.WindowManager.TRANSIT_KEYGUARD_OCCLUDE;
 import static android.view.WindowManager.TRANSIT_KEYGUARD_UNOCCLUDE;
 import static android.view.WindowManager.TRANSIT_NONE;
+import static android.view.WindowManager.TRANSIT_SHOW_SINGLE_TASK_DISPLAY;
 import static android.view.WindowManager.TRANSIT_TASK_CHANGE_WINDOWING_MODE;
 import static android.view.WindowManager.TRANSIT_TASK_CLOSE;
 import static android.view.WindowManager.TRANSIT_TASK_IN_PLACE;
@@ -1801,8 +1803,10 @@
         }
         final boolean toShade =
                 (mNextAppTransitionFlags & TRANSIT_FLAG_KEYGUARD_GOING_AWAY_TO_SHADE) != 0;
+        final boolean subtle =
+                (mNextAppTransitionFlags & TRANSIT_FLAG_KEYGUARD_GOING_AWAY_SUBTLE_ANIMATION) != 0;
         return mService.mPolicy.createHiddenByKeyguardExit(
-                transit == TRANSIT_KEYGUARD_GOING_AWAY_ON_WALLPAPER, toShade);
+                transit == TRANSIT_KEYGUARD_GOING_AWAY_ON_WALLPAPER, toShade, subtle);
     }
 
     int getAppStackClipMode() {
@@ -2080,6 +2084,9 @@
             case TRANSIT_CRASHING_ACTIVITY_CLOSE: {
                 return "TRANSIT_CRASHING_ACTIVITY_CLOSE";
             }
+            case TRANSIT_SHOW_SINGLE_TASK_DISPLAY: {
+                return "TRANSIT_SHOW_SINGLE_TASK_DISPLAY";
+            }
             default: {
                 return "<UNKNOWN: " + transition + ">";
             }
diff --git a/services/core/java/com/android/server/wm/AppTransitionController.java b/services/core/java/com/android/server/wm/AppTransitionController.java
index d4c4e6a..d4e95cf 100644
--- a/services/core/java/com/android/server/wm/AppTransitionController.java
+++ b/services/core/java/com/android/server/wm/AppTransitionController.java
@@ -23,11 +23,13 @@
 import static android.view.WindowManager.TRANSIT_CRASHING_ACTIVITY_CLOSE;
 import static android.view.WindowManager.TRANSIT_DOCK_TASK_FROM_RECENTS;
 import static android.view.WindowManager.TRANSIT_FLAG_KEYGUARD_GOING_AWAY_NO_ANIMATION;
+import static android.view.WindowManager.TRANSIT_FLAG_KEYGUARD_GOING_AWAY_SUBTLE_ANIMATION;
 import static android.view.WindowManager.TRANSIT_FLAG_KEYGUARD_GOING_AWAY_TO_SHADE;
 import static android.view.WindowManager.TRANSIT_FLAG_KEYGUARD_GOING_AWAY_WITH_WALLPAPER;
 import static android.view.WindowManager.TRANSIT_KEYGUARD_GOING_AWAY;
 import static android.view.WindowManager.TRANSIT_KEYGUARD_GOING_AWAY_ON_WALLPAPER;
 import static android.view.WindowManager.TRANSIT_NONE;
+import static android.view.WindowManager.TRANSIT_SHOW_SINGLE_TASK_DISPLAY;
 import static android.view.WindowManager.TRANSIT_TASK_CLOSE;
 import static android.view.WindowManager.TRANSIT_TASK_IN_PLACE;
 import static android.view.WindowManager.TRANSIT_TASK_OPEN;
@@ -211,6 +213,12 @@
         mService.mAtmInternal.notifyAppTransitionStarting(mTempTransitionReasons.clone(),
                 SystemClock.uptimeMillis());
 
+        if (transit == TRANSIT_SHOW_SINGLE_TASK_DISPLAY) {
+            mService.mAnimator.addAfterPrepareSurfacesRunnable(() -> {
+                mService.mAtmInternal.notifySingleTaskDisplayDrawn(mDisplayContent.getDisplayId());
+            });
+        }
+
         Trace.traceEnd(Trace.TRACE_TAG_WINDOW_MANAGER);
 
         mDisplayContent.pendingLayoutChanges |=
@@ -418,7 +426,8 @@
     private void handleNonAppWindowsInTransition(int transit, int flags) {
         if (transit == TRANSIT_KEYGUARD_GOING_AWAY) {
             if ((flags & TRANSIT_FLAG_KEYGUARD_GOING_AWAY_WITH_WALLPAPER) != 0
-                    && (flags & TRANSIT_FLAG_KEYGUARD_GOING_AWAY_NO_ANIMATION) == 0) {
+                    && (flags & TRANSIT_FLAG_KEYGUARD_GOING_AWAY_NO_ANIMATION) == 0
+                    && (flags & TRANSIT_FLAG_KEYGUARD_GOING_AWAY_SUBTLE_ANIMATION) == 0) {
                 Animation anim = mService.mPolicy.createKeyguardWallpaperExit(
                         (flags & TRANSIT_FLAG_KEYGUARD_GOING_AWAY_TO_SHADE) != 0);
                 if (anim != null) {
@@ -430,7 +439,8 @@
                 || transit == TRANSIT_KEYGUARD_GOING_AWAY_ON_WALLPAPER) {
             mDisplayContent.startKeyguardExitOnNonAppWindows(
                     transit == TRANSIT_KEYGUARD_GOING_AWAY_ON_WALLPAPER,
-                    (flags & TRANSIT_FLAG_KEYGUARD_GOING_AWAY_TO_SHADE) != 0);
+                    (flags & TRANSIT_FLAG_KEYGUARD_GOING_AWAY_TO_SHADE) != 0,
+                    (flags & TRANSIT_FLAG_KEYGUARD_GOING_AWAY_SUBTLE_ANIMATION) != 0);
         }
     }
 
diff --git a/services/core/java/com/android/server/wm/AppWindowToken.java b/services/core/java/com/android/server/wm/AppWindowToken.java
index eab5e0d..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);
@@ -2477,7 +2493,7 @@
         // transformed the task.
         final RecentsAnimationController controller = mWmService.getRecentsAnimationController();
         if (controller != null && controller.isAnimatingTask(getTask())
-                && controller.shouldCancelWithDeferredScreenshot()) {
+                && controller.shouldDeferCancelUntilNextTransition()) {
             return false;
         }
 
diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java
index b837d9e..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;
 
     /**
@@ -2559,6 +2564,9 @@
     void removeImmediately() {
         mRemovingDisplay = true;
         try {
+            if (mParentWindow != null) {
+                mParentWindow.removeEmbeddedDisplayContent(this);
+            }
             // Clear all transitions & screen frozen states when removing display.
             mOpeningApps.clear();
             mClosingApps.clear();
@@ -3489,12 +3497,14 @@
     /**
      * Starts the Keyguard exit animation on all windows that don't belong to an app token.
      */
-    void startKeyguardExitOnNonAppWindows(boolean onWallpaper, boolean goingToShade) {
+    void startKeyguardExitOnNonAppWindows(boolean onWallpaper, boolean goingToShade,
+            boolean subtle) {
         final WindowManagerPolicy policy = mWmService.mPolicy;
         forAllWindows(w -> {
             if (w.mAppToken == null && policy.canBeHiddenByKeyguardLw(w)
                     && w.wouldBeVisibleIfPolicyIgnored() && !w.isVisible()) {
-                w.startAnimation(policy.createHiddenByKeyguardExit(onWallpaper, goingToShade));
+                w.startAnimation(policy.createHiddenByKeyguardExit(
+                        onWallpaper, goingToShade, subtle));
             }
         }, true /* traverseTopToBottom */);
     }
@@ -4840,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.
@@ -5046,6 +5060,7 @@
      */
     void reparentDisplayContent(WindowState win, SurfaceControl sc) {
         mParentWindow = win;
+        mParentWindow.addEmbeddedDisplayContent(this);
         mParentSurfaceControl = sc;
         if (mPortalWindowHandle == null) {
             mPortalWindowHandle = createPortalWindowHandle(sc.toString());
@@ -5076,12 +5091,12 @@
             throw new IllegalArgumentException(
                     "The given window is not the parent window of this display.");
         }
-        if (mLocationInParentWindow.x != x || mLocationInParentWindow.y != y) {
-            mLocationInParentWindow.x = x;
-            mLocationInParentWindow.y = y;
+        if (!mLocationInParentWindow.equals(x, y)) {
+            mLocationInParentWindow.set(x, y);
             if (mWmService.mAccessibilityController != null) {
                 mWmService.mAccessibilityController.onSomeWindowResizedOrMovedLocked();
             }
+            notifyLocationInParentDisplayChanged();
         }
     }
 
@@ -5089,6 +5104,30 @@
         return mLocationInParentWindow;
     }
 
+    Point getLocationInParentDisplay() {
+        final Point location = new Point();
+        if (mParentWindow != null) {
+            // LocationInParentWindow indicates the offset to (0,0) of window, but what we need is
+            // the offset to (0,0) of display.
+            DisplayContent dc = this;
+            do {
+                final WindowState displayParent = dc.getParentWindow();
+                location.x += displayParent.getFrameLw().left
+                        + (dc.getLocationInParentWindow().x * displayParent.mGlobalScale + 0.5f);
+                location.y += displayParent.getFrameLw().top
+                        + (dc.getLocationInParentWindow().y * displayParent.mGlobalScale + 0.5f);
+                dc = displayParent.getDisplayContent();
+            } while (dc != null && dc.getParentWindow() != null);
+        }
+        return location;
+    }
+
+    void notifyLocationInParentDisplayChanged() {
+        forAllWindows(w -> {
+            w.updateLocationInParentDisplayIfNeeded();
+        }, false /* traverseTopToBottom */);
+    }
+
     @VisibleForTesting
     SurfaceControl getWindowingLayer() {
         return mWindowingLayer;
@@ -5105,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);
                 }
@@ -5126,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);
 
@@ -5136,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 =
@@ -5174,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;
     }
 
     /**
@@ -5213,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];
     }
@@ -5252,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/DockedStackDividerController.java b/services/core/java/com/android/server/wm/DockedStackDividerController.java
index 1d76a71..b1bc2197 100644
--- a/services/core/java/com/android/server/wm/DockedStackDividerController.java
+++ b/services/core/java/com/android/server/wm/DockedStackDividerController.java
@@ -569,7 +569,6 @@
             mMaximizeMeetFraction = getClipRevealMeetFraction(stack);
             animDuration = (long) (mAnimationDuration * mMaximizeMeetFraction);
         }
-        mService.mAtmInternal.notifyDockedStackMinimizedChanged(minimizedDock);
         final int size = mDockedStackListeners.beginBroadcast();
         for (int i = 0; i < size; ++i) {
             final IDockedStackListener listener = mDockedStackListeners.getBroadcastItem(i);
@@ -581,6 +580,9 @@
             }
         }
         mDockedStackListeners.finishBroadcast();
+        // Only notify ATM after we update the remote listeners, otherwise it may trigger another
+        // minimize change, which would lead to an inversion of states send to the listeners
+        mService.mAtmInternal.notifyDockedStackMinimizedChanged(minimizedDock);
     }
 
     void notifyDockSideChanged(int newDockSide) {
diff --git a/services/core/java/com/android/server/wm/HighRefreshRateBlacklist.java b/services/core/java/com/android/server/wm/HighRefreshRateBlacklist.java
index c0f53b8..271db289 100644
--- a/services/core/java/com/android/server/wm/HighRefreshRateBlacklist.java
+++ b/services/core/java/com/android/server/wm/HighRefreshRateBlacklist.java
@@ -16,60 +16,104 @@
 
 package com.android.server.wm;
 
+import static android.hardware.display.DisplayManager.DeviceConfig.KEY_HIGH_REFRESH_RATE_BLACKLIST;
+
 import android.annotation.NonNull;
-import android.os.SystemProperties;
+import android.annotation.Nullable;
+import android.content.res.Resources;
+import android.provider.DeviceConfig;
 import android.util.ArraySet;
 
+import com.android.internal.R;
 import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.os.BackgroundThread;
+
+import java.io.PrintWriter;
+import java.util.concurrent.Executor;
 
 /**
  * A Blacklist for packages that should force the display out of high refresh rate.
  */
 class HighRefreshRateBlacklist {
 
-    private static final String SYSPROP_KEY = "ro.window_manager.high_refresh_rate_blacklist";
-    private static final String SYSPROP_KEY_LENGTH_SUFFIX = "_length";
-    private static final String SYSPROP_KEY_ENTRY_SUFFIX = "_entry";
-    private static final int MAX_ENTRIES = 50;
+    private final ArraySet<String> mBlacklistedPackages = new ArraySet<>();
+    @NonNull
+    private final String[] mDefaultBlacklist;
+    private final Object mLock = new Object();
 
-    private ArraySet<String> mBlacklistedPackages = new ArraySet<>();
-
-    static HighRefreshRateBlacklist create() {
-        return new HighRefreshRateBlacklist(new SystemPropertyGetter() {
+    static HighRefreshRateBlacklist create(@NonNull Resources r) {
+        return new HighRefreshRateBlacklist(r, new DeviceConfigInterface() {
             @Override
-            public int getInt(String key, int def) {
-                return SystemProperties.getInt(key, def);
+            public @Nullable String getProperty(@NonNull String namespace, @NonNull String name) {
+                return DeviceConfig.getProperty(namespace, name);
             }
-
-            @Override
-            public String get(String key) {
-                return SystemProperties.get(key);
+            public void addOnPropertyChangedListener(@NonNull String namespace,
+                    @NonNull Executor executor,
+                    @NonNull DeviceConfig.OnPropertyChangedListener listener) {
+                DeviceConfig.addOnPropertyChangedListener(namespace, executor, listener);
             }
         });
     }
 
     @VisibleForTesting
-    HighRefreshRateBlacklist(SystemPropertyGetter propertyGetter) {
+    HighRefreshRateBlacklist(Resources r, DeviceConfigInterface deviceConfig) {
+        mDefaultBlacklist = r.getStringArray(R.array.config_highRefreshRateBlacklist);
+        deviceConfig.addOnPropertyChangedListener(DeviceConfig.NAMESPACE_DISPLAY_MANAGER,
+                BackgroundThread.getExecutor(), new OnPropertyChangedListener());
+        final String property = deviceConfig.getProperty(DeviceConfig.NAMESPACE_DISPLAY_MANAGER,
+                KEY_HIGH_REFRESH_RATE_BLACKLIST);
+        updateBlacklist(property);
+    }
 
-        // Read and populate the blacklist
-        final int length = Math.min(
-                propertyGetter.getInt(SYSPROP_KEY + SYSPROP_KEY_LENGTH_SUFFIX, 0),
-                MAX_ENTRIES);
-        for (int i = 1; i <= length; i++) {
-            final String packageName = propertyGetter.get(
-                    SYSPROP_KEY + SYSPROP_KEY_ENTRY_SUFFIX + i);
-            if (!packageName.isEmpty()) {
-                mBlacklistedPackages.add(packageName);
+    private void updateBlacklist(@Nullable String property) {
+        synchronized (mLock) {
+            mBlacklistedPackages.clear();
+            if (property != null) {
+                String[] packages = property.split(",");
+                for (String pkg : packages) {
+                    String pkgName = pkg.trim();
+                    if (!pkgName.isEmpty()) {
+                        mBlacklistedPackages.add(pkgName);
+                    }
+                }
+            } else {
+                // If there's no config, or the config has been deleted, fallback to the device's
+                // default blacklist
+                for (String pkg : mDefaultBlacklist) {
+                    mBlacklistedPackages.add(pkg);
+                }
             }
         }
     }
 
     boolean isBlacklisted(String packageName) {
-        return mBlacklistedPackages.contains(packageName);
+        synchronized (mLock) {
+            return mBlacklistedPackages.contains(packageName);
+        }
+    }
+    void dump(PrintWriter pw) {
+        pw.println("High Refresh Rate Blacklist");
+        pw.println("  Packages:");
+        synchronized (mLock) {
+            for (String pkg : mBlacklistedPackages) {
+                pw.println("    " + pkg);
+            }
+        }
     }
 
-    interface SystemPropertyGetter {
-        int getInt(String key, int def);
-        @NonNull String get(String key);
+    interface DeviceConfigInterface {
+        @Nullable String getProperty(@NonNull String namespace, @NonNull String name);
+        void addOnPropertyChangedListener(@NonNull String namespace, @NonNull Executor executor,
+                @NonNull DeviceConfig.OnPropertyChangedListener listener);
+    }
+
+    private class OnPropertyChangedListener implements DeviceConfig.OnPropertyChangedListener {
+        public void onPropertyChanged(@NonNull String namespace, @NonNull String name,
+                @Nullable String value) {
+            if (KEY_HIGH_REFRESH_RATE_BLACKLIST.equals(name)) {
+                updateBlacklist(value);
+            }
+        }
     }
 }
+
diff --git a/services/core/java/com/android/server/wm/KeyguardController.java b/services/core/java/com/android/server/wm/KeyguardController.java
index 169f03b..ca4749f 100644
--- a/services/core/java/com/android/server/wm/KeyguardController.java
+++ b/services/core/java/com/android/server/wm/KeyguardController.java
@@ -19,6 +19,7 @@
 import static android.os.Trace.TRACE_TAG_ACTIVITY_MANAGER;
 import static android.view.Display.DEFAULT_DISPLAY;
 import static android.view.WindowManager.TRANSIT_FLAG_KEYGUARD_GOING_AWAY_NO_ANIMATION;
+import static android.view.WindowManager.TRANSIT_FLAG_KEYGUARD_GOING_AWAY_SUBTLE_ANIMATION;
 import static android.view.WindowManager.TRANSIT_FLAG_KEYGUARD_GOING_AWAY_TO_SHADE;
 import static android.view.WindowManager.TRANSIT_FLAG_KEYGUARD_GOING_AWAY_WITH_WALLPAPER;
 import static android.view.WindowManager.TRANSIT_KEYGUARD_GOING_AWAY;
@@ -26,6 +27,7 @@
 import static android.view.WindowManager.TRANSIT_KEYGUARD_UNOCCLUDE;
 import static android.view.WindowManager.TRANSIT_UNSET;
 import static android.view.WindowManagerPolicyConstants.KEYGUARD_GOING_AWAY_FLAG_NO_WINDOW_ANIMATIONS;
+import static android.view.WindowManagerPolicyConstants.KEYGUARD_GOING_AWAY_FLAG_SUBTLE_WINDOW_ANIMATIONS;
 import static android.view.WindowManagerPolicyConstants.KEYGUARD_GOING_AWAY_FLAG_TO_SHADE;
 import static android.view.WindowManagerPolicyConstants.KEYGUARD_GOING_AWAY_FLAG_WITH_WALLPAPER;
 
@@ -238,6 +240,9 @@
         if ((keyguardGoingAwayFlags & KEYGUARD_GOING_AWAY_FLAG_WITH_WALLPAPER) != 0) {
             result |= TRANSIT_FLAG_KEYGUARD_GOING_AWAY_WITH_WALLPAPER;
         }
+        if ((keyguardGoingAwayFlags & KEYGUARD_GOING_AWAY_FLAG_SUBTLE_WINDOW_ANIMATIONS) != 0) {
+            result |= TRANSIT_FLAG_KEYGUARD_GOING_AWAY_SUBTLE_ANIMATION;
+        }
         return result;
     }
 
diff --git a/services/core/java/com/android/server/wm/RecentsAnimation.java b/services/core/java/com/android/server/wm/RecentsAnimation.java
index 434239f..036bef7 100644
--- a/services/core/java/com/android/server/wm/RecentsAnimation.java
+++ b/services/core/java/com/android/server/wm/RecentsAnimation.java
@@ -33,8 +33,8 @@
 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.app.IAssistDataReceiver;
 import android.content.ComponentName;
 import android.content.Intent;
 import android.os.RemoteException;
@@ -58,7 +58,12 @@
     private final ActivityStartController mActivityStartController;
     private final WindowManagerService mWindowManager;
     private final ActivityDisplay mDefaultDisplay;
-    private final int mCallingPid;
+    private final Intent mTargetIntent;
+    private final ComponentName mRecentsComponent;
+    private final int mRecentsUid;
+    private final @Nullable WindowProcessController mCaller;
+    private final int mUserId;
+    private final int mTargetActivityType;
 
     /**
      * The activity which has been launched behind. We need to remember the activity because the
@@ -66,27 +71,91 @@
      * for the exact activity.
      */
     private ActivityRecord mLaunchedTargetActivity;
-    private int mTargetActivityType;
 
     // The stack to restore the target stack behind when the animation is finished
     private ActivityStack mRestoreTargetBehindStack;
 
     RecentsAnimation(ActivityTaskManagerService atm, ActivityStackSupervisor stackSupervisor,
             ActivityStartController activityStartController, WindowManagerService wm,
-            int callingPid) {
+            Intent targetIntent, ComponentName recentsComponent, int recentsUid,
+            @Nullable WindowProcessController caller) {
         mService = atm;
         mStackSupervisor = stackSupervisor;
         mDefaultDisplay = mService.mRootActivityContainer.getDefaultDisplay();
         mActivityStartController = activityStartController;
         mWindowManager = wm;
-        mCallingPid = callingPid;
+        mTargetIntent = targetIntent;
+        mRecentsComponent = recentsComponent;
+        mRecentsUid = recentsUid;
+        mCaller = caller;
+        mUserId = atm.getCurrentUserId();
+        mTargetActivityType = targetIntent.getComponent() != null
+                && recentsComponent.equals(targetIntent.getComponent())
+                        ? ACTIVITY_TYPE_RECENTS
+                        : ACTIVITY_TYPE_HOME;
     }
 
-    void startRecentsActivity(Intent intent, IRecentsAnimationRunner recentsAnimationRunner,
-            ComponentName recentsComponent, int recentsUid,
-            @Deprecated IAssistDataReceiver assistDataReceiver) {
-        if (DEBUG) Slog.d(TAG, "startRecentsActivity(): intent=" + intent
-                + " assistDataReceiver=" + assistDataReceiver);
+    /**
+     * Starts the recents activity in background without animation if the record doesn't exist or
+     * the client isn't launched. If the recents activity is already alive, ensure its configuration
+     * is updated to the current one.
+     */
+    void preloadRecentsActivity() {
+        if (DEBUG) Slog.d(TAG, "Preload recents with " + mTargetIntent);
+        ActivityStack targetStack = mDefaultDisplay.getStack(WINDOWING_MODE_UNDEFINED,
+                mTargetActivityType);
+        ActivityRecord targetActivity = getTargetActivity(targetStack);
+        if (targetActivity != null) {
+            if (targetActivity.visible || targetActivity.isTopRunningActivity()) {
+                // The activity is ready.
+                return;
+            }
+            if (targetActivity.attachedToProcess()) {
+                // The activity may be relaunched if it cannot handle the current configuration
+                // changes. The activity will be paused state if it is relaunched, otherwise it
+                // keeps the original stopped state.
+                targetActivity.ensureActivityConfiguration(0 /* globalChanges */,
+                        false /* preserveWindow */, true /* ignoreVisibility */);
+                if (DEBUG) Slog.d(TAG, "Updated config=" + targetActivity.getConfiguration());
+            }
+        } else {
+            // Create the activity record. Because the activity is invisible, this doesn't really
+            // start the client.
+            startRecentsActivityInBackground("preloadRecents");
+            targetStack = mDefaultDisplay.getStack(WINDOWING_MODE_UNDEFINED, mTargetActivityType);
+            targetActivity = getTargetActivity(targetStack);
+            if (targetActivity == null) {
+                Slog.w(TAG, "Cannot start " + mTargetIntent);
+                return;
+            }
+        }
+
+        if (!targetActivity.attachedToProcess()) {
+            if (DEBUG) Slog.d(TAG, "Real start recents");
+            mStackSupervisor.startSpecificActivityLocked(targetActivity, false /* andResume */,
+                    false /* checkConfig */);
+            // Make sure the activity won't be involved in transition.
+            if (targetActivity.mAppWindowToken != null) {
+                targetActivity.mAppWindowToken.getDisplayContent().mUnknownAppVisibilityController
+                        .appRemovedOrHidden(targetActivity.mAppWindowToken);
+            }
+        }
+
+        // Invisible activity should be stopped. If the recents activity is alive and its doesn't
+        // need to relaunch by current configuration, then it may be already in stopped state.
+        if (!targetActivity.isState(ActivityStack.ActivityState.STOPPING,
+                ActivityStack.ActivityState.STOPPED)) {
+            // Add to stopping instead of stop immediately. So the client has the chance to perform
+            // traversal in non-stopped state (ViewRootImpl.mStopped) that would initialize more
+            // things (e.g. the measure can be done earlier). The actual stop will be performed when
+            // it reports idle.
+            targetStack.addToStopping(targetActivity, true /* scheduleIdle */,
+                    true /* idleDelayed */, "preloadRecents");
+        }
+    }
+
+    void startRecentsActivity(IRecentsAnimationRunner recentsAnimationRunner) {
+        if (DEBUG) Slog.d(TAG, "startRecentsActivity(): intent=" + mTargetIntent);
         Trace.traceBegin(TRACE_TAG_ACTIVITY_MANAGER, "RecentsAnimation#startRecentsActivity");
 
         // TODO(multi-display) currently only support recents animation in default display.
@@ -100,15 +169,9 @@
         }
 
         // If the activity is associated with the recents stack, then try and get that first
-        final int userId = mService.getCurrentUserId();
-        mTargetActivityType = intent.getComponent() != null
-                && recentsComponent.equals(intent.getComponent())
-                        ? ACTIVITY_TYPE_RECENTS
-                        : ACTIVITY_TYPE_HOME;
         ActivityStack targetStack = mDefaultDisplay.getStack(WINDOWING_MODE_UNDEFINED,
                 mTargetActivityType);
-        ActivityRecord targetActivity = getTargetActivity(targetStack, intent.getComponent(),
-                userId);
+        ActivityRecord targetActivity = getTargetActivity(targetStack);
         final boolean hasExistingActivity = targetActivity != null;
         if (hasExistingActivity) {
             final ActivityDisplay display = targetActivity.getDisplay();
@@ -127,9 +190,11 @@
                     true /* forceSend */, targetActivity);
         }
 
-        mStackSupervisor.getActivityMetricsLogger().notifyActivityLaunching(intent);
+        mStackSupervisor.getActivityMetricsLogger().notifyActivityLaunching(mTargetIntent);
 
-        mService.mH.post(() -> mService.mAmInternal.setRunningRemoteAnimation(mCallingPid, true));
+        if (mCaller != null) {
+            mCaller.setRunningRecentsAnimation(true);
+        }
 
         mWindowManager.deferSurfaceLayout();
         try {
@@ -148,23 +213,12 @@
                 }
             } else {
                 // No recents activity, create the new recents activity bottom most
-                ActivityOptions options = ActivityOptions.makeBasic();
-                options.setLaunchActivityType(mTargetActivityType);
-                options.setAvoidMoveToFront();
-                intent.addFlags(FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_NO_ANIMATION);
-
-                mActivityStartController
-                        .obtainStarter(intent, "startRecentsActivity_noTargetActivity")
-                        .setCallingUid(recentsUid)
-                        .setCallingPackage(recentsComponent.getPackageName())
-                        .setActivityOptions(SafeActivityOptions.fromBundle(options.toBundle()))
-                        .setMayWait(userId)
-                        .execute();
+                startRecentsActivityInBackground("startRecentsActivity_noTargetActivity");
 
                 // Move the recents activity into place for the animation
                 targetStack = mDefaultDisplay.getStack(WINDOWING_MODE_UNDEFINED,
                         mTargetActivityType);
-                targetActivity = getTargetActivity(targetStack, intent.getComponent(), userId);
+                targetActivity = getTargetActivity(targetStack);
                 mDefaultDisplay.moveStackBehindBottomMostVisibleStack(targetStack);
                 if (DEBUG) {
                     Slog.d(TAG, "Moved stack=" + targetStack + " behind stack="
@@ -176,7 +230,7 @@
 
                 // TODO: Maybe wait for app to draw in this particular case?
 
-                if (DEBUG) Slog.d(TAG, "Started intent=" + intent);
+                if (DEBUG) Slog.d(TAG, "Started intent=" + mTargetIntent);
             }
 
             // Mark the target activity as launch-behind to bump its visibility for the
@@ -236,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,
@@ -305,7 +360,7 @@
                         // launch-behind state is restored. That also prevents the next transition
                         // type being disturbed if the visibility is updated after setting the next
                         // transition (the target activity will be one of closing apps).
-                        if (!controller.shouldCancelWithDeferredScreenshot()
+                        if (!controller.shouldDeferCancelWithScreenshot()
                                 && !targetStack.isFocusedStackOnDisplay()) {
                             targetStack.ensureActivitiesVisibleLocked(null /* starting */,
                                     0 /* starting */, false /* preserveWindows */);
@@ -365,16 +420,18 @@
         final DisplayContent dc =
                 mService.mRootActivityContainer.getDefaultDisplay().mDisplayContent;
         dc.mBoundsAnimationController.setAnimationType(
-                controller.shouldCancelWithDeferredScreenshot() ? FADE_IN : BOUNDS);
+                controller.shouldDeferCancelUntilNextTransition() ? FADE_IN : BOUNDS);
 
-        // Cancel running recents animation and screenshot previous task when the next
-        // transition starts in below cases:
-        // 1) The next launching task is not in recents animation task.
+        // We defer canceling the recents animation until the next app transition in the following
+        // cases:
+        // 1) The next launching task is not being animated by the recents animation
         // 2) The next task is home activity. (i.e. pressing home key to back home in recents).
         if ((!controller.isAnimatingTask(stack.getTaskStack().getTopChild())
                 || controller.isTargetApp(stack.getTopActivity().mAppWindowToken))
-                && controller.shouldCancelWithDeferredScreenshot()) {
-            controller.cancelOnNextTransitionStart();
+                && controller.shouldDeferCancelUntilNextTransition()) {
+            // Always prepare an app transition since we rely on the transition callbacks to cleanup
+            mWindowManager.prepareAppTransition(TRANSIT_NONE, false);
+            controller.setCancelOnNextTransitionStart();
         } else {
             // Just cancel directly to unleash from launcher when the next launching task is the
             // current top task.
@@ -383,10 +440,25 @@
         }
     }
 
+    private void startRecentsActivityInBackground(String reason) {
+        final ActivityOptions options = ActivityOptions.makeBasic();
+        options.setLaunchActivityType(mTargetActivityType);
+        options.setAvoidMoveToFront();
+        mTargetIntent.addFlags(FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_NO_ANIMATION);
+
+        mActivityStartController
+                .obtainStarter(mTargetIntent, reason)
+                .setCallingUid(mRecentsUid)
+                .setCallingPackage(mRecentsComponent.getPackageName())
+                .setActivityOptions(new SafeActivityOptions(options))
+                .setMayWait(mUserId)
+                .execute();
+    }
+
     /**
      * 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) {
@@ -412,15 +484,15 @@
      * @return the top activity in the {@param targetStack} matching the {@param component}, or just
      * the top activity of the top task if no task matches the component.
      */
-    private ActivityRecord getTargetActivity(ActivityStack targetStack, ComponentName component,
-            int userId) {
+    private ActivityRecord getTargetActivity(ActivityStack targetStack) {
         if (targetStack == null) {
             return null;
         }
 
         for (int i = targetStack.getChildCount() - 1; i >= 0; i--) {
             final TaskRecord task = targetStack.getChildAt(i);
-            if (task.userId == userId && task.getBaseIntent().getComponent().equals(component)) {
+            if (task.userId == mUserId
+                    && task.getBaseIntent().getComponent().equals(mTargetIntent.getComponent())) {
                 return task.getTopActivity();
             }
         }
diff --git a/services/core/java/com/android/server/wm/RecentsAnimationController.java b/services/core/java/com/android/server/wm/RecentsAnimationController.java
index c03dabe..a8b0083 100644
--- a/services/core/java/com/android/server/wm/RecentsAnimationController.java
+++ b/services/core/java/com/android/server/wm/RecentsAnimationController.java
@@ -96,10 +96,9 @@
     private final Runnable mFailsafeRunnable = () ->
             cancelAnimation(REORDER_MOVE_TO_ORIGINAL_POSITION, "failSafeRunnable");
 
-    final Object mLock = new Object();
-
     // The recents component app token that is shown behind the visibile tasks
     private AppWindowToken mTargetAppToken;
+    private DisplayContent mDisplayContent;
     private int mTargetActivityType;
     private Rect mMinimizedHomeBounds = new Rect();
 
@@ -123,25 +122,47 @@
 
     private boolean mLinkedToDeathOfRunner;
 
-    private boolean mCancelWithDeferredScreenshot;
-
+    // Whether to try to defer canceling from a stack order change until the next transition
+    private boolean mRequestDeferCancelUntilNextTransition;
+    // Whether to actually defer canceling until the next transition
     private boolean mCancelOnNextTransitionStart;
+    // Whether to take a screenshot when handling a deferred cancel
+    private boolean mCancelDeferredWithScreenshot;
 
     /**
      * Animates the screenshot of task that used to be controlled by RecentsAnimation.
-     * @see {@link #cancelOnNextTransitionStart}
+     * @see {@link #setCancelOnNextTransitionStart}
      */
     SurfaceAnimator mRecentScreenshotAnimator;
 
+    /**
+     * An app transition listener to cancel the recents animation only after the app transition
+     * starts or is canceled.
+     */
     final AppTransitionListener mAppTransitionListener = new AppTransitionListener() {
         @Override
         public int onAppTransitionStartingLocked(int transit, long duration,
                 long statusBarAnimationStartTime, long statusBarAnimationDuration) {
-            onTransitionStart();
-            mService.mRoot.getDisplayContent(mDisplayId).mAppTransition
-                    .unregisterListener(this);
+            continueDeferredCancel();
             return 0;
         }
+
+        @Override
+        public void onAppTransitionCancelledLocked(int transit) {
+            continueDeferredCancel();
+        }
+
+        private void continueDeferredCancel() {
+            mDisplayContent.mAppTransition.unregisterListener(this);
+            if (mCanceled) {
+                return;
+            }
+
+            if (mCancelOnNextTransitionStart) {
+                mCancelOnNextTransitionStart = false;
+                cancelAnimationWithScreenshot(mCancelDeferredWithScreenshot);
+            }
+        }
     };
 
     public interface RecentsAnimationCallbacks {
@@ -201,8 +222,7 @@
                         ? REORDER_MOVE_TO_TOP
                         : REORDER_MOVE_TO_ORIGINAL_POSITION,
                         true /* runSynchronously */, sendUserLeaveHint);
-                final DisplayContent dc = mService.mRoot.getDisplayContent(mDisplayId);
-                dc.mBoundsAnimationController.setAnimationType(FADE_IN);
+                mDisplayContent.mBoundsAnimationController.setAnimationType(FADE_IN);
             } finally {
                 Binder.restoreCallingIdentity(token);
             }
@@ -239,8 +259,7 @@
                     }
 
                     mInputConsumerEnabled = enabled;
-                    final InputMonitor inputMonitor =
-                            mService.mRoot.getDisplayContent(mDisplayId).getInputMonitor();
+                    final InputMonitor inputMonitor = mDisplayContent.getInputMonitor();
                     inputMonitor.updateInputWindowsLw(true /*force*/);
                     mService.scheduleAnimationLocked();
                 }
@@ -281,15 +300,23 @@
         }
 
         @Override
+        @Deprecated
         public void setCancelWithDeferredScreenshot(boolean screenshot) {
-            synchronized (mLock) {
-                setCancelWithDeferredScreenshotLocked(screenshot);
+            synchronized (mService.mGlobalLock) {
+                setDeferredCancel(true /* deferred */, screenshot);
+            }
+        }
+
+        @Override
+        public void setDeferCancelUntilNextTransition(boolean defer, boolean screenshot) {
+            synchronized (mService.mGlobalLock) {
+                setDeferredCancel(defer, screenshot);
             }
         }
 
         @Override
         public void cleanupScreenshot() {
-            synchronized (mLock) {
+            synchronized (mService.mGlobalLock) {
                 if (mRecentScreenshotAnimator != null) {
                     mRecentScreenshotAnimator.cancelAnimation();
                     mRecentScreenshotAnimator = null;
@@ -311,10 +338,7 @@
         mCallbacks = callbacks;
         mDisplayId = displayId;
         mStatusBar = LocalServices.getService(StatusBarManagerInternal.class);
-    }
-
-    public void initialize(int targetActivityType, SparseBooleanArray recentTaskIds) {
-        initialize(mService.mRoot.getDisplayContent(mDisplayId), targetActivityType, recentTaskIds);
+        mDisplayContent = service.mRoot.getDisplayContent(displayId);
     }
 
     /**
@@ -322,15 +346,15 @@
      * because it may call cancelAnimation() which needs to properly clean up the controller
      * in the window manager.
      */
-    @VisibleForTesting
-    void initialize(DisplayContent dc, int targetActivityType, SparseBooleanArray recentTaskIds) {
+    public void initialize(int targetActivityType, SparseBooleanArray recentTaskIds) {
         mTargetActivityType = targetActivityType;
-        dc.mAppTransition.registerListenerLocked(mAppTransitionListener);
+        mDisplayContent.mAppTransition.registerListenerLocked(mAppTransitionListener);
 
         // Make leashes for each of the visible/target tasks and add it to the recents animation to
         // be started
-        final ArrayList<Task> visibleTasks = dc.getVisibleTasks();
-        final TaskStack targetStack = dc.getStack(WINDOWING_MODE_UNDEFINED, targetActivityType);
+        final ArrayList<Task> visibleTasks = mDisplayContent.getVisibleTasks();
+        final TaskStack targetStack = mDisplayContent.getStack(WINDOWING_MODE_UNDEFINED,
+                targetActivityType);
         if (targetStack != null) {
             for (int i = targetStack.getChildCount() - 1; i >= 0; i--) {
                 final Task t = targetStack.getChildAt(i);
@@ -364,29 +388,31 @@
         }
 
         // Adjust the wallpaper visibility for the showing target activity
-        final AppWindowToken recentsComponentAppToken = dc.getStack(WINDOWING_MODE_UNDEFINED,
-                targetActivityType).getTopChild().getTopFullscreenAppToken();
+        final AppWindowToken recentsComponentAppToken =
+                targetStack.getTopChild().getTopFullscreenAppToken();
         if (recentsComponentAppToken != null) {
             if (DEBUG_RECENTS_ANIMATIONS) Slog.d(TAG, "setHomeApp("
                     + recentsComponentAppToken.getName() + ")");
             mTargetAppToken = recentsComponentAppToken;
             if (recentsComponentAppToken.windowsCanBeWallpaperTarget()) {
-                dc.pendingLayoutChanges |= FINISH_LAYOUT_REDO_WALLPAPER;
-                dc.setLayoutNeeded();
+                mDisplayContent.pendingLayoutChanges |= FINISH_LAYOUT_REDO_WALLPAPER;
+                mDisplayContent.setLayoutNeeded();
             }
         }
 
         // Save the minimized home height
-        final TaskStack dockedStack = dc.getSplitScreenPrimaryStackIgnoringVisibility();
-        dc.getDockedDividerController().getHomeStackBoundsInDockedMode(
-                dc.getConfiguration(),
+        final TaskStack dockedStack = mDisplayContent.getSplitScreenPrimaryStackIgnoringVisibility();
+        mDisplayContent.getDockedDividerController().getHomeStackBoundsInDockedMode(
+                mDisplayContent.getConfiguration(),
                 dockedStack == null ? DOCKED_INVALID : dockedStack.getDockSide(),
                 mMinimizedHomeBounds);
 
         mService.mWindowPlacerLocked.performSurfacePlacement();
 
         // Notify that the animation has started
-        mStatusBar.onRecentsAnimationStateChanged(true /* running */);
+        if (mStatusBar != null) {
+            mStatusBar.onRecentsAnimationStateChanged(true /* running */);
+        }
     }
 
     @VisibleForTesting
@@ -440,8 +466,7 @@
 
             // Perform layout if it was scheduled before to make sure that we get correct content
             // insets for the target app window after a rotation
-            final DisplayContent displayContent = mService.mRoot.getDisplayContent(mDisplayId);
-            displayContent.performLayout(false /* initial */, false /* updateInputWindows */);
+            mDisplayContent.performLayout(false /* initial */, false /* updateInputWindows */);
 
             final Rect minimizedHomeBounds = mTargetAppToken != null
                     && mTargetAppToken.inSplitScreenSecondaryWindowingMode()
@@ -479,9 +504,8 @@
         cancelAnimation(reorderMode, true /* runSynchronously */, false /* screenshot */, reason);
     }
 
-    void cancelAnimationWithScreenShot() {
-        cancelAnimation(REORDER_KEEP_IN_PLACE, true /* sync */, true /* screenshot */,
-                "stackOrderChanged");
+    void cancelAnimationWithScreenshot(boolean screenshot) {
+        cancelAnimation(REORDER_KEEP_IN_PLACE, true /* sync */, screenshot, "stackOrderChanged");
     }
 
     private void cancelAnimation(@ReorderMode int reorderMode, boolean runSynchronously,
@@ -495,21 +519,29 @@
             }
             mService.mH.removeCallbacks(mFailsafeRunnable);
             mCanceled = true;
-            try {
-                if (screenshot) {
-                    // Screen shot previous task when next task starts transition.
-                    final Task task = mPendingAnimations.get(0).mTask;
-                    screenshotRecentTask(task, reorderMode, runSynchronously);
+
+            if (screenshot) {
+                // Screen shot previous task when next task starts transition and notify the runner.
+                // We will actually finish the animation once the runner calls cleanUpScreenshot().
+                final Task task = mPendingAnimations.get(0).mTask;
+                screenshotRecentTask(task, reorderMode, runSynchronously);
+                try {
                     mRunner.onAnimationCanceled(true /* deferredWithScreenshot */);
-                    return;
+                } catch (RemoteException e) {
+                    Slog.e(TAG, "Failed to cancel recents animation", e);
                 }
-                mRunner.onAnimationCanceled(false /* deferredWithScreenshot */);
-            } catch (RemoteException e) {
-                Slog.e(TAG, "Failed to cancel recents animation", e);
+            } else {
+                // Otherwise, notify the runner and clean up the animation immediately
+                // Note: In the fallback case, this can trigger multiple onAnimationCancel() calls
+                // to the runner if we this actually triggers cancel twice on the caller
+                try {
+                    mRunner.onAnimationCanceled(false /* deferredWithScreenshot */);
+                } catch (RemoteException e) {
+                    Slog.e(TAG, "Failed to cancel recents animation", e);
+                }
+                mCallbacks.onAnimationFinished(reorderMode, runSynchronously,
+                        false /* sendUserLeaveHint */);
             }
-            // Clean up and return to the previous app
-            mCallbacks.onAnimationFinished(reorderMode, runSynchronously,
-                    false /* sendUserLeaveHint */);
         }
     }
 
@@ -522,27 +554,36 @@
      * screenshot, so that Launcher can still control the leash lifecycle & make the next app
      * transition animate smoothly without flickering.
      */
-    void cancelOnNextTransitionStart() {
+    void setCancelOnNextTransitionStart() {
         mCancelOnNextTransitionStart = true;
     }
 
-    void setCancelWithDeferredScreenshotLocked(boolean screenshot) {
-        mCancelWithDeferredScreenshot = screenshot;
+    /**
+     * Requests that we attempt to defer the cancel until the next app transition if we are
+     * canceling from a stack order change.  If {@param screenshot} is specified, then the system
+     * will replace the contents of the leash with a screenshot, which must be cleaned up when the
+     * runner calls cleanUpScreenshot().
+     */
+    void setDeferredCancel(boolean defer, boolean screenshot) {
+        mRequestDeferCancelUntilNextTransition = defer;
+        mCancelDeferredWithScreenshot = screenshot;
     }
 
-    boolean shouldCancelWithDeferredScreenshot() {
-        return mCancelWithDeferredScreenshot;
+    /**
+     * @return Whether we should defer the cancel from a stack order change until the next app
+     * transition.
+     */
+    boolean shouldDeferCancelUntilNextTransition() {
+        return mRequestDeferCancelUntilNextTransition;
     }
 
-    void onTransitionStart() {
-        if (mCanceled) {
-            return;
-        }
-
-        if (mCancelOnNextTransitionStart) {
-            mCancelOnNextTransitionStart = false;
-            cancelAnimationWithScreenShot();
-        }
+    /**
+     * @return Whether we should both defer the cancel from a stack order change until the next
+     * app transition, and also that the deferred cancel should replace the contents of the leash
+     * with a screenshot.
+     */
+    boolean shouldDeferCancelWithScreenshot() {
+        return mRequestDeferCancelUntilNextTransition && mCancelDeferredWithScreenshot;
     }
 
     void screenshotRecentTask(Task task, @ReorderMode int reorderMode, boolean runSynchronously) {
@@ -575,6 +616,7 @@
 
         // Clear any pending failsafe runnables
         mService.mH.removeCallbacks(mFailsafeRunnable);
+        mDisplayContent.mAppTransition.unregisterListener(mAppTransitionListener);
 
         // Clear references to the runner
         unlinkToDeathOfRunner();
@@ -588,21 +630,22 @@
         }
 
         // Update the input windows after the animation is complete
-        final InputMonitor inputMonitor =
-                mService.mRoot.getDisplayContent(mDisplayId).getInputMonitor();
+        final InputMonitor inputMonitor = mDisplayContent.getInputMonitor();
         inputMonitor.updateInputWindowsLw(true /*force*/);
 
         // We have deferred all notifications to the target app as a part of the recents animation,
         // so if we are actually transitioning there, notify again here
         if (mTargetAppToken != null) {
             if (reorderMode == REORDER_MOVE_TO_TOP || reorderMode == REORDER_KEEP_IN_PLACE) {
-                mService.mRoot.getDisplayContent(mDisplayId)
-                        .mAppTransition.notifyAppTransitionFinishedLocked(mTargetAppToken.token);
+                mDisplayContent.mAppTransition.notifyAppTransitionFinishedLocked(
+                        mTargetAppToken.token);
             }
         }
 
         // Notify that the animation has ended
-        mStatusBar.onRecentsAnimationStateChanged(false /* running */);
+        if (mStatusBar != null) {
+            mStatusBar.onRecentsAnimationStateChanged(false /* running */);
+        }
     }
 
     void scheduleFailsafe() {
@@ -629,8 +672,7 @@
 
         synchronized (mService.getWindowManagerLock()) {
             // Clear associated input consumers on runner death
-            final InputMonitor inputMonitor =
-                    mService.mRoot.getDisplayContent(mDisplayId).getInputMonitor();
+            final InputMonitor inputMonitor = mDisplayContent.getInputMonitor();
             inputMonitor.destroyInputConsumer(INPUT_CONSUMER_RECENTS_ANIMATION);
         }
     }
@@ -826,5 +868,11 @@
         pw.print(innerPrefix); pw.println("mSplitScreenMinimized=" + mSplitScreenMinimized);
         pw.print(innerPrefix); pw.println("mTargetAppToken=" + mTargetAppToken);
         pw.print(innerPrefix); pw.println("isTargetOverWallpaper=" + isTargetOverWallpaper());
+        pw.print(innerPrefix); pw.println("mRequestDeferCancelUntilNextTransition="
+                + mRequestDeferCancelUntilNextTransition);
+        pw.print(innerPrefix); pw.println("mCancelOnNextTransitionStart="
+                + mCancelOnNextTransitionStart);
+        pw.print(innerPrefix); pw.println("mCancelDeferredWithScreenshot="
+                + mCancelDeferredWithScreenshot);
     }
 }
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/RootActivityContainer.java b/services/core/java/com/android/server/wm/RootActivityContainer.java
index 3ec461d..d58c613 100644
--- a/services/core/java/com/android/server/wm/RootActivityContainer.java
+++ b/services/core/java/com/android/server/wm/RootActivityContainer.java
@@ -35,6 +35,7 @@
 import static android.os.Trace.TRACE_TAG_ACTIVITY_MANAGER;
 import static android.view.Display.DEFAULT_DISPLAY;
 import static android.view.Display.INVALID_DISPLAY;
+import static android.view.WindowManager.TRANSIT_SHOW_SINGLE_TASK_DISPLAY;
 
 import static com.android.server.am.ActivityStackSupervisorProto.CONFIGURATION_CONTAINER;
 import static com.android.server.am.ActivityStackSupervisorProto.DISPLAYS;
@@ -1217,6 +1218,15 @@
                 if (displayShouldSleep) {
                     stack.goToSleepIfPossible(false /* shuttingDown */);
                 } else {
+                    // When the display which can only contain one task turns on, start a special
+                    // transition. {@link AppTransitionController#handleAppTransitionReady} later
+                    // picks up the transition, and schedules
+                    // {@link ITaskStackListener#onSingleTaskDisplayDrawn} callback which is
+                    // triggered after contents are drawn on the display.
+                    if (display.isSingleTaskInstance()) {
+                        display.mDisplayContent.prepareAppTransition(
+                                TRANSIT_SHOW_SINGLE_TASK_DISPLAY, false);
+                    }
                     stack.awakeFromSleepingLocked();
                     if (stack.isFocusedStackOnDisplay()
                             && !mStackSupervisor.getKeyguardController()
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/ScreenRotationAnimation.java b/services/core/java/com/android/server/wm/ScreenRotationAnimation.java
index c0942c9..0be9736 100644
--- a/services/core/java/com/android/server/wm/ScreenRotationAnimation.java
+++ b/services/core/java/com/android/server/wm/ScreenRotationAnimation.java
@@ -279,7 +279,8 @@
                 mService.mDisplayManagerInternal.screenshot(displayId);
             if (gb != null) {
                 try {
-                    surface.attachAndQueueBuffer(gb.getGraphicBuffer());
+                    surface.attachAndQueueBufferWithColorSpace(gb.getGraphicBuffer(),
+                            gb.getColorSpace());
                 } catch (RuntimeException e) {
                     Slog.w(TAG, "Failed to attach screenshot - " + e.getMessage());
                 }
diff --git a/services/core/java/com/android/server/wm/SurfaceAnimationRunner.java b/services/core/java/com/android/server/wm/SurfaceAnimationRunner.java
index cb50460..85176be 100644
--- a/services/core/java/com/android/server/wm/SurfaceAnimationRunner.java
+++ b/services/core/java/com/android/server/wm/SurfaceAnimationRunner.java
@@ -193,7 +193,9 @@
             public void onAnimationStart(Animator animation) {
                 synchronized (mCancelLock) {
                     if (!a.mCancelled) {
-                        mFrameTransaction.show(a.mLeash);
+                        // TODO: change this back to use show instead of alpha when b/138459974 is
+                        // fixed.
+                        mFrameTransaction.setAlpha(a.mLeash, 1);
                     }
                 }
             }
diff --git a/services/core/java/com/android/server/wm/SurfaceAnimator.java b/services/core/java/com/android/server/wm/SurfaceAnimator.java
index 3d9dfeb..cd211a2 100644
--- a/services/core/java/com/android/server/wm/SurfaceAnimator.java
+++ b/services/core/java/com/android/server/wm/SurfaceAnimator.java
@@ -324,9 +324,9 @@
                 .setName(surface + " - animation-leash");
         final SurfaceControl leash = builder.build();
         t.setWindowCrop(leash, width, height);
-        if (!hidden) {
-            t.show(leash);
-        }
+        t.show(leash);
+        // TODO: change this back to use show instead of alpha when b/138459974 is fixed.
+        t.setAlpha(leash, hidden ? 0 : 1);
         t.reparent(surface, leash);
         return leash;
     }
diff --git a/services/core/java/com/android/server/wm/TapExcludeRegionHolder.java b/services/core/java/com/android/server/wm/TapExcludeRegionHolder.java
index 22f529b..8f72cda 100644
--- a/services/core/java/com/android/server/wm/TapExcludeRegionHolder.java
+++ b/services/core/java/com/android/server/wm/TapExcludeRegionHolder.java
@@ -52,4 +52,11 @@
             region.op(r, Region.Op.UNION);
         }
     }
+
+    /**
+     * Return true if tap exclude region is empty.
+     */
+    boolean isEmpty() {
+        return mTapExcludeRegions.size() == 0;
+    }
 }
diff --git a/services/core/java/com/android/server/wm/TaskChangeNotificationController.java b/services/core/java/com/android/server/wm/TaskChangeNotificationController.java
index c7fcc2c..f776062 100644
--- a/services/core/java/com/android/server/wm/TaskChangeNotificationController.java
+++ b/services/core/java/com/android/server/wm/TaskChangeNotificationController.java
@@ -54,7 +54,8 @@
     private static final int NOTIFY_ACTIVITY_LAUNCH_ON_SECONDARY_DISPLAY_REROUTED_MSG = 19;
     private static final int NOTIFY_SIZE_COMPAT_MODE_ACTIVITY_CHANGED_MSG = 20;
     private static final int NOTIFY_BACK_PRESSED_ON_TASK_ROOT = 21;
-    private static final int NOTIFY_TASK_DISPLAY_CHANGED_LISTENERS_MSG = 22;
+    private static final int NOTIFY_SINGLE_TASK_DISPLAY_DRAWN = 22;
+    private static final int NOTIFY_TASK_DISPLAY_CHANGED_LISTENERS_MSG = 23;
 
     // Delay in notifying task stack change listeners (in millis)
     private static final int NOTIFY_TASK_STACK_CHANGE_LISTENERS_DELAY = 100;
@@ -155,6 +156,10 @@
         l.onSizeCompatModeActivityChanged(m.arg1, (IBinder) m.obj);
     };
 
+    private final TaskStackConsumer mNotifySingleTaskDisplayDrawn = (l, m) -> {
+        l.onSingleTaskDisplayDrawn(m.arg1);
+    };
+
     private final TaskStackConsumer mNotifyTaskDisplayChanged = (l, m) -> {
         l.onTaskDisplayChanged(m.arg1, m.arg2);
     };
@@ -238,6 +243,9 @@
                 case NOTIFY_BACK_PRESSED_ON_TASK_ROOT:
                     forAllRemoteListeners(mNotifyBackPressedOnTaskRoot, msg);
                     break;
+                case NOTIFY_SINGLE_TASK_DISPLAY_DRAWN:
+                    forAllRemoteListeners(mNotifySingleTaskDisplayDrawn, msg);
+                    break;
                 case NOTIFY_TASK_DISPLAY_CHANGED_LISTENERS_MSG:
                     forAllRemoteListeners(mNotifyTaskDisplayChanged, msg);
                     break;
@@ -487,6 +495,16 @@
     }
 
     /**
+     * Notify listeners that contents are drawn for the first time on a single task display.
+     */
+    void notifySingleTaskDisplayDrawn(int displayId) {
+        final Message msg = mHandler.obtainMessage(NOTIFY_SINGLE_TASK_DISPLAY_DRAWN,
+                displayId, 0 /* unused */);
+        forAllLocalListeners(mNotifySingleTaskDisplayDrawn, msg);
+        msg.sendToTarget();
+    }
+
+    /**
      * Notify listeners that a task is reparented to another display.
      */
     void notifyTaskDisplayChanged(int taskId, int newDisplayId) {
diff --git a/services/core/java/com/android/server/wm/TaskScreenshotAnimatable.java b/services/core/java/com/android/server/wm/TaskScreenshotAnimatable.java
index ee4e462..c0877a0 100644
--- a/services/core/java/com/android/server/wm/TaskScreenshotAnimatable.java
+++ b/services/core/java/com/android/server/wm/TaskScreenshotAnimatable.java
@@ -28,7 +28,7 @@
  * Class used by {@link RecentsAnimationController} to create a surface control with taking
  * screenshot of task when canceling recents animation.
  *
- * @see {@link RecentsAnimationController#cancelOnNextTransitionStart}
+ * @see {@link RecentsAnimationController#setCancelOnNextTransitionStart}
  */
 class TaskScreenshotAnimatable implements SurfaceAnimator.Animatable {
     private static final String TAG = "TaskScreenshotAnim";
@@ -69,7 +69,7 @@
         if (buffer != null) {
             final Surface surface = new Surface();
             surface.copyFrom(mSurfaceControl);
-            surface.attachAndQueueBuffer(buffer);
+            surface.attachAndQueueBufferWithColorSpace(buffer, screenshotBuffer.getColorSpace());
             surface.release();
         }
         getPendingTransaction().show(mSurfaceControl);
diff --git a/services/core/java/com/android/server/wm/TaskSnapshotSurface.java b/services/core/java/com/android/server/wm/TaskSnapshotSurface.java
index c3762d6..1905476 100644
--- a/services/core/java/com/android/server/wm/TaskSnapshotSurface.java
+++ b/services/core/java/com/android/server/wm/TaskSnapshotSurface.java
@@ -284,7 +284,6 @@
     }
 
     private void drawSnapshot() {
-        final GraphicBuffer buffer = mSnapshot.getSnapshot();
         mSurface.copyFrom(mSurfaceControl);
 
         if (DEBUG_STARTING_WINDOW) Slog.v(TAG, "Drawing snapshot surface sizeMismatch="
@@ -293,9 +292,9 @@
             // The dimensions of the buffer and the window don't match, so attaching the buffer
             // will fail. Better create a child window with the exact dimensions and fill the parent
             // window with the background color!
-            drawSizeMismatchSnapshot(buffer);
+            drawSizeMismatchSnapshot();
         } else {
-            drawSizeMatchSnapshot(buffer);
+            drawSizeMatchSnapshot();
         }
         synchronized (mService.mGlobalLock) {
             mShownTime = SystemClock.uptimeMillis();
@@ -307,15 +306,17 @@
         mSnapshot = null;
     }
 
-    private void drawSizeMatchSnapshot(GraphicBuffer buffer) {
-        mSurface.attachAndQueueBuffer(buffer);
+    private void drawSizeMatchSnapshot() {
+        mSurface.attachAndQueueBufferWithColorSpace(mSnapshot.getSnapshot(),
+                mSnapshot.getColorSpace());
         mSurface.release();
     }
 
-    private void drawSizeMismatchSnapshot(GraphicBuffer buffer) {
+    private void drawSizeMismatchSnapshot() {
         if (!mSurface.isValid()) {
             throw new IllegalStateException("mSurface does not hold a valid surface.");
         }
+        final GraphicBuffer buffer = mSnapshot.getSnapshot();
         final SurfaceSession session = new SurfaceSession();
         // We consider nearly matched dimensions as there can be rounding errors and the user won't
         // notice very minute differences from scaling one dimension more than the other
@@ -355,7 +356,7 @@
         } finally {
             SurfaceControl.closeTransaction();
         }
-        surface.attachAndQueueBuffer(buffer);
+        surface.attachAndQueueBufferWithColorSpace(buffer, mSnapshot.getColorSpace());
         surface.release();
 
         if (aspectRatioMismatch) {
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index 436a5c7..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();
@@ -854,7 +865,7 @@
 
     final Configuration mTempConfiguration = new Configuration();
 
-    final HighRefreshRateBlacklist mHighRefreshRateBlacklist = HighRefreshRateBlacklist.create();
+    final HighRefreshRateBlacklist mHighRefreshRateBlacklist;
 
     // If true, only the core apps and services are being launched because the device
     // is in a special boot mode, such as being encrypted or waiting for a decryption password.
@@ -1141,9 +1152,14 @@
                 this, mInputManager, mActivityTaskManager, mH.getLooper());
         mDragDropController = new DragDropController(this, mH.getLooper());
 
+        mHighRefreshRateBlacklist = HighRefreshRateBlacklist.create(context.getResources());
+
         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);
@@ -1161,6 +1177,10 @@
                             mSystemGestureExcludedByPreQStickyImmersive = excludedByPreQSticky;
                             mRoot.forAllDisplays(DisplayContent::updateSystemGestureExclusionLimit);
                         }
+
+                        mSystemGestureExclusionLogDebounceTimeoutMillis =
+                                DeviceConfig.getInt(DeviceConfig.NAMESPACE_WINDOW_MANAGER,
+                                        KEY_SYSTEM_GESTURE_EXCLUSION_LOG_DEBOUNCE_MILLIS, 0);
                     }
                 });
 
@@ -2002,6 +2022,7 @@
 
             int attrChanges = 0;
             int flagChanges = 0;
+            int privateFlagChanges = 0;
             if (attrs != null) {
                 displayPolicy.adjustWindowParamsLw(win, attrs, pid, uid);
                 // if they don't have the permission, mask out the status bar bits
@@ -2030,6 +2051,7 @@
                 }
 
                 flagChanges = win.mAttrs.flags ^= attrs.flags;
+                privateFlagChanges = win.mAttrs.privateFlags ^ attrs.privateFlags;
                 attrChanges = win.mAttrs.copyFrom(attrs);
                 if ((attrChanges & (WindowManager.LayoutParams.LAYOUT_CHANGED
                         | WindowManager.LayoutParams.SYSTEM_UI_VISIBILITY_CHANGED)) != 0) {
@@ -2047,7 +2069,7 @@
                     mAccessibilityController.onSomeWindowResizedOrMovedLocked();
                 }
 
-                if ((flagChanges & SYSTEM_FLAG_HIDE_NON_SYSTEM_OVERLAY_WINDOWS) != 0) {
+                if ((privateFlagChanges & SYSTEM_FLAG_HIDE_NON_SYSTEM_OVERLAY_WINDOWS) != 0) {
                     updateNonSystemOverlayWindowsVisibilityIfNeeded(
                             win, win.mWinAnimator.getShown());
                 }
@@ -4552,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;
@@ -4576,8 +4597,11 @@
                     AccessibilityController accessibilityController = null;
 
                     synchronized (mGlobalLock) {
-                        // TODO(multidisplay): Accessibility supported only of default desiplay.
-                        if (mAccessibilityController != null && displayContent.isDefaultDisplay) {
+                        // TODO(multidisplay): Accessibility supported only of default display and
+                        // embedded displays.
+                        if (mAccessibilityController != null
+                                && (displayContent.isDefaultDisplay
+                                || displayContent.getParentWindow() != null)) {
                             accessibilityController = mAccessibilityController;
                         }
 
@@ -4928,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) {
@@ -5919,6 +5939,12 @@
         mRoot.dumpTokens(pw, dumpAll);
     }
 
+
+    private void dumpHighRefreshRateBlacklist(PrintWriter pw) {
+        pw.println("WINDOW MANAGER HIGH REFRESH RATE BLACKLIST (dumpsys window refresh)");
+        mHighRefreshRateBlacklist.dump(pw);
+    }
+
     private void dumpTraceStatus(PrintWriter pw) {
         pw.println("WINDOW MANAGER TRACE (dumpsys window trace)");
         pw.print(mWindowTracing.getStatus() + "\n");
@@ -6318,6 +6344,9 @@
             } else if ("trace".equals(cmd)) {
                 dumpTraceStatus(pw);
                 return;
+            } else if ("refresh".equals(cmd)) {
+                dumpHighRefreshRateBlacklist(pw);
+                return;
             } else {
                 // Dumping a single name?
                 if (!dumpWindows(pw, cmd, args, opti, dumpAll)) {
@@ -6373,6 +6402,10 @@
                 pw.println(separator);
             }
             dumpTraceStatus(pw);
+            if (dumpAll) {
+                pw.println(separator);
+            }
+            dumpHighRefreshRateBlacklist(pw);
         }
     }
 
@@ -7574,7 +7607,7 @@
             return;
         }
         final boolean systemAlertWindowsHidden = !mHidingNonSystemOverlayWindows.isEmpty();
-        if (surfaceShown) {
+        if (surfaceShown && win.hideNonSystemOverlayWindowsWhenVisible()) {
             if (!mHidingNonSystemOverlayWindows.contains(win)) {
                 mHidingNonSystemOverlayWindows.add(win);
             }
@@ -7605,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 bc5e328..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;
@@ -565,7 +572,8 @@
      * activities are allowed to be resumed per process.
      * @return {@code true} if the activity is allowed to be resumed by compatibility
      * restrictions, which the activity was the topmost visible activity in process or the app is
-     * targeting after Q.
+     * targeting after Q. Note that non-focusable activity, in picture-in-picture mode for instance,
+     * does not count as a topmost activity.
      */
     boolean updateTopResumingActivityInProcessIfNeeded(@NonNull ActivityRecord activity) {
         if (mInfo.targetSdkVersion >= Q || mPreQTopResumedActivity == activity) {
@@ -581,9 +589,13 @@
         boolean canUpdate = false;
         final ActivityDisplay topDisplay =
                 mPreQTopResumedActivity != null ? mPreQTopResumedActivity.getDisplay() : null;
-        // Update the topmost activity if current top activity was not on any display or no
-        // longer visible.
-        if (topDisplay == null || !mPreQTopResumedActivity.visible) {
+        // Update the topmost activity if current top activity is
+        // - not on any display OR
+        // - no longer visible OR
+        // - not focusable (in PiP mode for instance)
+        if (topDisplay == null
+                || !mPreQTopResumedActivity.visible
+                || !mPreQTopResumedActivity.isFocusable()) {
             canUpdate = true;
         }
 
@@ -1074,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 703fe4a..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;
@@ -170,9 +173,11 @@
 import android.os.WorkSource;
 import android.provider.Settings;
 import android.text.TextUtils;
+import android.util.ArraySet;
 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;
@@ -226,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;
@@ -319,6 +327,9 @@
 
     int mLayoutSeq = -1;
 
+    /** @see #addEmbeddedDisplayContent(DisplayContent dc) */
+    private final ArraySet<DisplayContent> mEmbeddedDisplayContents = new ArraySet<>();
+
     /**
      * Used to store last reported to client configuration and check if we have newer available.
      * We'll send configuration to client only if it is different from the last applied one and
@@ -393,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;
@@ -539,6 +557,12 @@
     private final Point mTmpPoint = new Point();
 
     /**
+     * If a window is on a display which has been re-parented to a view in another window,
+     * use this offset to indicate the correct location.
+     */
+    private final Point mLastReportedDisplayOffset = new Point();
+
+    /**
      * Whether the window was resized by us while it was gone for layout.
      */
     boolean mResizedWhileGone = false;
@@ -669,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);
 
@@ -1792,11 +1830,13 @@
             startMoveAnimation(left, top);
         }
 
-        //TODO (multidisplay): Accessibility supported only for the default display.
-        if (mWmService.mAccessibilityController != null
-                && getDisplayContent().getDisplayId() == DEFAULT_DISPLAY) {
+        // TODO (multidisplay): Accessibility supported only for the default display and
+        // embedded displays
+        if (mWmService.mAccessibilityController != null && (getDisplayId() == DEFAULT_DISPLAY
+                || getDisplayContent().getParentWindow() != null)) {
             mWmService.mAccessibilityController.onSomeWindowResizedOrMovedLocked();
         }
+        updateLocationInParentDisplayIfNeeded();
 
         try {
             mClient.moved(left, top);
@@ -2945,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();
@@ -3177,11 +3260,13 @@
                         displayCutout);
             }
 
-            //TODO (multidisplay): Accessibility supported only for the default display.
+            // TODO (multidisplay): Accessibility supported only for the default display and
+            // embedded displays
             if (mWmService.mAccessibilityController != null && (getDisplayId() == DEFAULT_DISPLAY
                     || getDisplayContent().getParentWindow() != null)) {
                 mWmService.mAccessibilityController.onSomeWindowResizedOrMovedLocked();
             }
+            updateLocationInParentDisplayIfNeeded();
 
             mWindowFrames.resetInsetsChanged();
             mWinAnimator.mSurfaceResized = false;
@@ -3199,6 +3284,36 @@
         Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER);
     }
 
+    void updateLocationInParentDisplayIfNeeded() {
+        final int embeddedDisplayContentsSize = mEmbeddedDisplayContents.size();
+        // If there is any embedded display which is re-parented to this window, we need to
+        // notify all windows in the embedded display about the location change.
+        if (embeddedDisplayContentsSize != 0) {
+            for (int i = embeddedDisplayContentsSize - 1; i >= 0; i--) {
+                final DisplayContent edc = mEmbeddedDisplayContents.valueAt(i);
+                edc.notifyLocationInParentDisplayChanged();
+            }
+        }
+        // If this window is in a embedded display which is re-parented to another window,
+        // we may need to update its correct on-screen location.
+        final DisplayContent dc = getDisplayContent();
+        if (dc.getParentWindow() == null) {
+            return;
+        }
+
+        final Point offset = dc.getLocationInParentDisplay();
+        if (mLastReportedDisplayOffset.equals(offset)) {
+            return;
+        }
+
+        mLastReportedDisplayOffset.set(offset.x, offset.y);
+        try {
+            mClient.locationInParentDisplayChanged(mLastReportedDisplayOffset);
+        } catch (RemoteException e) {
+            Slog.e(TAG, "Failed to update offset from DisplayContent", e);
+        }
+    }
+
     /**
      * Called when the insets state changed.
      */
@@ -3618,6 +3733,7 @@
         }
         pw.println(prefix + "isOnScreen=" + isOnScreen());
         pw.println(prefix + "isVisible=" + isVisible());
+        pw.println(prefix + "mEmbeddedDisplayContents=" + mEmbeddedDisplayContents);
     }
 
     @Override
@@ -4248,7 +4364,8 @@
             return;
         }
 
-        //TODO (multidisplay): Accessibility is supported only for the default display.
+        // TODO (multidisplay): Accessibility supported only for the default display and
+        // embedded displays
         if (mWmService.mAccessibilityController != null && (getDisplayId() == DEFAULT_DISPLAY
                 || getDisplayContent().getParentWindow() != null)) {
             mWmService.mAccessibilityController.onSomeWindowResizedOrMovedLocked();
@@ -4620,6 +4737,28 @@
     }
 
     /**
+     * Add the DisplayContent of the embedded display which is re-parented to this window to
+     * the list of embedded displays.
+     *
+     * @param dc DisplayContent of the re-parented embedded display.
+     * @return {@code true} if the giving DisplayContent is added, {@code false} otherwise.
+     */
+    boolean addEmbeddedDisplayContent(DisplayContent dc) {
+        return mEmbeddedDisplayContents.add(dc);
+    }
+
+    /**
+     * Remove the DisplayContent of the embedded display which is re-parented to this window from
+     * the list of embedded displays.
+     *
+     * @param dc DisplayContent of the re-parented embedded display.
+     * @return {@code true} if the giving DisplayContent is removed, {@code false} otherwise.
+     */
+    boolean removeEmbeddedDisplayContent(DisplayContent dc) {
+        return mEmbeddedDisplayContents.remove(dc);
+    }
+
+    /**
      * Updates the last inset values to the current ones.
      */
     void updateLastInsetValues() {
@@ -5041,6 +5180,10 @@
         tempRegion.recycle();
     }
 
+    boolean hasTapExcludeRegion() {
+        return mTapExcludeRegionHolder != null && !mTapExcludeRegionHolder.isEmpty();
+    }
+
     @Override
     public boolean isInputMethodTarget() {
         return getDisplayContent().mInputMethodTarget == this;
diff --git a/services/core/java/com/android/server/wm/WindowStateAnimator.java b/services/core/java/com/android/server/wm/WindowStateAnimator.java
index 2c0a733..3505afb 100644
--- a/services/core/java/com/android/server/wm/WindowStateAnimator.java
+++ b/services/core/java/com/android/server/wm/WindowStateAnimator.java
@@ -1493,6 +1493,12 @@
     }
 
     void detachChildren() {
+
+        // Do not detach children of starting windows, as their lifecycle is well under control and
+        // it may lead to issues in case we relaunch when we just added the starting window.
+        if (mWin.mAttrs.type == TYPE_APPLICATION_STARTING) {
+            return;
+        }
         if (mSurfaceController != null) {
             mSurfaceController.detachChildren();
         }
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/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java
index 5c1dfef..e6ed2ed 100644
--- a/services/java/com/android/server/SystemServer.java
+++ b/services/java/com/android/server/SystemServer.java
@@ -38,6 +38,7 @@
 import android.database.sqlite.SQLiteGlobal;
 import android.hardware.display.DisplayManagerInternal;
 import android.net.ConnectivityModuleConnector;
+import android.net.Network;
 import android.net.NetworkStackClient;
 import android.os.BaseBundle;
 import android.os.Binder;
diff --git a/services/net/java/android/net/ConnectivityModuleConnector.java b/services/net/java/android/net/ConnectivityModuleConnector.java
index 19ade33..62f2c35 100644
--- a/services/net/java/android/net/ConnectivityModuleConnector.java
+++ b/services/net/java/android/net/ConnectivityModuleConnector.java
@@ -32,7 +32,7 @@
 import android.os.Process;
 import android.os.SystemClock;
 import android.os.UserHandle;
-import android.provider.Settings;
+import android.provider.DeviceConfig;
 import android.text.format.DateUtils;
 import android.util.ArraySet;
 import android.util.Slog;
@@ -296,8 +296,6 @@
     private synchronized void maybeCrashWithTerribleFailure(@NonNull String message,
             @Nullable String packageName) {
         logWtf(message, null);
-        // Called DeviceConfig to minimize merge conflicts
-        final DeviceConfigStub DeviceConfig = new DeviceConfigStub(mContext);
         // uptime is monotonic even after a framework restart
         final long uptime = SystemClock.elapsedRealtime();
         final long now = System.currentTimeMillis();
@@ -417,36 +415,4 @@
         // dump is thread-safe on SharedLog
         mLog.dump(null, pw, null);
     }
-
-    /**
-     * Stub class to replicate DeviceConfig behavior with minimal merge conflicts.
-     */
-    private class DeviceConfigStub {
-        private final Context mContext;
-
-        // Namespace is actually unused, but is here to replicate the final API.
-        private static final String NAMESPACE_CONNECTIVITY = "connectivity";
-
-        private DeviceConfigStub(Context context) {
-            mContext = context;
-        }
-
-        private long getLong(
-                @NonNull String namespace, @NonNull String key, long defaultVal) {
-            // Temporary solution until DeviceConfig is available
-            try {
-                return Settings.Global.getLong(
-                        mContext.getContentResolver(), TAG + "_" + key, defaultVal);
-            } catch (Throwable e) {
-                logWtf("Could not obtain setting " + key, e);
-                return defaultVal;
-            }
-        }
-
-        private boolean getBoolean(
-                @NonNull String namespace, @NonNull String key, boolean defaultVal) {
-            // Temporary solution until DeviceConfig is available
-            return getLong(namespace, key, defaultVal ? 1 : 0) != 0;
-        }
-    }
 }
diff --git a/services/robotests/backup/src/com/android/server/backup/keyvalue/KeyValueBackupTaskTest.java b/services/robotests/backup/src/com/android/server/backup/keyvalue/KeyValueBackupTaskTest.java
index cc64323..1d082c7 100644
--- a/services/robotests/backup/src/com/android/server/backup/keyvalue/KeyValueBackupTaskTest.java
+++ b/services/robotests/backup/src/com/android/server/backup/keyvalue/KeyValueBackupTaskTest.java
@@ -94,7 +94,6 @@
 import android.os.Looper;
 import android.os.Message;
 import android.os.ParcelFileDescriptor;
-import android.os.PowerManager;
 import android.os.RemoteException;
 import android.platform.test.annotations.Presubmit;
 import android.util.Pair;
@@ -184,7 +183,7 @@
     private TransportData mTransport;
     private ShadowLooper mShadowBackupLooper;
     private Handler mBackupHandler;
-    private PowerManager.WakeLock mWakeLock;
+    private UserBackupManagerService.BackupWakeLock mWakeLock;
     private KeyValueBackupReporter mReporter;
     private PackageManager mPackageManager;
     private ShadowPackageManager mShadowPackageManager;
diff --git a/services/robotests/backup/src/com/android/server/backup/restore/ActiveRestoreSessionTest.java b/services/robotests/backup/src/com/android/server/backup/restore/ActiveRestoreSessionTest.java
index f4cea7a..3fc421d 100644
--- a/services/robotests/backup/src/com/android/server/backup/restore/ActiveRestoreSessionTest.java
+++ b/services/robotests/backup/src/com/android/server/backup/restore/ActiveRestoreSessionTest.java
@@ -18,7 +18,7 @@
 
 import static com.android.server.backup.testing.BackupManagerServiceTestUtils.createBackupWakeLock;
 import static com.android.server.backup.testing.BackupManagerServiceTestUtils.setUpBackupManagerServiceBasics;
-import static com.android.server.backup.testing.BackupManagerServiceTestUtils.startBackupThreadAndGetLooper;
+import static com.android.server.backup.testing.BackupManagerServiceTestUtils.startBackupThread;
 import static com.android.server.backup.testing.TestUtils.assertEventLogged;
 import static com.android.server.backup.testing.TestUtils.assertEventNotLogged;
 import static com.android.server.backup.testing.TransportData.backupTransport;
@@ -44,8 +44,8 @@
 import android.content.pm.ApplicationInfo;
 import android.content.pm.PackageInfo;
 import android.os.Handler;
+import android.os.HandlerThread;
 import android.os.Looper;
-import android.os.PowerManager;
 import android.os.RemoteException;
 import android.platform.test.annotations.Presubmit;
 
@@ -98,7 +98,7 @@
     @Mock private IBackupManagerMonitor mMonitor;
     private ShadowLooper mShadowBackupLooper;
     private ShadowApplication mShadowApplication;
-    private PowerManager.WakeLock mWakeLock;
+    private UserBackupManagerService.BackupWakeLock mWakeLock;
     private TransportData mTransport;
     private RestoreSet mRestoreSet1;
     private RestoreSet mRestoreSet2;
@@ -118,7 +118,8 @@
 
         mShadowPackageManager = shadowOf(application.getPackageManager());
 
-        Looper backupLooper = startBackupThreadAndGetLooper();
+        HandlerThread handlerThread = startBackupThread(null);
+        Looper backupLooper = handlerThread.getLooper();
         mShadowBackupLooper = shadowOf(backupLooper);
 
         Handler mainHandler = new Handler(Looper.getMainLooper());
@@ -129,7 +130,7 @@
         // We need to mock BMS timeout parameters before initializing the BackupHandler since
         // the constructor of BackupHandler relies on it.
         when(mBackupManagerService.getAgentTimeoutParameters()).thenReturn(agentTimeoutParameters);
-        BackupHandler backupHandler = new BackupHandler(mBackupManagerService, backupLooper);
+        BackupHandler backupHandler = new BackupHandler(mBackupManagerService, handlerThread);
 
         mWakeLock = createBackupWakeLock(application);
 
diff --git a/services/robotests/backup/src/com/android/server/backup/testing/BackupManagerServiceTestUtils.java b/services/robotests/backup/src/com/android/server/backup/testing/BackupManagerServiceTestUtils.java
index 47abcc5..392d182 100644
--- a/services/robotests/backup/src/com/android/server/backup/testing/BackupManagerServiceTestUtils.java
+++ b/services/robotests/backup/src/com/android/server/backup/testing/BackupManagerServiceTestUtils.java
@@ -113,7 +113,7 @@
             TransportManager transportManager,
             PackageManager packageManager,
             Handler backupHandler,
-            PowerManager.WakeLock wakeLock,
+            UserBackupManagerService.BackupWakeLock wakeLock,
             BackupAgentTimeoutParameters agentTimeoutParameters) {
 
         when(backupManagerService.getContext()).thenReturn(application);
@@ -161,10 +161,12 @@
                 });
     }
 
-    public static PowerManager.WakeLock createBackupWakeLock(Application application) {
+    public static UserBackupManagerService.BackupWakeLock createBackupWakeLock(
+            Application application) {
         PowerManager powerManager =
                 (PowerManager) application.getSystemService(Context.POWER_SERVICE);
-        return powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "*backup*");
+        return new UserBackupManagerService.BackupWakeLock(
+                powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "*backup*"));
     }
 
     /**
diff --git a/services/tests/mockingservicestests/src/com/android/server/display/color/DisplayTransformManagerTest.java b/services/tests/mockingservicestests/src/com/android/server/display/color/DisplayTransformManagerTest.java
index 73b3b8b..a785300 100644
--- a/services/tests/mockingservicestests/src/com/android/server/display/color/DisplayTransformManagerTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/display/color/DisplayTransformManagerTest.java
@@ -19,6 +19,7 @@
 import static com.android.dx.mockito.inline.extended.ExtendedMockito.anyString;
 import static com.android.dx.mockito.inline.extended.ExtendedMockito.doAnswer;
 import static com.android.server.display.color.DisplayTransformManager.LEVEL_COLOR_MATRIX_NIGHT_DISPLAY;
+import static com.android.server.display.color.DisplayTransformManager.PERSISTENT_PROPERTY_COMPOSITION_COLOR_MODE;
 import static com.android.server.display.color.DisplayTransformManager.PERSISTENT_PROPERTY_DISPLAY_COLOR;
 import static com.android.server.display.color.DisplayTransformManager.PERSISTENT_PROPERTY_SATURATION;
 
@@ -28,6 +29,7 @@
 
 import android.hardware.display.ColorDisplayManager;
 import android.os.SystemProperties;
+import android.view.Display;
 
 import androidx.test.runner.AndroidJUnit4;
 
@@ -79,7 +81,7 @@
 
     @Test
     public void setColorMode_natural() {
-        mDtm.setColorMode(ColorDisplayManager.COLOR_MODE_NATURAL, mNightDisplayMatrix);
+        mDtm.setColorMode(ColorDisplayManager.COLOR_MODE_NATURAL, mNightDisplayMatrix, -1);
         assertThat(mSystemProperties.get(PERSISTENT_PROPERTY_DISPLAY_COLOR))
                 .isEqualTo("0" /* managed */);
         assertThat(mSystemProperties.get(PERSISTENT_PROPERTY_SATURATION))
@@ -88,7 +90,7 @@
 
     @Test
     public void setColorMode_boosted() {
-        mDtm.setColorMode(ColorDisplayManager.COLOR_MODE_BOOSTED, mNightDisplayMatrix);
+        mDtm.setColorMode(ColorDisplayManager.COLOR_MODE_BOOSTED, mNightDisplayMatrix, -1);
 
         assertThat(mSystemProperties.get(PERSISTENT_PROPERTY_DISPLAY_COLOR))
                 .isEqualTo("0" /* managed */);
@@ -98,7 +100,7 @@
 
     @Test
     public void setColorMode_saturated() {
-        mDtm.setColorMode(ColorDisplayManager.COLOR_MODE_SATURATED, mNightDisplayMatrix);
+        mDtm.setColorMode(ColorDisplayManager.COLOR_MODE_SATURATED, mNightDisplayMatrix, -1);
         assertThat(mSystemProperties.get(PERSISTENT_PROPERTY_DISPLAY_COLOR))
                 .isEqualTo("1" /* unmanaged */);
         assertThat(mSystemProperties.get(PERSISTENT_PROPERTY_SATURATION))
@@ -107,7 +109,7 @@
 
     @Test
     public void setColorMode_automatic() {
-        mDtm.setColorMode(ColorDisplayManager.COLOR_MODE_AUTOMATIC, mNightDisplayMatrix);
+        mDtm.setColorMode(ColorDisplayManager.COLOR_MODE_AUTOMATIC, mNightDisplayMatrix, -1);
         assertThat(mSystemProperties.get(PERSISTENT_PROPERTY_DISPLAY_COLOR))
                 .isEqualTo("2" /* enhanced */);
         assertThat(mSystemProperties.get(PERSISTENT_PROPERTY_SATURATION))
@@ -116,7 +118,7 @@
 
     @Test
     public void setColorMode_vendor() {
-        mDtm.setColorMode(0x100, mNightDisplayMatrix);
+        mDtm.setColorMode(0x100, mNightDisplayMatrix, -1);
         assertThat(mSystemProperties.get(PERSISTENT_PROPERTY_DISPLAY_COLOR))
                 .isEqualTo(Integer.toString(0x100) /* pass-through */);
         assertThat(mSystemProperties.get(PERSISTENT_PROPERTY_SATURATION))
@@ -125,10 +127,38 @@
 
     @Test
     public void setColorMode_outOfBounds() {
-        mDtm.setColorMode(0x50, mNightDisplayMatrix);
+        mDtm.setColorMode(0x50, mNightDisplayMatrix, -1);
         assertThat(mSystemProperties.get(PERSISTENT_PROPERTY_DISPLAY_COLOR))
                 .isEqualTo(null);
         assertThat(mSystemProperties.get(PERSISTENT_PROPERTY_SATURATION))
                 .isEqualTo(null);
     }
+
+    @Test
+    public void setColorMode_withoutColorSpace() {
+        String magicPropertyValue = "magic";
+
+        // Start with a known state, which we expect to remain unmodified
+        SystemProperties.set(PERSISTENT_PROPERTY_COMPOSITION_COLOR_MODE, magicPropertyValue);
+
+        mDtm.setColorMode(ColorDisplayManager.COLOR_MODE_NATURAL, mNightDisplayMatrix,
+                Display.COLOR_MODE_INVALID);
+        assertThat(mSystemProperties.get(PERSISTENT_PROPERTY_COMPOSITION_COLOR_MODE))
+                .isEqualTo(magicPropertyValue);
+    }
+
+    @Test
+    public void setColorMode_withColorSpace() {
+        String magicPropertyValue = "magic";
+        int testPropertyValue = Display.COLOR_MODE_SRGB;
+
+        // Start with a known state, which we expect to get modified
+        SystemProperties.set(PERSISTENT_PROPERTY_COMPOSITION_COLOR_MODE, magicPropertyValue);
+
+        mDtm.setColorMode(ColorDisplayManager.COLOR_MODE_NATURAL, mNightDisplayMatrix,
+                testPropertyValue);
+        assertThat(mSystemProperties.get(PERSISTENT_PROPERTY_COMPOSITION_COLOR_MODE))
+                .isEqualTo(Integer.toString(testPropertyValue));
+    }
+
 }
diff --git a/services/tests/servicestests/AndroidManifest.xml b/services/tests/servicestests/AndroidManifest.xml
index c1bbb30..178ae253 100644
--- a/services/tests/servicestests/AndroidManifest.xml
+++ b/services/tests/servicestests/AndroidManifest.xml
@@ -69,8 +69,10 @@
     <uses-permission android:name="android.permission.READ_DEVICE_CONFIG" />
     <uses-permission android:name="android.permission.WRITE_DEVICE_CONFIG" />
     <uses-permission android:name="android.permission.HARDWARE_TEST"/>
+    <uses-permission android:name="android.permission.MANAGE_APPOPS"/>
     <uses-permission android:name="android.permission.BLUETOOTH"/>
 
+
     <!-- Uses API introduced in O (26) -->
     <uses-sdk android:minSdkVersion="1"
           android:targetSdkVersion="26"/>
diff --git a/services/tests/servicestests/src/com/android/server/display/color/ColorDisplayServiceTest.java b/services/tests/servicestests/src/com/android/server/display/color/ColorDisplayServiceTest.java
index 8bb8aae..a19b387 100644
--- a/services/tests/servicestests/src/com/android/server/display/color/ColorDisplayServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/display/color/ColorDisplayServiceTest.java
@@ -18,13 +18,19 @@
 
 import static com.google.common.truth.Truth.assertWithMessage;
 
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.eq;
 import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.reset;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
 
 import android.annotation.NonNull;
 import android.app.ActivityManager;
 import android.app.AlarmManager;
 import android.content.Context;
 import android.content.ContextWrapper;
+import android.content.res.Resources;
 import android.hardware.display.ColorDisplayManager;
 import android.hardware.display.Time;
 import android.os.Handler;
@@ -33,6 +39,7 @@
 import android.provider.Settings.Secure;
 import android.provider.Settings.System;
 import android.test.mock.MockContentResolver;
+import android.view.Display;
 
 import androidx.test.InstrumentationRegistry;
 import androidx.test.runner.AndroidJUnit4;
@@ -73,6 +80,8 @@
     private ColorDisplayService mCds;
     private ColorDisplayService.BinderService mBinderService;
 
+    private Resources mResourcesSpy;
+
     @BeforeClass
     public static void setDtm() {
         final DisplayTransformManager dtm = Mockito.mock(DisplayTransformManager.class);
@@ -84,6 +93,9 @@
         mContext = Mockito.spy(new ContextWrapper(InstrumentationRegistry.getTargetContext()));
         doReturn(mContext).when(mContext).getApplicationContext();
 
+        mResourcesSpy = Mockito.spy(mContext.getResources());
+        when(mContext.getResources()).thenReturn(mResourcesSpy);
+
         mUserId = ActivityManager.getCurrentUser();
 
         final MockContentResolver cr = new MockContentResolver(mContext);
@@ -113,6 +125,8 @@
         mUserId = UserHandle.USER_NULL;
         mContext = null;
 
+        FakeSettingsProvider.clearSettingsProvider();
+
         LocalServices.removeServiceForTest(ColorDisplayService.ColorDisplayServiceInternal.class);
     }
 
@@ -924,11 +938,8 @@
 
         startService();
         assertUserColorMode(ColorDisplayManager.COLOR_MODE_NATURAL);
-        if (isColorModeValid(ColorDisplayManager.COLOR_MODE_SATURATED)) {
-            assertActiveColorMode(ColorDisplayManager.COLOR_MODE_SATURATED);
-        } else if (isColorModeValid(ColorDisplayManager.COLOR_MODE_AUTOMATIC)) {
-            assertActiveColorMode(ColorDisplayManager.COLOR_MODE_AUTOMATIC);
-        }
+        assertActiveColorMode(mContext.getResources().getInteger(
+                R.integer.config_accessibilityColorMode));
     }
 
     @Test
@@ -942,11 +953,8 @@
 
         startService();
         assertUserColorMode(ColorDisplayManager.COLOR_MODE_NATURAL);
-        if (isColorModeValid(ColorDisplayManager.COLOR_MODE_SATURATED)) {
-            assertActiveColorMode(ColorDisplayManager.COLOR_MODE_SATURATED);
-        } else if (isColorModeValid(ColorDisplayManager.COLOR_MODE_AUTOMATIC)) {
-            assertActiveColorMode(ColorDisplayManager.COLOR_MODE_AUTOMATIC);
-        }
+        assertActiveColorMode(mContext.getResources().getInteger(
+                R.integer.config_accessibilityColorMode));
     }
 
     @Test
@@ -961,11 +969,8 @@
 
         startService();
         assertUserColorMode(ColorDisplayManager.COLOR_MODE_NATURAL);
-        if (isColorModeValid(ColorDisplayManager.COLOR_MODE_SATURATED)) {
-            assertActiveColorMode(ColorDisplayManager.COLOR_MODE_SATURATED);
-        } else if (isColorModeValid(ColorDisplayManager.COLOR_MODE_AUTOMATIC)) {
-            assertActiveColorMode(ColorDisplayManager.COLOR_MODE_AUTOMATIC);
-        }
+        assertActiveColorMode(mContext.getResources().getInteger(
+                R.integer.config_accessibilityColorMode));
     }
 
     @Test
@@ -1020,11 +1025,15 @@
 
     @Test
     public void displayWhiteBalance_enabledAfterLinearColorModeSelected() {
+        if (!isColorModeValid(ColorDisplayManager.COLOR_MODE_SATURATED)) {
+            return;
+        }
         setDisplayWhiteBalanceEnabled(true);
-        setNightDisplayActivated(false /* activated */, -30 /* lastActivatedTimeOffset */);
+        mBinderService.setColorMode(ColorDisplayManager.COLOR_MODE_SATURATED);
         startService();
-        mBinderService.setColorMode(ColorDisplayManager.COLOR_MODE_NATURAL);
+        assertDwbActive(false);
 
+        mBinderService.setColorMode(ColorDisplayManager.COLOR_MODE_NATURAL);
         mCds.updateDisplayWhiteBalanceStatus();
         assertDwbActive(true);
     }
@@ -1032,10 +1041,8 @@
     @Test
     public void displayWhiteBalance_disabledWhileAccessibilityColorCorrectionEnabled() {
         setDisplayWhiteBalanceEnabled(true);
-        startService();
         setAccessibilityColorCorrection(true);
-
-        mCds.updateDisplayWhiteBalanceStatus();
+        startService();
         assertDwbActive(false);
 
         setAccessibilityColorCorrection(false);
@@ -1046,10 +1053,8 @@
     @Test
     public void displayWhiteBalance_disabledWhileAccessibilityColorInversionEnabled() {
         setDisplayWhiteBalanceEnabled(true);
-        startService();
         setAccessibilityColorInversion(true);
-
-        mCds.updateDisplayWhiteBalanceStatus();
+        startService();
         assertDwbActive(false);
 
         setAccessibilityColorInversion(false);
@@ -1057,6 +1062,80 @@
         assertDwbActive(true);
     }
 
+    @Test
+    public void compositionColorSpaces_noResources() {
+        final DisplayTransformManager dtm = LocalServices.getService(DisplayTransformManager.class);
+        reset(dtm);
+
+        when(mResourcesSpy.getIntArray(R.array.config_displayCompositionColorModes))
+            .thenReturn(new int[] {});
+        when(mResourcesSpy.getIntArray(R.array.config_displayCompositionColorSpaces))
+            .thenReturn(new int[] {});
+        setColorMode(ColorDisplayManager.COLOR_MODE_NATURAL);
+        startService();
+        verify(dtm).setColorMode(eq(ColorDisplayManager.COLOR_MODE_NATURAL), any(),
+                eq(Display.COLOR_MODE_INVALID));
+    }
+
+    @Test
+    public void compositionColorSpaces_invalidResources() {
+        final DisplayTransformManager dtm = LocalServices.getService(DisplayTransformManager.class);
+        reset(dtm);
+
+        when(mResourcesSpy.getIntArray(R.array.config_displayCompositionColorModes))
+            .thenReturn(new int[] {
+               ColorDisplayManager.COLOR_MODE_NATURAL,
+               // Missing second color mode
+            });
+        when(mResourcesSpy.getIntArray(R.array.config_displayCompositionColorSpaces))
+            .thenReturn(new int[] {
+               Display.COLOR_MODE_SRGB,
+               Display.COLOR_MODE_DISPLAY_P3
+            });
+        setColorMode(ColorDisplayManager.COLOR_MODE_NATURAL);
+        startService();
+        verify(dtm).setColorMode(eq(ColorDisplayManager.COLOR_MODE_NATURAL), any(),
+                eq(Display.COLOR_MODE_INVALID));
+    }
+
+    @Test
+    public void compositionColorSpaces_validResources_validColorMode() {
+        final DisplayTransformManager dtm = LocalServices.getService(DisplayTransformManager.class);
+        reset(dtm);
+
+        when(mResourcesSpy.getIntArray(R.array.config_displayCompositionColorModes))
+            .thenReturn(new int[] {
+               ColorDisplayManager.COLOR_MODE_NATURAL
+            });
+        when(mResourcesSpy.getIntArray(R.array.config_displayCompositionColorSpaces))
+            .thenReturn(new int[] {
+               Display.COLOR_MODE_SRGB,
+            });
+        setColorMode(ColorDisplayManager.COLOR_MODE_NATURAL);
+        startService();
+        verify(dtm).setColorMode(eq(ColorDisplayManager.COLOR_MODE_NATURAL), any(),
+                eq(Display.COLOR_MODE_SRGB));
+    }
+
+    @Test
+    public void compositionColorSpaces_validResources_invalidColorMode() {
+        final DisplayTransformManager dtm = LocalServices.getService(DisplayTransformManager.class);
+        reset(dtm);
+
+        when(mResourcesSpy.getIntArray(R.array.config_displayCompositionColorModes))
+            .thenReturn(new int[] {
+               ColorDisplayManager.COLOR_MODE_NATURAL
+            });
+        when(mResourcesSpy.getIntArray(R.array.config_displayCompositionColorSpaces))
+            .thenReturn(new int[] {
+               Display.COLOR_MODE_SRGB,
+            });
+        setColorMode(ColorDisplayManager.COLOR_MODE_BOOSTED);
+        startService();
+        verify(dtm).setColorMode(eq(ColorDisplayManager.COLOR_MODE_BOOSTED), any(),
+                eq(Display.COLOR_MODE_INVALID));
+    }
+
     /**
      * Configures Night display to use a custom schedule.
      *
@@ -1159,7 +1238,7 @@
 
         InstrumentationRegistry.getInstrumentation().runOnMainSync(() -> {
             mCds.onBootPhase(SystemService.PHASE_BOOT_COMPLETED);
-            mCds.onStartUser(mUserId);
+            mCds.onUserChanged(mUserId);
         });
     }
 
diff --git a/services/tests/servicestests/src/com/android/server/display/whitebalance/AmbientLuxTest.java b/services/tests/servicestests/src/com/android/server/display/whitebalance/AmbientLuxTest.java
new file mode 100644
index 0000000..6b0798b
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/display/whitebalance/AmbientLuxTest.java
@@ -0,0 +1,490 @@
+/*
+ * 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.display.whitebalance;
+
+import com.android.internal.R;
+import com.google.common.collect.ImmutableList;
+
+import static org.junit.Assert.assertEquals;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.when;
+import static org.mockito.Mockito.doAnswer;
+import static org.mockito.Matchers.any;
+import static org.mockito.Matchers.anyLong;
+import static org.mockito.Matchers.eq;
+import org.mockito.stubbing.Answer;
+import org.mockito.invocation.InvocationOnMock;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+import org.mockito.Spy;
+
+import android.content.ContextWrapper;
+import android.content.res.Resources;
+import android.content.res.TypedArray;
+import android.hardware.Sensor;
+import android.hardware.SensorEvent;
+import android.hardware.SensorEventListener;
+import android.hardware.SensorManager;
+import android.os.Handler;
+import android.os.Looper;
+import android.util.TypedValue;
+
+import androidx.test.InstrumentationRegistry;
+
+import org.junit.Before;
+import org.junit.After;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+import java.lang.reflect.Constructor;
+import java.lang.reflect.Field;
+import java.lang.reflect.Method;
+import java.util.List;
+
+@RunWith(JUnit4.class)
+public final class AmbientLuxTest {
+    private static final int AMBIENT_COLOR_TYPE = 20705;
+    private static final String AMBIENT_COLOR_TYPE_STR = "colorSensoryDensoryDoc";
+    private static final float LOW_LIGHT_AMBIENT_COLOR_TEMPERATURE = 5432.1f;
+    private static final float HIGH_LIGHT_AMBIENT_COLOR_TEMPERATURE = 3456.7f;
+
+    private Handler mHandler = new Handler(Looper.getMainLooper());
+    private Sensor mLightSensor;
+    private Sensor mAmbientColorSensor;
+    private ContextWrapper mContextSpy;
+    private Resources mResourcesSpy;
+
+    @Mock private SensorManager mSensorManagerMock;
+
+    @Mock private TypedArray mBrightnesses;
+    @Mock private TypedArray mBiases;
+    @Mock private TypedArray mHighLightBrightnesses;
+    @Mock private TypedArray mHighLightBiases;
+
+    @Before
+    public void setUp() throws Exception {
+        MockitoAnnotations.initMocks(this);
+        mLightSensor = createSensor(Sensor.TYPE_LIGHT, null);
+        mAmbientColorSensor = createSensor(AMBIENT_COLOR_TYPE, AMBIENT_COLOR_TYPE_STR);
+        mContextSpy = spy(new ContextWrapper(InstrumentationRegistry.getContext()));
+        mResourcesSpy = spy(mContextSpy.getResources());
+        when(mContextSpy.getResources()).thenReturn(mResourcesSpy);
+        when(mSensorManagerMock.getDefaultSensor(Sensor.TYPE_LIGHT)).thenReturn(mLightSensor);
+        final List<Sensor> sensorList = ImmutableList.of(mLightSensor, mAmbientColorSensor);
+        when(mSensorManagerMock.getSensorList(Sensor.TYPE_ALL)).thenReturn(sensorList);
+        when(mResourcesSpy.getString(
+                R.string.config_displayWhiteBalanceColorTemperatureSensorName))
+                .thenReturn(AMBIENT_COLOR_TYPE_STR);
+        when(mResourcesSpy.getInteger(
+                R.integer.config_displayWhiteBalanceDecreaseDebounce))
+                .thenReturn(0);
+        when(mResourcesSpy.getInteger(
+                R.integer.config_displayWhiteBalanceIncreaseDebounce))
+                .thenReturn(0);
+        mockResourcesFloat(R.dimen.config_displayWhiteBalanceLowLightAmbientColorTemperature,
+                LOW_LIGHT_AMBIENT_COLOR_TEMPERATURE);
+        mockResourcesFloat(R.dimen.config_displayWhiteBalanceHighLightAmbientColorTemperature,
+                HIGH_LIGHT_AMBIENT_COLOR_TEMPERATURE);
+        when(mResourcesSpy.obtainTypedArray(
+                R.array.config_displayWhiteBalanceAmbientColorTemperatures))
+                .thenReturn(createTypedArray());
+        when(mResourcesSpy.obtainTypedArray(
+                R.array.config_displayWhiteBalanceDisplayColorTemperatures))
+                .thenReturn(createTypedArray());
+
+        when(mResourcesSpy.obtainTypedArray(
+                R.array.config_displayWhiteBalanceLowLightAmbientBrightnesses))
+                .thenReturn(mBrightnesses);
+        when(mResourcesSpy.obtainTypedArray(
+                R.array.config_displayWhiteBalanceLowLightAmbientBiases))
+                .thenReturn(mBiases);
+        when(mResourcesSpy.obtainTypedArray(
+                R.array.config_displayWhiteBalanceHighLightAmbientBrightnesses))
+                .thenReturn(mHighLightBrightnesses);
+        when(mResourcesSpy.obtainTypedArray(
+                R.array.config_displayWhiteBalanceHighLightAmbientBiases))
+                .thenReturn(mHighLightBiases);
+        mockThrottler();
+    }
+
+    @Test
+    public void testNoSpline() throws Exception {
+        setBrightnesses();
+        setBiases();
+
+        DisplayWhiteBalanceController controller =
+                DisplayWhiteBalanceFactory.create(mHandler, mSensorManagerMock, mResourcesSpy);
+        final float ambientColorTemperature = 8000.0f;
+        setEstimatedColorTemperature(controller, ambientColorTemperature);
+        controller.mBrightnessFilter = spy(controller.mBrightnessFilter);
+
+        for (float luxOverride = 0.1f; luxOverride <= 10000; luxOverride *= 10) {
+            setEstimatedBrightnessAndUpdate(controller, luxOverride);
+            assertEquals(controller.mPendingAmbientColorTemperature,
+                    ambientColorTemperature, 0.001);
+        }
+    }
+
+    @Test
+    public void testSpline_OneSegment() throws Exception {
+        final float lowerBrightness = 10.0f;
+        final float upperBrightness = 50.0f;
+        setBrightnesses(lowerBrightness, upperBrightness);
+        setBiases(0.0f, 1.0f);
+
+        DisplayWhiteBalanceController controller =
+                DisplayWhiteBalanceFactory.create(mHandler, mSensorManagerMock, mResourcesSpy);
+        final float ambientColorTemperature = 8000.0f;
+        setEstimatedColorTemperature(controller, ambientColorTemperature);
+        controller.mBrightnessFilter = spy(controller.mBrightnessFilter);
+
+        for (float t = 0.0f; t <= 1.0f; t += 0.1f) {
+            setEstimatedBrightnessAndUpdate(controller,
+                    mix(lowerBrightness, upperBrightness, t));
+            assertEquals(controller.mPendingAmbientColorTemperature,
+                    mix(LOW_LIGHT_AMBIENT_COLOR_TEMPERATURE, ambientColorTemperature, t), 0.001);
+        }
+
+        setEstimatedBrightnessAndUpdate(controller, 0.0f);
+        assertEquals(controller.mPendingAmbientColorTemperature,
+                LOW_LIGHT_AMBIENT_COLOR_TEMPERATURE, 0.001);
+
+        setEstimatedBrightnessAndUpdate(controller, upperBrightness + 1.0f);
+        assertEquals(controller.mPendingAmbientColorTemperature, ambientColorTemperature, 0.001);
+    }
+
+    @Test
+    public void testSpline_TwoSegments() throws Exception {
+        final float brightness0 = 10.0f;
+        final float brightness1 = 50.0f;
+        final float brightness2 = 60.0f;
+        setBrightnesses(brightness0, brightness1, brightness2);
+        final float bias0 = 0.0f;
+        final float bias1 = 0.25f;
+        final float bias2 = 1.0f;
+        setBiases(bias0, bias1, bias2);
+
+        DisplayWhiteBalanceController controller =
+                DisplayWhiteBalanceFactory.create(mHandler, mSensorManagerMock, mResourcesSpy);
+        final float ambientColorTemperature = 8000.0f;
+        setEstimatedColorTemperature(controller, ambientColorTemperature);
+        controller.mBrightnessFilter = spy(controller.mBrightnessFilter);
+
+        for (float t = 0.0f; t <= 1.0f; t += 0.1f) {
+            float luxOverride = mix(brightness0, brightness1, t);
+            setEstimatedBrightnessAndUpdate(controller, luxOverride);
+            float bias = mix(bias0, bias1, t);
+            assertEquals(controller.mPendingAmbientColorTemperature,
+                    mix(LOW_LIGHT_AMBIENT_COLOR_TEMPERATURE, ambientColorTemperature, bias), 0.001);
+        }
+
+        for (float t = 0.0f; t <= 1.0f; t += 0.1f) {
+            float luxOverride = mix(brightness1, brightness2, t);
+            setEstimatedBrightnessAndUpdate(controller, luxOverride);
+            float bias = mix(bias1, bias2, t);
+            assertEquals(controller.mPendingAmbientColorTemperature,
+                    mix(LOW_LIGHT_AMBIENT_COLOR_TEMPERATURE, ambientColorTemperature, bias), 0.001);
+        }
+
+        setEstimatedBrightnessAndUpdate(controller, 0.0f);
+        assertEquals(controller.mPendingAmbientColorTemperature,
+                LOW_LIGHT_AMBIENT_COLOR_TEMPERATURE, 0.001);
+
+        setEstimatedBrightnessAndUpdate(controller, brightness2 + 1.0f);
+        assertEquals(controller.mPendingAmbientColorTemperature, ambientColorTemperature, 0.001);
+    }
+
+    @Test
+    public void testSpline_VerticalSegment() throws Exception {
+        final float lowerBrightness = 10.0f;
+        final float upperBrightness = 10.0f;
+        setBrightnesses(lowerBrightness, upperBrightness);
+        setBiases(0.0f, 1.0f);
+
+        DisplayWhiteBalanceController controller =
+                DisplayWhiteBalanceFactory.create(mHandler, mSensorManagerMock, mResourcesSpy);
+        final float ambientColorTemperature = 8000.0f;
+        setEstimatedColorTemperature(controller, ambientColorTemperature);
+        controller.mBrightnessFilter = spy(controller.mBrightnessFilter);
+
+        setEstimatedBrightnessAndUpdate(controller, 0.0f);
+        assertEquals(controller.mPendingAmbientColorTemperature,
+                LOW_LIGHT_AMBIENT_COLOR_TEMPERATURE, 0.001);
+
+        setEstimatedBrightnessAndUpdate(controller, upperBrightness + 1.0f);
+        assertEquals(controller.mPendingAmbientColorTemperature, ambientColorTemperature, 0.001);
+    }
+
+    @Test
+    public void testSpline_InvalidEndBias() throws Exception {
+        setBrightnesses(10.0f, 1000.0f);
+        setBiases(0.0f, 2.0f);
+
+        DisplayWhiteBalanceController controller =
+                DisplayWhiteBalanceFactory.create(mHandler, mSensorManagerMock, mResourcesSpy);
+        final float ambientColorTemperature = 8000.0f;
+        setEstimatedColorTemperature(controller, ambientColorTemperature);
+        controller.mBrightnessFilter = spy(controller.mBrightnessFilter);
+
+        for (float luxOverride = 0.1f; luxOverride <= 10000; luxOverride *= 10) {
+        setEstimatedBrightnessAndUpdate(controller, luxOverride);
+        assertEquals(controller.mPendingAmbientColorTemperature,
+                ambientColorTemperature, 0.001);
+        }
+    }
+
+    @Test
+    public void testSpline_InvalidBeginBias() throws Exception {
+        setBrightnesses(10.0f, 1000.0f);
+        setBiases(0.1f, 1.0f);
+
+        DisplayWhiteBalanceController controller =
+                DisplayWhiteBalanceFactory.create(mHandler, mSensorManagerMock, mResourcesSpy);
+        final float ambientColorTemperature = 8000.0f;
+        setEstimatedColorTemperature(controller, ambientColorTemperature);
+        controller.mBrightnessFilter = spy(controller.mBrightnessFilter);
+
+        for (float luxOverride = 0.1f; luxOverride <= 10000; luxOverride *= 10) {
+        setEstimatedBrightnessAndUpdate(controller, luxOverride);
+        assertEquals(controller.mPendingAmbientColorTemperature,
+                ambientColorTemperature, 0.001);
+        }
+    }
+
+    @Test
+    public void testSpline_OneSegmentHighLight() throws Exception {
+        final float lowerBrightness = 10.0f;
+        final float upperBrightness = 50.0f;
+        setHighLightBrightnesses(lowerBrightness, upperBrightness);
+        setHighLightBiases(0.0f, 1.0f);
+
+        DisplayWhiteBalanceController controller =
+                DisplayWhiteBalanceFactory.create(mHandler, mSensorManagerMock, mResourcesSpy);
+        final float ambientColorTemperature = 8000.0f;
+        setEstimatedColorTemperature(controller, ambientColorTemperature);
+        controller.mBrightnessFilter = spy(controller.mBrightnessFilter);
+
+        for (float t = 0.0f; t <= 1.0f; t += 0.1f) {
+            setEstimatedBrightnessAndUpdate(controller,
+                    mix(lowerBrightness, upperBrightness, t));
+            assertEquals(controller.mPendingAmbientColorTemperature,
+                    mix(HIGH_LIGHT_AMBIENT_COLOR_TEMPERATURE, ambientColorTemperature, 1.0f - t),
+                    0.001);
+        }
+
+        setEstimatedBrightnessAndUpdate(controller, upperBrightness + 1.0f);
+        assertEquals(controller.mPendingAmbientColorTemperature,
+                HIGH_LIGHT_AMBIENT_COLOR_TEMPERATURE, 0.001);
+
+        setEstimatedBrightnessAndUpdate(controller, 0.0f);
+        assertEquals(controller.mPendingAmbientColorTemperature, ambientColorTemperature, 0.001);
+    }
+
+    @Test
+    public void testSpline_TwoSegmentsHighLight() throws Exception {
+        final float brightness0 = 10.0f;
+        final float brightness1 = 50.0f;
+        final float brightness2 = 60.0f;
+        setHighLightBrightnesses(brightness0, brightness1, brightness2);
+        final float bias0 = 0.0f;
+        final float bias1 = 0.25f;
+        final float bias2 = 1.0f;
+        setHighLightBiases(bias0, bias1, bias2);
+
+        DisplayWhiteBalanceController controller =
+                DisplayWhiteBalanceFactory.create(mHandler, mSensorManagerMock, mResourcesSpy);
+        final float ambientColorTemperature = 6000.0f;
+        setEstimatedColorTemperature(controller, ambientColorTemperature);
+        controller.mBrightnessFilter = spy(controller.mBrightnessFilter);
+
+        for (float t = 0.0f; t <= 1.0f; t += 0.1f) {
+            float luxOverride = mix(brightness0, brightness1, t);
+            setEstimatedBrightnessAndUpdate(controller, luxOverride);
+            float bias = mix(bias0, bias1, t);
+            assertEquals(controller.mPendingAmbientColorTemperature,
+                    mix(HIGH_LIGHT_AMBIENT_COLOR_TEMPERATURE, ambientColorTemperature, 1.0f - bias),
+                    0.01);
+        }
+
+        for (float t = 0.0f; t <= 1.0f; t += 0.1f) {
+            float luxOverride = mix(brightness1, brightness2, t);
+            setEstimatedBrightnessAndUpdate(controller, luxOverride);
+            float bias = mix(bias1, bias2, t);
+            assertEquals(controller.mPendingAmbientColorTemperature,
+                    mix(HIGH_LIGHT_AMBIENT_COLOR_TEMPERATURE, ambientColorTemperature, 1.0f - bias),
+                    0.01);
+        }
+
+        setEstimatedBrightnessAndUpdate(controller, brightness2 + 1.0f);
+        assertEquals(controller.mPendingAmbientColorTemperature,
+                HIGH_LIGHT_AMBIENT_COLOR_TEMPERATURE, 0.001);
+
+        setEstimatedBrightnessAndUpdate(controller, 0.0f);
+        assertEquals(controller.mPendingAmbientColorTemperature, ambientColorTemperature, 0.001);
+    }
+
+    @Test
+    public void testSpline_InvalidCombinations() throws Exception {
+            setBrightnesses(100.0f, 200.0f);
+            setBiases(0.0f, 1.0f);
+            setHighLightBrightnesses(150.0f, 250.0f);
+            setHighLightBiases(0.0f, 1.0f);
+
+            DisplayWhiteBalanceController controller =
+                    DisplayWhiteBalanceFactory.create(mHandler, mSensorManagerMock, mResourcesSpy);
+            final float ambientColorTemperature = 8000.0f;
+            setEstimatedColorTemperature(controller, ambientColorTemperature);
+            controller.mBrightnessFilter = spy(controller.mBrightnessFilter);
+
+            for (float luxOverride = 0.1f; luxOverride <= 10000; luxOverride *= 10) {
+                setEstimatedBrightnessAndUpdate(controller, luxOverride);
+                assertEquals(controller.mPendingAmbientColorTemperature,
+                        ambientColorTemperature, 0.001);
+            }
+    }
+
+    @Test
+    public void testLowLight_DefaultAmbient() throws Exception {
+        final float lowerBrightness = 10.0f;
+        final float upperBrightness = 50.0f;
+        setBrightnesses(lowerBrightness, upperBrightness);
+        setBiases(0.0f, 1.0f);
+
+        DisplayWhiteBalanceController controller =
+                DisplayWhiteBalanceFactory.create(mHandler, mSensorManagerMock, mResourcesSpy);
+        final float ambientColorTemperature = -1.0f;
+        setEstimatedColorTemperature(controller, ambientColorTemperature);
+        controller.mBrightnessFilter = spy(controller.mBrightnessFilter);
+
+        for (float t = 0.0f; t <= 1.0f; t += 0.1f) {
+            setEstimatedBrightnessAndUpdate(controller,
+                    mix(lowerBrightness, upperBrightness, t));
+            assertEquals(controller.mPendingAmbientColorTemperature, ambientColorTemperature,
+                        0.001);
+        }
+
+        setEstimatedBrightnessAndUpdate(controller, 0.0f);
+        assertEquals(controller.mPendingAmbientColorTemperature, ambientColorTemperature, 0.001);
+
+        setEstimatedBrightnessAndUpdate(controller, upperBrightness + 1.0f);
+        assertEquals(controller.mPendingAmbientColorTemperature, ambientColorTemperature, 0.001);
+    }
+
+    void mockThrottler() {
+        when(mResourcesSpy.getInteger(
+                R.integer.config_displayWhiteBalanceDecreaseDebounce)).thenReturn(0);
+        when(mResourcesSpy.getInteger(
+                R.integer.config_displayWhiteBalanceIncreaseDebounce)).thenReturn(0);
+        TypedArray base = mResourcesSpy.obtainTypedArray(
+                R.array.config_displayWhiteBalanceBaseThresholds);
+        TypedArray inc = mResourcesSpy.obtainTypedArray(
+                R.array.config_displayWhiteBalanceIncreaseThresholds);
+        TypedArray dec = mResourcesSpy.obtainTypedArray(
+                R.array.config_displayWhiteBalanceDecreaseThresholds);
+        base = spy(base);
+        inc = spy(inc);
+        dec = spy(dec);
+        when(mResourcesSpy.obtainTypedArray(
+                R.array.config_displayWhiteBalanceBaseThresholds)).thenReturn(base);
+        when(mResourcesSpy.obtainTypedArray(
+                R.array.config_displayWhiteBalanceIncreaseThresholds)).thenReturn(inc);
+        when(mResourcesSpy.obtainTypedArray(
+                R.array.config_displayWhiteBalanceDecreaseThresholds)).thenReturn(dec);
+        setFloatArrayResource(base, new float[]{0.0f});
+        setFloatArrayResource(inc, new float[]{0.0f});
+        setFloatArrayResource(dec, new float[]{0.0f});
+    }
+
+    private void mockResourcesFloat(int id, float floatValue) {
+        doAnswer(new Answer<Void>() {
+            public Void answer(InvocationOnMock invocation) {
+                TypedValue value = (TypedValue)invocation.getArgument(1);
+                value.type = TypedValue.TYPE_FLOAT;
+                value.data = Float.floatToIntBits(floatValue);
+                return null;
+            }
+        }).when(mResourcesSpy).getValue(
+                eq(id),
+                any(TypedValue.class), eq(true));
+    }
+
+    private void setEstimatedColorTemperature(DisplayWhiteBalanceController controller,
+                                              float ambientColorTemperature) {
+        AmbientFilter colorTemperatureFilter = spy(controller.mColorTemperatureFilter);
+        controller.mColorTemperatureFilter = colorTemperatureFilter;
+        when(colorTemperatureFilter.getEstimate(anyLong())).thenReturn(ambientColorTemperature);
+    }
+
+    private void setEstimatedBrightnessAndUpdate(DisplayWhiteBalanceController controller,
+                                                 float brightness) {
+        when(controller.mBrightnessFilter.getEstimate(anyLong())).thenReturn(brightness);
+        controller.updateAmbientColorTemperature();
+    }
+
+    private void setBrightnesses(float... vals) {
+        setFloatArrayResource(mBrightnesses, vals);
+    }
+
+    private void setBiases(float... vals) {
+        setFloatArrayResource(mBiases, vals);
+    }
+
+    private void setHighLightBrightnesses(float... vals) {
+        setFloatArrayResource(mHighLightBrightnesses, vals);
+    }
+
+    private void setHighLightBiases(float... vals) {
+        setFloatArrayResource(mHighLightBiases, vals);
+    }
+
+    private void setFloatArrayResource(TypedArray array, float[] vals) {
+        when(array.length()).thenReturn(vals.length);
+        for (int i = 0; i < vals.length; i++) {
+            when(array.getFloat(i, Float.NaN)).thenReturn(vals[i]);
+        }
+    }
+
+    private void setSensorType(Sensor sensor, int type, String strType) throws Exception {
+        Method setter = Sensor.class.getDeclaredMethod("setType", Integer.TYPE);
+        setter.setAccessible(true);
+        setter.invoke(sensor, type);
+        if (strType != null) {
+            Field f = sensor.getClass().getDeclaredField("mStringType");
+            f.setAccessible(true);
+            f.set(sensor, strType);
+        }
+    }
+
+    private Sensor createSensor(int type, String strType) throws Exception {
+        Constructor<Sensor> constr = Sensor.class.getDeclaredConstructor();
+        constr.setAccessible(true);
+        Sensor sensor = constr.newInstance();
+        setSensorType(sensor, type, strType);
+        return sensor;
+    }
+
+    private TypedArray createTypedArray() throws Exception {
+        TypedArray mockArray = mock(TypedArray.class);
+        return mockArray;
+    }
+
+    private static float mix(float a, float b, float t) {
+        return (1.0f - t) * a + t * b;
+    }
+}
diff --git a/services/tests/servicestests/src/com/android/server/locksettings/LockSettingsServiceTestable.java b/services/tests/servicestests/src/com/android/server/locksettings/LockSettingsServiceTestable.java
index f85e2cc..5c67d04 100644
--- a/services/tests/servicestests/src/com/android/server/locksettings/LockSettingsServiceTestable.java
+++ b/services/tests/servicestests/src/com/android/server/locksettings/LockSettingsServiceTestable.java
@@ -110,7 +110,7 @@
         }
 
         @Override
-        public boolean hasEnrolledBiometrics() {
+        public boolean hasEnrolledBiometrics(int userId) {
             return false;
         }
 
diff --git a/services/tests/servicestests/src/com/android/server/power/AttentionDetectorTest.java b/services/tests/servicestests/src/com/android/server/power/AttentionDetectorTest.java
index a63f49b..4476918 100644
--- a/services/tests/servicestests/src/com/android/server/power/AttentionDetectorTest.java
+++ b/services/tests/servicestests/src/com/android/server/power/AttentionDetectorTest.java
@@ -42,6 +42,8 @@
 import android.test.AndroidTestCase;
 import android.test.suitebuilder.annotation.SmallTest;
 
+import com.android.server.wm.WindowManagerInternal;
+
 import org.junit.After;
 import org.junit.Before;
 import org.junit.Test;
@@ -57,6 +59,8 @@
     @Mock
     private AttentionManagerInternal mAttentionManagerInternal;
     @Mock
+    private WindowManagerInternal mWindowManagerInternal;
+    @Mock
     private Runnable mOnUserAttention;
     private TestableAttentionDetector mAttentionDetector;
     private long mAttentionTimeout;
@@ -71,6 +75,7 @@
                 PackageManager.PERMISSION_GRANTED);
         when(mAttentionManagerInternal.checkAttention(anyLong(), any()))
                 .thenReturn(true);
+        when(mWindowManagerInternal.isKeyguardShowingAndNotOccluded()).thenReturn(false);
         mAttentionDetector = new TestableAttentionDetector();
         mAttentionDetector.onWakefulnessChangeStarted(PowerManagerInternal.WAKEFULNESS_AWAKE);
         mAttentionDetector.setAttentionServiceSupported(true);
@@ -117,6 +122,15 @@
     }
 
     @Test
+    public void testOnUserActivity_doesntCheckIfInLockscreen() {
+        when(mWindowManagerInternal.isKeyguardShowingAndNotOccluded()).thenReturn(true);
+
+        long when = registerAttention();
+        verify(mAttentionManagerInternal, never()).checkAttention(anyLong(), any());
+        assertThat(mNextDimming).isEqualTo(when);
+    }
+
+    @Test
     public void testOnUserActivity_doesntCheckIfNotSufficientPermissions() {
         when(mPackageManager.checkPermission(any(), any())).thenReturn(
                 PackageManager.PERMISSION_DENIED);
@@ -299,6 +313,7 @@
         TestableAttentionDetector() {
             super(AttentionDetectorTest.this.mOnUserAttention, new Object());
             mAttentionManager = mAttentionManagerInternal;
+            mWindowManager = mWindowManagerInternal;
             mPackageManager = AttentionDetectorTest.this.mPackageManager;
             mContentResolver = getContext().getContentResolver();
             mMaximumExtensionMillis = 10000L;
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/uiservicestests/src/com/android/server/notification/BuzzBeepBlinkTest.java b/services/tests/uiservicestests/src/com/android/server/notification/BuzzBeepBlinkTest.java
index 6061d51..8c3373f 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/BuzzBeepBlinkTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/BuzzBeepBlinkTest.java
@@ -156,7 +156,7 @@
         mService.setUsageStats(mUsageStats);
         mService.setAccessibilityManager(accessibilityManager);
         mService.mScreenOn = false;
-        mService.mInCall = false;
+        mService.mInCallStateOffHook = false;
         mService.mNotificationPulseEnabled = true;
     }
 
@@ -681,7 +681,7 @@
         mService.buzzBeepBlinkLocked(r);
         Mockito.reset(mRingtonePlayer);
 
-        mService.mInCall = true;
+        mService.mInCallStateOffHook = true;
         mService.buzzBeepBlinkLocked(r);
 
         verify(mService, times(1)).playInCallNotification();
@@ -1137,7 +1137,7 @@
 
     @Test
     public void testLightsInCall() {
-        mService.mInCall = true;
+        mService.mInCallStateOffHook = true;
         NotificationRecord r = getLightsNotification();
         mService.buzzBeepBlinkLocked(r);
         verifyNeverLights();
diff --git a/services/tests/uiservicestests/src/com/android/server/slice/PinnedSliceStateTest.java b/services/tests/uiservicestests/src/com/android/server/slice/PinnedSliceStateTest.java
index f5002ac..3b336eb 100644
--- a/services/tests/uiservicestests/src/com/android/server/slice/PinnedSliceStateTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/slice/PinnedSliceStateTest.java
@@ -7,10 +7,12 @@
 import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertNull;
 import static org.junit.Assert.assertTrue;
+import static org.mockito.ArgumentMatchers.any;
 import static org.mockito.ArgumentMatchers.anyInt;
 import static org.mockito.ArgumentMatchers.anyString;
 import static org.mockito.ArgumentMatchers.argThat;
 import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.doAnswer;
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
@@ -159,4 +161,25 @@
         verify(mSliceService).removePinnedSlice(eq(TEST_URI));
         assertFalse(mPinnedSliceManager.hasPinOrListener());
     }
+
+    @Test
+    public void testPinFailed() throws Exception {
+        // Throw exception when trying to pin
+        doAnswer(invocation -> {
+            throw new Exception("Pin failed");
+        }).when(mIContentProvider).call(
+                anyString(), anyString(), anyString(), eq(null), any());
+
+        TestableLooper.get(this).processAllMessages();
+
+        // When pinned for the first time, a pinned message should be sent.
+        mPinnedSliceManager.pin("pkg", FIRST_SPECS, mToken);
+        TestableLooper.get(this).processAllMessages();
+
+        verify(mIContentProvider).call(anyString(), anyString(), eq(SliceProvider.METHOD_PIN),
+                eq(null), argThat(b -> {
+                    assertEquals(TEST_URI, b.getParcelable(SliceProvider.EXTRA_BIND_URI));
+                    return true;
+                }));
+    }
 }
diff --git a/services/tests/wmtests/AndroidManifest.xml b/services/tests/wmtests/AndroidManifest.xml
index 2ce33fc..8c454424 100644
--- a/services/tests/wmtests/AndroidManifest.xml
+++ b/services/tests/wmtests/AndroidManifest.xml
@@ -50,6 +50,9 @@
         <activity android:name="com.android.server.wm.TaskStackChangedListenerTest$ActivityRequestedOrientationChange" />
         <activity android:name="com.android.server.wm.TaskStackChangedListenerTest$ActivityTaskChangeCallbacks" />
         <activity android:name="com.android.server.wm.TaskStackChangedListenerTest$ActivityTaskDescriptionChange" />
+        <activity android:name="com.android.server.wm.TaskStackChangedListenerTest$ActivityViewTestActivity" />
+        <activity android:name="com.android.server.wm.TaskStackChangedListenerTest$ActivityInActivityView"
+                  android:resizeableActivity="true" />
         <activity android:name="com.android.server.wm.ScreenDecorWindowTests$TestActivity"
                   android:showWhenLocked="true" />
     </application>
diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java b/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java
index 8fbb7f5..4608c3b 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java
@@ -16,6 +16,7 @@
 
 package com.android.server.wm;
 
+import static android.os.Process.NOBODY_UID;
 import static android.view.Display.DEFAULT_DISPLAY;
 import static android.view.Surface.ROTATION_0;
 import static android.view.Surface.ROTATION_90;
@@ -40,6 +41,8 @@
 import static com.android.server.wm.ActivityStack.STACK_VISIBILITY_VISIBLE;
 import static com.android.server.wm.ActivityStack.STACK_VISIBILITY_VISIBLE_BEHIND_TRANSLUCENT;
 
+import static com.google.common.truth.Truth.assertThat;
+
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertNotEquals;
@@ -54,8 +57,10 @@
 import android.app.servertransaction.ActivityConfigurationChangeItem;
 import android.app.servertransaction.ClientTransaction;
 import android.app.servertransaction.PauseActivityItem;
+import android.content.ComponentName;
 import android.content.pm.ActivityInfo;
 import android.content.res.Configuration;
+import android.content.res.Resources;
 import android.graphics.Rect;
 import android.platform.test.annotations.Presubmit;
 import android.util.MergedConfiguration;
@@ -67,6 +72,7 @@
 
 import androidx.test.filters.MediumTest;
 
+import com.android.internal.R;
 import com.android.server.wm.utils.WmDisplayCutout;
 
 import org.junit.Before;
@@ -605,6 +611,15 @@
         assertNull(mActivity.pendingOptions);
     }
 
+    @Test
+    public void testCanLaunchHomeActivityFromChooser() {
+        ComponentName chooserComponent = ComponentName.unflattenFromString(
+                Resources.getSystem().getString(R.string.config_chooserActivity));
+        ActivityRecord chooserActivity = new ActivityBuilder(mService).setComponent(
+                chooserComponent).build();
+        assertThat(mActivity.canLaunchHomeActivity(NOBODY_UID, chooserActivity)).isTrue();
+    }
+
     /** Setup {@link #mActivity} as a size-compat-mode-able activity without fixed orientation. */
     private void prepareFixedAspectRatioUnresizableActivity() {
         setupDisplayContentForCompatDisplayInsets();
diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityStarterTests.java b/services/tests/wmtests/src/com/android/server/wm/ActivityStarterTests.java
index a08923b..3d94467 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ActivityStarterTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ActivityStarterTests.java
@@ -842,4 +842,51 @@
         // Ensure the activity is moved to secondary display.
         assertEquals(secondaryDisplay, topActivity.getDisplay());
     }
+
+    /**
+     * This test ensures that starting an activity with the freeze-task-list activity option will
+     * actually freeze the task list
+     */
+    @Test
+    public void testFreezeTaskListActivityOption() {
+        RecentTasks recentTasks = mock(RecentTasks.class);
+        mService.mStackSupervisor.setRecentTasks(recentTasks);
+        doReturn(true).when(recentTasks).isCallerRecents(anyInt());
+
+        final ActivityStarter starter = prepareStarter(0 /* flags */);
+        final ActivityOptions options = ActivityOptions.makeBasic();
+        options.setFreezeRecentTasksReordering();
+
+        starter.setReason("testFreezeTaskListActivityOption")
+                .setActivityOptions(new SafeActivityOptions(options))
+                .execute();
+
+        verify(recentTasks, times(1)).setFreezeTaskListReordering();
+        verify(recentTasks, times(0)).resetFreezeTaskListReorderingOnTimeout();
+    }
+
+    /**
+     * This test ensures that if we froze the task list as a part of starting an activity that fails
+     * to start, that we also reset the task list.
+     */
+    @Test
+    public void testFreezeTaskListActivityOptionFailedStart_expectResetFreezeTaskList() {
+        RecentTasks recentTasks = mock(RecentTasks.class);
+        mService.mStackSupervisor.setRecentTasks(recentTasks);
+        doReturn(true).when(recentTasks).isCallerRecents(anyInt());
+
+        final ActivityStarter starter = prepareStarter(0 /* flags */);
+        final ActivityOptions options = ActivityOptions.makeBasic();
+        options.setFreezeRecentTasksReordering();
+
+        starter.setReason("testFreezeTaskListActivityOptionFailedStart")
+                .setActivityOptions(new SafeActivityOptions(options))
+                .execute();
+
+        // Simulate a failed start
+        starter.postStartActivityProcessing(null, START_ABORTED, null);
+
+        verify(recentTasks, times(1)).setFreezeTaskListReordering();
+        verify(recentTasks, times(1)).resetFreezeTaskListReorderingOnTimeout();
+    }
 }
diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityTestsBase.java b/services/tests/wmtests/src/com/android/server/wm/ActivityTestsBase.java
index 4986a6d..ecf3acd 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ActivityTestsBase.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ActivityTestsBase.java
@@ -85,6 +85,7 @@
 
 import java.io.File;
 import java.util.List;
+import java.util.function.Consumer;
 
 /**
  * A base class to handle common operations in activity related unit tests.
@@ -169,8 +170,12 @@
      * Delegates task creation to {@link #TaskBuilder} to avoid the dependency of window hierarchy
      * when starting activity in unit tests.
      */
-    void mockTaskRecordFactory() {
-        final TaskRecord task = new TaskBuilder(mSupervisor).setCreateStack(false).build();
+    void mockTaskRecordFactory(Consumer<TaskBuilder> taskBuilderSetup) {
+        final TaskBuilder taskBuilder = new TaskBuilder(mSupervisor).setCreateStack(false);
+        if (taskBuilderSetup != null) {
+            taskBuilderSetup.accept(taskBuilder);
+        }
+        final TaskRecord task = taskBuilder.build();
         final TaskRecordFactory factory = mock(TaskRecordFactory.class);
         TaskRecord.setTaskRecordFactory(factory);
         doReturn(task).when(factory).create(any() /* service */, anyInt() /* taskId */,
@@ -178,6 +183,10 @@
                 any() /* voiceInteractor */);
     }
 
+    void mockTaskRecordFactory() {
+        mockTaskRecordFactory(null /* taskBuilderSetup */);
+    }
+
     /**
      * Builder for creating new activities.
      */
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/HighRefreshRateBlacklistTest.java b/services/tests/wmtests/src/com/android/server/wm/HighRefreshRateBlacklistTest.java
index 5586726..cd90462 100644
--- a/services/tests/wmtests/src/com/android/server/wm/HighRefreshRateBlacklistTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/HighRefreshRateBlacklistTest.java
@@ -16,71 +16,153 @@
 
 package com.android.server.wm;
 
+import static android.hardware.display.DisplayManager.DeviceConfig.KEY_HIGH_REFRESH_RATE_BLACKLIST;
+
 import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertTrue;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
 
+import android.content.res.Resources;
 import android.platform.test.annotations.Presubmit;
+import android.provider.DeviceConfig;
+import android.util.Pair;
 
-import androidx.test.filters.FlakyTest;
 import androidx.test.filters.SmallTest;
 
-import com.android.server.wm.HighRefreshRateBlacklist.SystemPropertyGetter;
+import com.android.internal.R;
+import com.android.server.wm.HighRefreshRateBlacklist.DeviceConfigInterface;
 
 import org.junit.Test;
 
+import java.util.ArrayList;
+import java.util.List;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.Executor;
+import java.util.concurrent.TimeUnit;
+
 /**
  * Build/Install/Run:
- *  atest WmTests:HighRefreshRateBlacklistTest
+ * atest WmTests:HighRefreshRateBlacklistTest
  */
 @SmallTest
 @Presubmit
-@FlakyTest
 public class HighRefreshRateBlacklistTest {
 
     @Test
-    public void testBlacklist() {
-        HighRefreshRateBlacklist blacklist = new HighRefreshRateBlacklist(
-                new SystemPropertyGetter() {
-
-                    @Override
-                    public int getInt(String key, int def) {
-                        if ("ro.window_manager.high_refresh_rate_blacklist_length".equals(key)) {
-                            return 2;
-                        }
-                        return def;
-                    }
-
-                    @Override
-                    public String get(String key) {
-                        if ("ro.window_manager.high_refresh_rate_blacklist_entry1".equals(key)) {
-                            return "com.android.sample1";
-                        }
-                        if ("ro.window_manager.high_refresh_rate_blacklist_entry2".equals(key)) {
-                            return "com.android.sample2";
-                        }
-                        return "";
-                    }
-                });
+    public void testDefaultBlacklist() {
+        final Resources r = createResources("com.android.sample1", "com.android.sample2");
+        HighRefreshRateBlacklist blacklist =
+                new HighRefreshRateBlacklist(r, new FakeDeviceConfigInterface());
         assertTrue(blacklist.isBlacklisted("com.android.sample1"));
         assertTrue(blacklist.isBlacklisted("com.android.sample2"));
         assertFalse(blacklist.isBlacklisted("com.android.sample3"));
     }
 
     @Test
-    public void testNoBlacklist() {
-        HighRefreshRateBlacklist blacklist = new HighRefreshRateBlacklist(
-                new SystemPropertyGetter() {
-
-                    @Override
-                    public int getInt(String key, int def) {
-                        return def;
-                    }
-
-                    @Override
-                    public String get(String key) {
-                        return "";
-                    }
-                });
+    public void testNoDefaultBlacklist() {
+        final Resources r = createResources();
+        HighRefreshRateBlacklist blacklist =
+                new HighRefreshRateBlacklist(r, new FakeDeviceConfigInterface());
         assertFalse(blacklist.isBlacklisted("com.android.sample1"));
     }
+
+    @Test
+    public void testDefaultBlacklistIsOverriddenByDeviceConfig() {
+        final Resources r = createResources("com.android.sample1");
+        final FakeDeviceConfigInterface config = new FakeDeviceConfigInterface();
+        config.setBlacklist("com.android.sample2,com.android.sample3");
+        HighRefreshRateBlacklist blacklist = new HighRefreshRateBlacklist(r, config);
+        assertFalse(blacklist.isBlacklisted("com.android.sample1"));
+        assertTrue(blacklist.isBlacklisted("com.android.sample2"));
+        assertTrue(blacklist.isBlacklisted("com.android.sample3"));
+    }
+
+    @Test
+    public void testDefaultBlacklistIsOverriddenByEmptyDeviceConfig() {
+        final Resources r = createResources("com.android.sample1");
+        final FakeDeviceConfigInterface config = new FakeDeviceConfigInterface();
+        config.setBlacklist("");
+        HighRefreshRateBlacklist blacklist = new HighRefreshRateBlacklist(r, config);
+        assertFalse(blacklist.isBlacklisted("com.android.sample1"));
+    }
+
+    @Test
+    public void testDefaultBlacklistIsOverriddenByDeviceConfigUpdate() {
+        final Resources r = createResources("com.android.sample1");
+        final FakeDeviceConfigInterface config = new FakeDeviceConfigInterface();
+        HighRefreshRateBlacklist blacklist = new HighRefreshRateBlacklist(r, config);
+
+        // First check that the default blacklist is in effect
+        assertTrue(blacklist.isBlacklisted("com.android.sample1"));
+        assertFalse(blacklist.isBlacklisted("com.android.sample2"));
+        assertFalse(blacklist.isBlacklisted("com.android.sample3"));
+
+        //  Then confirm that the DeviceConfig list has propagated and taken effect.
+        config.setBlacklist("com.android.sample2,com.android.sample3");
+        assertFalse(blacklist.isBlacklisted("com.android.sample1"));
+        assertTrue(blacklist.isBlacklisted("com.android.sample2"));
+        assertTrue(blacklist.isBlacklisted("com.android.sample3"));
+
+        //  Finally make sure we go back to the default list if the DeviceConfig gets deleted.
+        config.setBlacklist(null);
+        assertTrue(blacklist.isBlacklisted("com.android.sample1"));
+        assertFalse(blacklist.isBlacklisted("com.android.sample2"));
+        assertFalse(blacklist.isBlacklisted("com.android.sample3"));
+    }
+
+    private Resources createResources(String... defaultBlacklist) {
+        Resources r = mock(Resources.class);
+        when(r.getStringArray(R.array.config_highRefreshRateBlacklist))
+                .thenReturn(defaultBlacklist);
+        return r;
+    }
+
+
+    class FakeDeviceConfigInterface implements DeviceConfigInterface {
+        private List<Pair<DeviceConfig.OnPropertyChangedListener, Executor>> mListeners =
+                new ArrayList<>();
+        private String mBlacklist;
+
+        @Override
+        public String getProperty(String namespace, String name) {
+            if (!DeviceConfig.NAMESPACE_DISPLAY_MANAGER.equals(namespace)
+                    || !KEY_HIGH_REFRESH_RATE_BLACKLIST.equals(name)) {
+                throw new IllegalArgumentException("Only things in NAMESPACE_DISPLAY_MANAGER "
+                        + "supported.");
+            }
+            return mBlacklist;
+        }
+
+        @Override
+        public void addOnPropertyChangedListener(String namespace, Executor executor,
+                DeviceConfig.OnPropertyChangedListener listener) {
+
+            if (!DeviceConfig.NAMESPACE_DISPLAY_MANAGER.equals(namespace)) {
+                throw new IllegalArgumentException("Only things in NAMESPACE_DISPLAY_MANAGER "
+                        + "supported.");
+            }
+            mListeners.add(new Pair<>(listener, executor));
+        }
+
+        void setBlacklist(String blacklist) {
+            mBlacklist = blacklist;
+            CountDownLatch latch = new CountDownLatch(mListeners.size());
+            for (Pair<DeviceConfig.OnPropertyChangedListener, Executor> listenerInfo :
+                    mListeners) {
+                final Executor executor = listenerInfo.second;
+                final DeviceConfig.OnPropertyChangedListener listener = listenerInfo.first;
+                executor.execute(() -> {
+                    listener.onPropertyChanged(DeviceConfig.NAMESPACE_DISPLAY_MANAGER,
+                            KEY_HIGH_REFRESH_RATE_BLACKLIST, blacklist);
+                    latch.countDown();
+                });
+            }
+            try {
+                latch.await(10, TimeUnit.SECONDS);
+            } catch (InterruptedException e) {
+                throw new RuntimeException("Failed to notify all blacklist listeners in time.", e);
+            }
+        }
+    }
 }
diff --git a/services/tests/wmtests/src/com/android/server/wm/RecentsAnimationControllerTest.java b/services/tests/wmtests/src/com/android/server/wm/RecentsAnimationControllerTest.java
index 26cd63c..cd292b2 100644
--- a/services/tests/wmtests/src/com/android/server/wm/RecentsAnimationControllerTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/RecentsAnimationControllerTest.java
@@ -25,6 +25,7 @@
 
 import static com.android.dx.mockito.inline.extended.ExtendedMockito.atLeast;
 import static com.android.dx.mockito.inline.extended.ExtendedMockito.doNothing;
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn;
 import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn;
 import static com.android.dx.mockito.inline.extended.ExtendedMockito.verify;
 import static com.android.dx.mockito.inline.extended.ExtendedMockito.verifyNoMoreInteractions;
@@ -35,10 +36,12 @@
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
 import static org.junit.Assert.assertTrue;
 import static org.junit.Assert.fail;
 import static org.mockito.ArgumentMatchers.any;
 import static org.mockito.ArgumentMatchers.anyBoolean;
+import static org.mockito.ArgumentMatchers.anyInt;
 import static org.mockito.ArgumentMatchers.eq;
 
 import android.os.Binder;
@@ -79,6 +82,7 @@
             // Hold the lock to protect the stubbing from being accessed by other threads.
             spyOn(mWm.mRoot);
             doNothing().when(mWm.mRoot).performSurfacePlacement(anyBoolean());
+            doReturn(mDisplayContent).when(mWm.mRoot).getDisplayContent(anyInt());
         }
         when(mMockRunner.asBinder()).thenReturn(new Binder());
         mController = new RecentsAnimationController(mWm, mMockRunner, mAnimationCallbacks,
@@ -135,7 +139,7 @@
         hiddenAppWindow.setHidden(true);
         mDisplayContent.getConfiguration().windowConfiguration.setRotation(
                 mDisplayContent.getRotation());
-        mController.initialize(mDisplayContent, ACTIVITY_TYPE_HOME, new SparseBooleanArray());
+        mController.initialize(ACTIVITY_TYPE_HOME, new SparseBooleanArray());
 
         // Ensure that we are animating the target activity as well
         assertTrue(mController.isAnimatingTask(homeAppWindow.getTask()));
@@ -144,7 +148,7 @@
     }
 
     @Test
-    public void testCancelAnimationWithScreenShot() throws Exception {
+    public void testDeferCancelAnimation() throws Exception {
         mWm.setRecentsAnimationController(mController);
         final AppWindowToken appWindow = createAppWindowToken(mDisplayContent,
                 WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD);
@@ -156,8 +160,31 @@
         mController.addAnimation(appWindow.getTask(), false /* isRecentTaskInvisible */);
         assertTrue(mController.isAnimatingTask(appWindow.getTask()));
 
-        mController.setCancelWithDeferredScreenshotLocked(true);
-        mController.cancelAnimationWithScreenShot();
+        mController.setDeferredCancel(true /* deferred */, false /* screenshot */);
+        mController.cancelAnimationWithScreenshot(false /* screenshot */);
+        verify(mMockRunner).onAnimationCanceled(false /* deferredWithScreenshot */);
+        assertNull(mController.mRecentScreenshotAnimator);
+
+        // Simulate the app transition finishing
+        mController.mAppTransitionListener.onAppTransitionStartingLocked(0, 0, 0, 0);
+        verify(mAnimationCallbacks).onAnimationFinished(REORDER_KEEP_IN_PLACE, true, false);
+    }
+
+    @Test
+    public void testDeferCancelAnimationWithScreenShot() throws Exception {
+        mWm.setRecentsAnimationController(mController);
+        final AppWindowToken appWindow = createAppWindowToken(mDisplayContent,
+                WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD);
+        final WindowState win1 = createWindow(null, TYPE_BASE_APPLICATION, appWindow, "win1");
+        appWindow.addWindow(win1);
+        assertEquals(appWindow.getTask().getTopVisibleAppToken(), appWindow);
+        assertEquals(appWindow.findMainWindow(), win1);
+
+        mController.addAnimation(appWindow.getTask(), false /* isRecentTaskInvisible */);
+        assertTrue(mController.isAnimatingTask(appWindow.getTask()));
+
+        mController.setDeferredCancel(true /* deferred */, true /* screenshot */);
+        mController.cancelAnimationWithScreenshot(true /* screenshot */);
         verify(mMockRunner).onAnimationCanceled(true /* deferredWithScreenshot */);
         assertNotNull(mController.mRecentScreenshotAnimator);
         assertTrue(mController.mRecentScreenshotAnimator.isAnimating());
@@ -185,7 +212,7 @@
 
         // Assume appWindow transition should animate when no
         // IRecentsAnimationController#setCancelWithDeferredScreenshot called.
-        assertFalse(mController.shouldCancelWithDeferredScreenshot());
+        assertFalse(mController.shouldDeferCancelWithScreenshot());
         assertTrue(appWindow.shouldAnimate(TRANSIT_ACTIVITY_CLOSE));
     }
 
diff --git a/services/tests/wmtests/src/com/android/server/wm/RecentsAnimationTest.java b/services/tests/wmtests/src/com/android/server/wm/RecentsAnimationTest.java
index 1f8b33e..0e119e3 100644
--- a/services/tests/wmtests/src/com/android/server/wm/RecentsAnimationTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/RecentsAnimationTest.java
@@ -42,8 +42,11 @@
 import static org.mockito.ArgumentMatchers.anyBoolean;
 import static org.mockito.ArgumentMatchers.anyInt;
 
+import android.app.IApplicationThread;
 import android.content.ComponentName;
 import android.content.Intent;
+import android.content.pm.ActivityInfo;
+import android.content.pm.ApplicationInfo;
 import android.platform.test.annotations.Presubmit;
 import android.view.IRecentsAnimationRunner;
 
@@ -111,6 +114,57 @@
     }
 
     @Test
+    public void testPreloadRecentsActivity() {
+        // Ensure that the fake recent component can be resolved by the recents intent.
+        mockTaskRecordFactory(builder -> builder.setComponent(mRecentsComponent));
+        ActivityInfo aInfo = new ActivityInfo();
+        aInfo.applicationInfo = new ApplicationInfo();
+        aInfo.applicationInfo.uid = 10001;
+        aInfo.applicationInfo.targetSdkVersion = mContext.getApplicationInfo().targetSdkVersion;
+        aInfo.packageName = aInfo.applicationInfo.packageName = mRecentsComponent.getPackageName();
+        aInfo.processName = "recents";
+        doReturn(aInfo).when(mSupervisor).resolveActivity(any() /* intent */, any() /* rInfo */,
+                anyInt() /* startFlags */, any() /* profilerInfo */);
+
+        // Assume its process is alive because the caller should be the recents service.
+        WindowProcessController wpc = new WindowProcessController(mService, aInfo.applicationInfo,
+                aInfo.processName, aInfo.applicationInfo.uid, 0 /* userId */,
+                mock(Object.class) /* owner */, mock(WindowProcessListener.class));
+        wpc.setThread(mock(IApplicationThread.class));
+        doReturn(wpc).when(mService).getProcessController(eq(wpc.mName), eq(wpc.mUid));
+
+        Intent recentsIntent = new Intent().setComponent(mRecentsComponent);
+        // Null animation indicates to preload.
+        mService.startRecentsActivity(recentsIntent, null /* assistDataReceiver */,
+                null /* recentsAnimationRunner */);
+
+        ActivityDisplay display = mRootActivityContainer.getDefaultDisplay();
+        ActivityStack recentsStack = display.getStack(WINDOWING_MODE_FULLSCREEN,
+                ACTIVITY_TYPE_RECENTS);
+        assertThat(recentsStack).isNotNull();
+
+        ActivityRecord recentsActivity = recentsStack.getTopActivity();
+        // The activity is started in background so it should be invisible and will be stopped.
+        assertThat(recentsActivity).isNotNull();
+        assertThat(mSupervisor.mStoppingActivities).contains(recentsActivity);
+        assertFalse(recentsActivity.visible);
+
+        // Assume it is stopped to test next use case.
+        recentsActivity.activityStoppedLocked(null /* newIcicle */, null /* newPersistentState */,
+                null /* description */);
+        mSupervisor.mStoppingActivities.remove(recentsActivity);
+
+        spyOn(recentsActivity);
+        // Start when the recents activity exists. It should ensure the configuration.
+        mService.startRecentsActivity(recentsIntent, null /* assistDataReceiver */,
+                null /* recentsAnimationRunner */);
+
+        verify(recentsActivity).ensureActivityConfiguration(anyInt() /* globalChanges */,
+                anyBoolean() /* preserveWindow */, eq(true) /* ignoreVisibility */);
+        assertThat(mSupervisor.mStoppingActivities).contains(recentsActivity);
+    }
+
+    @Test
     public void testRestartRecentsActivity() throws Exception {
         // Have a recents activity that is not attached to its process (ActivityRecord.app = null).
         ActivityDisplay display = mRootActivityContainer.getDefaultDisplay();
@@ -220,12 +274,13 @@
 
         // Assume recents animation already started, set a state that cancel recents animation
         // with screenshot.
-        doReturn(true).when(mRecentsAnimationController).shouldCancelWithDeferredScreenshot();
+        doReturn(true).when(mRecentsAnimationController).shouldDeferCancelUntilNextTransition();
+        doReturn(true).when(mRecentsAnimationController).shouldDeferCancelWithScreenshot();
         // Start another fullscreen activity.
         fullscreenStack2.moveToFront("Activity start");
 
-        // Ensure that the recents animation was canceled by cancelOnNextTransitionStart().
-        verify(mRecentsAnimationController, times(1)).cancelOnNextTransitionStart();
+        // Ensure that the recents animation was canceled by setCancelOnNextTransitionStart().
+        verify(mRecentsAnimationController, times(1)).setCancelOnNextTransitionStart();
     }
 
     @Test
@@ -261,7 +316,7 @@
         // Ensure that the recents animation was NOT canceled
         verify(mService.mWindowManager, times(0)).cancelRecentsAnimationSynchronously(
                 eq(REORDER_KEEP_IN_PLACE), any());
-        verify(mRecentsAnimationController, times(0)).cancelOnNextTransitionStart();
+        verify(mRecentsAnimationController, times(0)).setCancelOnNextTransitionStart();
     }
 
     @Test
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/TaskStackChangedListenerTest.java b/services/tests/wmtests/src/com/android/server/wm/TaskStackChangedListenerTest.java
index 62247d8..19fd93fe 100644
--- a/services/tests/wmtests/src/com/android/server/wm/TaskStackChangedListenerTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/TaskStackChangedListenerTest.java
@@ -16,6 +16,8 @@
 
 package com.android.server.wm;
 
+import static android.view.ViewGroup.LayoutParams.MATCH_PARENT;
+
 import static androidx.test.platform.app.InstrumentationRegistry.getInstrumentation;
 
 import static org.junit.Assert.assertEquals;
@@ -26,18 +28,22 @@
 import android.app.ActivityManager;
 import android.app.ActivityManager.TaskDescription;
 import android.app.ActivityTaskManager;
+import android.app.ActivityView;
 import android.app.IActivityManager;
 import android.app.ITaskStackListener;
+import android.app.Instrumentation;
 import android.app.Instrumentation.ActivityMonitor;
 import android.app.TaskStackListener;
 import android.content.ComponentName;
 import android.content.Context;
 import android.content.Intent;
 import android.content.pm.ActivityInfo;
+import android.os.Bundle;
 import android.os.RemoteException;
 import android.platform.test.annotations.Presubmit;
 import android.support.test.uiautomator.UiDevice;
 import android.text.TextUtils;
+import android.view.ViewGroup;
 
 import androidx.test.filters.FlakyTest;
 import androidx.test.filters.MediumTest;
@@ -231,6 +237,40 @@
         assertTrue(activity.mOnDetachedFromWindowCalled);
     }
 
+    @Test
+    public void testTaskOnSingleTaskDisplayDrawn() throws Exception {
+        final Instrumentation instrumentation = getInstrumentation();
+
+        final CountDownLatch activityViewReadyLatch = new CountDownLatch(1);
+        final CountDownLatch singleTaskDisplayDrawnLatch = new CountDownLatch(1);
+        registerTaskStackChangedListener(new TaskStackListener() {
+            @Override
+            public void onSingleTaskDisplayDrawn(int displayId) throws RemoteException {
+                singleTaskDisplayDrawnLatch.countDown();
+            }
+        });
+        final ActivityViewTestActivity activity =
+                (ActivityViewTestActivity) startTestActivity(ActivityViewTestActivity.class);
+        final ActivityView activityView = activity.getActivityView();
+        activityView.setCallback(new ActivityView.StateCallback() {
+            @Override
+            public void onActivityViewReady(ActivityView view) {
+                activityViewReadyLatch.countDown();
+            }
+
+            @Override
+            public void onActivityViewDestroyed(ActivityView view) {
+            }
+        });
+        waitForCallback(activityViewReadyLatch);
+
+        final Context context = instrumentation.getContext();
+        Intent intent = new Intent(context, ActivityInActivityView.class);
+        intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_MULTIPLE_TASK);
+        activityView.startActivity(intent);
+        waitForCallback(singleTaskDisplayDrawnLatch);
+    }
+
     /**
      * Starts the provided activity and returns the started instance.
      */
@@ -369,4 +409,29 @@
             mOnDetachedFromWindowCountDownLatch = countDownLatch;
         }
     }
+
+    public static class ActivityViewTestActivity extends TestActivity {
+        private ActivityView mActivityView;
+
+        @Override
+        public void onCreate(Bundle savedInstanceState) {
+            super.onCreate(savedInstanceState);
+
+            mActivityView = new ActivityView(this, null /* attrs */, 0 /* defStyle */,
+                    true /* singleTaskInstance */);
+            setContentView(mActivityView);
+
+            ViewGroup.LayoutParams layoutParams = mActivityView.getLayoutParams();
+            layoutParams.width = MATCH_PARENT;
+            layoutParams.height = MATCH_PARENT;
+            mActivityView.requestLayout();
+        }
+
+        ActivityView getActivityView() {
+            return mActivityView;
+        }
+    }
+
+    // Activity that has {@link android.R.attr#resizeableActivity} attribute set to {@code true}
+    public static class ActivityInActivityView extends TestActivity {}
 }
diff --git a/services/tests/wmtests/src/com/android/server/wm/TestIWindow.java b/services/tests/wmtests/src/com/android/server/wm/TestIWindow.java
index 83aa620..a758681 100644
--- a/services/tests/wmtests/src/com/android/server/wm/TestIWindow.java
+++ b/services/tests/wmtests/src/com/android/server/wm/TestIWindow.java
@@ -16,6 +16,7 @@
 
 package com.android.server.wm;
 
+import android.graphics.Point;
 import android.graphics.Rect;
 import android.os.Bundle;
 import android.os.ParcelFileDescriptor;
@@ -43,6 +44,10 @@
     }
 
     @Override
+    public void locationInParentDisplayChanged(Point offset) throws RemoteException {
+    }
+
+    @Override
     public void insetsChanged(InsetsState insetsState) throws RemoteException {
     }
 
diff --git a/services/tests/wmtests/src/com/android/server/wm/TestWindowManagerPolicy.java b/services/tests/wmtests/src/com/android/server/wm/TestWindowManagerPolicy.java
index d034f27..2e5ce69 100644
--- a/services/tests/wmtests/src/com/android/server/wm/TestWindowManagerPolicy.java
+++ b/services/tests/wmtests/src/com/android/server/wm/TestWindowManagerPolicy.java
@@ -142,7 +142,7 @@
 
     @Override
     public Animation createHiddenByKeyguardExit(boolean onWallpaper,
-            boolean goingToNotificationShade) {
+            boolean goingToNotificationShade, boolean subtleAnimation) {
         return null;
     }
 
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/services/voiceinteraction/java/com/android/server/soundtrigger/SoundTriggerHelper.java b/services/voiceinteraction/java/com/android/server/soundtrigger/SoundTriggerHelper.java
index 94352b2..9933756 100644
--- a/services/voiceinteraction/java/com/android/server/soundtrigger/SoundTriggerHelper.java
+++ b/services/voiceinteraction/java/com/android/server/soundtrigger/SoundTriggerHelper.java
@@ -104,8 +104,8 @@
     // This is an indirect indication of the microphone being open in some other application.
     private boolean mServiceDisabled = false;
 
-    // Whether we have ANY recognition (keyphrase or generic) running.
-    private boolean mRecognitionRunning = false;
+    // Whether ANY recognition (keyphrase or generic) has been requested.
+    private boolean mRecognitionRequested = false;
 
     private PowerSaveModeListener mPowerSaveModeListener;
 
@@ -252,11 +252,6 @@
                 }
             }
 
-            // Initialize power save, call active state monitoring logic.
-            if (!mRecognitionRunning) {
-                initializeTelephonyAndPowerStateListeners();
-            }
-
             // If the existing SoundModel is different (for the same UUID for Generic and same
             // keyphrase ID for voice), ensure that it is unloaded and stopped before proceeding.
             // This works for both keyphrase and generic models. This logic also ensures that a
@@ -326,8 +321,16 @@
             modelData.setRecognitionConfig(recognitionConfig);
             modelData.setSoundModel(soundModel);
 
-            return startRecognitionLocked(modelData,
+            int status = startRecognitionLocked(modelData,
                     false /* Don't notify for synchronous calls */);
+
+                                // Initialize power save, call active state monitoring logic.
+            if (status == STATUS_OK && !mRecognitionRequested) {
+                initializeTelephonyAndPowerStateListeners();
+                mRecognitionRequested = true;
+            }
+
+            return status;
         }
     }
 
@@ -450,7 +453,7 @@
             modelData.clearCallback();
             modelData.setRecognitionConfig(null);
 
-            if (!computeRecognitionRunningLocked()) {
+            if (!computeRecognitionRequestedLocked()) {
                 internalClearGlobalStateLocked();
             }
 
@@ -1196,20 +1199,20 @@
     }
 
     // Computes whether we have any recognition running at all (voice or generic). Sets
-    // the mRecognitionRunning variable with the result.
-    private boolean computeRecognitionRunningLocked() {
+    // the mRecognitionRequested variable with the result.
+    private boolean computeRecognitionRequestedLocked() {
         if (mModuleProperties == null || mModule == null) {
-            mRecognitionRunning = false;
-            return mRecognitionRunning;
+            mRecognitionRequested = false;
+            return mRecognitionRequested;
         }
         for (ModelData modelData : mModelDataMap.values()) {
-            if (modelData.isModelStarted()) {
-                mRecognitionRunning = true;
-                return mRecognitionRunning;
+            if (modelData.isRequested()) {
+                mRecognitionRequested = true;
+                return mRecognitionRequested;
             }
         }
-        mRecognitionRunning = false;
-        return mRecognitionRunning;
+        mRecognitionRequested = false;
+        return mRecognitionRequested;
     }
 
     // This class encapsulates the callbacks, state, handles and any other information that
diff --git a/services/voiceinteraction/java/com/android/server/soundtrigger/SoundTriggerService.java b/services/voiceinteraction/java/com/android/server/soundtrigger/SoundTriggerService.java
index 7a83469..a8cafb3 100644
--- a/services/voiceinteraction/java/com/android/server/soundtrigger/SoundTriggerService.java
+++ b/services/voiceinteraction/java/com/android/server/soundtrigger/SoundTriggerService.java
@@ -61,6 +61,7 @@
 import android.os.ParcelUuid;
 import android.os.PowerManager;
 import android.os.RemoteException;
+import android.os.SystemClock;
 import android.os.UserHandle;
 import android.provider.Settings;
 import android.util.ArrayMap;
@@ -75,6 +76,7 @@
 import java.io.FileDescriptor;
 import java.io.PrintWriter;
 import java.util.ArrayList;
+import java.util.Map;
 import java.util.TreeMap;
 import java.util.UUID;
 import java.util.concurrent.TimeUnit;
@@ -102,6 +104,80 @@
     private Object mCallbacksLock;
     private final TreeMap<UUID, IRecognitionStatusCallback> mCallbacks;
 
+    class SoundModelStatTracker {
+        private class SoundModelStat {
+            SoundModelStat() {
+                mStartCount = 0;
+                mTotalTimeMsec = 0;
+                mLastStartTimestampMsec = 0;
+                mLastStopTimestampMsec = 0;
+                mIsStarted = false;
+            }
+            long mStartCount; // Number of times that given model started
+            long mTotalTimeMsec; // Total time (msec) that given model was running since boot
+            long mLastStartTimestampMsec; // SystemClock.elapsedRealtime model was last started
+            long mLastStopTimestampMsec; // SystemClock.elapsedRealtime model was last stopped
+            boolean mIsStarted; // true if model is currently running
+        }
+        private final TreeMap<UUID, SoundModelStat> mModelStats;
+
+        SoundModelStatTracker() {
+            mModelStats = new TreeMap<UUID, SoundModelStat>();
+        }
+
+        public synchronized void onStart(UUID id) {
+            SoundModelStat stat = mModelStats.get(id);
+            if (stat == null) {
+                stat = new SoundModelStat();
+                mModelStats.put(id, stat);
+            }
+
+            if (stat.mIsStarted) {
+                Slog.e(TAG, "error onStart(): Model " + id + " already started");
+                return;
+            }
+
+            stat.mStartCount++;
+            stat.mLastStartTimestampMsec = SystemClock.elapsedRealtime();
+            stat.mIsStarted = true;
+        }
+
+        public synchronized void onStop(UUID id) {
+            SoundModelStat stat = mModelStats.get(id);
+            if (stat == null) {
+                Slog.e(TAG, "error onStop(): Model " + id + " has no stats available");
+                return;
+            }
+
+            if (!stat.mIsStarted) {
+                Slog.e(TAG, "error onStop(): Model " + id + " already stopped");
+                return;
+            }
+
+            stat.mLastStopTimestampMsec = SystemClock.elapsedRealtime();
+            stat.mTotalTimeMsec += stat.mLastStopTimestampMsec - stat.mLastStartTimestampMsec;
+            stat.mIsStarted = false;
+        }
+
+        public synchronized void dump(PrintWriter pw) {
+            long curTime = SystemClock.elapsedRealtime();
+            pw.println("Model Stats:");
+            for (Map.Entry<UUID, SoundModelStat> entry : mModelStats.entrySet()) {
+                UUID uuid = entry.getKey();
+                SoundModelStat stat = entry.getValue();
+                long totalTimeMsec = stat.mTotalTimeMsec;
+                if (stat.mIsStarted) {
+                    totalTimeMsec += curTime - stat.mLastStartTimestampMsec;
+                }
+                pw.println(uuid + ", total_time(msec)=" + totalTimeMsec
+                        + ", total_count=" + stat.mStartCount
+                        + ", last_start=" + stat.mLastStartTimestampMsec
+                        + ", last_stop=" + stat.mLastStopTimestampMsec);
+            }
+        }
+    }
+
+    private final SoundModelStatTracker mSoundModelStatTracker;
     /** Number of ops run by the {@link RemoteSoundTriggerDetectionService} per package name */
     @GuardedBy("mLock")
     private final ArrayMap<String, NumOps> mNumOpsPerPackage = new ArrayMap<>();
@@ -115,6 +191,7 @@
         mCallbacksLock = new Object();
         mCallbacks = new TreeMap<>();
         mLock = new Object();
+        mSoundModelStatTracker = new SoundModelStatTracker();
     }
 
     @Override
@@ -193,8 +270,12 @@
                 return STATUS_ERROR;
             }
 
-            return mSoundTriggerHelper.startGenericRecognition(parcelUuid.getUuid(), model,
+            int ret = mSoundTriggerHelper.startGenericRecognition(parcelUuid.getUuid(), model,
                     callback, config);
+            if (ret == STATUS_OK) {
+                mSoundModelStatTracker.onStart(parcelUuid.getUuid());
+            }
+            return ret;
         }
 
         @Override
@@ -208,7 +289,12 @@
                     + parcelUuid));
 
             if (!isInitialized()) return STATUS_ERROR;
-            return mSoundTriggerHelper.stopGenericRecognition(parcelUuid.getUuid(), callback);
+
+            int ret = mSoundTriggerHelper.stopGenericRecognition(parcelUuid.getUuid(), callback);
+            if (ret == STATUS_OK) {
+                mSoundModelStatTracker.onStop(parcelUuid.getUuid());
+            }
+            return ret;
         }
 
         @Override
@@ -252,6 +338,9 @@
             // Unload the model if it is loaded.
             mSoundTriggerHelper.unloadGenericSoundModel(soundModelId.getUuid());
             mDbHelper.deleteGenericSoundModel(soundModelId.getUuid());
+
+            // Stop recognition if it is started.
+            mSoundModelStatTracker.onStop(soundModelId.getUuid());
         }
 
         @Override
@@ -403,6 +492,8 @@
                 synchronized (mCallbacksLock) {
                     mCallbacks.put(soundModelId.getUuid(), callback);
                 }
+
+                mSoundModelStatTracker.onStart(soundModelId.getUuid());
             }
             return STATUS_OK;
         }
@@ -467,6 +558,8 @@
                 synchronized (mCallbacksLock) {
                     mCallbacks.remove(soundModelId.getUuid());
                 }
+
+                mSoundModelStatTracker.onStop(soundModelId.getUuid());
             }
             return STATUS_OK;
         }
@@ -1266,6 +1359,9 @@
             mSoundTriggerHelper.dump(fd, pw, args);
             // log
             sEventLogger.dump(pw);
+
+            // stats
+            mSoundModelStatTracker.dump(pw);
         }
 
         private synchronized boolean isInitialized() {
diff --git a/telephony/java/android/telephony/CarrierConfigManager.java b/telephony/java/android/telephony/CarrierConfigManager.java
index acf4681..2ffc825 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>
@@ -1018,6 +1026,18 @@
             "call_forwarding_map_non_number_to_voicemail_bool";
 
     /**
+     * When {@code true}, the phone will always tell the IMS stack to keep RTT enabled and
+     * determine on a per-call basis (based on extras from the dialer app) whether a call should be
+     * an RTT call or not.
+     *
+     * When {@code false}, the old behavior is used, where the toggle in accessibility settings is
+     * used to set the IMS stack's RTT enabled state.
+     * @hide
+     */
+    public static final String KEY_IGNORE_RTT_MODE_SETTING_BOOL =
+            "ignore_rtt_mode_setting_bool";
+
+    /**
      * Determines whether conference calls are supported by a carrier.  When {@code true},
      * conference calling is supported, {@code false otherwise}.
      */
@@ -1413,6 +1433,13 @@
             "show_4g_for_lte_data_icon_bool";
 
     /**
+     * Boolean indicating if default data account should show 4G icon when in 3G.
+     * @hide
+     */
+    public static final String KEY_SHOW_4G_FOR_3G_DATA_ICON_BOOL =
+            "show_4g_for_3g_data_icon_bool";
+
+    /**
      * Boolean indicating if lte+ icon should be shown if available
      * @hide
      */
@@ -2151,6 +2178,15 @@
             "data_warning_notification_bool";
 
     /**
+     * Controls if the device should automatically warn the user that sim voice & data function
+     * might be limited due to dual sim scenario. When set to {@true} display the notification,
+     * {@code false} otherwise.
+     * @hide
+     */
+    public static final String KEY_LIMITED_SIM_FUNCTION_NOTIFICATION_FOR_DSDS_BOOL =
+            "limited_sim_function_notification_for_dsds_bool";
+
+    /**
      * Controls the cellular data limit.
      * <p>
      * If the user uses more than this amount of data in their billing cycle, as defined by
@@ -2319,6 +2355,13 @@
     public static final String KEY_RTT_DOWNGRADE_SUPPORTED_BOOL = "rtt_downgrade_supported_bool";
 
     /**
+     * Indicates if the TTY HCO and VCO options should be hidden in the accessibility menu
+     * if the device is capable of RTT.
+     * @hide
+     */
+    public static final String KEY_HIDE_TTY_HCO_VCO_WITH_RTT_BOOL = "hide_tty_hco_vco_with_rtt";
+
+    /**
      * The flag to disable the popup dialog which warns the user of data charges.
      * @hide
      */
@@ -3098,6 +3141,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, "");
@@ -3235,6 +3279,7 @@
         sDefaults.putInt(KEY_IMS_DTMF_TONE_DELAY_INT, 0);
         sDefaults.putInt(KEY_CDMA_DTMF_TONE_DELAY_INT, 100);
         sDefaults.putBoolean(KEY_CALL_FORWARDING_MAP_NON_NUMBER_TO_VOICEMAIL_BOOL, false);
+        sDefaults.putBoolean(KEY_IGNORE_RTT_MODE_SETTING_BOOL, false);
         sDefaults.putInt(KEY_CDMA_3WAYCALL_FLASH_DELAY_INT , 0);
         sDefaults.putBoolean(KEY_SUPPORT_CONFERENCE_CALL_BOOL, true);
         sDefaults.putBoolean(KEY_SUPPORT_IMS_CONFERENCE_CALL_BOOL, true);
@@ -3352,6 +3397,7 @@
         sDefaults.putInt(KEY_MONTHLY_DATA_CYCLE_DAY_INT, DATA_CYCLE_USE_PLATFORM_DEFAULT);
         sDefaults.putLong(KEY_DATA_WARNING_THRESHOLD_BYTES_LONG, DATA_CYCLE_USE_PLATFORM_DEFAULT);
         sDefaults.putBoolean(KEY_DATA_WARNING_NOTIFICATION_BOOL, true);
+        sDefaults.putBoolean(KEY_LIMITED_SIM_FUNCTION_NOTIFICATION_FOR_DSDS_BOOL, false);
         sDefaults.putLong(KEY_DATA_LIMIT_THRESHOLD_BYTES_LONG, DATA_CYCLE_USE_PLATFORM_DEFAULT);
         sDefaults.putBoolean(KEY_DATA_LIMIT_NOTIFICATION_BOOL, true);
         sDefaults.putBoolean(KEY_DATA_RAPID_NOTIFICATION_BOOL, true);
@@ -3405,6 +3451,7 @@
         sDefaults.putBoolean(KEY_SHOW_IMS_REGISTRATION_STATUS_BOOL, false);
         sDefaults.putBoolean(KEY_RTT_SUPPORTED_BOOL, false);
         sDefaults.putBoolean(KEY_TTY_SUPPORTED_BOOL, true);
+        sDefaults.putBoolean(KEY_HIDE_TTY_HCO_VCO_WITH_RTT_BOOL, false);
         sDefaults.putBoolean(KEY_DISABLE_CHARGE_INDICATION_BOOL, false);
         sDefaults.putBoolean(KEY_SUPPORT_NO_REPLY_TIMER_FOR_CFNRY_BOOL, true);
         sDefaults.putStringArray(KEY_FEATURE_ACCESS_CODES_STRING_ARRAY, null);
@@ -3413,6 +3460,7 @@
         sDefaults.putBoolean(KEY_SPN_DISPLAY_RULE_USE_ROAMING_FROM_SERVICE_STATE_BOOL, false);
         sDefaults.putBoolean(KEY_ALWAYS_SHOW_DATA_RAT_ICON_BOOL, false);
         sDefaults.putBoolean(KEY_SHOW_4G_FOR_LTE_DATA_ICON_BOOL, false);
+        sDefaults.putBoolean(KEY_SHOW_4G_FOR_3G_DATA_ICON_BOOL, false);
         sDefaults.putString(KEY_OPERATOR_NAME_FILTER_PATTERN_STRING, "");
         sDefaults.putString(KEY_SHOW_CARRIER_DATA_ICON_PATTERN_STRING, "");
         sDefaults.putBoolean(KEY_HIDE_LTE_PLUS_DATA_ICON_BOOL, true);
diff --git a/telephony/java/android/telephony/DisconnectCause.java b/telephony/java/android/telephony/DisconnectCause.java
index cdf4c93..aa7e21a 100644
--- a/telephony/java/android/telephony/DisconnectCause.java
+++ b/telephony/java/android/telephony/DisconnectCause.java
@@ -340,6 +340,19 @@
      */
     public static final int MEDIA_TIMEOUT = 77;
 
+    /**
+     * Indicates that an emergency call cannot be placed over WFC because the service is not
+     * available in the current location.
+     * @hide
+     */
+    public static final int EMERGENCY_CALL_OVER_WFC_NOT_AVAILABLE = 78;
+
+    /**
+     * Indicates that WiFi calling service is not available in the current location.
+     * @hide
+     */
+    public static final int WFC_SERVICE_NOT_AVAILABLE_IN_THIS_LOCATION = 79;
+
     //*********************************************************************************************
     // When adding a disconnect type:
     // 1) Update toString() with the newly added disconnect type.
@@ -510,6 +523,10 @@
             return "OTASP_PROVISIONING_IN_PROCESS";
         case MEDIA_TIMEOUT:
             return "MEDIA_TIMEOUT";
+        case EMERGENCY_CALL_OVER_WFC_NOT_AVAILABLE:
+            return "EMERGENCY_CALL_OVER_WFC_NOT_AVAILABLE";
+        case WFC_SERVICE_NOT_AVAILABLE_IN_THIS_LOCATION:
+            return "WFC_SERVICE_NOT_AVAILABLE_IN_THIS_LOCATION";
         default:
             return "INVALID: " + cause;
         }
diff --git a/telephony/java/android/telephony/SubscriptionManager.java b/telephony/java/android/telephony/SubscriptionManager.java
index 519a954..bd0f225 100644
--- a/telephony/java/android/telephony/SubscriptionManager.java
+++ b/telephony/java/android/telephony/SubscriptionManager.java
@@ -2116,29 +2116,36 @@
     }
 
     /**
+     * TODO(b/137102918) Make this static, tests use this as an instance method currently.
+     *
      * @return the list of subId's that are active,
      *         is never null but the length maybe 0.
      * @hide
      */
     @UnsupportedAppUsage
     public @NonNull int[] getActiveSubscriptionIdList() {
-        int[] subId = null;
+        return getActiveSubscriptionIdList(/* visibleOnly */ true);
+    }
 
+    /**
+     * TODO(b/137102918) Make this static, tests use this as an instance method currently.
+     *
+     * @return a non-null list of subId's that are active.
+     *
+     * @hide
+     */
+    public @NonNull int[] getActiveSubscriptionIdList(boolean visibleOnly) {
         try {
             ISub iSub = ISub.Stub.asInterface(ServiceManager.getService("isub"));
             if (iSub != null) {
-                subId = iSub.getActiveSubIdList(/*visibleOnly*/true);
+                int[] subId = iSub.getActiveSubIdList(visibleOnly);
+                if (subId != null) return subId;
             }
         } catch (RemoteException ex) {
             // ignore it
         }
 
-        if (subId == null) {
-            subId = new int[0];
-        }
-
-        return subId;
-
+        return new int[0];
     }
 
     /**
@@ -2989,10 +2996,10 @@
      * @param info the subscriptionInfo to check against.
      * @return true if this subscription should be visible to the API caller.
      *
+     * @hide
      */
-    private boolean isSubscriptionVisible(SubscriptionInfo info) {
+    public boolean isSubscriptionVisible(SubscriptionInfo info) {
         if (info == null) return false;
-
         // If subscription is NOT grouped opportunistic subscription, it's visible.
         if (info.getGroupUuid() == null || !info.isOpportunistic()) return true;
 
diff --git a/telephony/java/android/telephony/TelephonyManager.java b/telephony/java/android/telephony/TelephonyManager.java
index 74c6d5d..00288d7 100644
--- a/telephony/java/android/telephony/TelephonyManager.java
+++ b/telephony/java/android/telephony/TelephonyManager.java
@@ -4063,9 +4063,14 @@
      * The returned set of subscriber IDs will include the subscriber ID corresponding to this
      * TelephonyManager's subId.
      *
+     * This is deprecated and {@link #getMergedSubscriberIdsFromGroup()} should be used for data
+     * usage merging purpose.
+     * TODO: remove this API.
+     *
      * @hide
      */
     @UnsupportedAppUsage
+    @Deprecated
     public @Nullable String[] getMergedSubscriberIds() {
         try {
             ITelephony telephony = getITelephony();
@@ -4078,6 +4083,28 @@
     }
 
     /**
+     * Return the set of subscriber IDs that should be considered "merged together" for data usage
+     * purposes. Unlike {@link #getMergedSubscriberIds()} this API merge subscriberIds based on
+     * subscription grouping: subscriberId of those in the same group will all be returned.
+     *
+     * <p>Requires the calling app to have READ_PRIVILEGED_PHONE_STATE permission.
+     *
+     * @hide
+     */
+    @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
+    public @Nullable String[] getMergedSubscriberIdsFromGroup() {
+        try {
+            ITelephony telephony = getITelephony();
+            if (telephony != null) {
+                return telephony.getMergedSubscriberIdsFromGroup(getSubId(), getOpPackageName());
+            }
+        } catch (RemoteException ex) {
+        } catch (NullPointerException ex) {
+        }
+        return null;
+    }
+
+    /**
      * Returns the MSISDN string.
      * for a GSM phone. Return null if it is unavailable.
      *
@@ -10916,7 +10943,6 @@
      * @param callback Callback will be triggered once it succeeds or failed.
      *                 See {@link TelephonyManager.SetOpportunisticSubscriptionResult}
      *                 for more details. Pass null if don't care about the result.
-     *
      */
     public void setPreferredOpportunisticDataSubscription(int subId, boolean needValidation,
             @Nullable @CallbackExecutor Executor executor, @Nullable Consumer<Integer> callback) {
@@ -10924,6 +10950,12 @@
         try {
             IOns iOpportunisticNetworkService = getIOns();
             if (iOpportunisticNetworkService == null) {
+                if (executor == null || callback == null) {
+                    return;
+                }
+                Binder.withCleanCallingIdentity(() -> executor.execute(() -> {
+                    callback.accept(SET_OPPORTUNISTIC_SUB_INACTIVE_SUBSCRIPTION);
+                }));
                 return;
             }
             ISetOpportunisticDataCallback callbackStub = new ISetOpportunisticDataCallback.Stub() {
@@ -11002,9 +11034,19 @@
         try {
             IOns iOpportunisticNetworkService = getIOns();
             if (iOpportunisticNetworkService == null || availableNetworks == null) {
-                Binder.withCleanCallingIdentity(() -> executor.execute(() -> {
-                    callback.accept(UPDATE_AVAILABLE_NETWORKS_INVALID_ARGUMENTS);
-                }));
+                if (executor == null || callback == null) {
+                    return;
+                }
+                if (iOpportunisticNetworkService == null) {
+                    /* Todo<b/130595455> passing unknown due to lack of good error codes */
+                    Binder.withCleanCallingIdentity(() -> executor.execute(() -> {
+                        callback.accept(UPDATE_AVAILABLE_NETWORKS_UNKNOWN_FAILURE);
+                    }));
+                } else {
+                    Binder.withCleanCallingIdentity(() -> executor.execute(() -> {
+                        callback.accept(UPDATE_AVAILABLE_NETWORKS_INVALID_ARGUMENTS);
+                    }));
+                }
                 return;
             }
             IUpdateAvailableNetworksCallback callbackStub =
diff --git a/telephony/java/android/telephony/ims/ImsReasonInfo.java b/telephony/java/android/telephony/ims/ImsReasonInfo.java
index 036a7b3..1e0d9a78 100644
--- a/telephony/java/android/telephony/ims/ImsReasonInfo.java
+++ b/telephony/java/android/telephony/ims/ImsReasonInfo.java
@@ -872,6 +872,19 @@
      */
     public static final int CODE_REJECT_ONGOING_CS_CALL = 1621;
 
+    /**
+     * An attempt was made to place an emergency call over WFC when emergency services is not
+     * currently available in the current location.
+     * @hide
+     */
+    public static final int CODE_EMERGENCY_CALL_OVER_WFC_NOT_AVAILABLE = 1622;
+
+    /**
+     * Indicates that WiFi calling service is not available in the current location.
+     * @hide
+     */
+    public static final int CODE_WFC_SERVICE_NOT_AVAILABLE_IN_THIS_LOCATION = 1623;
+
     /*
      * OEM specific error codes. To be used by OEMs when they don't want to reveal error code which
      * would be replaced by ERROR_UNSPECIFIED.
diff --git a/telephony/java/com/android/internal/telephony/ITelephony.aidl b/telephony/java/com/android/internal/telephony/ITelephony.aidl
index a2dcc78..dcfd193 100644
--- a/telephony/java/com/android/internal/telephony/ITelephony.aidl
+++ b/telephony/java/com/android/internal/telephony/ITelephony.aidl
@@ -1087,6 +1087,11 @@
     String[] getMergedSubscriberIds(int subId, String callingPackage);
 
     /**
+     * @hide
+     */
+    String[] getMergedSubscriberIdsFromGroup(int subId, String callingPackage);
+
+    /**
      * Override the operator branding for the current ICCID.
      *
      * Once set, whenever the SIM is present in the device, the service
diff --git a/telephony/java/com/android/internal/telephony/ITelephonyRegistry.aidl b/telephony/java/com/android/internal/telephony/ITelephonyRegistry.aidl
index f2f3c2d..dc026d4 100644
--- a/telephony/java/com/android/internal/telephony/ITelephonyRegistry.aidl
+++ b/telephony/java/com/android/internal/telephony/ITelephonyRegistry.aidl
@@ -68,8 +68,7 @@
     void notifyOtaspChanged(in int subId, in int otaspMode);
     @UnsupportedAppUsage
     void notifyCellInfo(in List<CellInfo> cellInfo);
-    void notifyPhysicalChannelConfiguration(in List<PhysicalChannelConfig> configs);
-    void notifyPhysicalChannelConfigurationForSubscriber(in int subId,
+    void notifyPhysicalChannelConfigurationForSubscriber(in int phoneId, in int subId,
             in List<PhysicalChannelConfig> configs);
     void notifyPreciseCallState(int phoneId, int subId, int ringingCallState,
             int foregroundCallState, int backgroundCallState);
diff --git a/telephony/java/com/android/internal/telephony/TelephonyPermissions.java b/telephony/java/com/android/internal/telephony/TelephonyPermissions.java
index 7a0ab9c..51c5d12 100644
--- a/telephony/java/com/android/internal/telephony/TelephonyPermissions.java
+++ b/telephony/java/com/android/internal/telephony/TelephonyPermissions.java
@@ -600,26 +600,21 @@
         }
     }
 
-    /**
-     * Returns whether the provided uid has carrier privileges for any active subscription ID.
-     */
-    private static boolean checkCarrierPrivilegeForAnySubId(Context context,
-            Supplier<ITelephony> telephonySupplier, int uid) {
+    /** Returns whether the provided uid has carrier privileges for any active subscription ID. */
+    private static boolean checkCarrierPrivilegeForAnySubId(
+            Context context, Supplier<ITelephony> telephonySupplier, int uid) {
         SubscriptionManager sm = (SubscriptionManager) context.getSystemService(
                 Context.TELEPHONY_SUBSCRIPTION_SERVICE);
-        int[] activeSubIds = sm.getActiveSubscriptionIdList();
-        if (activeSubIds != null) {
-            for (int activeSubId : activeSubIds) {
-                if (getCarrierPrivilegeStatus(telephonySupplier, activeSubId, uid)
-                        == TelephonyManager.CARRIER_PRIVILEGE_STATUS_HAS_ACCESS) {
-                    return true;
-                }
+        int[] activeSubIds = sm.getActiveSubscriptionIdList(/* visibleOnly */ false);
+        for (int activeSubId : activeSubIds) {
+            if (getCarrierPrivilegeStatus(telephonySupplier, activeSubId, uid)
+                    == TelephonyManager.CARRIER_PRIVILEGE_STATUS_HAS_ACCESS) {
+                return true;
             }
         }
         return false;
     }
 
-
     private static int getCarrierPrivilegeStatus(
             Supplier<ITelephony> telephonySupplier, int subId, int uid) {
         ITelephony telephony = telephonySupplier.get();
diff --git a/tests/Internal/src/com/android/internal/colorextraction/ColorExtractorTest.java b/tests/Internal/src/com/android/internal/colorextraction/ColorExtractorTest.java
index 45ddc3e..f88a7c4 100644
--- a/tests/Internal/src/com/android/internal/colorextraction/ColorExtractorTest.java
+++ b/tests/Internal/src/com/android/internal/colorextraction/ColorExtractorTest.java
@@ -39,8 +39,6 @@
 import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
-import org.mockito.Mock;
-import org.mockito.MockitoAnnotations;
 
 /**
  * Tests color extraction generation.
@@ -49,14 +47,13 @@
 @RunWith(AndroidJUnit4.class)
 public class ColorExtractorTest {
 
-    Context mContext;
-    @Mock
-    WallpaperManager mWallpaperManager;
+    private Context mContext;
+    private WallpaperManager mWallpaperManager;
 
     @Before
     public void setup() {
-        MockitoAnnotations.initMocks(this);
         mContext = InstrumentationRegistry.getContext();
+        mWallpaperManager = mock(WallpaperManager.class);
     }
 
     @Test
diff --git a/tests/RollbackTest/StagedRollbackTest/src/com/android/tests/rollback/host/StagedRollbackTest.java b/tests/RollbackTest/StagedRollbackTest/src/com/android/tests/rollback/host/StagedRollbackTest.java
index bad2947..4315514 100644
--- a/tests/RollbackTest/StagedRollbackTest/src/com/android/tests/rollback/host/StagedRollbackTest.java
+++ b/tests/RollbackTest/StagedRollbackTest/src/com/android/tests/rollback/host/StagedRollbackTest.java
@@ -25,6 +25,7 @@
 
 import org.junit.After;
 import org.junit.Before;
+import org.junit.Ignore;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
@@ -63,6 +64,7 @@
      * Tests watchdog triggered staged rollbacks involving only apks.
      */
     @Test
+    @Ignore("b/139175593 flaky test")
     public void testBadApkOnly() throws Exception {
         runPhase("testBadApkOnlyEnableRollback");
         getDevice().reboot();
diff --git a/tests/permission/src/com/android/framework/permission/tests/VibratorServicePermissionTest.java b/tests/permission/src/com/android/framework/permission/tests/VibratorServicePermissionTest.java
index 388c7d0..c50229a 100644
--- a/tests/permission/src/com/android/framework/permission/tests/VibratorServicePermissionTest.java
+++ b/tests/permission/src/com/android/framework/permission/tests/VibratorServicePermissionTest.java
@@ -16,9 +16,7 @@
 
 package com.android.framework.permission.tests;
 
-import junit.framework.TestCase;
-
-import android.media.AudioManager;
+import android.media.AudioAttributes;
 import android.os.Binder;
 import android.os.IVibratorService;
 import android.os.Process;
@@ -27,6 +25,9 @@
 import android.os.VibrationEffect;
 import android.test.suitebuilder.annotation.SmallTest;
 
+import junit.framework.TestCase;
+
+
 /**
  * Verify that Hardware apis cannot be called without required permissions.
  */
@@ -51,7 +52,10 @@
         try {
             final VibrationEffect effect =
                     VibrationEffect.createOneShot(100, VibrationEffect.DEFAULT_AMPLITUDE);
-            mVibratorService.vibrate(Process.myUid(), null, effect, AudioManager.STREAM_ALARM,
+            final AudioAttributes attrs = new AudioAttributes.Builder()
+                    .setUsage(AudioAttributes.USAGE_ALARM)
+                    .build();
+            mVibratorService.vibrate(Process.myUid(), null, effect, attrs,
                     "testVibrate", new Binder());
             fail("vibrate did not throw SecurityException as expected");
         } catch (SecurityException e) {
diff --git a/wifi/java/android/net/wifi/WifiManager.java b/wifi/java/android/net/wifi/WifiManager.java
index 452ac65..77e02df 100644
--- a/wifi/java/android/net/wifi/WifiManager.java
+++ b/wifi/java/android/net/wifi/WifiManager.java
@@ -671,6 +671,14 @@
     public static final int IFACE_IP_MODE_LOCAL_ONLY = 2;
 
     /**
+     * Broadcast intent action indicating that the wifi network settings
+     * had been reset.
+     * @hide
+     */
+    public static final String WIFI_NETWORK_SETTINGS_RESET_ACTION =
+            "android.net.wifi.action.NETWORK_SETTINGS_RESET";
+
+    /**
      * Broadcast intent action indicating that a connection to the supplicant has
      * been established (and it is now possible
      * to perform Wi-Fi operations) or the connection to the supplicant has been
diff --git a/wifi/java/android/net/wifi/p2p/WifiP2pManager.java b/wifi/java/android/net/wifi/p2p/WifiP2pManager.java
index cd659e2..d37c4a2 100644
--- a/wifi/java/android/net/wifi/p2p/WifiP2pManager.java
+++ b/wifi/java/android/net/wifi/p2p/WifiP2pManager.java
@@ -190,7 +190,7 @@
      * has changed. One extra {@link #EXTRA_WIFI_P2P_INFO} provides the p2p connection info in
      * the form of a {@link WifiP2pInfo} object. Another extra {@link #EXTRA_NETWORK_INFO} provides
      * the network info in the form of a {@link android.net.NetworkInfo}. A third extra provides
-     * the details of the group.
+     * the details of the group and may contain a {@code null}.
      *
      * All of these permissions are required to receive this broadcast:
      * {@link android.Manifest.permission#ACCESS_FINE_LOCATION} and
diff --git a/wifi/java/android/net/wifi/rtt/ResponderLocation.java b/wifi/java/android/net/wifi/rtt/ResponderLocation.java
index e1d82f8..970a75d 100644
--- a/wifi/java/android/net/wifi/rtt/ResponderLocation.java
+++ b/wifi/java/android/net/wifi/rtt/ResponderLocation.java
@@ -605,11 +605,11 @@
             // Negative 2's complement value
             // Note: The Math.pow(...) method cannot return a NaN value because the bitFieldSize
             // for Lat or Lng is limited to exactly 34 bits.
-            angle = Math.scalb(fields[offset] - Math.pow(2, bitFieldSizes[offset]),
+            angle = Math.scalb((double) fields[offset] - Math.pow(2, bitFieldSizes[offset]),
                     -LATLNG_FRACTION_BITS);
         } else {
             // Positive 2's complement value
-            angle = Math.scalb(fields[offset], -LATLNG_FRACTION_BITS);
+            angle = Math.scalb((double) fields[offset], -LATLNG_FRACTION_BITS);
         }
         if (angle > limit) {
             angle = limit;
@@ -732,10 +732,11 @@
 
         int maxBssidIndicator = (int) buffer[SUBELEMENT_BSSID_MAX_INDICATOR_INDEX] & BYTE_MASK;
         int bssidListLength = (buffer.length - 1) / BYTES_IN_A_BSSID;
-        // Check the max number of BSSIDs agrees with the list length.
-        if (maxBssidIndicator != bssidListLength) {
-            return false;
-        }
+        // The maxBSSIDIndicator is ignored. Its use is still being clarified in 802.11REVmd,
+        // which is not published at this time. This field will be used in a future
+        // release of Android after 802.11REVmd is public. Here, we interpret the following
+        // params as an explicit list of BSSIDs.
+
 
         int bssidOffset = SUBELEMENT_BSSID_LIST_INDEX;
         for (int i = 0; i < bssidListLength; i++) {
diff --git a/wifi/tests/src/android/net/wifi/rtt/ResponderLocationTest.java b/wifi/tests/src/android/net/wifi/rtt/ResponderLocationTest.java
index 47c30409..b02eebb 100644
--- a/wifi/tests/src/android/net/wifi/rtt/ResponderLocationTest.java
+++ b/wifi/tests/src/android/net/wifi/rtt/ResponderLocationTest.java
@@ -37,7 +37,7 @@
  */
 @RunWith(JUnit4.class)
 public class ResponderLocationTest {
-    private static final double LATLNG_TOLERANCE_DEGREES = 0.00001;
+    private static final double LATLNG_TOLERANCE_DEGREES = 0.000_000_05D; // 5E-8 = 6mm of meridian
     private static final double ALT_TOLERANCE_METERS = 0.01;
     private static final double HEIGHT_TOLERANCE_METERS = 0.01;
     private static final int INDEX_ELEMENT_TYPE = 2;
@@ -103,7 +103,7 @@
     private static final byte[] sTestBssidListSE = {
             (byte) 0x07, // Subelement BSSID list
             (byte) 13, // length dependent on number of BSSIDs in list
-            (byte) 0x02, // Number of BSSIDs in list
+            (byte) 0x00, // List is explicit; no expansion of list required
             (byte) 0x01, // BSSID #1 (MSB)
             (byte) 0x02,
             (byte) 0x03,
@@ -266,11 +266,11 @@
         assertTrue(valid);
         assertTrue(lciValid);
         assertFalse(zValid);
-        assertEquals(0.0009765625, responderLocation.getLatitudeUncertainty());
-        assertEquals(-33.857009, responderLocation.getLatitude(),
+        assertEquals(0.0009765625D, responderLocation.getLatitudeUncertainty());
+        assertEquals(-33.8570095D, responderLocation.getLatitude(),
                 LATLNG_TOLERANCE_DEGREES);
-        assertEquals(0.0009765625, responderLocation.getLongitudeUncertainty());
-        assertEquals(151.215200, responderLocation.getLongitude(),
+        assertEquals(0.0009765625D, responderLocation.getLongitudeUncertainty());
+        assertEquals(151.2152005D, responderLocation.getLongitude(),
                 LATLNG_TOLERANCE_DEGREES);
         assertEquals(1, responderLocation.getAltitudeType());
         assertEquals(64.0, responderLocation.getAltitudeUncertainty());
@@ -282,11 +282,11 @@
         assertEquals(1, responderLocation.getLciVersion());
 
         // Testing Location Object
-        assertEquals(-33.857009, location.getLatitude(),
+        assertEquals(-33.8570095D, location.getLatitude(),
                 LATLNG_TOLERANCE_DEGREES);
-        assertEquals(151.215200, location.getLongitude(),
+        assertEquals(151.2152005D, location.getLongitude(),
                 LATLNG_TOLERANCE_DEGREES);
-        assertEquals((0.0009765625 + 0.0009765625) / 2, location.getAccuracy(),
+        assertEquals((0.0009765625D + 0.0009765625D) / 2, location.getAccuracy(),
                 LATLNG_TOLERANCE_DEGREES);
         assertEquals(11.2, location.getAltitude(), ALT_TOLERANCE_METERS);
         assertEquals(64.0, location.getVerticalAccuracyMeters(), ALT_TOLERANCE_METERS);