Merge "Update battery saver footer strings" into sc-dev
diff --git a/StubLibraries.bp b/StubLibraries.bp
index a83cb4d..aa073fe 100644
--- a/StubLibraries.bp
+++ b/StubLibraries.bp
@@ -310,13 +310,9 @@
 ]
 
 java_defaults {
-    name: "android_defaults_stubs_current",
-    libs: [ "stub-annotations" ],
-    static_libs: [
-        // License notices from art module
-        "art-notices-for-framework-stubs-jar",
-        "framework-res-package-jar", // Export package of framework-res
-    ],
+    name: "android-non-updatable_defaults_stubs_current",
+    libs: ["stub-annotations"],
+    static_libs: ["framework-res-package-jar"], // Export package of framework-res
     errorprone: {
         javacflags: [
             "-XepDisableAllChecks",
@@ -326,6 +322,64 @@
     system_modules: "none",
     java_version: "1.8",
     compile_dex: true,
+    dist: {
+        targets: ["sdk", "win_sdk"],
+        tag: ".jar",
+        dest: "android-non-updatable.jar",
+    }
+}
+
+java_library_static {
+    name: "android-non-updatable.stubs",
+    defaults: ["android-non-updatable_defaults_stubs_current"],
+    srcs: [":api-stubs-docs-non-updatable"],
+    libs: modules_public_stubs,
+    dist: {
+        dir: "apistubs/android/public",
+    },
+}
+
+java_library_static {
+    name: "android-non-updatable.stubs.system",
+    defaults: ["android-non-updatable_defaults_stubs_current"],
+    srcs: [ ":system-api-stubs-docs-non-updatable" ],
+    libs: modules_system_stubs,
+    dist: {
+        dir: "apistubs/android/system",
+    },
+}
+
+java_library_static {
+    name: "android-non-updatable.stubs.module_lib",
+    defaults: ["android-non-updatable_defaults_stubs_current"],
+    srcs: [":module-lib-api-stubs-docs-non-updatable"],
+    libs: [
+        "sdk_system_current_android",
+        // NOTE: The below can be removed once the prebuilt stub contains IKE.
+        "sdk_system_current_android.net.ipsec.ike",
+    ],
+    dist: {
+        dir: "apistubs/android/module-lib",
+    },
+}
+
+java_library_static {
+    name: "android-non-updatable.stubs.test",
+    defaults: ["android-non-updatable_defaults_stubs_current"],
+    srcs: [":test-api-stubs-docs-non-updatable"],
+    libs: modules_system_stubs,
+    dist: {
+        dir: "apistubs/android/test",
+    },
+}
+
+java_defaults {
+    name: "android_defaults_stubs_current",
+    static_libs: ["art-notices-for-framework-stubs-jar"], // License notices from art module
+    sdk_version: "none",
+    system_modules: "none",
+    java_version: "1.8",
+    compile_dex: true,
 }
 
 java_defaults {
@@ -339,8 +393,8 @@
 
 java_library_static {
     name: "android_stubs_current",
-    srcs: [ ":api-stubs-docs-non-updatable" ],
     static_libs: modules_public_stubs + [
+        "android-non-updatable.stubs",
         "private-stub-annotations-jar",
     ],
     defaults: ["android_defaults_stubs_current"],
@@ -348,8 +402,8 @@
 
 java_library_static {
     name: "android_system_stubs_current",
-    srcs: [ ":system-api-stubs-docs-non-updatable" ],
     static_libs: modules_system_stubs + [
+        "android-non-updatable.stubs.system",
         "private-stub-annotations-jar",
     ],
     defaults: [
@@ -371,10 +425,10 @@
 
 java_library_static {
     name: "android_test_stubs_current",
-    srcs: [ ":test-api-stubs-docs-non-updatable" ],
     // Modules do not have test APIs, but we want to include their SystemApis, like we include
     // the SystemApi of framework-non-updatable-sources.
     static_libs: modules_system_stubs + [
+        "android-non-updatable.stubs.test",
         "private-stub-annotations-jar",
     ],
     defaults: [
@@ -396,17 +450,14 @@
 
 java_library_static {
     name: "android_module_lib_stubs_current",
-    srcs: [ ":module-lib-api-stubs-docs-non-updatable" ],
     defaults: [
         "android_defaults_stubs_current",
         "android_stubs_dists_default",
     ],
-    libs: [
-        "sdk_system_current_android",
-        // NOTE: The below can be removed once the prebuilt stub contains IKE.
-        "sdk_system_current_android.net.ipsec.ike",
+    static_libs: [
+        "android-non-updatable.stubs.module_lib",
+        "art.module.public.api.stubs",
     ],
-    static_libs: ["art.module.public.api.stubs"],
     dist: {
         dir: "apistubs/android/module-lib",
     },
diff --git a/core/api/current.txt b/core/api/current.txt
index 62aacac..aad6b37 100644
--- a/core/api/current.txt
+++ b/core/api/current.txt
@@ -3960,6 +3960,7 @@
     method public boolean isImmersive();
     method public boolean isInMultiWindowMode();
     method public boolean isInPictureInPictureMode();
+    method public boolean isLaunchedFromBubble();
     method public boolean isLocalVoiceInteractionSupported();
     method public boolean isTaskRoot();
     method public boolean isVoiceInteraction();
@@ -7202,7 +7203,6 @@
     method public boolean isComplianceAcknowledgementRequired();
     method public boolean isDeviceIdAttestationSupported();
     method public boolean isDeviceOwnerApp(String);
-    method public boolean isEnterpriseNetworkPreferenceEnabled();
     method public boolean isEphemeralUser(@NonNull android.content.ComponentName);
     method public boolean isKeyPairGrantedToWifiAuth(@NonNull String);
     method public boolean isLockTaskPermitted(String);
@@ -7213,6 +7213,7 @@
     method public boolean isOrganizationOwnedDeviceWithManagedProfile();
     method public boolean isOverrideApnEnabled(@NonNull android.content.ComponentName);
     method public boolean isPackageSuspended(@NonNull android.content.ComponentName, String) throws android.content.pm.PackageManager.NameNotFoundException;
+    method public boolean isPreferentialNetworkServiceEnabled();
     method public boolean isProfileOwnerApp(String);
     method public boolean isProvisioningAllowed(@NonNull String);
     method public boolean isResetPasswordTokenActive(android.content.ComponentName);
@@ -7264,7 +7265,6 @@
     method public void setDelegatedScopes(@NonNull android.content.ComponentName, @NonNull String, @NonNull java.util.List<java.lang.String>);
     method public void setDeviceOwnerLockScreenInfo(@NonNull android.content.ComponentName, CharSequence);
     method public void setEndUserSessionMessage(@NonNull android.content.ComponentName, @Nullable CharSequence);
-    method public void setEnterpriseNetworkPreferenceEnabled(boolean);
     method public void setFactoryResetProtectionPolicy(@NonNull android.content.ComponentName, @Nullable android.app.admin.FactoryResetProtectionPolicy);
     method public int setGlobalPrivateDnsModeOpportunistic(@NonNull android.content.ComponentName);
     method @WorkerThread public int setGlobalPrivateDnsModeSpecifiedHost(@NonNull android.content.ComponentName, @NonNull String);
@@ -7307,6 +7307,7 @@
     method public boolean setPermittedCrossProfileNotificationListeners(@NonNull android.content.ComponentName, @Nullable java.util.List<java.lang.String>);
     method public boolean setPermittedInputMethods(@NonNull android.content.ComponentName, java.util.List<java.lang.String>);
     method public void setPersonalAppsSuspended(@NonNull android.content.ComponentName, boolean);
+    method public void setPreferentialNetworkServiceEnabled(boolean);
     method public void setProfileEnabled(@NonNull android.content.ComponentName);
     method public void setProfileName(@NonNull android.content.ComponentName, String);
     method public void setRecommendedGlobalProxy(@NonNull android.content.ComponentName, @Nullable android.net.ProxyInfo);
@@ -11222,7 +11223,6 @@
     field public static final String EXTRA_INITIAL_INTENTS = "android.intent.extra.INITIAL_INTENTS";
     field public static final String EXTRA_INSTALLER_PACKAGE_NAME = "android.intent.extra.INSTALLER_PACKAGE_NAME";
     field public static final String EXTRA_INTENT = "android.intent.extra.INTENT";
-    field public static final String EXTRA_IS_BUBBLED = "android.intent.extra.IS_BUBBLED";
     field public static final String EXTRA_KEY_EVENT = "android.intent.extra.KEY_EVENT";
     field public static final String EXTRA_LOCAL_ONLY = "android.intent.extra.LOCAL_ONLY";
     field public static final String EXTRA_LOCUS_ID = "android.intent.extra.LOCUS_ID";
diff --git a/core/api/system-current.txt b/core/api/system-current.txt
index 5242782..d560ead 100644
--- a/core/api/system-current.txt
+++ b/core/api/system-current.txt
@@ -8020,14 +8020,14 @@
     method @NonNull @RequiresPermission(android.Manifest.permission.UPDATE_DEVICE_STATS) public android.os.connectivity.WifiBatteryStats getWifiBatteryStats();
     method @RequiresPermission(android.Manifest.permission.UPDATE_DEVICE_STATS) public void reportFullWifiLockAcquiredFromSource(@NonNull android.os.WorkSource);
     method @RequiresPermission(android.Manifest.permission.UPDATE_DEVICE_STATS) public void reportFullWifiLockReleasedFromSource(@NonNull android.os.WorkSource);
-    method @RequiresPermission(android.Manifest.permission.UPDATE_DEVICE_STATS) public void reportMobileRadioPowerState(boolean, int) throws java.lang.RuntimeException;
+    method @RequiresPermission(android.Manifest.permission.UPDATE_DEVICE_STATS) public void reportMobileRadioPowerState(boolean, int);
     method @RequiresPermission(android.Manifest.permission.UPDATE_DEVICE_STATS) public void reportWifiBatchedScanStartedFromSource(@NonNull android.os.WorkSource, @IntRange(from=0) int);
     method @RequiresPermission(android.Manifest.permission.UPDATE_DEVICE_STATS) public void reportWifiBatchedScanStoppedFromSource(@NonNull android.os.WorkSource);
     method @RequiresPermission(android.Manifest.permission.UPDATE_DEVICE_STATS) public void reportWifiMulticastDisabled(@NonNull android.os.WorkSource);
     method @RequiresPermission(android.Manifest.permission.UPDATE_DEVICE_STATS) public void reportWifiMulticastEnabled(@NonNull android.os.WorkSource);
     method @RequiresPermission(android.Manifest.permission.UPDATE_DEVICE_STATS) public void reportWifiOff();
     method @RequiresPermission(android.Manifest.permission.UPDATE_DEVICE_STATS) public void reportWifiOn();
-    method @RequiresPermission(android.Manifest.permission.UPDATE_DEVICE_STATS) public void reportWifiRadioPowerState(boolean, int) throws java.lang.RuntimeException;
+    method @RequiresPermission(android.Manifest.permission.UPDATE_DEVICE_STATS) public void reportWifiRadioPowerState(boolean, int);
     method @RequiresPermission(android.Manifest.permission.UPDATE_DEVICE_STATS) public void reportWifiRssiChanged(@IntRange(from=0xffffff81, to=0) int);
     method @RequiresPermission(android.Manifest.permission.UPDATE_DEVICE_STATS) public void reportWifiScanStartedFromSource(@NonNull android.os.WorkSource);
     method @RequiresPermission(android.Manifest.permission.UPDATE_DEVICE_STATS) public void reportWifiScanStoppedFromSource(@NonNull android.os.WorkSource);
diff --git a/core/api/test-current.txt b/core/api/test-current.txt
index 63e9010..04dd04c 100644
--- a/core/api/test-current.txt
+++ b/core/api/test-current.txt
@@ -137,6 +137,7 @@
     method public void setLaunchActivityType(int);
     method public void setLaunchTaskId(int);
     method public void setLaunchWindowingMode(int);
+    method public void setLaunchedFromBubble(boolean);
     method public void setTaskAlwaysOnTop(boolean);
     method public void setTaskOverlay(boolean, boolean);
   }
diff --git a/core/java/android/app/Activity.java b/core/java/android/app/Activity.java
index f0d5a89..45120b6 100644
--- a/core/java/android/app/Activity.java
+++ b/core/java/android/app/Activity.java
@@ -899,6 +899,9 @@
     /** The options for scene transition. */
     ActivityOptions mPendingOptions;
 
+    /** Whether this activity was launched from a bubble. **/
+    boolean mLaunchedFromBubble;
+
     private static final class ManagedCursor {
         ManagedCursor(Cursor cursor) {
             mCursor = cursor;
@@ -6790,6 +6793,25 @@
         return getSharedPreferences(getLocalClassName(), mode);
     }
 
+    /**
+     * Indicates whether this activity is launched from a bubble. A bubble is a floating shortcut
+     * on the screen that expands to show an activity.
+     *
+     * If your activity can be used normally or as a bubble, you might use this method to check
+     * if the activity is bubbled to modify any behaviour that might be different between the
+     * normal activity and the bubbled activity. For example, if you normally cancel the
+     * notification associated with the activity when you open the activity, you might not want to
+     * do that when you're bubbled as that would remove the bubble.
+     *
+     * @return {@code true} if the activity is launched from a bubble.
+     *
+     * @see Notification.Builder#setBubbleMetadata(Notification.BubbleMetadata)
+     * @see Notification.BubbleMetadata.Builder#Builder(String)
+     */
+    public boolean isLaunchedFromBubble() {
+        return mLaunchedFromBubble;
+    }
+
     private void ensureSearchManager() {
         if (mSearchManager != null) {
             return;
diff --git a/core/java/android/app/ActivityOptions.java b/core/java/android/app/ActivityOptions.java
index 006b2b5..c21de62 100644
--- a/core/java/android/app/ActivityOptions.java
+++ b/core/java/android/app/ActivityOptions.java
@@ -323,6 +323,9 @@
     /** See {@link #setRemoveWithTaskOrganizer(boolean)}. */
     private static final String KEY_REMOVE_WITH_TASK_ORGANIZER =
             "android.activity.removeWithTaskOrganizer";
+    /** See {@link #setLaunchedFromBubble(boolean)}. */
+    private static final String KEY_LAUNCHED_FROM_BUBBLE =
+            "android.activity.launchTypeBubble";
 
     /**
      * @see #setLaunchCookie
@@ -410,6 +413,7 @@
     private boolean mOverrideTaskTransition;
     private int mSplashScreenThemeResId;
     private boolean mRemoveWithTaskOrganizer;
+    private boolean mLaunchedFromBubble;
 
     /**
      * Create an ActivityOptions specifying a custom animation to run when
@@ -1161,6 +1165,7 @@
         mOverrideTaskTransition = opts.getBoolean(KEY_OVERRIDE_TASK_TRANSITION);
         mSplashScreenThemeResId = opts.getInt(KEY_SPLASH_SCREEN_THEME);
         mRemoveWithTaskOrganizer = opts.getBoolean(KEY_REMOVE_WITH_TASK_ORGANIZER);
+        mLaunchedFromBubble = opts.getBoolean(KEY_LAUNCHED_FROM_BUBBLE);
     }
 
     /**
@@ -1647,6 +1652,23 @@
     }
 
     /**
+     * Sets whether this activity is launched from a bubble.
+     * @hide
+     */
+    @TestApi
+    public void setLaunchedFromBubble(boolean fromBubble) {
+        mLaunchedFromBubble = fromBubble;
+    }
+
+    /**
+     * @return whether the activity was launched from a bubble.
+     * @hide
+     */
+    public boolean getLaunchedFromBubble() {
+        return mLaunchedFromBubble;
+    }
+
+    /**
      * Update the current values in this ActivityOptions from those supplied
      * in <var>otherOptions</var>.  Any values
      * defined in <var>otherOptions</var> replace those in the base options.
@@ -1883,6 +1905,9 @@
         if (mRemoveWithTaskOrganizer) {
             b.putBoolean(KEY_REMOVE_WITH_TASK_ORGANIZER, mRemoveWithTaskOrganizer);
         }
+        if (mLaunchedFromBubble) {
+            b.putBoolean(KEY_LAUNCHED_FROM_BUBBLE, mLaunchedFromBubble);
+        }
         return b;
     }
 
diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java
index 35890c8..8ff14b0 100644
--- a/core/java/android/app/ActivityThread.java
+++ b/core/java/android/app/ActivityThread.java
@@ -594,6 +594,9 @@
          */
         FixedRotationAdjustments mPendingFixedRotationAdjustments;
 
+        /** Whether this activiy was launched from a bubble. */
+        boolean mLaunchedFromBubble;
+
         @LifecycleState
         private int mLifecycleState = PRE_ON_CREATE;
 
@@ -613,7 +616,7 @@
                 List<ReferrerIntent> pendingNewIntents, ActivityOptions activityOptions,
                 boolean isForward, ProfilerInfo profilerInfo, ClientTransactionHandler client,
                 IBinder assistToken, FixedRotationAdjustments fixedRotationAdjustments,
-                IBinder shareableActivityToken) {
+                IBinder shareableActivityToken, boolean launchedFromBubble) {
             this.token = token;
             this.assistToken = assistToken;
             this.shareableActivityToken = shareableActivityToken;
@@ -634,6 +637,7 @@
                     compatInfo);
             mActivityOptions = activityOptions;
             mPendingFixedRotationAdjustments = fixedRotationAdjustments;
+            mLaunchedFromBubble = launchedFromBubble;
             init();
         }
 
@@ -3549,6 +3553,7 @@
                     activity.mPendingOptions = r.mActivityOptions;
                     r.mActivityOptions = null;
                 }
+                activity.mLaunchedFromBubble = r.mLaunchedFromBubble;
                 activity.mCalled = false;
                 if (r.isPersistable()) {
                     mInstrumentation.callActivityOnCreate(activity, r.state, r.persistentState);
diff --git a/core/java/android/app/Notification.java b/core/java/android/app/Notification.java
index 0ca0b85..a60f1ca 100644
--- a/core/java/android/app/Notification.java
+++ b/core/java/android/app/Notification.java
@@ -10205,13 +10205,8 @@
              * <p>The shortcut activity will be used when the bubble is expanded. This will display
              * the shortcut activity in a floating window over the existing foreground activity.</p>
              *
-             * <p>When the shortcut is displayed in a bubble, there will be an intent
-             * extra set on the activity, {@link Intent#EXTRA_IS_BUBBLED}
-             * with {@code true}. You may check this in the onCreate of your activity via:
-             *
-             * <pre class="prettyprint">
-             * boolean isBubbled = getIntent().getBooleanExtra(Intent.EXTRA_IS_BUBBLED, false);
-             * </pre>
+             * <p>When the activity is launched from a bubble,
+             * {@link Activity#isLaunchedFromBubble()} will return with {@code true}.
              * </p>
              *
              * <p>If the shortcut has not been published when the bubble notification is sent,
@@ -10242,13 +10237,8 @@
              * app content in a floating window over the existing foreground activity. The intent
              * should point to a resizable activity. </p>
              *
-             * <p>When the activity is displayed in a bubble, there will be an intent
-             * extra set on the activity, {@link Intent#EXTRA_IS_BUBBLED}
-             * with {@code true}. You may check this in the onCreate of your activity via:
-             *
-             * <pre class="prettyprint">
-             * boolean isBubbled = getIntent().getBooleanExtra(Intent.EXTRA_IS_BUBBLED, false);
-             * </pre>
+             * <p>When the activity is launched from a bubble,
+             * {@link Activity#isLaunchedFromBubble()} will return with {@code true}.
              * </p>
              *
              * @throws NullPointerException if intent is null.
diff --git a/core/java/android/app/admin/DevicePolicyManager.java b/core/java/android/app/admin/DevicePolicyManager.java
index 1594e70..fa3c767 100644
--- a/core/java/android/app/admin/DevicePolicyManager.java
+++ b/core/java/android/app/admin/DevicePolicyManager.java
@@ -10121,45 +10121,51 @@
     }
 
     /**
-     * Sets whether enterprise network preference is enabled on the work profile.
+     * Sets whether preferential network service is enabled on the work profile.
+     * For example, an organization can have a deal/agreement with a carrier that all of
+     * the work data from its employees’ devices will be sent via a network service dedicated
+     * for enterprise use.
      *
-     * For example, a corporation can have a deal/agreement with a carrier that all of its
-     * employees’ devices use data on a network preference dedicated for enterprise use.
+     * An example of a supported preferential network service is the Enterprise
+     * slice on 5G networks.
      *
-     * By default, enterprise network preference is enabled on the work profile on supported
+     * By default, preferential network service is enabled on the work profile on supported
      * carriers and devices. Admins can explicitly disable it with this API.
+     * On fully-managed devices this method is unsupported because all traffic is considered
+     * work traffic.
      *
      * <p>This method can only be called by the profile owner of a managed profile.
-     *
-     * @param enabled whether enterprise network preference should be enabled.
+     * @param enabled whether preferential network service should be enabled.
      * @throws SecurityException if the caller is not the profile owner.
      **/
-    public void setEnterpriseNetworkPreferenceEnabled(boolean enabled) {
-        throwIfParentInstance("setEnterpriseNetworkPreferenceEnabled");
-        if (mService != null) {
-            try {
-                mService.setEnterpriseNetworkPreferenceEnabled(enabled);
-            } catch (RemoteException e) {
-                throw e.rethrowFromSystemServer();
-            }
+    public void setPreferentialNetworkServiceEnabled(boolean enabled) {
+        throwIfParentInstance("setPreferentialNetworkServiceEnabled");
+        if (mService == null) {
+            return;
+        }
+
+        try {
+            mService.setPreferentialNetworkServiceEnabled(enabled);
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
         }
     }
 
     /**
-     * Indicates whether whether enterprise network preference is enabled.
+     * Indicates whether preferential network service is enabled.
      *
      * <p>This method can be called by the profile owner of a managed profile.
      *
-     * @return whether whether enterprise network preference is enabled.
+     * @return whether preferential network service is enabled.
      * @throws SecurityException if the caller is not the profile owner.
      */
-    public boolean isEnterpriseNetworkPreferenceEnabled() {
-        throwIfParentInstance("isEnterpriseNetworkPreferenceEnabled");
+    public boolean isPreferentialNetworkServiceEnabled() {
+        throwIfParentInstance("isPreferentialNetworkServiceEnabled");
         if (mService == null) {
             return false;
         }
         try {
-            return mService.isEnterpriseNetworkPreferenceEnabled(myUserId());
+            return mService.isPreferentialNetworkServiceEnabled(myUserId());
         } catch (RemoteException e) {
             throw e.rethrowFromSystemServer();
         }
diff --git a/core/java/android/app/admin/IDevicePolicyManager.aidl b/core/java/android/app/admin/IDevicePolicyManager.aidl
index 8a8c69c..05b0be4 100644
--- a/core/java/android/app/admin/IDevicePolicyManager.aidl
+++ b/core/java/android/app/admin/IDevicePolicyManager.aidl
@@ -274,8 +274,8 @@
     void setSecondaryLockscreenEnabled(in ComponentName who, boolean enabled);
     boolean isSecondaryLockscreenEnabled(in UserHandle userHandle);
 
-    void setEnterpriseNetworkPreferenceEnabled(in boolean enabled);
-    boolean isEnterpriseNetworkPreferenceEnabled(int userHandle);
+    void setPreferentialNetworkServiceEnabled(in boolean enabled);
+    boolean isPreferentialNetworkServiceEnabled(int userHandle);
 
     void setLockTaskPackages(in ComponentName who, in String[] packages);
     String[] getLockTaskPackages(in ComponentName who);
diff --git a/core/java/android/app/servertransaction/LaunchActivityItem.java b/core/java/android/app/servertransaction/LaunchActivityItem.java
index 9f8fcc1..e281a02 100644
--- a/core/java/android/app/servertransaction/LaunchActivityItem.java
+++ b/core/java/android/app/servertransaction/LaunchActivityItem.java
@@ -72,6 +72,7 @@
     private ProfilerInfo mProfilerInfo;
     private IBinder mAssistToken;
     private IBinder mShareableActivityToken;
+    private boolean mLaunchedFromBubble;
     /**
      * It is only non-null if the process is the first time to launch activity. It is only an
      * optimization for quick look up of the interface so the field is ignored for comparison.
@@ -96,7 +97,8 @@
         ActivityClientRecord r = new ActivityClientRecord(token, mIntent, mIdent, mInfo,
                 mOverrideConfig, mCompatInfo, mReferrer, mVoiceInteractor, mState, mPersistentState,
                 mPendingResults, mPendingNewIntents, mActivityOptions, mIsForward, mProfilerInfo,
-                client, mAssistToken, mFixedRotationAdjustments, mShareableActivityToken);
+                client, mAssistToken, mFixedRotationAdjustments, mShareableActivityToken,
+                mLaunchedFromBubble);
         client.handleLaunchActivity(r, pendingActions, null /* customIntent */);
         Trace.traceEnd(TRACE_TAG_ACTIVITY_MANAGER);
     }
@@ -120,7 +122,8 @@
             List<ReferrerIntent> pendingNewIntents, ActivityOptions activityOptions,
             boolean isForward, ProfilerInfo profilerInfo, IBinder assistToken,
             IActivityClientController activityClientController,
-            FixedRotationAdjustments fixedRotationAdjustments, IBinder shareableActivityToken) {
+            FixedRotationAdjustments fixedRotationAdjustments, IBinder shareableActivityToken,
+            boolean launchedFromBubble) {
         LaunchActivityItem instance = ObjectPool.obtain(LaunchActivityItem.class);
         if (instance == null) {
             instance = new LaunchActivityItem();
@@ -128,7 +131,8 @@
         setValues(instance, intent, ident, info, curConfig, overrideConfig, compatInfo, referrer,
                 voiceInteractor, procState, state, persistentState, pendingResults,
                 pendingNewIntents, activityOptions, isForward, profilerInfo, assistToken,
-                activityClientController, fixedRotationAdjustments, shareableActivityToken);
+                activityClientController, fixedRotationAdjustments, shareableActivityToken,
+                launchedFromBubble);
 
         return instance;
     }
@@ -136,7 +140,7 @@
     @Override
     public void recycle() {
         setValues(this, null, 0, null, null, null, null, null, null, 0, null, null, null, null,
-                null, false, null, null, null, null, null);
+                null, false, null, null, null, null, null, false);
         ObjectPool.recycle(this);
     }
 
@@ -166,6 +170,7 @@
         dest.writeStrongInterface(mActivityClientController);
         dest.writeTypedObject(mFixedRotationAdjustments, flags);
         dest.writeStrongBinder(mShareableActivityToken);
+        dest.writeBoolean(mLaunchedFromBubble);
     }
 
     /** Read from Parcel. */
@@ -183,7 +188,8 @@
                 in.readTypedObject(ProfilerInfo.CREATOR),
                 in.readStrongBinder(),
                 IActivityClientController.Stub.asInterface(in.readStrongBinder()),
-                in.readTypedObject(FixedRotationAdjustments.CREATOR), in.readStrongBinder());
+                in.readTypedObject(FixedRotationAdjustments.CREATOR), in.readStrongBinder(),
+                in.readBoolean());
     }
 
     public static final @NonNull Creator<LaunchActivityItem> CREATOR =
@@ -293,7 +299,8 @@
             List<ResultInfo> pendingResults, List<ReferrerIntent> pendingNewIntents,
             ActivityOptions activityOptions, boolean isForward, ProfilerInfo profilerInfo,
             IBinder assistToken, IActivityClientController activityClientController,
-            FixedRotationAdjustments fixedRotationAdjustments, IBinder shareableActivityToken) {
+            FixedRotationAdjustments fixedRotationAdjustments, IBinder shareableActivityToken,
+            boolean launchedFromBubble) {
         instance.mIntent = intent;
         instance.mIdent = ident;
         instance.mInfo = info;
@@ -314,5 +321,6 @@
         instance.mActivityClientController = activityClientController;
         instance.mFixedRotationAdjustments = fixedRotationAdjustments;
         instance.mShareableActivityToken = shareableActivityToken;
+        instance.mLaunchedFromBubble = launchedFromBubble;
     }
 }
diff --git a/core/java/android/content/Intent.java b/core/java/android/content/Intent.java
index a482b8c..9ad017c 100644
--- a/core/java/android/content/Intent.java
+++ b/core/java/android/content/Intent.java
@@ -6177,16 +6177,6 @@
      */
     public static final String EXTRA_UNSTARTABLE_REASON = "android.intent.extra.UNSTARTABLE_REASON";
 
-    /**
-     * A boolean extra indicating whether an activity is bubbled. Set on the shortcut or
-     * pending intent provided for the bubble. If the extra is not present or false, then it is not
-     * bubbled.
-     *
-     * @see android.app.Notification.Builder#setBubbleMetadata(Notification.BubbleMetadata)
-     * @see android.app.Notification.BubbleMetadata.Builder#Builder(String)
-     */
-    public static final String EXTRA_IS_BUBBLED = "android.intent.extra.IS_BUBBLED";
-
     // ---------------------------------------------------------------------
     // ---------------------------------------------------------------------
     // Intent flags (see mFlags variable).
diff --git a/core/java/android/os/BatteryStatsManager.java b/core/java/android/os/BatteryStatsManager.java
index e47478a..2c088e2 100644
--- a/core/java/android/os/BatteryStatsManager.java
+++ b/core/java/android/os/BatteryStatsManager.java
@@ -429,10 +429,9 @@
      * @param uid Uid of this event. For the active state it represents the uid that was responsible
      *            for waking the radio, or -1 if the system was responsible for waking the radio.
      *            For inactive state, the UID should always be -1.
-     * @throws RuntimeException if there are binder remote-invocation errors.
      */
     @RequiresPermission(android.Manifest.permission.UPDATE_DEVICE_STATS)
-    public void reportMobileRadioPowerState(boolean isActive, int uid) throws RuntimeException {
+    public void reportMobileRadioPowerState(boolean isActive, int uid) {
         try {
             mBatteryStats.noteMobileRadioPowerState(getDataConnectionPowerState(isActive),
                     SystemClock.elapsedRealtimeNanos(), uid);
@@ -448,10 +447,9 @@
      * @param uid Uid of this event. For the active state it represents the uid that was responsible
      *            for waking the radio, or -1 if the system was responsible for waking the radio.
      *            For inactive state, the UID should always be -1.
-     * @throws RuntimeException if there are binder remote-invocation errors.
      */
     @RequiresPermission(android.Manifest.permission.UPDATE_DEVICE_STATS)
-    public void reportWifiRadioPowerState(boolean isActive, int uid) throws RuntimeException {
+    public void reportWifiRadioPowerState(boolean isActive, int uid) {
         try {
             mBatteryStats.noteWifiRadioPowerState(getDataConnectionPowerState(isActive),
                     SystemClock.elapsedRealtimeNanos(), uid);
diff --git a/core/java/android/os/FileUtils.java b/core/java/android/os/FileUtils.java
index 40c658f..a06a857 100644
--- a/core/java/android/os/FileUtils.java
+++ b/core/java/android/os/FileUtils.java
@@ -22,6 +22,8 @@
 import static android.os.ParcelFileDescriptor.MODE_READ_WRITE;
 import static android.os.ParcelFileDescriptor.MODE_TRUNCATE;
 import static android.os.ParcelFileDescriptor.MODE_WRITE_ONLY;
+import static android.system.OsConstants.EINVAL;
+import static android.system.OsConstants.ENOSYS;
 import static android.system.OsConstants.F_OK;
 import static android.system.OsConstants.O_ACCMODE;
 import static android.system.OsConstants.O_APPEND;
@@ -441,7 +443,19 @@
                 final StructStat st_in = Os.fstat(in);
                 final StructStat st_out = Os.fstat(out);
                 if (S_ISREG(st_in.st_mode) && S_ISREG(st_out.st_mode)) {
-                    return copyInternalSendfile(in, out, count, signal, executor, listener);
+                    try {
+                        return copyInternalSendfile(in, out, count, signal, executor, listener);
+                    } catch (ErrnoException e) {
+                        if (e.errno == EINVAL || e.errno == ENOSYS) {
+                            // sendfile(2) will fail in at least any of the following conditions:
+                            // 1. |in| doesn't support mmap(2)
+                            // 2. |out| was opened with O_APPEND
+                            // We fallback to userspace copy if that fails
+                            return copyInternalUserspace(in, out, count, signal, executor,
+                                    listener);
+                        }
+                        throw e;
+                    }
                 } else if (S_ISFIFO(st_in.st_mode) || S_ISFIFO(st_out.st_mode)) {
                     return copyInternalSplice(in, out, count, signal, executor, listener);
                 }
diff --git a/core/tests/coretests/src/android/app/admin/OWNERS b/core/tests/coretests/src/android/app/admin/OWNERS
new file mode 100644
index 0000000..e95633a
--- /dev/null
+++ b/core/tests/coretests/src/android/app/admin/OWNERS
@@ -0,0 +1 @@
+include /core/java/android/app/admin/OWNERS
diff --git a/core/tests/coretests/src/android/app/servertransaction/TestUtils.java b/core/tests/coretests/src/android/app/servertransaction/TestUtils.java
index 1a06789e..75da0bf 100644
--- a/core/tests/coretests/src/android/app/servertransaction/TestUtils.java
+++ b/core/tests/coretests/src/android/app/servertransaction/TestUtils.java
@@ -111,6 +111,7 @@
         private IBinder mAssistToken;
         private IBinder mShareableActivityToken;
         private FixedRotationAdjustments mFixedRotationAdjustments;
+        private boolean mLaunchedFromBubble;
 
         LaunchActivityItemBuilder setIntent(Intent intent) {
             mIntent = intent;
@@ -207,13 +208,18 @@
             return this;
         }
 
+        LaunchActivityItemBuilder setLaunchedFromBubble(boolean launchedFromBubble) {
+            mLaunchedFromBubble = launchedFromBubble;
+            return this;
+        }
+
         LaunchActivityItem build() {
             return LaunchActivityItem.obtain(mIntent, mIdent, mInfo,
                     mCurConfig, mOverrideConfig, mCompatInfo, mReferrer, mVoiceInteractor,
                     mProcState, mState, mPersistentState, mPendingResults, mPendingNewIntents,
                     mActivityOptions, mIsForward, mProfilerInfo, mAssistToken,
                     null /* activityClientController */, mFixedRotationAdjustments,
-                    mShareableActivityToken);
+                    mShareableActivityToken, mLaunchedFromBubble);
         }
     }
 }
diff --git a/core/tests/coretests/src/android/app/time/ExternalTimeSuggestionTest.java b/core/tests/coretests/src/android/app/time/ExternalTimeSuggestionTest.java
deleted file mode 100644
index 1c6b3cc..0000000
--- a/core/tests/coretests/src/android/app/time/ExternalTimeSuggestionTest.java
+++ /dev/null
@@ -1,71 +0,0 @@
-/*
- * Copyright 2021 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.app.time;
-
-import static android.app.timezonedetector.ParcelableTestSupport.assertRoundTripParcelable;
-import static android.app.timezonedetector.ParcelableTestSupport.roundTripParcelable;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertNotEquals;
-
-import android.os.TimestampedValue;
-
-import org.junit.Test;
-
-public class ExternalTimeSuggestionTest {
-
-    private static final TimestampedValue<Long> ARBITRARY_TIME =
-            new TimestampedValue<>(1111L, 2222L);
-
-    @Test
-    public void testEquals() {
-        ExternalTimeSuggestion one = new ExternalTimeSuggestion(
-                ARBITRARY_TIME.getReferenceTimeMillis(),
-                ARBITRARY_TIME.getValue());
-        assertEquals(one, one);
-
-        ExternalTimeSuggestion two = new ExternalTimeSuggestion(
-                ARBITRARY_TIME.getReferenceTimeMillis(),
-                ARBITRARY_TIME.getValue());
-        assertEquals(one, two);
-        assertEquals(two, one);
-
-        ExternalTimeSuggestion three = new ExternalTimeSuggestion(
-                ARBITRARY_TIME.getReferenceTimeMillis() + 1,
-                ARBITRARY_TIME.getValue());
-        assertNotEquals(one, three);
-        assertNotEquals(three, one);
-
-        // DebugInfo must not be considered in equals().
-        one.addDebugInfo("Debug info 1");
-        two.addDebugInfo("Debug info 2");
-        assertEquals(one, two);
-    }
-
-    @Test
-    public void testParcelable() {
-        ExternalTimeSuggestion suggestion = new ExternalTimeSuggestion(
-                ARBITRARY_TIME.getReferenceTimeMillis(),
-                ARBITRARY_TIME.getValue());
-        assertRoundTripParcelable(suggestion);
-
-        // DebugInfo should also be stored (but is not checked by equals())
-        suggestion.addDebugInfo("This is debug info");
-        ExternalTimeSuggestion rtSuggestion = roundTripParcelable(suggestion);
-        assertEquals(suggestion.getDebugInfo(), rtSuggestion.getDebugInfo());
-    }
-}
diff --git a/core/tests/coretests/src/android/os/FileUtilsTest.java b/core/tests/coretests/src/android/os/FileUtilsTest.java
index 1a86678..c1e72fe 100644
--- a/core/tests/coretests/src/android/os/FileUtilsTest.java
+++ b/core/tests/coretests/src/android/os/FileUtilsTest.java
@@ -228,6 +228,27 @@
     }
 
     @Test
+    public void testCopyFileWithAppend() throws Exception {
+        final File src = new File(mTarget, "src");
+        final File dest = new File(mTarget, "dest");
+
+        byte[] expected = new byte[10];
+        byte[] actual = new byte[10];
+        new Random().nextBytes(expected);
+        writeFile(src, expected);
+
+        try (FileInputStream in = new FileInputStream(src);
+                FileOutputStream out = new FileOutputStream(dest, true /* append */)) {
+            // sendfile(2) fails if output fd is opened with O_APPEND, but FileUtils#copy should
+            // fallback to userspace copy
+            FileUtils.copy(in, out);
+        }
+
+        actual = readFile(dest);
+        assertArrayEquals(expected, actual);
+    }
+
+    @Test
     public void testIsFilenameSafe() throws Exception {
         assertTrue(FileUtils.isFilenameSafe(new File("foobar")));
         assertTrue(FileUtils.isFilenameSafe(new File("a_b-c=d.e/0,1+23")));
@@ -577,7 +598,6 @@
 
         final File validVideoCameraDir = new File(cameraDir, "validVideo-" + nonce + ".mp4");
         final File validImageCameraDir = new File(cameraDir, "validImage-" + nonce + ".jpg");
-        final File invalidVideoCameraDir = new File(cameraDir, ".invalidVideo-" + nonce + ".mp4");
 
         final File validVideoNonCameraDir = new File(nonCameraDir, "validVideo-" + nonce + ".mp4");
         final File validImageNonCameraDir = new File(nonCameraDir, "validImage-" + nonce + ".jpg");
@@ -589,9 +609,6 @@
             FileDescriptor pfdValidImageCameraDir =
                     ParcelFileDescriptor.open(validImageCameraDir,
                             MODE_CREATE | MODE_READ_WRITE).getFileDescriptor();
-            FileDescriptor pfdInvalidVideoCameraDir =
-                    ParcelFileDescriptor.open(invalidVideoCameraDir,
-                            MODE_CREATE | MODE_READ_WRITE).getFileDescriptor();
 
             FileDescriptor pfdValidVideoNonCameraDir =
                     ParcelFileDescriptor.open(validVideoNonCameraDir,
@@ -603,13 +620,11 @@
             assertNotNull(convertToModernFd(pfdValidVideoCameraDir));
 
             assertNull(convertToModernFd(pfdValidImageCameraDir));
-            assertNull(convertToModernFd(pfdInvalidVideoCameraDir));
             assertNull(convertToModernFd(pfdValidVideoNonCameraDir));
             assertNull(convertToModernFd(pfdValidImageNonCameraDir));
         } finally {
             validVideoCameraDir.delete();
             validImageCameraDir.delete();
-            invalidVideoCameraDir.delete();
             validVideoNonCameraDir.delete();
             validImageNonCameraDir.delete();
         }
diff --git a/core/tests/coretests/src/android/service/timezone/ParcelableTestSupport.java b/core/tests/coretests/src/android/service/timezone/ParcelableTestSupport.java
deleted file mode 100644
index 777bda9..0000000
--- a/core/tests/coretests/src/android/service/timezone/ParcelableTestSupport.java
+++ /dev/null
@@ -1,53 +0,0 @@
-/*
- * 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.
- */
-
-package android.service.timezone;
-
-import static org.junit.Assert.assertEquals;
-
-import android.os.Parcel;
-import android.os.Parcelable;
-
-import java.lang.reflect.Field;
-
-/** Utility methods related to {@link Parcelable} objects used in several tests. */
-final class ParcelableTestSupport {
-
-    private ParcelableTestSupport() {}
-
-    /** Returns the result of parceling and unparceling the argument. */
-    @SuppressWarnings("unchecked")
-    public static <T extends Parcelable> T roundTripParcelable(T parcelable) {
-        Parcel parcel = Parcel.obtain();
-        parcel.writeTypedObject(parcelable, 0);
-        parcel.setDataPosition(0);
-
-        Parcelable.Creator<T> creator;
-        try {
-            Field creatorField = parcelable.getClass().getField("CREATOR");
-            creator = (Parcelable.Creator<T>) creatorField.get(null);
-        } catch (NoSuchFieldException | IllegalAccessException e) {
-            throw new AssertionError(e);
-        }
-        T toReturn = parcel.readTypedObject(creator);
-        parcel.recycle();
-        return toReturn;
-    }
-
-    public static <T extends Parcelable> void assertRoundTripParcelable(T instance) {
-        assertEquals(instance, roundTripParcelable(instance));
-    }
-}
diff --git a/core/tests/coretests/src/android/service/timezone/TimeZoneProviderSuggestionTest.java b/core/tests/coretests/src/android/service/timezone/TimeZoneProviderSuggestionTest.java
deleted file mode 100644
index f805555..0000000
--- a/core/tests/coretests/src/android/service/timezone/TimeZoneProviderSuggestionTest.java
+++ /dev/null
@@ -1,107 +0,0 @@
-/*
- * Copyright 2020 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.service.timezone;
-
-import static android.service.timezone.ParcelableTestSupport.assertRoundTripParcelable;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertNotEquals;
-
-import static java.util.Collections.singletonList;
-
-import org.junit.Test;
-
-import java.util.List;
-
-public class TimeZoneProviderSuggestionTest {
-
-    private static final long ARBITRARY_ELAPSED_REALTIME_MILLIS = 9999;
-
-    private static final List<String> ARBITRARY_TIME_ZONE_IDS = singletonList("Europe/London");
-
-    @Test(expected = RuntimeException.class)
-    public void testInvalidTimeZoneIds() {
-        new TimeZoneProviderSuggestion.Builder()
-                .setTimeZoneIds(null);
-    }
-
-    @Test
-    public void testEquals() {
-        TimeZoneProviderSuggestion.Builder builder1 = new TimeZoneProviderSuggestion.Builder()
-                .setElapsedRealtimeMillis(ARBITRARY_ELAPSED_REALTIME_MILLIS);
-        {
-            TimeZoneProviderSuggestion one = builder1.build();
-            assertEquals(one, one);
-        }
-
-        TimeZoneProviderSuggestion.Builder builder2 = new TimeZoneProviderSuggestion.Builder()
-                .setElapsedRealtimeMillis(ARBITRARY_ELAPSED_REALTIME_MILLIS);
-        {
-            TimeZoneProviderSuggestion one = builder1.build();
-            TimeZoneProviderSuggestion two = builder2.build();
-            assertEquals(one, two);
-            assertEquals(two, one);
-        }
-
-        builder1.setElapsedRealtimeMillis(ARBITRARY_ELAPSED_REALTIME_MILLIS + 1);
-        {
-            TimeZoneProviderSuggestion one = builder1.build();
-            TimeZoneProviderSuggestion two = builder2.build();
-            assertNotEquals(one, two);
-            assertNotEquals(two, one);
-        }
-
-        builder2.setElapsedRealtimeMillis(ARBITRARY_ELAPSED_REALTIME_MILLIS + 1);
-        {
-            TimeZoneProviderSuggestion one = builder1.build();
-            TimeZoneProviderSuggestion two = builder2.build();
-            assertEquals(one, two);
-            assertEquals(two, one);
-        }
-
-        builder2.setTimeZoneIds(ARBITRARY_TIME_ZONE_IDS);
-        {
-            TimeZoneProviderSuggestion one = builder1.build();
-            TimeZoneProviderSuggestion two = builder2.build();
-            assertNotEquals(one, two);
-            assertNotEquals(two, one);
-        }
-
-        builder1.setTimeZoneIds(ARBITRARY_TIME_ZONE_IDS);
-        {
-            TimeZoneProviderSuggestion one = builder1.build();
-            TimeZoneProviderSuggestion two = builder2.build();
-            assertEquals(one, two);
-            assertEquals(two, one);
-        }
-    }
-
-    @Test
-    public void testParcelable_noTimeZoneIds() {
-        TimeZoneProviderSuggestion.Builder builder = new TimeZoneProviderSuggestion.Builder()
-                .setElapsedRealtimeMillis(ARBITRARY_ELAPSED_REALTIME_MILLIS);
-        assertRoundTripParcelable(builder.build());
-    }
-
-    @Test
-    public void testParcelable_withTimeZoneIds() {
-        TimeZoneProviderSuggestion.Builder builder = new TimeZoneProviderSuggestion.Builder()
-                .setElapsedRealtimeMillis(ARBITRARY_ELAPSED_REALTIME_MILLIS)
-                .setTimeZoneIds(ARBITRARY_TIME_ZONE_IDS);
-        assertRoundTripParcelable(builder.build());
-    }
-}
diff --git a/core/tests/mockingcoretests/src/android/app/activity/ActivityThreadClientTest.java b/core/tests/mockingcoretests/src/android/app/activity/ActivityThreadClientTest.java
index 0808186..269d842 100644
--- a/core/tests/mockingcoretests/src/android/app/activity/ActivityThreadClientTest.java
+++ b/core/tests/mockingcoretests/src/android/app/activity/ActivityThreadClientTest.java
@@ -298,7 +298,8 @@
                     null /* pendingResults */, null /* pendingNewIntents */,
                     null /* activityOptions */, true /* isForward */, null /* profilerInfo */,
                     mThread /* client */, null /* asssitToken */,
-                    null /* fixedRotationAdjustments */, null /* shareableActivityToken */);
+                    null /* fixedRotationAdjustments */, null /* shareableActivityToken */,
+                    false /* launchedFromBubble */);
         }
 
         @Override
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleController.java
index 4ff1ce9..11c1464 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleController.java
@@ -16,6 +16,7 @@
 
 package com.android.wm.shell.bubbles;
 
+import static android.app.ActivityTaskManager.INVALID_TASK_ID;
 import static android.service.notification.NotificationListenerService.REASON_CANCEL;
 import static android.view.View.INVISIBLE;
 import static android.view.View.VISIBLE;
@@ -78,6 +79,8 @@
 import com.android.wm.shell.WindowManagerShellWrapper;
 import com.android.wm.shell.common.FloatingContentCoordinator;
 import com.android.wm.shell.common.ShellExecutor;
+import com.android.wm.shell.common.TaskStackListenerCallback;
+import com.android.wm.shell.common.TaskStackListenerImpl;
 import com.android.wm.shell.pip.PinnedStackListenerForwarder;
 
 import java.io.FileDescriptor;
@@ -124,6 +127,7 @@
     private final LauncherApps mLauncherApps;
     private final IStatusBarService mBarService;
     private final WindowManager mWindowManager;
+    private final TaskStackListenerImpl mTaskStackListener;
     private final ShellTaskOrganizer mTaskOrganizer;
 
     // Used to post to main UI thread
@@ -194,6 +198,7 @@
             WindowManager windowManager,
             WindowManagerShellWrapper windowManagerShellWrapper,
             LauncherApps launcherApps,
+            TaskStackListenerImpl taskStackListener,
             UiEventLogger uiEventLogger,
             ShellTaskOrganizer organizer,
             ShellExecutor mainExecutor,
@@ -204,7 +209,7 @@
         return new BubbleController(context, data, synchronizer, floatingContentCoordinator,
                 new BubbleDataRepository(context, launcherApps, mainExecutor),
                 statusBarService, windowManager, windowManagerShellWrapper, launcherApps,
-                logger, organizer, positioner, mainExecutor, mainHandler);
+                logger, taskStackListener, organizer, positioner, mainExecutor, mainHandler);
     }
 
     /**
@@ -221,6 +226,7 @@
             WindowManagerShellWrapper windowManagerShellWrapper,
             LauncherApps launcherApps,
             BubbleLogger bubbleLogger,
+            TaskStackListenerImpl taskStackListener,
             ShellTaskOrganizer organizer,
             BubblePositioner positioner,
             ShellExecutor mainExecutor,
@@ -238,6 +244,7 @@
         mLogger = bubbleLogger;
         mMainExecutor = mainExecutor;
         mMainHandler = mainHandler;
+        mTaskStackListener = taskStackListener;
         mTaskOrganizer = organizer;
         mSurfaceSynchronizer = synchronizer;
         mCurrentUserId = ActivityManager.getCurrentUser();
@@ -319,6 +326,42 @@
                         packageName, validShortcuts, DISMISS_SHORTCUT_REMOVED);
             }
         }, mMainHandler);
+
+        mTaskStackListener.addListener(new TaskStackListenerCallback() {
+            @Override
+            public void onTaskMovedToFront(int taskId) {
+                if (mSysuiProxy == null) {
+                    return;
+                }
+
+                mSysuiProxy.isNotificationShadeExpand((expand) -> {
+                    mMainExecutor.execute(() -> {
+                        int expandedId = INVALID_TASK_ID;
+                        if (mStackView != null && mStackView.getExpandedBubble() != null
+                                && isStackExpanded() && !mStackView.isExpansionAnimating()
+                                && !expand) {
+                            expandedId = mStackView.getExpandedBubble().getTaskId();
+                        }
+
+                        if (expandedId != INVALID_TASK_ID && expandedId != taskId) {
+                            mBubbleData.setExpanded(false);
+                        }
+                    });
+                });
+            }
+
+            @Override
+            public void onActivityRestartAttempt(ActivityManager.RunningTaskInfo task,
+                    boolean homeTaskVisible, boolean clearedTask, boolean wasVisible) {
+                for (Bubble b : mBubbleData.getBubbles()) {
+                    if (task.taskId == b.getTaskId()) {
+                        mBubbleData.setSelectedBubble(b);
+                        mBubbleData.setExpanded(true);
+                        return;
+                    }
+                }
+            }
+        });
     }
 
     @VisibleForTesting
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleExpandedView.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleExpandedView.java
index 9ef3fb5..abe1f71 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleExpandedView.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleExpandedView.java
@@ -154,6 +154,7 @@
                 }
                 try {
                     options.setTaskAlwaysOnTop(true);
+                    options.setLaunchedFromBubble(true);
                     if (!mIsOverflow && mBubble.hasMetadataShortcutId()) {
                         options.setApplyActivityFlagsForBubbles(true);
                         mTaskView.startShortcutActivity(mBubble.getShortcutInfo(),
@@ -163,7 +164,6 @@
                         // Apply flags to make behaviour match documentLaunchMode=always.
                         fillInIntent.addFlags(FLAG_ACTIVITY_NEW_DOCUMENT);
                         fillInIntent.addFlags(FLAG_ACTIVITY_MULTIPLE_TASK);
-                        fillInIntent.putExtra(Intent.EXTRA_IS_BUBBLED, true);
                         if (mBubble != null) {
                             mBubble.setIntentActive();
                         }
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/Bubbles.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/Bubbles.java
index 98978b5..9fc8aef 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/Bubbles.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/Bubbles.java
@@ -248,6 +248,8 @@
 
     /** Callback to tell SysUi components execute some methods. */
     interface SysuiProxy {
+        void isNotificationShadeExpand(Consumer<Boolean> callback);
+
         void getPendingOrActiveEntry(String key, Consumer<BubbleEntry> callback);
 
         void getShouldRestoredEntries(ArraySet<String> savedBubbleKeys,
diff --git a/native/android/surface_control.cpp b/native/android/surface_control.cpp
index e0f6379..7433cf9 100644
--- a/native/android/surface_control.cpp
+++ b/native/android/surface_control.cpp
@@ -432,14 +432,27 @@
                                      const ARect& destination, int32_t transform) {
     CHECK_NOT_NULL(aSurfaceTransaction);
     CHECK_NOT_NULL(aSurfaceControl);
-    CHECK_VALID_RECT(source);
     CHECK_VALID_RECT(destination);
 
+    Rect sourceRect = static_cast<const Rect&>(source);
+    // Adjust the source so its top and left are not negative
+    sourceRect.left = std::max(sourceRect.left, 0);
+    sourceRect.top = std::max(sourceRect.top, 0);
+    LOG_ALWAYS_FATAL_IF(sourceRect.isEmpty(), "invalid arg passed as source argument");
+
     sp<SurfaceControl> surfaceControl = ASurfaceControl_to_SurfaceControl(aSurfaceControl);
     Transaction* transaction = ASurfaceTransaction_to_Transaction(aSurfaceTransaction);
 
-    transaction->setCrop(surfaceControl, static_cast<const Rect&>(source));
-    transaction->setFrame(surfaceControl, static_cast<const Rect&>(destination));
+    transaction->setCrop(surfaceControl, sourceRect);
+
+    float dsdx = (destination.right - destination.left) /
+            static_cast<float>(sourceRect.right - sourceRect.left);
+    float dsdy = (destination.bottom - destination.top) /
+            static_cast<float>(sourceRect.bottom - sourceRect.top);
+
+    transaction->setPosition(surfaceControl, destination.left - (sourceRect.left * dsdx),
+                             destination.top - (sourceRect.top * dsdy));
+    transaction->setMatrix(surfaceControl, dsdx, 0, 0, dsdy);
     transaction->setTransform(surfaceControl, transform);
     bool transformToInverseDisplay = (NATIVE_WINDOW_TRANSFORM_INVERSE_DISPLAY & transform) ==
             NATIVE_WINDOW_TRANSFORM_INVERSE_DISPLAY;
@@ -458,16 +471,18 @@
     transaction->setCrop(surfaceControl, static_cast<const Rect&>(source));
 }
 
-void ASurfaceTransaction_setPosition(ASurfaceTransaction* aSurfaceTransaction,
-                                     ASurfaceControl* aSurfaceControl, const ARect& destination) {
-    CHECK_NOT_NULL(aSurfaceTransaction);
+void ASurfaceTransaction_setPosition(ASurfaceTransaction* /* aSurfaceTransaction */,
+                                     ASurfaceControl* /* aSurfaceControl */,
+                                     const ARect& /* destination */) {
+    // TODO: Fix this function
+    /* CHECK_NOT_NULL(aSurfaceTransaction);
     CHECK_NOT_NULL(aSurfaceControl);
     CHECK_VALID_RECT(destination);
 
     sp<SurfaceControl> surfaceControl = ASurfaceControl_to_SurfaceControl(aSurfaceControl);
     Transaction* transaction = ASurfaceTransaction_to_Transaction(aSurfaceTransaction);
 
-    transaction->setFrame(surfaceControl, static_cast<const Rect&>(destination));
+    transaction->setFrame(surfaceControl, static_cast<const Rect&>(destination));*/
 }
 
 void ASurfaceTransaction_setTransform(ASurfaceTransaction* aSurfaceTransaction,
diff --git a/packages/Connectivity/framework/api/module-lib-current.txt b/packages/Connectivity/framework/api/module-lib-current.txt
index caf7f49..4719772 100644
--- a/packages/Connectivity/framework/api/module-lib-current.txt
+++ b/packages/Connectivity/framework/api/module-lib-current.txt
@@ -133,16 +133,6 @@
     method @NonNull public android.net.NetworkRequest.Builder setUids(@Nullable java.util.Set<android.util.Range<java.lang.Integer>>);
   }
 
-  public final class TcpRepairWindow {
-    ctor public TcpRepairWindow(int, int, int, int, int, int);
-    field public final int maxWindow;
-    field public final int rcvWnd;
-    field public final int rcvWndScale;
-    field public final int rcvWup;
-    field public final int sndWl1;
-    field public final int sndWnd;
-  }
-
   public final class TestNetworkInterface implements android.os.Parcelable {
     ctor public TestNetworkInterface(@NonNull android.os.ParcelFileDescriptor, @NonNull String);
     method public int describeContents();
diff --git a/packages/Connectivity/framework/api/system-current.txt b/packages/Connectivity/framework/api/system-current.txt
index 2ac019d..63e0fe9 100644
--- a/packages/Connectivity/framework/api/system-current.txt
+++ b/packages/Connectivity/framework/api/system-current.txt
@@ -260,15 +260,15 @@
   public static final class NetworkAgentConfig.Builder {
     ctor public NetworkAgentConfig.Builder();
     method @NonNull public android.net.NetworkAgentConfig build();
-    method @NonNull public android.net.NetworkAgentConfig.Builder disableNat64Detection();
-    method @NonNull public android.net.NetworkAgentConfig.Builder disableProvisioningNotification();
     method @NonNull public android.net.NetworkAgentConfig.Builder setExplicitlySelected(boolean);
     method @NonNull public android.net.NetworkAgentConfig.Builder setLegacyExtraInfo(@NonNull String);
     method @NonNull public android.net.NetworkAgentConfig.Builder setLegacySubType(int);
     method @NonNull public android.net.NetworkAgentConfig.Builder setLegacySubTypeName(@NonNull String);
     method @NonNull public android.net.NetworkAgentConfig.Builder setLegacyType(int);
     method @NonNull public android.net.NetworkAgentConfig.Builder setLegacyTypeName(@NonNull String);
+    method @NonNull public android.net.NetworkAgentConfig.Builder setNat64DetectionEnabled(boolean);
     method @NonNull public android.net.NetworkAgentConfig.Builder setPartialConnectivityAcceptable(boolean);
+    method @NonNull public android.net.NetworkAgentConfig.Builder setProvisioningNotificationEnabled(boolean);
     method @NonNull public android.net.NetworkAgentConfig.Builder setUnvalidatedConnectivityAcceptable(boolean);
   }
 
diff --git a/packages/Connectivity/framework/src/android/net/NetworkAgentConfig.java b/packages/Connectivity/framework/src/android/net/NetworkAgentConfig.java
index 3f058d8..ad8396b 100644
--- a/packages/Connectivity/framework/src/android/net/NetworkAgentConfig.java
+++ b/packages/Connectivity/framework/src/android/net/NetworkAgentConfig.java
@@ -311,26 +311,28 @@
         }
 
         /**
-         * Disables active detection of NAT64 (e.g., via RFC 7050 DNS lookups). Used to save power
-         * and reduce idle traffic on networks that are known to be IPv6-only without a NAT64.
+         * Enables or disables active detection of NAT64 (e.g., via RFC 7050 DNS lookups). Used to
+         * save power and reduce idle traffic on networks that are known to be IPv6-only without a
+         * NAT64. By default, NAT64 detection is enabled.
          *
          * @return this builder, to facilitate chaining.
          */
         @NonNull
-        public Builder disableNat64Detection() {
-            mConfig.skip464xlat = true;
+        public Builder setNat64DetectionEnabled(boolean enabled) {
+            mConfig.skip464xlat = !enabled;
             return this;
         }
 
         /**
-         * Disables the "Sign in to network" notification. Used if the network transport will
-         * perform its own carrier-specific provisioning procedure.
+         * Enables or disables the "Sign in to network" notification. Used if the network transport
+         * will perform its own carrier-specific provisioning procedure. By default, the
+         * notification is enabled.
          *
          * @return this builder, to facilitate chaining.
          */
         @NonNull
-        public Builder disableProvisioningNotification() {
-            mConfig.provisioningNotificationDisabled = true;
+        public Builder setProvisioningNotificationEnabled(boolean enabled) {
+            mConfig.provisioningNotificationDisabled = !enabled;
             return this;
         }
 
diff --git a/packages/Connectivity/framework/src/android/net/TcpRepairWindow.java b/packages/Connectivity/framework/src/android/net/TcpRepairWindow.java
index f062fa9..86034f0 100644
--- a/packages/Connectivity/framework/src/android/net/TcpRepairWindow.java
+++ b/packages/Connectivity/framework/src/android/net/TcpRepairWindow.java
@@ -16,15 +16,12 @@
 
 package android.net;
 
-import android.annotation.SystemApi;
-
 /**
  * Corresponds to C's {@code struct tcp_repair_window} from
  * include/uapi/linux/tcp.h
  *
  * @hide
  */
-@SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
 public final class TcpRepairWindow {
     public final int sndWl1;
     public final int sndWnd;
diff --git a/packages/SettingsLib/MainSwitchPreference/res/layout-v31/main_switch_bar.xml b/packages/SettingsLib/MainSwitchPreference/res/layout-v31/main_switch_bar.xml
new file mode 100644
index 0000000..3ce9421
--- /dev/null
+++ b/packages/SettingsLib/MainSwitchPreference/res/layout-v31/main_switch_bar.xml
@@ -0,0 +1,75 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  Copyright (C) 2021 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.
+  -->
+
+<LinearLayout
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_height="wrap_content"
+    android:layout_width="match_parent"
+    android:background="?android:attr/colorBackground"
+    android:orientation="vertical">
+
+    <LinearLayout
+        android:id="@+id/frame"
+        android:minHeight="@dimen/min_switch_bar_height"
+        android:layout_height="wrap_content"
+        android:layout_width="match_parent"
+        android:background="?android:attr/selectableItemBackground"
+        android:paddingLeft="@dimen/switchbar_margin_start"
+        android:paddingRight="@dimen/switchbar_margin_end">
+
+        <TextView
+            android:id="@+id/switch_text"
+            android:layout_height="wrap_content"
+            android:layout_width="0dp"
+            android:layout_weight="1"
+            android:layout_marginRight="16dp"
+            android:layout_gravity="center_vertical"
+            android:maxLines="2"
+            android:ellipsize="end"
+            android:textAppearance="?android:attr/textAppearanceListItem"
+            android:textAlignment="viewStart"
+            style="@style/MainSwitchText" />
+
+        <ImageView
+            android:id="@+id/restricted_icon"
+            android:layout_width="@dimen/restricted_icon_size"
+            android:layout_height="@dimen/restricted_icon_size"
+            android:tint="?android:attr/colorAccent"
+            android:theme="@android:style/Theme.Material"
+            android:layout_gravity="center_vertical"
+            android:layout_marginEnd="@dimen/restricted_icon_margin_end"
+            android:src="@*android:drawable/ic_info"
+            android:visibility="gone" />
+
+        <Switch
+            android:id="@android:id/switch_widget"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:layout_gravity="center_vertical"
+            android:track="@drawable/track_selector"
+            android:thumb="@drawable/thumb_selector"
+            android:theme="@style/Settings.MainSwitch"/>
+    </LinearLayout>
+
+    <View
+        android:id="@+id/below_divider"
+        android:layout_width="match_parent"
+        android:layout_height="1dp"
+        android:background="?android:attr/listDivider" />
+</LinearLayout>
+
+
diff --git a/packages/SettingsLib/MainSwitchPreference/res/layout/main_switch_bar.xml b/packages/SettingsLib/MainSwitchPreference/res/layout/main_switch_bar.xml
index 85c01c5..5dc3209 100644
--- a/packages/SettingsLib/MainSwitchPreference/res/layout/main_switch_bar.xml
+++ b/packages/SettingsLib/MainSwitchPreference/res/layout/main_switch_bar.xml
@@ -1,6 +1,6 @@
 <?xml version="1.0" encoding="utf-8"?>
 <!--
-  Copyright (C) 2020 The Android Open Source Project
+  Copyright (C) 2021 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.
@@ -18,58 +18,40 @@
 <LinearLayout
     xmlns:android="http://schemas.android.com/apk/res/android"
     android:layout_height="wrap_content"
-    android:layout_width="match_parent"
-    android:background="?android:attr/colorBackground"
-    android:orientation="vertical">
+    android:layout_width="match_parent">
 
-    <LinearLayout
-        android:id="@+id/frame"
-        android:minHeight="@dimen/min_switch_bar_height"
+    <TextView
+        android:id="@+id/switch_text"
         android:layout_height="wrap_content"
-        android:layout_width="match_parent"
-        android:background="?android:attr/selectableItemBackground"
-        android:paddingLeft="@dimen/switchbar_margin_start"
-        android:paddingRight="@dimen/switchbar_margin_end">
+        android:layout_width="0dp"
+        android:layout_weight="1"
+        android:layout_gravity="center_vertical"
+        android:maxLines="2"
+        android:ellipsize="end"
+        android:textAppearance="@*android:style/TextAppearance.DeviceDefault.Widget.ActionBar.Title"
+        android:textSize="16sp"
+        android:textColor="?android:attr/textColorPrimaryInverse"
+        android:layout_marginStart="@dimen/switchbar_subsettings_margin_start"
+        android:textAlignment="viewStart"/>
 
-        <TextView
-            android:id="@+id/switch_text"
-            android:layout_height="wrap_content"
-            android:layout_width="0dp"
-            android:layout_weight="1"
-            android:layout_marginRight="16dp"
-            android:layout_gravity="center_vertical"
-            android:maxLines="2"
-            android:ellipsize="end"
-            android:textAppearance="?android:attr/textAppearanceListItem"
-            android:textAlignment="viewStart"
-            style="@style/MainSwitchText" />
+    <ImageView
+        android:id="@+id/restricted_icon"
+        android:layout_width="@dimen/restricted_icon_size"
+        android:layout_height="@dimen/restricted_icon_size"
+        android:tint="?android:attr/colorAccent"
+        android:theme="@android:style/Theme.Material"
+        android:layout_gravity="center_vertical"
+        android:layout_marginEnd="@dimen/restricted_icon_margin_end"
+        android:src="@*android:drawable/ic_info"
+        android:visibility="gone"/>
 
-        <ImageView
-            android:id="@+id/restricted_icon"
-            android:layout_width="@dimen/restricted_icon_size"
-            android:layout_height="@dimen/restricted_icon_size"
-            android:tint="?android:attr/colorAccent"
-            android:theme="@android:style/Theme.Material"
-            android:layout_gravity="center_vertical"
-            android:layout_marginEnd="@dimen/restricted_icon_margin_end"
-            android:src="@*android:drawable/ic_info"
-            android:visibility="gone" />
-
-        <Switch
-            android:id="@android:id/switch_widget"
-            android:layout_width="wrap_content"
-            android:layout_height="wrap_content"
-            android:layout_gravity="center_vertical"
-            android:track="@drawable/track_selector"
-            android:thumb="@drawable/thumb_selector"
-            android:theme="@style/Settings.MainSwitch"/>
-    </LinearLayout>
-
-    <View
-        android:id="@+id/below_divider"
-        android:layout_width="match_parent"
-        android:layout_height="1dp"
-        android:background="?android:attr/listDivider" />
+    <Switch
+        android:id="@android:id/switch_widget"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_gravity="center_vertical"
+        android:layout_marginEnd="@dimen/switchbar_subsettings_margin_end"
+        android:theme="@style/Widget.SwitchBar.Switch"/>
 </LinearLayout>
 
 
diff --git a/packages/SettingsLib/MainSwitchPreference/res/values-night/colors.xml b/packages/SettingsLib/MainSwitchPreference/res/values-night/colors.xml
index 147db77..e54569e 100644
--- a/packages/SettingsLib/MainSwitchPreference/res/values-night/colors.xml
+++ b/packages/SettingsLib/MainSwitchPreference/res/values-night/colors.xml
@@ -20,4 +20,6 @@
     <color name="thumb_off">#BFFFFFFF</color>
     <color name="track_off">@*android:color/material_grey_600</color>
 
+    <color name="switchbar_switch_track_tint">#82000000</color>
+    <color name="switchbar_switch_thumb_tint">@android:color/black</color>
 </resources>
diff --git a/packages/SettingsLib/MainSwitchPreference/res/values-sw600dp/dmiens.xml b/packages/SettingsLib/MainSwitchPreference/res/values-sw600dp/dmiens.xml
new file mode 100644
index 0000000..c6bb77d
--- /dev/null
+++ b/packages/SettingsLib/MainSwitchPreference/res/values-sw600dp/dmiens.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  Copyright (C) 2021 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>
+
+    <!-- SwitchBar sub settings margin start / end -->
+    <dimen name="switchbar_subsettings_margin_start">80dp</dimen>
+</resources>
diff --git a/packages/SettingsLib/MainSwitchPreference/res/values-sw720dp-land/dmiens.xml b/packages/SettingsLib/MainSwitchPreference/res/values-sw720dp-land/dmiens.xml
new file mode 100644
index 0000000..3e941c2
--- /dev/null
+++ b/packages/SettingsLib/MainSwitchPreference/res/values-sw720dp-land/dmiens.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  Copyright (C) 2021 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>
+
+    <!-- SwitchBar sub settings margin start / end -->
+    <dimen name="switchbar_subsettings_margin_start">128dp</dimen>
+    <dimen name="switchbar_subsettings_margin_end">128dp</dimen>
+</resources>
diff --git a/packages/SettingsLib/MainSwitchPreference/res/values-sw720dp/dmiens.xml b/packages/SettingsLib/MainSwitchPreference/res/values-sw720dp/dmiens.xml
new file mode 100644
index 0000000..2f040da
--- /dev/null
+++ b/packages/SettingsLib/MainSwitchPreference/res/values-sw720dp/dmiens.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  Copyright (C) 2021 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>
+
+    <!-- SwitchBar sub settings margin start / end -->
+    <dimen name="switchbar_subsettings_margin_start">80dp</dimen>
+    <dimen name="switchbar_subsettings_margin_end">80dp</dimen>
+</resources>
diff --git a/packages/SettingsLib/MainSwitchPreference/res/values/colors.xml b/packages/SettingsLib/MainSwitchPreference/res/values/colors.xml
index 147db77..b5a73b1 100644
--- a/packages/SettingsLib/MainSwitchPreference/res/values/colors.xml
+++ b/packages/SettingsLib/MainSwitchPreference/res/values/colors.xml
@@ -20,4 +20,7 @@
     <color name="thumb_off">#BFFFFFFF</color>
     <color name="track_off">@*android:color/material_grey_600</color>
 
+    <color name="switchbar_background_color">@*android:color/material_grey_600</color>
+    <color name="switchbar_switch_track_tint">#BFFFFFFF</color>
+    <color name="switchbar_switch_thumb_tint">@android:color/white</color>
 </resources>
diff --git a/packages/SettingsLib/MainSwitchPreference/res/values/dimens.xml b/packages/SettingsLib/MainSwitchPreference/res/values/dimens.xml
index b145c9b..c471bcd 100644
--- a/packages/SettingsLib/MainSwitchPreference/res/values/dimens.xml
+++ b/packages/SettingsLib/MainSwitchPreference/res/values/dimens.xml
@@ -34,4 +34,8 @@
 
     <!-- Restricted icon in switch bar -->
     <dimen name="restricted_icon_margin_end">16dp</dimen>
+
+    <!-- SwitchBar sub settings margin start / end -->
+    <dimen name="switchbar_subsettings_margin_start">72dp</dimen>
+    <dimen name="switchbar_subsettings_margin_end">16dp</dimen>
 </resources>
diff --git a/packages/SettingsLib/MainSwitchPreference/res/values/styles.xml b/packages/SettingsLib/MainSwitchPreference/res/values/styles.xml
index 59b5899..e058097 100644
--- a/packages/SettingsLib/MainSwitchPreference/res/values/styles.xml
+++ b/packages/SettingsLib/MainSwitchPreference/res/values/styles.xml
@@ -25,4 +25,10 @@
         <item name="android:switchMinWidth">@dimen/min_switch_width</item>
     </style>
 
+    <style name="Widget.SwitchBar.Switch" parent="@android:style/Widget.Material.CompoundButton.Switch">
+        <item name="android:trackTint">@color/switchbar_switch_track_tint</item>
+        <item name="android:thumbTint">@color/switchbar_switch_thumb_tint</item>
+        <item name="android:minHeight">48dp</item>
+        <item name="android:minWidth">48dp</item>
+    </style>
 </resources>
diff --git a/packages/SettingsLib/MainSwitchPreference/src/com/android/settingslib/widget/MainSwitchBar.java b/packages/SettingsLib/MainSwitchPreference/src/com/android/settingslib/widget/MainSwitchBar.java
index ae9261c..2be3f0d 100644
--- a/packages/SettingsLib/MainSwitchPreference/src/com/android/settingslib/widget/MainSwitchBar.java
+++ b/packages/SettingsLib/MainSwitchPreference/src/com/android/settingslib/widget/MainSwitchBar.java
@@ -28,7 +28,8 @@
 import android.widget.Switch;
 import android.widget.TextView;
 
-import androidx.core.content.res.TypedArrayUtils;
+import androidx.annotation.ColorInt;
+import androidx.core.os.BuildCompat;
 
 import java.util.ArrayList;
 import java.util.List;
@@ -42,8 +43,11 @@
 
     private final List<OnMainSwitchChangeListener> mSwitchChangeListeners = new ArrayList<>();
 
-    private View mAboveDivider;
-    private View mBelowDivider;
+    @ColorInt
+    private int mBackgroundColor;
+    @ColorInt
+    private int mBackgroundActivatedColor;
+
     protected TextView mTextView;
     protected Switch mSwitch;
 
@@ -66,6 +70,14 @@
         LayoutInflater.from(context).inflate(resourceId(context, "layout", "main_switch_bar"),
                 this);
 
+        if (!BuildCompat.isAtLeastS()) {
+            final TypedArray a = context.obtainStyledAttributes(
+                    new int[]{android.R.attr.colorAccent});
+            mBackgroundActivatedColor = a.getColor(0, 0);
+            mBackgroundColor = context.getColor(R.color.switchbar_background_color);
+            a.recycle();
+        }
+
         setFocusable(true);
         setClickable(true);
 
@@ -80,12 +92,13 @@
             final TypedArray a = context.obtainStyledAttributes(attrs,
                     androidx.preference.R.styleable.Preference, 0 /*defStyleAttr*/,
                     0 /*defStyleRes*/);
-            final CharSequence title = TypedArrayUtils.getText(a,
-                    androidx.preference.R.styleable.Preference_title,
+            final CharSequence title = a.getText(
                     androidx.preference.R.styleable.Preference_android_title);
             setTitle(title);
             a.recycle();
         }
+
+        setBackground(true);
     }
 
     @Override
@@ -105,6 +118,7 @@
         if (mSwitch != null) {
             mSwitch.setChecked(checked);
         }
+        setBackground(checked);
     }
 
     /**
@@ -189,6 +203,14 @@
         }
     }
 
+    private void setBackground(boolean checked) {
+        if (BuildCompat.isAtLeastS()) {
+            return;
+        }
+
+        setBackgroundColor(checked ? mBackgroundActivatedColor : mBackgroundColor);
+    }
+
     static class SavedState extends BaseSavedState {
         boolean mChecked;
         boolean mVisible;
diff --git a/packages/SettingsLib/MainSwitchPreference/src/com/android/settingslib/widget/MainSwitchPreference.java b/packages/SettingsLib/MainSwitchPreference/src/com/android/settingslib/widget/MainSwitchPreference.java
index ebeffcc..1f7f8d4 100644
--- a/packages/SettingsLib/MainSwitchPreference/src/com/android/settingslib/widget/MainSwitchPreference.java
+++ b/packages/SettingsLib/MainSwitchPreference/src/com/android/settingslib/widget/MainSwitchPreference.java
@@ -20,7 +20,6 @@
 import android.content.res.TypedArray;
 import android.util.AttributeSet;
 
-import androidx.core.content.res.TypedArrayUtils;
 import androidx.preference.PreferenceViewHolder;
 import androidx.preference.TwoStatePreference;
 
@@ -79,8 +78,7 @@
             final TypedArray a = context.obtainStyledAttributes(attrs,
                     androidx.preference.R.styleable.Preference, 0 /*defStyleAttr*/,
                     0 /*defStyleRes*/);
-            final CharSequence title = TypedArrayUtils.getText(a,
-                    androidx.preference.R.styleable.Preference_title,
+            final CharSequence title = a.getText(
                     androidx.preference.R.styleable.Preference_android_title);
             setTitle(title);
             a.recycle();
diff --git a/packages/SettingsLib/SettingsTheme/res/values-v31/dimens.xml b/packages/SettingsLib/SettingsTheme/res/values-v31/dimens.xml
index 17b6805..d092666 100644
--- a/packages/SettingsLib/SettingsTheme/res/values-v31/dimens.xml
+++ b/packages/SettingsLib/SettingsTheme/res/values-v31/dimens.xml
@@ -19,7 +19,7 @@
     <dimen name="preference_title_font_size">20sp</dimen>
     <dimen name="icon_min_width">48dp</dimen>
     <dimen name="preference_padding_start">24dp</dimen>
-    <dimen name="preference_padding_end">24dp</dimen>
+    <dimen name="preference_padding_end">16dp</dimen>
     <dimen name="app_preference_padding_start">20dp</dimen>
     <dimen name="app_icon_min_width">52dp</dimen>
 </resources>
diff --git a/packages/SettingsLib/SettingsTheme/res/values/styles_preference.xml b/packages/SettingsLib/SettingsTheme/res/values/styles_preference.xml
index 17596ac2..dcbdc07 100644
--- a/packages/SettingsLib/SettingsTheme/res/values/styles_preference.xml
+++ b/packages/SettingsLib/SettingsTheme/res/values/styles_preference.xml
@@ -15,6 +15,7 @@
   limitations under the License.
   -->
 <resources>
+    <!--DEPRECATED. It will remove after all of client team migrated to new style. -->
     <style name="PreferenceTheme" parent="@style/PreferenceThemeOverlay">
         <item name="preferenceCategoryStyle">@style/SettingsCategoryPreference</item>
         <item name="preferenceStyle">@style/SettingsPreference</item>
@@ -27,6 +28,18 @@
         <item name="footerPreferenceStyle">@style/Preference.Material</item>
     </style>
 
+    <style name="SettingsPreferenceTheme" parent="@style/PreferenceThemeOverlay">
+        <item name="preferenceCategoryStyle">@style/SettingsCategoryPreference</item>
+        <item name="preferenceStyle">@style/SettingsPreference</item>
+        <item name="checkBoxPreferenceStyle">@style/SettingsCheckBoxPreference</item>
+        <item name="dialogPreferenceStyle">@style/SettingsPreference</item>
+        <item name="editTextPreferenceStyle">@style/SettingsEditTextPreference</item>
+        <item name="dropdownPreferenceStyle">@style/SettingsDropdownPreference</item>
+        <item name="switchPreferenceStyle">@style/SettingsSwitchPreference</item>
+        <item name="seekBarPreferenceStyle">@style/SettingsSeekbarPreference</item>
+        <item name="footerPreferenceStyle">@style/Preference.Material</item>
+    </style>
+
     <style name="SettingsCategoryPreference" parent="@style/Preference.Category.Material">
         <item name="iconSpaceReserved">@bool/config_icon_space_reserved</item>
         <item name="allowDividerAbove">@bool/config_allow_divider</item>
diff --git a/packages/SettingsLib/SettingsTheme/res/values/themes.xml b/packages/SettingsLib/SettingsTheme/res/values/themes.xml
index 36ca684..13c7523 100644
--- a/packages/SettingsLib/SettingsTheme/res/values/themes.xml
+++ b/packages/SettingsLib/SettingsTheme/res/values/themes.xml
@@ -21,7 +21,7 @@
         <item name="android:textAppearanceListItem">@style/TextAppearance.PreferenceTitle</item>
         <item name="android:listPreferredItemPaddingStart">@dimen/preference_padding_start</item>
         <item name="android:listPreferredItemPaddingEnd">@dimen/preference_padding_end</item>
-        <item name="preferenceTheme">@style/PreferenceTheme</item>
+        <item name="preferenceTheme">@style/SettingsPreferenceTheme</item>
     </style>
 
     <!-- Using in SubSettings page including injected settings page -->
diff --git a/packages/SettingsLib/tests/integ/src/com/android/settingslib/wifi/AccessPointTest.java b/packages/SettingsLib/tests/integ/src/com/android/settingslib/wifi/AccessPointTest.java
index 46ecbd4..cb41743 100644
--- a/packages/SettingsLib/tests/integ/src/com/android/settingslib/wifi/AccessPointTest.java
+++ b/packages/SettingsLib/tests/integ/src/com/android/settingslib/wifi/AccessPointTest.java
@@ -694,6 +694,16 @@
         assertThat(ap.getTitle()).isEqualTo(providerFriendlyName);
     }
 
+    // This method doesn't copy mIsFailover, mIsAvailable and mIsRoaming because NetworkInfo
+    // doesn't expose those three set methods. But that's fine since the tests don't use those three
+    // variables.
+    private NetworkInfo copyNetworkInfo(NetworkInfo ni) {
+        final NetworkInfo copy = new NetworkInfo(ni.getType(), ni.getSubtype(), ni.getTypeName(),
+                ni.getSubtypeName());
+        copy.setDetailedState(ni.getDetailedState(), ni.getReason(), ni.getExtraInfo());
+        return copy;
+    }
+
     @Test
     public void testUpdateNetworkInfo_returnsTrue() {
         int networkId = 123;
@@ -715,7 +725,7 @@
                 .setWifiInfo(wifiInfo)
                 .build();
 
-        NetworkInfo newInfo = new NetworkInfo(networkInfo);
+        NetworkInfo newInfo = copyNetworkInfo(networkInfo);
         newInfo.setDetailedState(NetworkInfo.DetailedState.CONNECTED, "", "");
         assertThat(ap.update(config, wifiInfo, newInfo)).isTrue();
     }
@@ -741,7 +751,7 @@
                 .setWifiInfo(wifiInfo)
                 .build();
 
-        NetworkInfo newInfo = new NetworkInfo(networkInfo); // same values
+        NetworkInfo newInfo = copyNetworkInfo(networkInfo); // same values
         assertThat(ap.update(config, wifiInfo, newInfo)).isFalse();
     }
 
@@ -766,7 +776,7 @@
                 .setWifiInfo(wifiInfo)
                 .build();
 
-        NetworkInfo newInfo = new NetworkInfo(networkInfo); // same values
+        NetworkInfo newInfo = copyNetworkInfo(networkInfo); // same values
         wifiInfo.setRssi(rssi + 1);
         assertThat(ap.update(config, wifiInfo, newInfo)).isTrue();
     }
@@ -792,7 +802,7 @@
                 .setWifiInfo(wifiInfo)
                 .build();
 
-        NetworkInfo newInfo = new NetworkInfo(networkInfo); // same values
+        NetworkInfo newInfo = copyNetworkInfo(networkInfo); // same values
         wifiInfo.setRssi(WifiInfo.INVALID_RSSI);
         assertThat(ap.update(config, wifiInfo, newInfo)).isFalse();
     }
diff --git a/packages/SystemUI/AndroidManifest.xml b/packages/SystemUI/AndroidManifest.xml
index bcde002..a834784 100644
--- a/packages/SystemUI/AndroidManifest.xml
+++ b/packages/SystemUI/AndroidManifest.xml
@@ -682,7 +682,7 @@
         <activity
             android:name=".settings.brightness.BrightnessDialog"
             android:label="@string/quick_settings_brightness_dialog_title"
-            android:theme="@*android:style/Theme.DeviceDefault.SystemUI.Dialog"
+            android:theme="@style/Theme.SystemUI.QuickSettings.BrightnessDialog"
             android:finishOnCloseSystemDialogs="true"
             android:launchMode="singleInstance"
             android:excludeFromRecents="true"
diff --git a/packages/SystemUI/res-keyguard/layout/keyguard_clock_switch.xml b/packages/SystemUI/res-keyguard/layout/keyguard_clock_switch.xml
index 6ecbe06..00c27bf 100644
--- a/packages/SystemUI/res-keyguard/layout/keyguard_clock_switch.xml
+++ b/packages/SystemUI/res-keyguard/layout/keyguard_clock_switch.xml
@@ -25,65 +25,30 @@
     android:layout_height="wrap_content"
     android:layout_gravity="center_horizontal|top">
     <FrameLayout
-         android:id="@+id/clock_view"
-         android:layout_width="match_parent"
-         android:layout_height="wrap_content"
-         android:layout_gravity="center_horizontal"
-         android:layout_alignParentTop="true">
-        <TextClock
-             android:id="@+id/default_clock_view"
-             android:layout_width="match_parent"
-             android:layout_height="wrap_content"
-             android:layout_gravity="center_horizontal"
-             android:gravity="center_horizontal"
-             android:paddingBottom="@dimen/title_clock_padding"
-             android:letterSpacing="0.02"
-             android:textColor="?attr/wallpaperTextColor"
-             android:singleLine="true"
-             style="@style/widget_big"
-             android:format12Hour="@string/keyguard_widget_12_hours_format"
-             android:format24Hour="@string/keyguard_widget_24_hours_format"
-             android:elegantTextHeight="false"
-        />
-        <TextClock
-             android:id="@+id/default_clock_view_bold"
-             android:layout_width="match_parent"
-             android:layout_height="wrap_content"
-             android:layout_gravity="bottom|center_horizontal"
-             android:gravity="center_horizontal"
-             android:textColor="?attr/wallpaperTextColor"
-             android:singleLine="true"
-             style="@style/widget_title_bold"
-             android:format12Hour="@string/keyguard_widget_12_hours_format"
-             android:format24Hour="@string/keyguard_widget_24_hours_format"
-             android:elegantTextHeight="false"
-             android:visibility="invisible"
-             />
-    </FrameLayout>
-    <FrameLayout
-        android:id="@+id/new_lockscreen_clock_view"
+        android:id="@+id/lockscreen_clock_view"
         android:layout_width="wrap_content"
         android:layout_height="wrap_content"
         android:layout_alignParentStart="true"
         android:layout_alignParentTop="true"
-        android:visibility="gone">
+        android:paddingStart="@dimen/clock_padding_start">
         <com.android.keyguard.AnimatableClockView
             android:id="@+id/animatable_clock_view"
             android:layout_width="wrap_content"
             android:layout_height="wrap_content"
             android:layout_gravity="center_horizontal"
             android:gravity="center_horizontal"
-            android:textSize="86dp"
+            android:textSize="@dimen/clock_text_size"
             android:fontFamily="@font/clock"
             android:typeface="monospace"
             android:elegantTextHeight="false"
             android:singleLine="true"
+            chargeAnimationDelay="350"
             dozeWeight="200"
             lockScreenWeight="400"
         />
     </FrameLayout>
     <FrameLayout
-        android:id="@+id/new_lockscreen_clock_view_large"
+        android:id="@+id/lockscreen_clock_view_large"
         android:layout_width="match_parent"
         android:layout_height="wrap_content"
         android:layout_below="@id/keyguard_status_area"
@@ -98,6 +63,7 @@
             android:fontFamily="@font/clock"
             android:typeface="monospace"
             android:elegantTextHeight="false"
+            chargeAnimationDelay="200"
             dozeWeight="200"
             lockScreenWeight="400"
         />
@@ -106,7 +72,8 @@
         android:id="@+id/keyguard_status_area"
         android:layout_width="match_parent"
         android:layout_height="wrap_content"
-        android:layout_below="@id/clock_view" />
+        android:layout_alignParentStart="true"
+        android:layout_below="@id/lockscreen_clock_view" />
 
     <com.android.systemui.statusbar.phone.NotificationIconContainer
         android:id="@+id/left_aligned_notification_icon_container"
@@ -114,6 +81,6 @@
         android:layout_height="@dimen/notification_shelf_height"
         android:layout_marginTop="@dimen/widget_vertical_padding"
         android:layout_below="@id/keyguard_status_area"
-        android:visibility="gone"
+        android:paddingStart="@dimen/below_clock_padding_start"
     />
 </com.android.keyguard.KeyguardClockSwitch>
diff --git a/packages/SystemUI/res-keyguard/layout/keyguard_status_area.xml b/packages/SystemUI/res-keyguard/layout/keyguard_status_area.xml
index 9f3ca74..95eb5c1 100644
--- a/packages/SystemUI/res-keyguard/layout/keyguard_status_area.xml
+++ b/packages/SystemUI/res-keyguard/layout/keyguard_status_area.xml
@@ -25,6 +25,7 @@
     android:layout_gravity="center_horizontal"
     android:clipToPadding="false"
     android:orientation="vertical"
+    android:paddingStart="@dimen/below_clock_padding_start"
     android:layout_centerHorizontal="true">
     <TextView
               android:id="@+id/title"
diff --git a/packages/SystemUI/res-keyguard/layout/keyguard_status_view.xml b/packages/SystemUI/res-keyguard/layout/keyguard_status_view.xml
index 10cd3cb..c5ba3d2 100644
--- a/packages/SystemUI/res-keyguard/layout/keyguard_status_view.xml
+++ b/packages/SystemUI/res-keyguard/layout/keyguard_status_view.xml
@@ -70,12 +70,5 @@
             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"
-            android:visibility="invisible"
-        />
     </LinearLayout>
 </com.android.keyguard.KeyguardStatusView>
diff --git a/packages/SystemUI/res-keyguard/values/attrs.xml b/packages/SystemUI/res-keyguard/values/attrs.xml
index eb7a1f7..25be37a 100644
--- a/packages/SystemUI/res-keyguard/values/attrs.xml
+++ b/packages/SystemUI/res-keyguard/values/attrs.xml
@@ -45,5 +45,6 @@
     <declare-styleable name="AnimatableClockView">
         <attr name="dozeWeight" format="integer" />
         <attr name="lockScreenWeight" format="integer" />
+        <attr name="chargeAnimationDelay" format="integer" />
     </declare-styleable>
 </resources>
diff --git a/packages/SystemUI/res-keyguard/values/dimens.xml b/packages/SystemUI/res-keyguard/values/dimens.xml
index 07bd2e6..9b8035d 100644
--- a/packages/SystemUI/res-keyguard/values/dimens.xml
+++ b/packages/SystemUI/res-keyguard/values/dimens.xml
@@ -90,4 +90,8 @@
     <dimen name="num_pad_key_width">72dp</dimen>
     <dimen name="num_pad_row_margin_bottom">6dp</dimen>
     <dimen name="num_pad_key_margin_end">12dp</dimen>
+
+    <!-- additional offset for clock switch area items -->
+    <dimen name="clock_padding_start">28dp</dimen>
+    <dimen name="below_clock_padding_start">32dp</dimen>
 </resources>
diff --git a/packages/SystemUI/res/drawable/brightness_mirror_background.xml b/packages/SystemUI/res/drawable/brightness_mirror_background.xml
index 4b225b7..ae3d312 100644
--- a/packages/SystemUI/res/drawable/brightness_mirror_background.xml
+++ b/packages/SystemUI/res/drawable/brightness_mirror_background.xml
@@ -15,6 +15,6 @@
   ~ limitations under the License
   -->
 <shape xmlns:android="http://schemas.android.com/apk/res/android">
-    <solid android:color="?android:attr/colorBackgroundFloating" />
+    <solid android:color="?attr/underSurfaceColor" />
     <corners android:radius="8dp" />
 </shape>
diff --git a/packages/SystemUI/res/drawable/brightness_progress_drawable.xml b/packages/SystemUI/res/drawable/brightness_progress_drawable.xml
index 73b02f4..88d8f78f 100644
--- a/packages/SystemUI/res/drawable/brightness_progress_drawable.xml
+++ b/packages/SystemUI/res/drawable/brightness_progress_drawable.xml
@@ -24,7 +24,7 @@
             <shape>
                 <size android:height="@dimen/rounded_slider_track_width" />
                 <corners android:radius="@dimen/rounded_slider_track_corner_radius" />
-                <solid android:color="?android:attr/textColorPrimary" />
+                <solid android:color="?attr/offStateColor" />
             </shape>
         </inset>
     </item>
diff --git a/packages/SystemUI/res/drawable/brightness_progress_full_drawable.xml b/packages/SystemUI/res/drawable/brightness_progress_full_drawable.xml
index f8f455d..ceef9f9 100644
--- a/packages/SystemUI/res/drawable/brightness_progress_full_drawable.xml
+++ b/packages/SystemUI/res/drawable/brightness_progress_full_drawable.xml
@@ -16,12 +16,13 @@
   -->
 
 <layer-list xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:priv-android="http://schemas.android.com/apk/prv/res/android"
     android:autoMirrored="true">
     <item android:id="@+id/slider_foreground"
         android:height="@dimen/rounded_slider_height">
         <shape>
             <size android:height="@dimen/rounded_slider_height" />
-            <solid android:color="?android:attr/colorControlActivated" />
+            <solid android:color="?priv-android:attr/colorAccentPrimary" />
             <corners android:radius="@dimen/rounded_slider_corner_radius"/>
         </shape>
     </item>
diff --git a/packages/SystemUI/res/drawable/qs_background_primary.xml b/packages/SystemUI/res/drawable/qs_background_primary.xml
index 0a3afc5..30d026e 100644
--- a/packages/SystemUI/res/drawable/qs_background_primary.xml
+++ b/packages/SystemUI/res/drawable/qs_background_primary.xml
@@ -16,7 +16,7 @@
   -->
 <inset xmlns:android="http://schemas.android.com/apk/res/android">
     <shape>
-        <solid android:color="?android:attr/colorBackground"/>
+        <solid android:color="?attr/underSurfaceColor"/>
         <corners android:radius="@dimen/notification_corner_radius" />
     </shape>
 </inset>
\ No newline at end of file
diff --git a/packages/SystemUI/res/drawable/qs_customize_tile_decoration.xml b/packages/SystemUI/res/drawable/qs_customize_tile_decoration.xml
index f086cec..1124a92 100644
--- a/packages/SystemUI/res/drawable/qs_customize_tile_decoration.xml
+++ b/packages/SystemUI/res/drawable/qs_customize_tile_decoration.xml
@@ -14,4 +14,4 @@
      limitations under the License.
 -->
 <color xmlns:android="http://schemas.android.com/apk/res/android"
-       android:color="@color/qs_customize_decoration"/>
\ No newline at end of file
+       android:color="?android:attr/colorBackground"/>
\ No newline at end of file
diff --git a/packages/SystemUI/res/drawable/qs_customizer_background_primary.xml b/packages/SystemUI/res/drawable/qs_customizer_background_primary.xml
index c2d0841..ea0aafd 100644
--- a/packages/SystemUI/res/drawable/qs_customizer_background_primary.xml
+++ b/packages/SystemUI/res/drawable/qs_customizer_background_primary.xml
@@ -15,7 +15,7 @@
 -->
 <inset xmlns:android="http://schemas.android.com/apk/res/android">
     <shape>
-        <solid android:color="?android:attr/colorBackgroundFloating"/>
+        <solid android:color="?attr/underSurfaceColor"/>
         <corners android:radius="?android:attr/dialogCornerRadius" />
     </shape>
 </inset>
diff --git a/packages/SystemUI/res/drawable/qs_customizer_toolbar.xml b/packages/SystemUI/res/drawable/qs_customizer_toolbar.xml
index 4165830..ef950fe 100644
--- a/packages/SystemUI/res/drawable/qs_customizer_toolbar.xml
+++ b/packages/SystemUI/res/drawable/qs_customizer_toolbar.xml
@@ -15,6 +15,6 @@
 -->
 <inset xmlns:android="http://schemas.android.com/apk/res/android">
     <shape>
-        <solid android:color="?android:attr/colorBackgroundFloating"/>
+        <solid android:color="?attr/underSurfaceColor"/>
     </shape>
 </inset>
diff --git a/packages/SystemUI/res/drawable/privacy_dialog_bg.xml b/packages/SystemUI/res/drawable/qs_dialog_bg.xml
similarity index 91%
rename from packages/SystemUI/res/drawable/privacy_dialog_bg.xml
rename to packages/SystemUI/res/drawable/qs_dialog_bg.xml
index 96136c4..b307781 100644
--- a/packages/SystemUI/res/drawable/privacy_dialog_bg.xml
+++ b/packages/SystemUI/res/drawable/qs_dialog_bg.xml
@@ -18,5 +18,5 @@
 <shape xmlns:android="http://schemas.android.com/apk/res/android"
        android:shape="rectangle">
     <solid android:color="?android:attr/colorBackground" />
-    <corners android:radius="@dimen/ongoing_appops_dialog_bg_corner_radius" />
+    <corners android:radius="?android:attr/dialogCornerRadius" />
 </shape>
\ No newline at end of file
diff --git a/packages/SystemUI/res/layout/brightness_mirror.xml b/packages/SystemUI/res/layout/brightness_mirror.xml
index 8b47ab9..b714767 100644
--- a/packages/SystemUI/res/layout/brightness_mirror.xml
+++ b/packages/SystemUI/res/layout/brightness_mirror.xml
@@ -16,6 +16,7 @@
   -->
 <FrameLayout
     xmlns:android="http://schemas.android.com/apk/res/android"
+    android:theme="@style/Theme.SystemUI.QuickSettings"
     android:id="@+id/brightness_mirror"
     android:layout_width="@dimen/qs_panel_width"
     android:layout_height="@dimen/brightness_mirror_height"
diff --git a/packages/SystemUI/res/layout/privacy_dialog.xml b/packages/SystemUI/res/layout/privacy_dialog.xml
index 4d77a0d..720ae8db 100644
--- a/packages/SystemUI/res/layout/privacy_dialog.xml
+++ b/packages/SystemUI/res/layout/privacy_dialog.xml
@@ -28,7 +28,7 @@
     android:paddingRight="@dimen/ongoing_appops_dialog_side_padding"
     android:paddingBottom="12dp"
     android:paddingTop="8dp"
-    android:background="@drawable/privacy_dialog_bg"
+    android:background="@drawable/qs_dialog_bg"
 />
 <!-- 12dp padding bottom so there's 20dp total under the icon -->
 <!-- 8dp padding top, as there's 4dp margin in each row -->
\ No newline at end of file
diff --git a/packages/SystemUI/res/layout/privacy_dialog_item.xml b/packages/SystemUI/res/layout/privacy_dialog_item.xml
index 91ffe22..0c8ed9f 100644
--- a/packages/SystemUI/res/layout/privacy_dialog_item.xml
+++ b/packages/SystemUI/res/layout/privacy_dialog_item.xml
@@ -51,6 +51,7 @@
     />
 
     <ImageView
+        android:id="@+id/chevron"
         android:layout_height="24dp"
         android:layout_width="24dp"
         android:layout_gravity="center_vertical"
diff --git a/packages/SystemUI/res/values-night/colors.xml b/packages/SystemUI/res/values-night/colors.xml
index 471f36b..d7a6103 100644
--- a/packages/SystemUI/res/values-night/colors.xml
+++ b/packages/SystemUI/res/values-night/colors.xml
@@ -47,9 +47,6 @@
     <color name="notification_section_clear_all_btn_color">@color/GM2_grey_500</color>
     <color name="notification_channel_dialog_separator">@color/GM2_grey_700</color>
 
-    <!-- The color of the background in the bottom part of QSCustomizer -->
-    <color name="qs_customize_decoration">@color/GM2_grey_900</color>
-
     <!-- The color of the background in the separated list of the Global Actions menu -->
     <color name="global_actions_separated_background">@color/GM2_grey_900</color>
 
diff --git a/packages/SystemUI/res/values-sw600dp-land/dimens.xml b/packages/SystemUI/res/values-sw600dp-land/dimens.xml
index f2df4b9..302e5e4 100644
--- a/packages/SystemUI/res/values-sw600dp-land/dimens.xml
+++ b/packages/SystemUI/res/values-sw600dp-land/dimens.xml
@@ -40,4 +40,9 @@
     <dimen name="qs_tile_margin_top">32dp</dimen>
     <dimen name="qs_brightness_padding_top">6dp</dimen>
     <dimen name="qs_detail_margin_top">28dp</dimen>
+
+    <!-- In split shade mode notifications should be aligned to QS header so the value should be
+     adjusted to qs header height and height of centered content inside of it:
+    (quick_qs_offset_height (48dp) - ongoing_appops_chip_height (24dp) ) / 2 -->
+    <dimen name="notifications_top_padding_split_shade">12dp</dimen>
 </resources>
diff --git a/packages/SystemUI/res/values/attrs.xml b/packages/SystemUI/res/values/attrs.xml
index 886f98e..e4bdbf3 100644
--- a/packages/SystemUI/res/values/attrs.xml
+++ b/packages/SystemUI/res/values/attrs.xml
@@ -126,6 +126,8 @@
     <attr name="wallpaperTextColorSecondary" format="reference|color" />
     <attr name="wallpaperTextColorAccent" format="reference|color" />
     <attr name="backgroundProtectedStyle" format="reference" />
+    <attr name="offStateColor" format="reference|color" />
+    <attr name="underSurfaceColor" format="reference|color" />
 
     <declare-styleable name="SmartReplyView">
         <attr name="spacing" format="dimension" />
diff --git a/packages/SystemUI/res/values/colors.xml b/packages/SystemUI/res/values/colors.xml
index bc7fcde..a807d4f 100644
--- a/packages/SystemUI/res/values/colors.xml
+++ b/packages/SystemUI/res/values/colors.xml
@@ -35,7 +35,6 @@
     <color name="status_bar_clock_color">#FFFFFFFF</color>
     <color name="qs_user_detail_icon_muted">#FFFFFFFF</color> <!-- not so muted after all -->
     <color name="qs_tile_disabled_color">#9E9E9E</color> <!-- 38% black -->
-    <color name="qs_customize_decoration">@color/GM2_grey_300</color>
     <color name="qs_footer_action_border">#2E312C</color>
 
     <!-- The color of the background in the separated list of the Global Actions menu -->
diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml
index eb19b2e..433e1be 100644
--- a/packages/SystemUI/res/values/dimens.xml
+++ b/packages/SystemUI/res/values/dimens.xml
@@ -426,6 +426,11 @@
     <!-- The padding between the notifications and the quick settings container -->
     <dimen name="qs_notification_padding">@dimen/notification_side_paddings</dimen>
 
+    <!-- In split shade mode notifications should be aligned to QS header so the value should be
+         adjusted to qs header height and height of centered content inside of it:
+        (quick_qs_offset_height (60dp)  - ongoing_appops_chip_height (24dp) ) / 2 -->
+    <dimen name="notifications_top_padding_split_shade">18dp</dimen>
+
     <!-- Height of the status bar header bar when expanded -->
     <dimen name="status_bar_header_height_expanded">124dp</dimen>
 
@@ -1086,8 +1091,9 @@
          burn-in on AOD. -->
     <dimen name="burn_in_prevention_offset_y_large_clock">42dp</dimen>
 
-    <!-- Large clock maximum font size (dp is intentional, to prevent any further scaling) -->
+    <!-- Clock maximum font size (dp is intentional, to prevent any further scaling) -->
     <dimen name="large_clock_text_size">150dp</dimen>
+    <dimen name="clock_text_size">86dp</dimen>
 
     <!-- The maximum offset in either direction that icons move to prevent burn-in on AOD. -->
     <dimen name="default_burn_in_prevention_offset">15dp</dimen>
@@ -1213,8 +1219,6 @@
     <!-- Radius of Ongoing App Ops chip corners -->
     <dimen name="ongoing_appops_chip_bg_corner_radius">16dp</dimen>
 
-    <dimen name="ongoing_appops_dialog_bg_corner_radius">@dimen/notification_corner_radius</dimen>
-
     <dimen name="ongoing_appops_dialog_side_margins">@dimen/notification_shade_content_margin_horizontal</dimen>
 
     <dimen name="ongoing_appops_dialog_circle_size">32dp</dimen>
diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml
index 269fdc5..d5b4f9b 100644
--- a/packages/SystemUI/res/values/strings.xml
+++ b/packages/SystemUI/res/values/strings.xml
@@ -245,10 +245,14 @@
     <string name="screenshot_dismiss_description">Dismiss screenshot</string>
     <!-- Content description indicating that the view is a preview of the screenshot that was just taken [CHAR LIMIT=NONE] -->
     <string name="screenshot_preview_description">Screenshot preview</string>
-    <!-- Content description for the top boundary of the screenshot being cropped [CHAR LIMIT=NONE] -->
-    <string name="screenshot_top_boundary">Top boundary</string>
-    <!-- Content description for the bottom boundary of the screenshot being cropped [CHAR LIMIT=NONE] -->
-    <string name="screenshot_bottom_boundary">Bottom boundary</string>
+    <!-- Content description for the top boundary of the screenshot being cropped, with the current position as a percentage. [CHAR LIMIT=NONE] -->
+    <string name="screenshot_top_boundary_pct">Top boundary <xliff:g id="percent" example="50">%1$d</xliff:g> percent</string>
+    <!-- Content description for the bottom boundary of the screenshot being cropped, with the current position as a percentage. [CHAR LIMIT=NONE] -->
+    <string name="screenshot_bottom_boundary_pct">Bottom boundary <xliff:g id="percent" example="50">%1$d</xliff:g> percent</string>
+    <!-- Content description for the left boundary of the screenshot being cropped, with the current position as a percentage. [CHAR LIMIT=NONE] -->
+    <string name="screenshot_left_boundary_pct">Left boundary <xliff:g id="percent" example="50">%1$d</xliff:g> percent</string>
+    <!-- Content description for the right boundary of the screenshot being cropped, with the current position as a percentage. [CHAR LIMIT=NONE] -->
+    <string name="screenshot_right_boundary_pct">Right boundary <xliff:g id="percent" example="50">%1$d</xliff:g> percent</string>
 
     <!-- Notification title displayed for screen recording [CHAR LIMIT=50]-->
     <string name="screenrecord_name">Screen Recorder</string>
diff --git a/packages/SystemUI/res/values/styles.xml b/packages/SystemUI/res/values/styles.xml
index ba07829..ce8c0c2 100644
--- a/packages/SystemUI/res/values/styles.xml
+++ b/packages/SystemUI/res/values/styles.xml
@@ -382,6 +382,17 @@
         <item name="android:colorError">@*android:color/error_color_material_dark</item>
         <item name="android:windowIsFloating">true</item>
         <item name="android:homeAsUpIndicator">@drawable/ic_arrow_back</item>
+        <item name="offStateColor">@android:color/system_neutral1_800</item>
+        <item name="underSurfaceColor">@android:color/system_neutral1_1000</item>
+        <item name="android:colorBackground">@android:color/system_neutral1_900</item>
+    </style>
+
+    <style name="Theme.SystemUI.QuickSettings.BrightnessDialog" parent="@android:style/Theme.DeviceDefault.Dialog">
+        <item name="android:dialogCornerRadius">8dp</item>
+    </style>
+
+    <style name="Theme.SystemUI.QuickSettings.Dialog" parent="@android:style/Theme.DeviceDefault.Dialog">
+        <item name="android:dialogCornerRadius">@dimen/notification_corner_radius</item>
     </style>
 
     <!-- Overridden by values-television/styles.xml with tv-specific settings -->
@@ -588,10 +599,6 @@
         <item name="android:elevation">10dp</item>
     </style>
 
-    <style name="Theme.SystemUI.QuickSettings.Edit">
-        <item name="android:colorBackground">?android:attr/colorSecondary</item>
-    </style>
-
     <style name="MediaPlayer.Button" parent="@android:style/Widget.Material.Button.Borderless.Small">
         <item name="android:background">@drawable/qs_media_light_source</item>
         <item name="android:tint">?android:attr/textColorPrimary</item>
@@ -628,7 +635,12 @@
     </style>
 
     <!-- Privacy dialog -->
-    <style name="PrivacyDialog" parent="ScreenRecord">
+    <style name="PrivacyDialog" parent="Theme.SystemUI.QuickSettings.Dialog">
+        <item name="android:windowIsTranslucent">true</item>
+        <item name="android:windowBackground">@android:color/transparent</item>
+        <item name="android:windowIsFloating">true</item>
+        <item name="android:backgroundDimEnabled">true</item>
+        <item name="android:windowCloseOnTouchOutside">true</item>
         <item name="android:windowAnimationStyle">@android:style/Animation.Dialog</item>
     </style>
 
diff --git a/packages/SystemUI/src/com/android/keyguard/AnimatableClockController.java b/packages/SystemUI/src/com/android/keyguard/AnimatableClockController.java
index ab219f3..60b677a 100644
--- a/packages/SystemUI/src/com/android/keyguard/AnimatableClockController.java
+++ b/packages/SystemUI/src/com/android/keyguard/AnimatableClockController.java
@@ -27,6 +27,7 @@
 import com.android.systemui.R;
 import com.android.systemui.broadcast.BroadcastDispatcher;
 import com.android.systemui.plugins.statusbar.StatusBarStateController;
+import com.android.systemui.statusbar.policy.BatteryController;
 import com.android.systemui.util.ViewController;
 
 import java.util.Locale;
@@ -45,6 +46,7 @@
     private int mLockScreenColor;
 
     private boolean mIsDozing;
+    private boolean mIsCharging;
     private float mDozeAmount;
     private Locale mLocale;
 
@@ -56,7 +58,8 @@
     public AnimatableClockController(
             AnimatableClockView view,
             StatusBarStateController statusBarStateController,
-            BroadcastDispatcher broadcastDispatcher) {
+            BroadcastDispatcher broadcastDispatcher,
+            BatteryController batteryController) {
         super(view);
         mStatusBarStateController = statusBarStateController;
         mIsDozing = mStatusBarStateController.isDozing();
@@ -68,6 +71,16 @@
                 R.dimen.keyguard_clock_line_spacing_scale_burmese);
         mDefaultLineSpacing = getContext().getResources().getFloat(
                 R.dimen.keyguard_clock_line_spacing_scale);
+
+        batteryController.addCallback(new BatteryController.BatteryStateChangeCallback() {
+            @Override
+            public void onBatteryLevelChanged(int level, boolean pluggedIn, boolean charging) {
+                if (!mIsCharging && charging) {
+                    mView.animateCharge(mIsDozing);
+                }
+                mIsCharging = charging;
+            }
+        });
     }
 
     private BroadcastReceiver mLocaleBroadcastReceiver = new BroadcastReceiver() {
diff --git a/packages/SystemUI/src/com/android/keyguard/AnimatableClockView.java b/packages/SystemUI/src/com/android/keyguard/AnimatableClockView.java
index c918d98..0d6f64f 100644
--- a/packages/SystemUI/src/com/android/keyguard/AnimatableClockView.java
+++ b/packages/SystemUI/src/com/android/keyguard/AnimatableClockView.java
@@ -42,7 +42,9 @@
     private static final CharSequence DOUBLE_LINE_FORMAT_24_HOUR = "HH\nmm";
     private static final CharSequence SINGLE_LINE_FORMAT_12_HOUR = "h:mm";
     private static final CharSequence SINGLE_LINE_FORMAT_24_HOUR = "H:mm";
-    private static final long ANIM_DURATION = 300;
+    private static final long DOZE_ANIM_DURATION = 300;
+    private static final long CHARGE_ANIM_DURATION_PHASE_0 = 500;
+    private static final long CHARGE_ANIM_DURATION_PHASE_1 = 1000;
 
     private final Calendar mTime = Calendar.getInstance();
 
@@ -53,6 +55,7 @@
     private int mDozingColor;
     private int mLockScreenColor;
     private float mLineSpacingScale = 1f;
+    private int mChargeAnimationDelay = 0;
 
     private TextAnimator mTextAnimator = null;
     private Runnable mOnTextAnimatorInitialized;
@@ -79,6 +82,8 @@
         try {
             mDozingWeight = ta.getInt(R.styleable.AnimatableClockView_dozeWeight, 100);
             mLockScreenWeight = ta.getInt(R.styleable.AnimatableClockView_lockScreenWeight, 300);
+            mChargeAnimationDelay = ta.getInt(
+                    R.styleable.AnimatableClockView_chargeAnimationDelay, 200);
         } finally {
             ta.recycle();
         }
@@ -150,11 +155,36 @@
         mLockScreenColor = lockScreenColor;
     }
 
+    void animateCharge(boolean isDozing) {
+        if (mTextAnimator == null || mTextAnimator.isRunning()) {
+            // Skip charge animation if dozing animation is already playing.
+            return;
+        }
+        Runnable startAnimPhase2 = () -> setTextStyle(
+                isDozing ? mDozingWeight : mLockScreenWeight/* weight */,
+                -1,
+                null,
+                true /* animate */,
+                CHARGE_ANIM_DURATION_PHASE_1,
+                0 /* delay */,
+                null /* onAnimationEnd */);
+        setTextStyle(isDozing ? mLockScreenWeight : mDozingWeight/* weight */,
+                -1,
+                null,
+                true /* animate */,
+                CHARGE_ANIM_DURATION_PHASE_0,
+                mChargeAnimationDelay,
+                startAnimPhase2);
+    }
+
     void animateDoze(boolean isDozing, boolean animate) {
         setTextStyle(isDozing ? mDozingWeight : mLockScreenWeight /* weight */,
                 -1,
                 isDozing ? mDozingColor : mLockScreenColor,
-                animate);
+                animate,
+                DOZE_ANIM_DURATION,
+                0 /* delay */,
+                null /* onAnimationEnd */);
     }
 
     /**
@@ -170,15 +200,20 @@
     private void setTextStyle(
             @IntRange(from = 0, to = 1000) int weight,
             @FloatRange(from = 0) float textSize,
-            int color,
-            boolean animate) {
+            Integer color,
+            boolean animate,
+            long duration,
+            long delay,
+            Runnable onAnimationEnd) {
         if (mTextAnimator != null) {
-            mTextAnimator.setTextStyle(weight, textSize, color, animate, ANIM_DURATION, null);
+            mTextAnimator.setTextStyle(weight, textSize, color, animate, duration, null,
+                    delay, onAnimationEnd);
         } else {
             // when the text animator is set, update its start values
             mOnTextAnimatorInitialized =
                     () -> mTextAnimator.setTextStyle(
-                            weight, textSize, color, false, ANIM_DURATION, null);
+                            weight, textSize, color, false, duration, null,
+                            delay, onAnimationEnd);
         }
     }
 
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitch.java b/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitch.java
index d2a82cf..407146f 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitch.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitch.java
@@ -4,35 +4,21 @@
 import android.animation.AnimatorListenerAdapter;
 import android.animation.AnimatorSet;
 import android.animation.ObjectAnimator;
-import android.animation.ValueAnimator;
 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;
-import android.transition.TransitionSet;
-import android.transition.TransitionValues;
 import android.util.AttributeSet;
-import android.util.Log;
-import android.util.MathUtils;
 import android.util.TypedValue;
 import android.view.View;
 import android.view.ViewGroup;
 import android.widget.FrameLayout;
 import android.widget.RelativeLayout;
-import android.widget.TextClock;
-import android.widget.TextView;
 
 import com.android.internal.colorextraction.ColorExtractor;
 import com.android.keyguard.dagger.KeyguardStatusViewScope;
 import com.android.systemui.R;
 import com.android.systemui.animation.Interpolators;
 import com.android.systemui.plugins.ClockPlugin;
-import com.android.systemui.statusbar.StatusBarState;
-import com.android.systemui.util.wakelock.KeepAwakeAnimationListener;
 
 import java.io.FileDescriptor;
 import java.io.PrintWriter;
@@ -47,53 +33,21 @@
 
     private static final String TAG = "KeyguardClockSwitch";
 
-    /**
-     * Animation fraction when text is transitioned to/from bold.
-     */
-    private static final float TO_BOLD_TRANSITION_FRACTION = 0.7f;
-
     private static final long CLOCK_OUT_MILLIS = 150;
     private static final long CLOCK_IN_MILLIS = 200;
 
     /**
-     * Layout transition that scales the default clock face.
-     */
-    private final Transition mTransition;
-
-    private final ClockVisibilityTransition mClockTransition;
-    private final ClockVisibilityTransition mBoldClockTransition;
-
-    /**
      * Optional/alternative clock injected via plugin.
      */
     private ClockPlugin mClockPlugin;
 
     /**
-     * Default clock.
+     * Frame for small/large clocks
      */
-    private TextClock mClockView;
-
-    /**
-     * Default clock, bold version.
-     * Used to transition to bold when shrinking the default clock.
-     */
-    private TextClock mClockViewBold;
-
-    /**
-     * Frame for clock when mode != KeyguardUpdateMonitor.LOCK_SCREEN_MODE_NORMAL.
-     */
-    private FrameLayout mNewLockscreenClockFrame;
-    private FrameLayout mNewLockscreenLargeClockFrame;
-
-    /**
-     * Frame for default and custom clock.
-     */
-    private FrameLayout mSmallClockFrame;
-
-    /**
-     * Container for big custom clock.
-     */
-    private ViewGroup mBigClockContainer;
+    private FrameLayout mClockFrame;
+    private FrameLayout mLargeClockFrame;
+    private AnimatableClockView mClockView;
+    private AnimatableClockView mLargeClockView;
 
     /**
      * Status area (date and other stuff) shown below the clock. Plugin can decide whether or not to
@@ -117,40 +71,23 @@
     /**
      * If the Keyguard Slice has a header (big center-aligned text.)
      */
-    private boolean mShowingHeader;
     private boolean mSupportsDarkText;
     private int[] mColorPalette;
 
-    private int mLockScreenMode = KeyguardUpdateMonitor.LOCK_SCREEN_MODE_NORMAL;
     private int mClockSwitchYAmount;
 
     public KeyguardClockSwitch(Context context, AttributeSet attrs) {
         super(context, attrs);
-
-        mClockTransition = new ClockVisibilityTransition().setCutoff(
-                1 - TO_BOLD_TRANSITION_FRACTION);
-        mClockTransition.addTarget(R.id.default_clock_view);
-        mBoldClockTransition = new ClockVisibilityTransition().setCutoff(
-                TO_BOLD_TRANSITION_FRACTION);
-        mBoldClockTransition.addTarget(R.id.default_clock_view_bold);
-        mTransition = new TransitionSet()
-                .setOrdering(TransitionSet.ORDERING_TOGETHER)
-                .addTransition(mClockTransition)
-                .addTransition(mBoldClockTransition)
-                .setDuration(KeyguardSliceView.DEFAULT_ANIM_DURATION / 2)
-                .setInterpolator(Interpolators.LINEAR_OUT_SLOW_IN);
     }
 
     /**
      * Apply dp changes on font/scale change
      */
     public void onDensityOrFontScaleChanged() {
-        setTextSize(TypedValue.COMPLEX_UNIT_PX, mContext.getResources()
-                .getDimensionPixelSize(R.dimen.widget_big_font_size));
-
-        ((TextView) mNewLockscreenLargeClockFrame.getChildAt(0))
-                .setTextSize(TypedValue.COMPLEX_UNIT_PX, mContext.getResources()
-                        .getDimensionPixelSize(R.dimen.large_clock_text_size));
+        mLargeClockView.setTextSize(TypedValue.COMPLEX_UNIT_PX, mContext.getResources()
+                .getDimensionPixelSize(R.dimen.large_clock_text_size));
+        mClockView.setTextSize(TypedValue.COMPLEX_UNIT_PX, mContext.getResources()
+                .getDimensionPixelSize(R.dimen.clock_text_size));
 
         mClockSwitchYAmount = mContext.getResources().getDimensionPixelSize(
                 R.dimen.keyguard_clock_switch_y_shift);
@@ -163,44 +100,14 @@
         return mClockPlugin != null;
     }
 
-    /**
-      * Update lock screen mode for testing different layouts
-      */
-    public void updateLockScreenMode(int mode) {
-        mLockScreenMode = mode;
-        RelativeLayout.LayoutParams statusAreaLP = (RelativeLayout.LayoutParams)
-                mKeyguardStatusArea.getLayoutParams();
-
-        if (mode == KeyguardUpdateMonitor.LOCK_SCREEN_MODE_LAYOUT_1) {
-            final int startEndPadding = (int) TypedValue.applyDimension(
-                    TypedValue.COMPLEX_UNIT_DIP,
-                    32,
-                    getResources().getDisplayMetrics());
-            setPaddingRelative(startEndPadding, 0, startEndPadding, 0);
-            mSmallClockFrame.setVisibility(GONE);
-            mNewLockscreenClockFrame.setVisibility(VISIBLE);
-            statusAreaLP.addRule(RelativeLayout.BELOW, R.id.new_lockscreen_clock_view);
-            statusAreaLP.addRule(RelativeLayout.ALIGN_PARENT_START);
-        } else {
-            setPaddingRelative(0, 0, 0, 0);
-            mSmallClockFrame.setVisibility(VISIBLE);
-            mNewLockscreenClockFrame.setVisibility(GONE);
-
-            statusAreaLP.removeRule(RelativeLayout.ALIGN_PARENT_START);
-            statusAreaLP.addRule(RelativeLayout.BELOW, R.id.clock_view);
-        }
-
-        requestLayout();
-    }
-
     @Override
     protected void onFinishInflate() {
         super.onFinishInflate();
-        mClockView = findViewById(R.id.default_clock_view);
-        mClockViewBold = findViewById(R.id.default_clock_view_bold);
-        mNewLockscreenClockFrame = findViewById(R.id.new_lockscreen_clock_view);
-        mNewLockscreenLargeClockFrame = findViewById(R.id.new_lockscreen_clock_view_large);
-        mSmallClockFrame = findViewById(R.id.clock_view);
+
+        mClockFrame = findViewById(R.id.lockscreen_clock_view);
+        mClockView = findViewById(R.id.animatable_clock_view);
+        mLargeClockFrame = findViewById(R.id.lockscreen_clock_view_large);
+        mLargeClockView = findViewById(R.id.animatable_clock_view_large);
         mKeyguardStatusArea = findViewById(R.id.keyguard_status_area);
 
         onDensityOrFontScaleChanged();
@@ -210,45 +117,35 @@
         // Disconnect from existing plugin.
         if (mClockPlugin != null) {
             View smallClockView = mClockPlugin.getView();
-            if (smallClockView != null && smallClockView.getParent() == mSmallClockFrame) {
-                mSmallClockFrame.removeView(smallClockView);
+            if (smallClockView != null && smallClockView.getParent() == mClockFrame) {
+                mClockFrame.removeView(smallClockView);
             }
-            if (mBigClockContainer != null) {
-                mBigClockContainer.removeAllViews();
-                updateBigClockVisibility(statusBarState);
+            View bigClockView = mClockPlugin.getBigClockView();
+            if (bigClockView != null && bigClockView.getParent() == mLargeClockFrame) {
+                mLargeClockFrame.removeView(bigClockView);
             }
             mClockPlugin.onDestroyView();
             mClockPlugin = null;
         }
         if (plugin == null) {
-            if (mShowingHeader) {
-                mClockView.setVisibility(View.GONE);
-                mClockViewBold.setVisibility(View.VISIBLE);
-            } else {
-                mClockView.setVisibility(View.VISIBLE);
-                mClockViewBold.setVisibility(View.INVISIBLE);
-            }
-            mKeyguardStatusArea.setVisibility(View.VISIBLE);
+            mClockView.setVisibility(View.VISIBLE);
+            mLargeClockView.setVisibility(View.VISIBLE);
             return;
         }
         // Attach small and big clock views to hierarchy.
         View smallClockView = plugin.getView();
         if (smallClockView != null) {
-            mSmallClockFrame.addView(smallClockView, -1,
+            mClockFrame.addView(smallClockView, -1,
                     new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT,
                             ViewGroup.LayoutParams.WRAP_CONTENT));
             mClockView.setVisibility(View.GONE);
-            mClockViewBold.setVisibility(View.GONE);
         }
         View bigClockView = plugin.getBigClockView();
-        if (bigClockView != null && mBigClockContainer != null) {
-            mBigClockContainer.addView(bigClockView);
-            updateBigClockVisibility(statusBarState);
+        if (bigClockView != null) {
+            mLargeClockFrame.addView(bigClockView);
+            mLargeClockView.setVisibility(View.GONE);
         }
-        // Hide default clock.
-        if (!plugin.shouldShowStatusArea()) {
-            mKeyguardStatusArea.setVisibility(View.GONE);
-        }
+
         // Initialize plugin parameters.
         mClockPlugin = plugin;
         mClockPlugin.setStyle(getPaint().getStyle());
@@ -259,31 +156,10 @@
         }
     }
 
-    float getClockTextTopPadding() {
-        Paint.FontMetrics fm = mClockView.getPaint().getFontMetrics();
-        return fm.ascent - fm.top;
-    }
-
-    /**
-     * Set container for big clock face appearing behind NSSL and KeyguardStatusView.
-     */
-    public void setBigClockContainer(ViewGroup container, int statusBarState) {
-        if (mClockPlugin != null && container != null) {
-            View bigClockView = mClockPlugin.getBigClockView();
-            if (bigClockView != null) {
-                container.addView(bigClockView);
-            }
-        }
-        mBigClockContainer = container;
-        updateBigClockVisibility(statusBarState);
-    }
-
     /**
      * It will also update plugin setStyle if plugin is connected.
      */
     public void setStyle(Style style) {
-        mClockView.getPaint().setStyle(style);
-        mClockViewBold.getPaint().setStyle(style);
         if (mClockPlugin != null) {
             mClockPlugin.setStyle(style);
         }
@@ -293,48 +169,25 @@
      * It will also update plugin setTextColor if plugin is connected.
      */
     public void setTextColor(int color) {
-        mClockView.setTextColor(color);
-        mClockViewBold.setTextColor(color);
         if (mClockPlugin != null) {
             mClockPlugin.setTextColor(color);
         }
     }
 
-    public void setShowCurrentUserTime(boolean showCurrentUserTime) {
-        mClockView.setShowCurrentUserTime(showCurrentUserTime);
-        mClockViewBold.setShowCurrentUserTime(showCurrentUserTime);
-    }
-
-    public void setTextSize(int unit, float size) {
-        mClockView.setTextSize(unit, size);
-    }
-
-    public void setFormat12Hour(CharSequence format) {
-        mClockView.setFormat12Hour(format);
-        mClockViewBold.setFormat12Hour(format);
-    }
-
-    public void setFormat24Hour(CharSequence format) {
-        mClockView.setFormat24Hour(format);
-        mClockViewBold.setFormat24Hour(format);
-    }
-
     private void animateClockChange(boolean useLargeClock) {
-        if (mLockScreenMode != KeyguardUpdateMonitor.LOCK_SCREEN_MODE_LAYOUT_1) return;
-
         if (mClockInAnim != null) mClockInAnim.cancel();
         if (mClockOutAnim != null) mClockOutAnim.cancel();
 
         View in, out;
         int direction = 1;
         if (useLargeClock) {
-            out = mNewLockscreenClockFrame;
-            in = mNewLockscreenLargeClockFrame;
+            out = mClockFrame;
+            in = mLargeClockFrame;
             if (indexOfChild(in) == -1) addView(in);
             direction = -1;
         } else {
-            in = mNewLockscreenClockFrame;
-            out = mNewLockscreenLargeClockFrame;
+            in = mClockFrame;
+            out = mLargeClockFrame;
 
             // Must remove in order for notifications to appear in the proper place
             removeView(out);
@@ -381,7 +234,6 @@
         if (mClockPlugin != null) {
             mClockPlugin.setDarkAmount(darkAmount);
         }
-        updateBigClockAlpha();
     }
 
     /**
@@ -394,13 +246,6 @@
         animateClockChange(!hasVisibleNotifications);
 
         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() {
@@ -433,15 +278,9 @@
      * Refresh the time of the clock, due to either time tick broadcast or doze time tick alarm.
      */
     public void refresh() {
-        mClockView.refreshTime();
-        mClockViewBold.refreshTime();
         if (mClockPlugin != null) {
             mClockPlugin.onTimeTick();
         }
-        if (Build.IS_DEBUGGABLE) {
-            // Log for debugging b/130888082 (sysui waking up, but clock not updating)
-            Log.d(TAG, "Updating clock: " + mClockView.getText());
-        }
     }
 
     /**
@@ -472,240 +311,14 @@
         }
     }
 
-    void updateBigClockVisibility(int statusBarState) {
-        if (mBigClockContainer == null) {
-            return;
-        }
-        final boolean inDisplayState = statusBarState == StatusBarState.KEYGUARD
-                || statusBarState == StatusBarState.SHADE_LOCKED;
-        final int visibility = !mShowingHeader && inDisplayState
-                    && mBigClockContainer.getChildCount() != 0 ? View.VISIBLE : View.GONE;
-        if (mBigClockContainer.getVisibility() != visibility) {
-            mBigClockContainer.setVisibility(visibility);
-        }
-    }
-
-    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 (mLockScreenMode != KeyguardUpdateMonitor.LOCK_SCREEN_MODE_NORMAL) {
-            hasHeader = false;
-        }
-
-        if (mShowingHeader == hasHeader) {
-            return;
-        }
-        mShowingHeader = hasHeader;
-        if (hasCustomClock()) {
-            return;
-        }
-
-        float smallFontSize = mContext.getResources().getDimensionPixelSize(
-                R.dimen.widget_small_font_size);
-        float bigFontSize = mContext.getResources().getDimensionPixelSize(
-                R.dimen.widget_big_font_size);
-        mClockTransition.setScale(smallFontSize / bigFontSize);
-        mBoldClockTransition.setScale(bigFontSize / smallFontSize);
-
-        // End any current transitions before starting a new transition so that the new transition
-        // starts from a good state instead of a potentially bad intermediate state arrived at
-        // during a transition animation.
-        TransitionManager.endTransitions((ViewGroup) mClockView.getParent());
-
-        if (hasHeader) {
-            // After the transition, make the default clock GONE so that it doesn't make the
-            // KeyguardStatusView appear taller in KeyguardClockPositionAlgorithm and elsewhere.
-            mTransition.addListener(new TransitionListenerAdapter() {
-                @Override
-                public void onTransitionEnd(Transition transition) {
-                    super.onTransitionEnd(transition);
-                    // Check that header is actually showing. I saw issues where this event was
-                    // fired after the big clock transitioned back to visible, which causes the time
-                    // to completely disappear.
-                    if (mShowingHeader) {
-                        mClockView.setVisibility(View.GONE);
-                    }
-                    transition.removeListener(this);
-                }
-            });
-        }
-
-        TransitionManager.beginDelayedTransition((ViewGroup) mClockView.getParent(), mTransition);
-        mClockView.setVisibility(hasHeader ? View.INVISIBLE : View.VISIBLE);
-        mClockViewBold.setVisibility(hasHeader ? View.VISIBLE : View.INVISIBLE);
-        int paddingBottom = mContext.getResources().getDimensionPixelSize(hasHeader
-                ? R.dimen.widget_vertical_padding_clock : R.dimen.title_clock_padding);
-        mClockView.setPadding(mClockView.getPaddingLeft(), mClockView.getPaddingTop(),
-                mClockView.getPaddingRight(), paddingBottom);
-        mClockViewBold.setPadding(mClockViewBold.getPaddingLeft(), mClockViewBold.getPaddingTop(),
-                mClockViewBold.getPaddingRight(), paddingBottom);
-    }
-
-    /**
-     * Hide big clock if the keyguard slice is showing a header, need to reduce visual clutter in
-     * these cases.
-     */
-    public void setKeyguardHidingBigClock(boolean hasHeader) {
-        if (mBigClockContainer != null) {
-            mBigClockContainer.setVisibility(hasHeader ? View.GONE : View.VISIBLE);
-        }
-    }
-
     public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
         pw.println("KeyguardClockSwitch:");
         pw.println("  mClockPlugin: " + mClockPlugin);
-        pw.println("  mClockView: " + mClockView);
-        pw.println("  mClockViewBold: " + mClockViewBold);
-        pw.println("  mSmallClockFrame: " + mSmallClockFrame);
-        pw.println("  mBigClockContainer: " + mBigClockContainer);
+        pw.println("  mClockFrame: " + mClockFrame);
+        pw.println("  mLargeClockFrame: " + mLargeClockFrame);
         pw.println("  mKeyguardStatusArea: " + mKeyguardStatusArea);
         pw.println("  mDarkAmount: " + mDarkAmount);
-        pw.println("  mShowingHeader: " + mShowingHeader);
         pw.println("  mSupportsDarkText: " + mSupportsDarkText);
         pw.println("  mColorPalette: " + Arrays.toString(mColorPalette));
     }
-
-    /**
-     * {@link Visibility} transformation that scales the view while it is disappearing/appearing and
-     * transitions suddenly at a cutoff fraction during the animation.
-     */
-    private class ClockVisibilityTransition extends android.transition.Visibility {
-
-        private static final String PROPNAME_VISIBILITY = "systemui:keyguard:visibility";
-
-        private float mCutoff;
-        private float mScale;
-
-        /**
-         * Constructs a transition that switches between visible/invisible at a cutoff and scales in
-         * size while appearing/disappearing.
-         */
-        ClockVisibilityTransition() {
-            setCutoff(1f);
-            setScale(1f);
-        }
-
-        /**
-         * Sets the transition point between visible/invisible.
-         *
-         * @param cutoff The fraction in [0, 1] when the view switches between visible/invisible.
-         * @return This transition object
-         */
-        public ClockVisibilityTransition setCutoff(float cutoff) {
-            mCutoff = cutoff;
-            return this;
-        }
-
-        /**
-         * Sets the scale factor applied while appearing/disappearing.
-         *
-         * @param scale Scale factor applied while appearing/disappearing. When factor is less than
-         *              one, the view will shrink while disappearing. When it is greater than one,
-         *              the view will expand while disappearing.
-         * @return This transition object
-         */
-        public ClockVisibilityTransition setScale(float scale) {
-            mScale = scale;
-            return this;
-        }
-
-        @Override
-        public void captureStartValues(TransitionValues transitionValues) {
-            super.captureStartValues(transitionValues);
-            captureVisibility(transitionValues);
-        }
-
-        @Override
-        public void captureEndValues(TransitionValues transitionValues) {
-            super.captureStartValues(transitionValues);
-            captureVisibility(transitionValues);
-        }
-
-        private void captureVisibility(TransitionValues transitionValues) {
-            transitionValues.values.put(PROPNAME_VISIBILITY,
-                    transitionValues.view.getVisibility());
-        }
-
-        @Override
-        public Animator onAppear(ViewGroup sceneRoot, View view, TransitionValues startValues,
-                TransitionValues endValues) {
-            if (!sceneRoot.isShown()) {
-                return null;
-            }
-            final float cutoff = mCutoff;
-            final int startVisibility = View.INVISIBLE;
-            final int endVisibility = (int) endValues.values.get(PROPNAME_VISIBILITY);
-            final float startScale = mScale;
-            final float endScale = 1f;
-            return createAnimator(view, cutoff, startVisibility, endVisibility, startScale,
-                    endScale);
-        }
-
-        @Override
-        public Animator onDisappear(ViewGroup sceneRoot, View view, TransitionValues startValues,
-                TransitionValues endValues) {
-            if (!sceneRoot.isShown()) {
-                return null;
-            }
-            final float cutoff = 1f - mCutoff;
-            final int startVisibility = View.VISIBLE;
-            final int endVisibility = (int) endValues.values.get(PROPNAME_VISIBILITY);
-            final float startScale = 1f;
-            final float endScale = mScale;
-            return createAnimator(view, cutoff, startVisibility, endVisibility, startScale,
-                    endScale);
-        }
-
-        private Animator createAnimator(View view, float cutoff, int startVisibility,
-                int endVisibility, float startScale, float endScale) {
-            view.setPivotY(view.getHeight() - view.getPaddingBottom());
-            ValueAnimator animator = ValueAnimator.ofFloat(0f, 1f);
-            animator.addUpdateListener(animation -> {
-                final float fraction = animation.getAnimatedFraction();
-                if (fraction > cutoff) {
-                    view.setVisibility(endVisibility);
-                }
-                final float scale = MathUtils.lerp(startScale, endScale, fraction);
-                view.setScaleX(scale);
-                view.setScaleY(scale);
-            });
-            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);
-                }
-            });
-            addListener(new TransitionListenerAdapter() {
-                @Override
-                public void onTransitionEnd(Transition transition) {
-                    view.setVisibility(endVisibility);
-                    view.setScaleX(1f);
-                    view.setScaleY(1f);
-                    transition.removeListener(this);
-                }
-            });
-            return animator;
-        }
-    }
 }
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitchController.java b/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitchController.java
index 24b7cd1..032ed7d 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitchController.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitchController.java
@@ -26,11 +26,9 @@
 import android.content.ContentResolver;
 import android.content.Context;
 import android.content.res.Resources;
-import android.provider.Settings;
 import android.text.TextUtils;
 import android.text.format.DateFormat;
 import android.view.View;
-import android.view.ViewGroup;
 import android.widget.FrameLayout;
 import android.widget.RelativeLayout;
 
@@ -51,6 +49,7 @@
 import com.android.systemui.statusbar.notification.stack.AnimationProperties;
 import com.android.systemui.statusbar.phone.NotificationIconAreaController;
 import com.android.systemui.statusbar.phone.NotificationIconContainer;
+import com.android.systemui.statusbar.policy.BatteryController;
 import com.android.systemui.util.ViewController;
 
 import java.util.Locale;
@@ -72,14 +71,15 @@
     private final KeyguardSliceViewController mKeyguardSliceViewController;
     private final NotificationIconAreaController mNotificationIconAreaController;
     private final BroadcastDispatcher mBroadcastDispatcher;
+    private final BatteryController mBatteryController;
 
     /**
-     * Gradient clock for usage when mode != KeyguardUpdateMonitor.LOCK_SCREEN_MODE_NORMAL.
+     * Clock for both small and large sizes
      */
-    private AnimatableClockController mNewLockScreenClockViewController;
-    private FrameLayout mNewLockScreenClockFrame;
-    private AnimatableClockController mNewLockScreenLargeClockViewController;
-    private FrameLayout mNewLockScreenLargeClockFrame;
+    private AnimatableClockController mClockViewController;
+    private FrameLayout mClockFrame;
+    private AnimatableClockController mLargeClockViewController;
+    private FrameLayout mLargeClockFrame;
 
     private PluginManager mPluginManager;
     private boolean mIsSmartspaceEnabled;
@@ -88,16 +88,6 @@
     private SmartspaceSession mSmartspaceSession;
     private SmartspaceSession.Callback mSmartspaceCallback;
 
-    private int mLockScreenMode = KeyguardUpdateMonitor.LOCK_SCREEN_MODE_NORMAL;
-
-    private final StatusBarStateController.StateListener mStateListener =
-            new StatusBarStateController.StateListener() {
-                @Override
-                public void onStateChanged(int newState) {
-                    mView.updateBigClockVisibility(newState);
-                }
-            };
-
     /**
      * Listener for changes to the color palette.
      *
@@ -114,7 +104,6 @@
     };
 
     private ClockManager.ClockChangedListener mClockChangedListener = this::setClockPlugin;
-    private String mTimeFormat;
 
     // If set, will replace keyguard_status_area
     private BcSmartspaceDataPlugin.SmartspaceView mSmartspaceView;
@@ -131,7 +120,8 @@
             BroadcastDispatcher broadcastDispatcher,
             PluginManager pluginManager,
             FeatureFlags featureFlags,
-            @Main Executor uiExecutor) {
+            @Main Executor uiExecutor,
+            BatteryController batteryController) {
         super(keyguardClockSwitch);
         mResources = resources;
         mStatusBarStateController = statusBarStateController;
@@ -140,10 +130,10 @@
         mKeyguardSliceViewController = keyguardSliceViewController;
         mNotificationIconAreaController = notificationIconAreaController;
         mBroadcastDispatcher = broadcastDispatcher;
-        mTimeFormat = Settings.System.getString(contentResolver, Settings.System.TIME_12_24);
         mPluginManager = pluginManager;
         mIsSmartspaceEnabled = featureFlags.isSmartspaceEnabled();
         mUiExecutor = uiExecutor;
+        mBatteryController = batteryController;
     }
 
     /**
@@ -159,13 +149,28 @@
         if (CUSTOM_CLOCKS_ENABLED) {
             mClockManager.addOnClockChangedListener(mClockChangedListener);
         }
-        refreshFormat();
-        mStatusBarStateController.addCallback(mStateListener);
         mColorExtractor.addOnColorsChangedListener(mColorsListener);
         mView.updateColors(getGradientColors());
         updateAodIcons();
-        mNewLockScreenClockFrame = mView.findViewById(R.id.new_lockscreen_clock_view);
-        mNewLockScreenLargeClockFrame = mView.findViewById(R.id.new_lockscreen_clock_view_large);
+
+        mClockFrame = mView.findViewById(R.id.lockscreen_clock_view);
+        mLargeClockFrame = mView.findViewById(R.id.lockscreen_clock_view_large);
+
+        mClockViewController =
+            new AnimatableClockController(
+                mView.findViewById(R.id.animatable_clock_view),
+                mStatusBarStateController,
+                mBroadcastDispatcher,
+                mBatteryController);
+        mClockViewController.init();
+
+        mLargeClockViewController =
+            new AnimatableClockController(
+                mView.findViewById(R.id.animatable_clock_view_large),
+                mStatusBarStateController,
+                mBroadcastDispatcher,
+                mBatteryController);
+        mLargeClockViewController.init();
 
         // If a smartspace plugin is detected, replace the existing smartspace
         // (keyguard_status_area), and initialize a new session
@@ -181,16 +186,21 @@
 
                 mSmartspaceView = plugin.getView(mView);
                 mSmartspaceView.registerDataProvider(plugin);
+                View asView = (View) mSmartspaceView;
 
                 RelativeLayout.LayoutParams lp = new RelativeLayout.LayoutParams(
                         MATCH_PARENT, WRAP_CONTENT);
-                lp.addRule(RelativeLayout.BELOW, R.id.new_lockscreen_clock_view);
-                mView.addView((View) mSmartspaceView, ksaIndex, lp);
+                lp.addRule(RelativeLayout.BELOW, R.id.lockscreen_clock_view);
+
+                mView.addView(asView, ksaIndex, lp);
+                int padding = getContext().getResources()
+                        .getDimensionPixelSize(R.dimen.below_clock_padding_start);
+                asView.setPadding(padding, 0, padding, 0);
 
                 View nic = mView.findViewById(
                         com.android.systemui.R.id.left_aligned_notification_icon_container);
                 lp = (RelativeLayout.LayoutParams) nic.getLayoutParams();
-                lp.addRule(RelativeLayout.BELOW, ((View) mSmartspaceView).getId());
+                lp.addRule(RelativeLayout.BELOW, asView.getId());
                 nic.setLayoutParams(lp);
 
                 createSmartspaceSession(plugin);
@@ -230,7 +240,6 @@
         if (CUSTOM_CLOCKS_ENABLED) {
             mClockManager.removeOnClockChangedListener(mClockChangedListener);
         }
-        mStatusBarStateController.removeCallback(mStateListener);
         mColorExtractor.removeOnColorsChangedListener(mColorsListener);
         mView.setClockPlugin(null, mStatusBarStateController.getState());
 
@@ -250,13 +259,6 @@
     }
 
     /**
-     * Set container for big clock face appearing behind NSSL and KeyguardStatusView.
-     */
-    public void setBigClockContainer(ViewGroup bigClockContainer) {
-        mView.setBigClockContainer(bigClockContainer, mStatusBarStateController.getState());
-    }
-
-    /**
      * Set whether or not the lock screen is showing notifications.
      */
     public void setHasVisibleNotifications(boolean hasVisibleNotifications) {
@@ -291,9 +293,9 @@
      * Refresh clock. Called in response to TIME_TICK broadcasts.
      */
     void refresh() {
-        if (mNewLockScreenClockViewController != null) {
-            mNewLockScreenClockViewController.refreshTime();
-            mNewLockScreenLargeClockViewController.refreshTime();
+        if (mClockViewController != null) {
+            mClockViewController.refreshTime();
+            mLargeClockViewController.refreshTime();
         }
 
         mView.refresh();
@@ -307,86 +309,45 @@
      */
     void updatePosition(int x, float scale, AnimationProperties props, boolean animate) {
         x = getCurrentLayoutDirection() == View.LAYOUT_DIRECTION_RTL ? -x : x;
-        if (mNewLockScreenClockFrame != null) {
-            PropertyAnimator.setProperty(mNewLockScreenClockFrame, AnimatableProperty.TRANSLATION_X,
-                    x, props, animate);
-            PropertyAnimator.setProperty(mNewLockScreenLargeClockFrame, AnimatableProperty.SCALE_X,
-                    scale, props, animate);
-            PropertyAnimator.setProperty(mNewLockScreenLargeClockFrame, AnimatableProperty.SCALE_Y,
-                    scale, props, animate);
-        }
+
+        PropertyAnimator.setProperty(mClockFrame, AnimatableProperty.TRANSLATION_X,
+                x, props, animate);
+        PropertyAnimator.setProperty(mLargeClockFrame, AnimatableProperty.SCALE_X,
+                scale, props, animate);
+        PropertyAnimator.setProperty(mLargeClockFrame, AnimatableProperty.SCALE_Y,
+                scale, props, animate);
 
         if (mSmartspaceView != null) {
             PropertyAnimator.setProperty((View) mSmartspaceView, AnimatableProperty.TRANSLATION_X,
                     x, props, animate);
         }
+
         mKeyguardSliceViewController.updatePosition(x, props, animate);
         mNotificationIconAreaController.updatePosition(x, props, animate);
     }
 
-    /**
-     * Update lockscreen mode that may change clock display.
-     */
-    void updateLockScreenMode(int mode) {
-        mLockScreenMode = mode;
-        if (mode == KeyguardUpdateMonitor.LOCK_SCREEN_MODE_LAYOUT_1) {
-            if (mNewLockScreenClockViewController == null) {
-                mNewLockScreenClockViewController =
-                        new AnimatableClockController(
-                                mView.findViewById(R.id.animatable_clock_view),
-                                mStatusBarStateController,
-                                mBroadcastDispatcher);
-                mNewLockScreenClockViewController.init();
-                mNewLockScreenLargeClockViewController =
-                        new AnimatableClockController(
-                                mView.findViewById(R.id.animatable_clock_view_large),
-                                mStatusBarStateController,
-                                mBroadcastDispatcher);
-                mNewLockScreenLargeClockViewController.init();
-            }
-        } else {
-            mNewLockScreenClockViewController = null;
-            mNewLockScreenLargeClockViewController = null;
-        }
-        mView.updateLockScreenMode(mLockScreenMode);
-        updateAodIcons();
-    }
-
     void updateTimeZone(TimeZone timeZone) {
         mView.onTimeZoneChanged(timeZone);
-        if (mNewLockScreenClockViewController != null) {
-            mNewLockScreenClockViewController.onTimeZoneChanged(timeZone);
-            mNewLockScreenLargeClockViewController.onTimeZoneChanged(timeZone);
+        if (mClockViewController != null) {
+            mClockViewController.onTimeZoneChanged(timeZone);
+            mLargeClockViewController.onTimeZoneChanged(timeZone);
         }
     }
 
     void refreshFormat(String timeFormat) {
-        mTimeFormat = timeFormat;
-        Patterns.update(mResources);
-        mView.setFormat12Hour(Patterns.sClockView12);
-        mView.setFormat24Hour(Patterns.sClockView24);
-        mView.onTimeFormatChanged(mTimeFormat);
-        if (mNewLockScreenClockViewController != null) {
-            mNewLockScreenClockViewController.refreshFormat();
-            mNewLockScreenLargeClockViewController.refreshFormat();
+        if (mClockViewController != null) {
+            mClockViewController.refreshFormat();
+            mLargeClockViewController.refreshFormat();
         }
     }
 
-    void refreshFormat() {
-        refreshFormat(mTimeFormat);
-    }
-
     private void updateAodIcons() {
         NotificationIconContainer nic = (NotificationIconContainer)
                 mView.findViewById(
                         com.android.systemui.R.id.left_aligned_notification_icon_container);
 
-        if (mLockScreenMode == KeyguardUpdateMonitor.LOCK_SCREEN_MODE_LAYOUT_1) {
-            // alt icon area is set in KeyguardClockSwitchController
-            mNotificationIconAreaController.setupAodIcons(nic, mLockScreenMode);
-        } else {
-            nic.setVisibility(View.GONE);
-        }
+        // alt icon area is set in KeyguardClockSwitchController
+        mNotificationIconAreaController.setupAodIcons(nic);
     }
 
     private void setClockPlugin(ClockPlugin plugin) {
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardStatusView.java b/packages/SystemUI/src/com/android/keyguard/KeyguardStatusView.java
index 5db4f9e..9df7734 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardStatusView.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardStatusView.java
@@ -44,7 +44,6 @@
  * - keyguard clock
  * - logout button (on certain managed devices)
  * - owner information (if set)
- * - notification icons (shown on AOD)
  */
 public class KeyguardStatusView extends GridLayout {
     private static final boolean DEBUG = KeyguardConstants.DEBUG;
@@ -59,7 +58,6 @@
     private TextView mOwnerInfo;
     private boolean mCanShowOwnerInfo = true; // by default, try to show the owner information here
     private KeyguardSliceView mKeyguardSlice;
-    private View mNotificationIcons;
     private Runnable mPendingMarqueeStart;
     private Handler mHandler;
 
@@ -132,13 +130,11 @@
     protected void onFinishInflate() {
         super.onFinishInflate();
         mLogoutView = findViewById(R.id.logout);
-        mNotificationIcons = findViewById(R.id.clock_notification_icon_container);
         if (mLogoutView != null) {
             mLogoutView.setOnClickListener(this::onLogoutClicked);
         }
 
         mClockView = findViewById(R.id.keyguard_clock_container);
-        mClockView.setShowCurrentUserTime(true);
         if (KeyguardClockAccessibilityDelegate.isNeeded(mContext)) {
             mClockView.setAccessibilityDelegate(new KeyguardClockAccessibilityDelegate(mContext));
         }
@@ -161,22 +157,10 @@
      */
     private void onSliceContentChanged() {
         final boolean hasHeader = mKeyguardSlice.hasHeader();
-        mClockView.setKeyguardShowingHeader(hasHeader);
         if (mShowingHeader == hasHeader) {
             return;
         }
         mShowingHeader = hasHeader;
-        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);
-        }
-
-        mClockView.setKeyguardHidingBigClock(hasHeader);
     }
 
     @Override
@@ -293,13 +277,6 @@
             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/KeyguardStatusViewController.java b/packages/SystemUI/src/com/android/keyguard/KeyguardStatusViewController.java
index 31ec003..fc80dbe 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardStatusViewController.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardStatusViewController.java
@@ -18,15 +18,12 @@
 
 import android.os.UserHandle;
 import android.util.Slog;
-import android.view.View;
 
 import com.android.systemui.statusbar.notification.AnimatableProperty;
 import com.android.systemui.statusbar.notification.PropertyAnimator;
 import com.android.systemui.statusbar.notification.stack.AnimationProperties;
 import com.android.systemui.statusbar.notification.stack.StackStateAnimator;
 import com.android.systemui.statusbar.phone.DozeParameters;
-import com.android.systemui.statusbar.phone.NotificationIconAreaController;
-import com.android.systemui.statusbar.phone.NotificationIconContainer;
 import com.android.systemui.statusbar.policy.ConfigurationController;
 import com.android.systemui.statusbar.policy.KeyguardStateController;
 import com.android.systemui.util.ViewController;
@@ -49,7 +46,6 @@
     private final KeyguardClockSwitchController mKeyguardClockSwitchController;
     private final KeyguardUpdateMonitor mKeyguardUpdateMonitor;
     private final ConfigurationController mConfigurationController;
-    private final NotificationIconAreaController mNotificationIconAreaController;
     private final DozeParameters mDozeParameters;
     private final KeyguardVisibilityHelper mKeyguardVisibilityHelper;
 
@@ -63,14 +59,12 @@
             KeyguardStateController keyguardStateController,
             KeyguardUpdateMonitor keyguardUpdateMonitor,
             ConfigurationController configurationController,
-            NotificationIconAreaController notificationIconAreaController,
             DozeParameters dozeParameters) {
         super(keyguardStatusView);
         mKeyguardSliceViewController = keyguardSliceViewController;
         mKeyguardClockSwitchController = keyguardClockSwitchController;
         mKeyguardUpdateMonitor = keyguardUpdateMonitor;
         mConfigurationController = configurationController;
-        mNotificationIconAreaController = notificationIconAreaController;
         mDozeParameters = dozeParameters;
         mKeyguardVisibilityHelper = new KeyguardVisibilityHelper(mView, keyguardStateController,
                 dozeParameters);
@@ -87,7 +81,6 @@
     protected void onViewAttached() {
         mKeyguardUpdateMonitor.registerCallback(mInfoCallback);
         mConfigurationController.addCallback(mConfigurationListener);
-        updateAodIcons();
     }
 
     @Override
@@ -237,17 +230,6 @@
         mKeyguardClockSwitchController.refresh();
     }
 
-    private void updateAodIcons() {
-        NotificationIconContainer nic = (NotificationIconContainer)
-                mView.findViewById(com.android.systemui.R.id.clock_notification_icon_container);
-        if (mLockScreenMode == KeyguardUpdateMonitor.LOCK_SCREEN_MODE_NORMAL) {
-            // alternate icon area is set in KeyguardClockSwitchController
-            mNotificationIconAreaController.setupAodIcons(nic, mLockScreenMode);
-        } else {
-            nic.setVisibility(View.GONE);
-        }
-    }
-
     private boolean shouldShowLogout() {
         return mKeyguardUpdateMonitor.isLogoutEnabled()
                 && KeyguardUpdateMonitor.getCurrentUser() != UserHandle.USER_SYSTEM;
@@ -271,16 +253,9 @@
         @Override
         public void onLockScreenModeChanged(int mode) {
             mLockScreenMode = mode;
-            mKeyguardClockSwitchController.updateLockScreenMode(mode);
             mKeyguardSliceViewController.updateLockScreenMode(mode);
-            if (mLockScreenMode == KeyguardUpdateMonitor.LOCK_SCREEN_MODE_LAYOUT_1) {
-                mView.setCanShowOwnerInfo(false);
-                mView.updateLogoutView(false);
-            } else {
-                mView.setCanShowOwnerInfo(true);
-                mView.updateLogoutView(false);
-            }
-            updateAodIcons();
+            mView.setCanShowOwnerInfo(false);
+            mView.updateLogoutView(false);
         }
 
         @Override
@@ -294,11 +269,6 @@
         }
 
         @Override
-        public void onTimeFormatChanged(String timeFormat) {
-            mKeyguardClockSwitchController.refreshFormat(timeFormat);
-        }
-
-        @Override
         public void onKeyguardVisibilityChanged(boolean showing) {
             if (showing) {
                 if (DEBUG) Slog.v(TAG, "refresh statusview showing:" + showing);
@@ -320,7 +290,6 @@
 
         @Override
         public void onUserSwitchComplete(int userId) {
-            mKeyguardClockSwitchController.refreshFormat();
             mView.updateOwnerInfo();
             mView.updateLogoutView(shouldShowLogout());
         }
diff --git a/packages/SystemUI/src/com/android/keyguard/LockIconViewController.java b/packages/SystemUI/src/com/android/keyguard/LockIconViewController.java
index 7329071..66ea2ad 100644
--- a/packages/SystemUI/src/com/android/keyguard/LockIconViewController.java
+++ b/packages/SystemUI/src/com/android/keyguard/LockIconViewController.java
@@ -199,14 +199,14 @@
     }
 
     private void updateVisibility() {
-        if (!mIsKeyguardShowing) {
+        if (!mIsKeyguardShowing || (!mUdfpsEnrolled && !mFaceAuthEnrolled)) {
             mView.setVisibility(View.INVISIBLE);
             return;
         }
 
         // these three states are mutually exclusive:
         mShowButton = mUdfpsEnrolled && !mCanDismissLockScreen && !mRunningFPS && isLockScreen();
-        mShowUnlockIcon = mCanDismissLockScreen && isLockScreen();
+        mShowUnlockIcon = mFaceAuthEnrolled & mCanDismissLockScreen && isLockScreen();
         mShowLockIcon = !mUdfpsEnrolled && !mCanDismissLockScreen && isLockScreen()
             && mFaceAuthEnrolled;
 
diff --git a/packages/SystemUI/src/com/android/keyguard/TextAnimator.kt b/packages/SystemUI/src/com/android/keyguard/TextAnimator.kt
index 5735a4f..cdb39ef 100644
--- a/packages/SystemUI/src/com/android/keyguard/TextAnimator.kt
+++ b/packages/SystemUI/src/com/android/keyguard/TextAnimator.kt
@@ -65,7 +65,9 @@
             invalidateCallback()
         }
         addListener(object : AnimatorListenerAdapter() {
-            override fun onAnimationEnd(animation: Animator?) = textInterpolator.rebase()
+            override fun onAnimationEnd(animation: Animator?) {
+                textInterpolator.rebase()
+            }
             override fun onAnimationCancel(animation: Animator?) = textInterpolator.rebase()
         })
     }
@@ -74,6 +76,10 @@
         textInterpolator.layout = layout
     }
 
+    fun isRunning(): Boolean {
+        return animator.isRunning
+    }
+
     fun draw(c: Canvas) = textInterpolator.draw(c)
 
     /**
@@ -101,7 +107,9 @@
         color: Int? = null,
         animate: Boolean = true,
         duration: Long = -1L,
-        interpolator: TimeInterpolator? = null
+        interpolator: TimeInterpolator? = null,
+        delay: Long = 0,
+        onAnimationEnd: Runnable? = null
     ) {
         if (animate) {
             animator.cancel()
@@ -120,12 +128,25 @@
         textInterpolator.onTargetPaintModified()
 
         if (animate) {
+            animator.startDelay = delay
             animator.duration = if (duration == -1L) {
                 DEFAULT_ANIMATION_DURATION
             } else {
                 duration
             }
             interpolator?.let { animator.interpolator = it }
+            if (onAnimationEnd != null) {
+                val listener = object : AnimatorListenerAdapter() {
+                    override fun onAnimationEnd(animation: Animator?) {
+                        onAnimationEnd.run()
+                        animator.removeListener(this)
+                    }
+                    override fun onAnimationCancel(animation: Animator?) {
+                        animator.removeListener(this)
+                    }
+                }
+                animator.addListener(listener)
+            }
             animator.start()
         } else {
             // No animation is requested, thus set base and target state to the same state.
diff --git a/packages/SystemUI/src/com/android/systemui/privacy/PrivacyDialog.kt b/packages/SystemUI/src/com/android/systemui/privacy/PrivacyDialog.kt
index 8ec9b68..dc22dc1 100644
--- a/packages/SystemUI/src/com/android/systemui/privacy/PrivacyDialog.kt
+++ b/packages/SystemUI/src/com/android/systemui/privacy/PrivacyDialog.kt
@@ -128,9 +128,14 @@
             )
         } ?: firstLine
         newView.requireViewById<TextView>(R.id.text).text = finalText
+        if (element.phoneCall) {
+            newView.requireViewById<View>(R.id.chevron).visibility = View.GONE
+        }
         newView.apply {
             setTag(element)
-            setOnClickListener(clickListener)
+            if (!element.phoneCall) {
+                setOnClickListener(clickListener)
+            }
         }
         return newView
     }
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSSecurityFooter.java b/packages/SystemUI/src/com/android/systemui/qs/QSSecurityFooter.java
index 2c5dbcd..670475f 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSSecurityFooter.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSSecurityFooter.java
@@ -36,7 +36,6 @@
 import android.text.method.LinkMovementMethod;
 import android.text.style.ClickableSpan;
 import android.util.Log;
-import android.view.ContextThemeWrapper;
 import android.view.LayoutInflater;
 import android.view.View;
 import android.view.View.OnClickListener;
@@ -89,7 +88,7 @@
     private Drawable mPrimaryFooterIconDrawable;
 
     @Inject
-    QSSecurityFooter(@Named(QS_SECURITY_FOOTER_VIEW) View rootView, Context context,
+    QSSecurityFooter(@Named(QS_SECURITY_FOOTER_VIEW) View rootView,
             UserTracker userTracker, @Main Handler mainHandler, ActivityStarter activityStarter,
             SecurityController securityController, @Background Looper bgLooper) {
         mRootView = rootView;
@@ -98,7 +97,7 @@
         mFooterIcon = mRootView.findViewById(R.id.footer_icon);
         mPrimaryFooterIcon = mRootView.findViewById(R.id.primary_footer_icon);
         mFooterIconId = R.drawable.ic_info_outline;
-        mContext = context;
+        mContext = rootView.getContext();
         mMainHandler = mainHandler;
         mActivityStarter = activityStarter;
         mSecurityController = securityController;
@@ -308,7 +307,7 @@
     }
 
     private void createDialog() {
-        mDialog = new SystemUIDialog(mContext);
+        mDialog = new SystemUIDialog(mContext, 0); // Use mContext theme
         mDialog.requestWindowFeature(Window.FEATURE_NO_TITLE);
         mDialog.setButton(DialogInterface.BUTTON_POSITIVE, getPositiveButton(), this);
         mDialog.setButton(DialogInterface.BUTTON_NEGATIVE, getNegativeButton(), this);
@@ -344,8 +343,7 @@
         final String vpnNameWorkProfile = mSecurityController.getWorkProfileVpnName();
 
 
-        View dialogView = LayoutInflater.from(
-                new ContextThemeWrapper(mContext, R.style.Theme_SystemUI_Dialog))
+        View dialogView = LayoutInflater.from(mContext)
                 .inflate(R.layout.quick_settings_footer_dialog, null, false);
 
         // device management section
@@ -420,8 +418,7 @@
     }
 
     private View createParentalControlsDialogView() {
-        View dialogView = LayoutInflater.from(
-                new ContextThemeWrapper(mContext, R.style.Theme_SystemUI_Dialog))
+        View dialogView = LayoutInflater.from(mContext)
                 .inflate(R.layout.quick_settings_footer_dialog_parental_controls, null, false);
 
         DeviceAdminInfo info = mSecurityController.getDeviceAdminInfo();
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 6f789d3..30a08c6 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/customize/QSCustomizer.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/customize/QSCustomizer.java
@@ -22,7 +22,6 @@
 import android.content.res.Configuration;
 import android.util.AttributeSet;
 import android.util.TypedValue;
-import android.view.ContextThemeWrapper;
 import android.view.LayoutInflater;
 import android.view.Menu;
 import android.view.View;
@@ -63,7 +62,7 @@
     private boolean mIsShowingNavBackdrop;
 
     public QSCustomizer(Context context, AttributeSet attrs) {
-        super(new ContextThemeWrapper(context, R.style.Theme_SystemUI_QuickSettings_Edit), attrs);
+        super(context, attrs);
 
         LayoutInflater.from(getContext()).inflate(R.layout.qs_customize_panel_content, this);
         mClipper = new QSDetailClipper(findViewById(R.id.customize_container));
diff --git a/packages/SystemUI/src/com/android/systemui/qs/customize/TileAdapter.java b/packages/SystemUI/src/com/android/systemui/qs/customize/TileAdapter.java
index 08aa599..006b230 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/customize/TileAdapter.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/customize/TileAdapter.java
@@ -52,6 +52,7 @@
 import com.android.systemui.qs.customize.TileQueryHelper.TileInfo;
 import com.android.systemui.qs.customize.TileQueryHelper.TileStateListener;
 import com.android.systemui.qs.dagger.QSScope;
+import com.android.systemui.qs.dagger.QSThemedContext;
 import com.android.systemui.qs.external.CustomTile;
 import com.android.systemui.qs.tileimpl.QSIconViewImpl;
 import com.android.systemui.qs.tileimpl.QSTileView;
@@ -89,7 +90,7 @@
     private final Handler mHandler = new Handler();
     private final List<TileInfo> mTiles = new ArrayList<>();
     private final ItemTouchHelper mItemTouchHelper;
-    private final ItemDecoration mDecoration;
+    private ItemDecoration mDecoration;
     private final MarginTileDecoration mMarginDecoration;
     private final int mMinNumTiles;
     private final QSTileHost mHost;
@@ -112,8 +113,12 @@
     private final boolean mUseHorizontalTiles;
 
     @Inject
-    public TileAdapter(Context context, QSTileHost qsHost, UiEventLogger uiEventLogger,
-            @Named(QS_LABELS_FLAG) boolean useHorizontalTiles) {
+    public TileAdapter(
+            @QSThemedContext Context context,
+            QSTileHost qsHost,
+            UiEventLogger uiEventLogger,
+            @Named(QS_LABELS_FLAG) boolean useHorizontalTiles
+    ) {
         mContext = context;
         mHost = qsHost;
         mUiEventLogger = uiEventLogger;
diff --git a/packages/SystemUI/src/com/android/systemui/qs/dagger/QSFragmentModule.java b/packages/SystemUI/src/com/android/systemui/qs/dagger/QSFragmentModule.java
index 2363aa4..3a5adce 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/dagger/QSFragmentModule.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/dagger/QSFragmentModule.java
@@ -49,6 +49,22 @@
     String QS_SECURITY_FOOTER_VIEW = "qs_security_footer";
     String QS_USING_MEDIA_PLAYER = "qs_using_media_player";
 
+    /**
+     * Provide a context themed using the QS theme
+     */
+    @Provides
+    @QSThemedContext
+    static Context provideThemedContext(@RootView View view) {
+        return view.getContext();
+    }
+
+    /** */
+    @Provides
+    @QSThemedContext
+    static LayoutInflater provideThemedLayoutInflater(@QSThemedContext Context context) {
+        return LayoutInflater.from(context);
+    }
+
     /** */
     @Provides
     @RootView
@@ -109,7 +125,10 @@
     @Provides
     @QSScope
     @Named(QS_SECURITY_FOOTER_VIEW)
-    static View providesQSSecurityFooterView(LayoutInflater layoutInflater, QSPanel qsPanel) {
+    static View providesQSSecurityFooterView(
+            @QSThemedContext LayoutInflater layoutInflater,
+            QSPanel qsPanel
+    ) {
         return layoutInflater.inflate(R.layout.quick_settings_footer, qsPanel, false);
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/qs/dagger/QSThemedContext.java b/packages/SystemUI/src/com/android/systemui/qs/dagger/QSThemedContext.java
new file mode 100644
index 0000000..a878d4c
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/qs/dagger/QSThemedContext.java
@@ -0,0 +1,32 @@
+/*
+ * Copyright (C) 2021 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.qs.dagger;
+
+import static java.lang.annotation.RetentionPolicy.RUNTIME;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.Retention;
+
+import javax.inject.Qualifier;
+
+/**
+ * Annotation for themed context in QS
+ */
+@Documented
+@Retention(RUNTIME)
+@Qualifier
+public @interface QSThemedContext {}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileBaseView.java b/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileBaseView.java
index abe3219..7e72f1a 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileBaseView.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileBaseView.java
@@ -72,7 +72,6 @@
     protected final ImageView mBg;
     private final int mColorActive;
     private final int mColorInactive;
-    private final int mColorDisabled;
     private int mCircleColor;
     private int mBgSize;
 
@@ -131,10 +130,9 @@
         setImportantForAccessibility(View.IMPORTANT_FOR_ACCESSIBILITY_YES);
         setBackground(mTileBackground);
 
-        mColorActive = Utils.getColorAttrDefaultColor(context, android.R.attr.colorAccent);
-        mColorDisabled = Utils.getDisabled(context,
-                Utils.getColorAttrDefaultColor(context, android.R.attr.colorControlActivated));
-        mColorInactive = Utils.getColorAttrDefaultColor(context, android.R.attr.textColorSecondary);
+        mColorActive = Utils.getColorAttrDefaultColor(context,
+                com.android.internal.R.attr.colorAccentPrimary);
+        mColorInactive = Utils.getColorAttrDefaultColor(context, R.attr.offStateColor);
 
         setPadding(0, 0, 0, 0);
         setClipChildren(false);
@@ -324,7 +322,7 @@
                 return mColorActive;
             case Tile.STATE_INACTIVE:
             case Tile.STATE_UNAVAILABLE:
-                return mColorDisabled;
+                return mColorInactive;
             default:
                 Log.e(TAG, "Invalid state " + state);
                 return 0;
diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/CropView.java b/packages/SystemUI/src/com/android/systemui/screenshot/CropView.java
index 78ee896..9e11451 100644
--- a/packages/SystemUI/src/com/android/systemui/screenshot/CropView.java
+++ b/packages/SystemUI/src/com/android/systemui/screenshot/CropView.java
@@ -28,21 +28,26 @@
 import android.os.Parcel;
 import android.os.Parcelable;
 import android.util.AttributeSet;
-import android.util.IntArray;
 import android.util.Log;
 import android.util.MathUtils;
 import android.util.Range;
+import android.view.KeyEvent;
 import android.view.MotionEvent;
 import android.view.View;
 import android.view.accessibility.AccessibilityEvent;
 import android.view.accessibility.AccessibilityNodeInfo;
+import android.widget.SeekBar;
 
 import androidx.annotation.Nullable;
+import androidx.core.view.ViewCompat;
+import androidx.core.view.accessibility.AccessibilityNodeInfoCompat;
+import androidx.customview.widget.ExploreByTouchHelper;
 import androidx.interpolator.view.animation.FastOutSlowInInterpolator;
 
-import com.android.internal.widget.ExploreByTouchHelper;
 import com.android.systemui.R;
 
+import java.util.List;
+
 /**
  * CropView has top and bottom draggable crop handles, with a scrim to darken the areas being
  * cropped out.
@@ -66,6 +71,7 @@
     private int mImageWidth;
 
     private CropBoundary mCurrentDraggingBoundary = CropBoundary.NONE;
+    private int mActivePointerId;
     // The starting value of mCurrentDraggingBoundary's crop, used to compute touch deltas.
     private float mMovementStartValue;
     private float mStartingY;  // y coordinate of ACTION_DOWN
@@ -74,6 +80,7 @@
     private Range<Float> mMotionRange;
 
     private CropInteractionListener mCropInteractionListener;
+    private final ExploreByTouchHelper mExploreByTouchHelper;
 
     public CropView(Context context, @Nullable AttributeSet attrs) {
         this(context, attrs, 0);
@@ -94,7 +101,8 @@
         // 48 dp touchable region around each handle.
         mCropTouchMargin = 24 * getResources().getDisplayMetrics().density;
 
-        setAccessibilityDelegate(new AccessibilityHelper());
+        mExploreByTouchHelper = new AccessibilityHelper();
+        ViewCompat.setAccessibilityDelegate(this, mExploreByTouchHelper);
     }
 
     @Override
@@ -131,64 +139,88 @@
     public boolean onTouchEvent(MotionEvent event) {
         int topPx = fractionToVerticalPixels(mCrop.top);
         int bottomPx = fractionToVerticalPixels(mCrop.bottom);
-        switch (event.getAction()) {
+        switch (event.getActionMasked()) {
             case MotionEvent.ACTION_DOWN:
                 mCurrentDraggingBoundary = nearestBoundary(event, topPx, bottomPx,
                         fractionToHorizontalPixels(mCrop.left),
                         fractionToHorizontalPixels(mCrop.right));
                 if (mCurrentDraggingBoundary != CropBoundary.NONE) {
+                    mActivePointerId = event.getPointerId(0);
                     mStartingY = event.getY();
                     mStartingX = event.getX();
                     mMovementStartValue = getBoundaryPosition(mCurrentDraggingBoundary);
-                    updateListener(event);
-                    switch (mCurrentDraggingBoundary) {
-                        case TOP:
-                            mMotionRange = new Range<>(0f,
-                                    mCrop.bottom - pixelDistanceToFraction(mCropTouchMargin,
-                                            CropBoundary.BOTTOM));
-                            break;
-                        case BOTTOM:
-                            mMotionRange = new Range<>(
-                                    mCrop.top + pixelDistanceToFraction(mCropTouchMargin,
-                                            CropBoundary.TOP), 1f);
-                            break;
-                        case LEFT:
-                            mMotionRange = new Range<>(0f,
-                                    mCrop.right - pixelDistanceToFraction(mCropTouchMargin,
-                                            CropBoundary.RIGHT));
-                            break;
-                        case RIGHT:
-                            mMotionRange = new Range<>(
-                                    mCrop.left + pixelDistanceToFraction(mCropTouchMargin,
-                                            CropBoundary.LEFT), 1f);
-                            break;
-                    }
+                    updateListener(MotionEvent.ACTION_DOWN, event.getX());
+                    mMotionRange = getAllowedValues(mCurrentDraggingBoundary);
                 }
                 return true;
             case MotionEvent.ACTION_MOVE:
                 if (mCurrentDraggingBoundary != CropBoundary.NONE) {
-                    float deltaPx = isVertical(mCurrentDraggingBoundary) ? event.getY() - mStartingY
-                            : event.getX() - mStartingX;
-                    float delta = pixelDistanceToFraction((int) deltaPx, mCurrentDraggingBoundary);
-                    setBoundaryPosition(mCurrentDraggingBoundary,
-                            mMotionRange.clamp(mMovementStartValue + delta));
-                    updateListener(event);
-                    invalidate();
+                    int pointerIndex = event.findPointerIndex(mActivePointerId);
+                    if (pointerIndex >= 0) {
+                        // Original pointer still active, do the move.
+                        float deltaPx = isVertical(mCurrentDraggingBoundary)
+                                ? event.getY(pointerIndex) - mStartingY
+                                : event.getX(pointerIndex) - mStartingX;
+                        float delta = pixelDistanceToFraction((int) deltaPx,
+                                mCurrentDraggingBoundary);
+                        setBoundaryPosition(mCurrentDraggingBoundary,
+                                mMotionRange.clamp(mMovementStartValue + delta));
+                        updateListener(MotionEvent.ACTION_MOVE, event.getX(pointerIndex));
+                        invalidate();
+                    }
                     return true;
                 }
+                break;
+            case MotionEvent.ACTION_POINTER_DOWN:
+                if (mActivePointerId == event.getPointerId(event.getActionIndex())
+                        && mCurrentDraggingBoundary != CropBoundary.NONE) {
+                    updateListener(MotionEvent.ACTION_DOWN, event.getX(event.getActionIndex()));
+                    return true;
+                }
+                break;
+            case MotionEvent.ACTION_POINTER_UP:
+                if (mActivePointerId == event.getPointerId(event.getActionIndex())
+                        && mCurrentDraggingBoundary != CropBoundary.NONE) {
+                    updateListener(MotionEvent.ACTION_UP, event.getX(event.getActionIndex()));
+                    return true;
+                }
+                break;
             case MotionEvent.ACTION_CANCEL:
             case MotionEvent.ACTION_UP:
-                if (mCurrentDraggingBoundary != CropBoundary.NONE) {
-                    updateListener(event);
+                if (mCurrentDraggingBoundary != CropBoundary.NONE
+                        && mActivePointerId == event.getPointerId(mActivePointerId)) {
+                    updateListener(MotionEvent.ACTION_UP, event.getX(0));
+                    return true;
                 }
+                break;
         }
         return super.onTouchEvent(event);
     }
 
+    @Override
+    public boolean dispatchHoverEvent(MotionEvent event) {
+        return mExploreByTouchHelper.dispatchHoverEvent(event)
+                || super.dispatchHoverEvent(event);
+    }
+
+    @Override
+    public boolean dispatchKeyEvent(KeyEvent event) {
+        return mExploreByTouchHelper.dispatchKeyEvent(event)
+                || super.dispatchKeyEvent(event);
+    }
+
+    @Override
+    public void onFocusChanged(boolean gainFocus, int direction,
+            Rect previouslyFocusedRect) {
+        super.onFocusChanged(gainFocus, direction, previouslyFocusedRect);
+        mExploreByTouchHelper.onFocusChanged(gainFocus, direction, previouslyFocusedRect);
+    }
+
     /**
      * Set the given boundary to the given value without animation.
      */
     public void setBoundaryPosition(CropBoundary boundary, float position) {
+        position = (float) getAllowedValues(boundary).clamp(position);
         switch (boundary) {
             case TOP:
                 mCrop.top = position;
@@ -280,12 +312,51 @@
         mCropInteractionListener = listener;
     }
 
-    private void updateListener(MotionEvent event) {
-        if (mCropInteractionListener != null && (isVertical(mCurrentDraggingBoundary))) {
+    private Range getAllowedValues(CropBoundary boundary) {
+        switch (boundary) {
+            case TOP:
+                return new Range<>(0f,
+                        mCrop.bottom - pixelDistanceToFraction(mCropTouchMargin,
+                                CropBoundary.BOTTOM));
+            case BOTTOM:
+                return new Range<>(
+                        mCrop.top + pixelDistanceToFraction(mCropTouchMargin,
+                                CropBoundary.TOP), 1f);
+            case LEFT:
+                return new Range<>(0f,
+                        mCrop.right - pixelDistanceToFraction(mCropTouchMargin,
+                                CropBoundary.RIGHT));
+            case RIGHT:
+                return new Range<>(
+                        mCrop.left + pixelDistanceToFraction(mCropTouchMargin,
+                                CropBoundary.LEFT), 1f);
+        }
+        return null;
+    }
+
+    /**
+     * @param action either ACTION_DOWN, ACTION_UP or ACTION_MOVE.
+     * @param x coordinate of the relevant pointer.
+     */
+    private void updateListener(int action, float x) {
+        if (mCropInteractionListener != null && isVertical(mCurrentDraggingBoundary)) {
             float boundaryPosition = getBoundaryPosition(mCurrentDraggingBoundary);
-            mCropInteractionListener.onCropMotionEvent(event, mCurrentDraggingBoundary,
-                    boundaryPosition, fractionToVerticalPixels(boundaryPosition),
-                    (mCrop.left + mCrop.right) / 2);
+            switch (action) {
+                case MotionEvent.ACTION_DOWN:
+                    mCropInteractionListener.onCropDragStarted(mCurrentDraggingBoundary,
+                            boundaryPosition, fractionToVerticalPixels(boundaryPosition),
+                            (mCrop.left + mCrop.right) / 2, x);
+                    break;
+                case MotionEvent.ACTION_MOVE:
+                    mCropInteractionListener.onCropDragMoved(mCurrentDraggingBoundary,
+                            boundaryPosition, fractionToVerticalPixels(boundaryPosition),
+                            (mCrop.left + mCrop.right) / 2, x);
+                    break;
+                case MotionEvent.ACTION_UP:
+                    mCropInteractionListener.onCropDragComplete();
+                    break;
+
+            }
         }
     }
 
@@ -371,6 +442,8 @@
 
         private static final int TOP_HANDLE_ID = 1;
         private static final int BOTTOM_HANDLE_ID = 2;
+        private static final int LEFT_HANDLE_ID = 3;
+        private static final int RIGHT_HANDLE_ID = 4;
 
         AccessibilityHelper() {
             super(CropView.this);
@@ -384,62 +457,125 @@
             if (Math.abs(y - fractionToVerticalPixels(mCrop.bottom)) < mCropTouchMargin) {
                 return BOTTOM_HANDLE_ID;
             }
-            return ExploreByTouchHelper.INVALID_ID;
+            if (y > fractionToVerticalPixels(mCrop.top)
+                    && y < fractionToVerticalPixels(mCrop.bottom)) {
+                if (Math.abs(x - fractionToHorizontalPixels(mCrop.left)) < mCropTouchMargin) {
+                    return LEFT_HANDLE_ID;
+                }
+                if (Math.abs(x - fractionToHorizontalPixels(mCrop.right)) < mCropTouchMargin) {
+                    return RIGHT_HANDLE_ID;
+                }
+            }
+
+            return ExploreByTouchHelper.HOST_ID;
         }
 
         @Override
-        protected void getVisibleVirtualViews(IntArray virtualViewIds) {
+        protected void getVisibleVirtualViews(List<Integer> virtualViewIds) {
+            // Add views in traversal order
             virtualViewIds.add(TOP_HANDLE_ID);
+            virtualViewIds.add(LEFT_HANDLE_ID);
+            virtualViewIds.add(RIGHT_HANDLE_ID);
             virtualViewIds.add(BOTTOM_HANDLE_ID);
         }
 
         @Override
         protected void onPopulateEventForVirtualView(int virtualViewId, AccessibilityEvent event) {
-            switch (virtualViewId) {
-                case TOP_HANDLE_ID:
-                    event.setContentDescription(
-                            getResources().getString(R.string.screenshot_top_boundary));
-                    break;
-                case BOTTOM_HANDLE_ID:
-                    event.setContentDescription(
-                            getResources().getString(R.string.screenshot_bottom_boundary));
-                    break;
-            }
+            CropBoundary boundary = viewIdToBoundary(virtualViewId);
+            event.setContentDescription(getBoundaryContentDescription(boundary));
         }
 
         @Override
         protected void onPopulateNodeForVirtualView(int virtualViewId,
-                AccessibilityNodeInfo node) {
-            switch (virtualViewId) {
-                case TOP_HANDLE_ID:
-                    node.setContentDescription(
-                            getResources().getString(R.string.screenshot_top_boundary));
-                    setNodePositions(mCrop.top, node);
-                    break;
-                case BOTTOM_HANDLE_ID:
-                    node.setContentDescription(
-                            getResources().getString(R.string.screenshot_bottom_boundary));
-                    setNodePositions(mCrop.bottom, node);
-                    break;
-            }
+                AccessibilityNodeInfoCompat node) {
+            CropBoundary boundary = viewIdToBoundary(virtualViewId);
+            node.setContentDescription(getBoundaryContentDescription(boundary));
+            setNodePosition(getNodeRect(boundary), node);
 
-            // TODO: need to figure out the full set of actions to support here.
-            node.addAction(
-                    AccessibilityNodeInfo.AccessibilityAction.ACTION_CLICK);
-            node.setClickable(true);
-            node.setFocusable(true);
+            // Intentionally set the class name to SeekBar so that TalkBack uses volume control to
+            // scroll.
+            node.setClassName(SeekBar.class.getName());
+            node.addAction(AccessibilityNodeInfoCompat.ACTION_SCROLL_FORWARD);
+            node.addAction(AccessibilityNodeInfoCompat.ACTION_SCROLL_BACKWARD);
         }
 
         @Override
         protected boolean onPerformActionForVirtualView(
                 int virtualViewId, int action, Bundle arguments) {
-            return false;
+            if (action != AccessibilityNodeInfo.ACTION_SCROLL_FORWARD
+                    && action != AccessibilityNodeInfo.ACTION_SCROLL_BACKWARD) {
+                return false;
+            }
+            CropBoundary boundary = viewIdToBoundary(virtualViewId);
+            float delta = pixelDistanceToFraction(mCropTouchMargin, boundary);
+            if (action == AccessibilityNodeInfo.ACTION_SCROLL_FORWARD) {
+                delta = -delta;
+            }
+            setBoundaryPosition(boundary, delta + getBoundaryPosition(boundary));
+            invalidateVirtualView(virtualViewId);
+            sendEventForVirtualView(virtualViewId, AccessibilityEvent.TYPE_VIEW_SELECTED);
+            return true;
         }
 
-        private void setNodePositions(float fraction, AccessibilityNodeInfo node) {
-            int pixels = fractionToVerticalPixels(fraction);
-            Rect rect = new Rect(0, (int) (pixels - mCropTouchMargin),
-                    getWidth(), (int) (pixels + mCropTouchMargin));
+        private CharSequence getBoundaryContentDescription(CropBoundary boundary) {
+            int template;
+            switch (boundary) {
+                case TOP:
+                    template = R.string.screenshot_top_boundary_pct;
+                    break;
+                case BOTTOM:
+                    template = R.string.screenshot_bottom_boundary_pct;
+                    break;
+                case LEFT:
+                    template = R.string.screenshot_left_boundary_pct;
+                    break;
+                case RIGHT:
+                    template = R.string.screenshot_right_boundary_pct;
+                    break;
+                default:
+                    return "";
+            }
+
+            return getResources().getString(template,
+                    Math.round(getBoundaryPosition(boundary) * 100));
+        }
+
+        private CropBoundary viewIdToBoundary(int viewId) {
+            switch (viewId) {
+                case TOP_HANDLE_ID:
+                    return CropBoundary.TOP;
+                case BOTTOM_HANDLE_ID:
+                    return CropBoundary.BOTTOM;
+                case LEFT_HANDLE_ID:
+                    return CropBoundary.LEFT;
+                case RIGHT_HANDLE_ID:
+                    return CropBoundary.RIGHT;
+            }
+            return CropBoundary.NONE;
+        }
+
+        private Rect getNodeRect(CropBoundary boundary) {
+            Rect rect;
+            if (isVertical(boundary)) {
+                int pixels = fractionToVerticalPixels(getBoundaryPosition(boundary));
+                rect = new Rect(0, (int) (pixels - mCropTouchMargin),
+                        getWidth(), (int) (pixels + mCropTouchMargin));
+                // Top boundary can sometimes go beyond the view, shift it down to compensate so
+                // the area is big enough.
+                if (rect.top < 0) {
+                    rect.offset(0, -rect.top);
+                }
+            } else {
+                int pixels = fractionToHorizontalPixels(getBoundaryPosition(boundary));
+                rect = new Rect((int) (pixels - mCropTouchMargin),
+                        (int) (fractionToVerticalPixels(mCrop.top) + mCropTouchMargin),
+                        (int) (pixels + mCropTouchMargin),
+                        (int) (fractionToVerticalPixels(mCrop.bottom) - mCropTouchMargin));
+            }
+            return rect;
+        }
+
+        private void setNodePosition(Rect rect, AccessibilityNodeInfoCompat node) {
             node.setBoundsInParent(rect);
             int[] pos = new int[2];
             getLocationOnScreen(pos);
@@ -452,12 +588,11 @@
      * Listen for crop motion events and state.
      */
     public interface CropInteractionListener {
-        /**
-         * Called whenever CropView has a MotionEvent that can impact the position of the crop
-         * boundaries.
-         */
-        void onCropMotionEvent(MotionEvent event, CropBoundary boundary, float boundaryPosition,
-                int boundaryPositionPx, float horizontalCenter);
+        void onCropDragStarted(CropBoundary boundary, float boundaryPosition,
+                int boundaryPositionPx, float horizontalCenter, float x);
+        void onCropDragMoved(CropBoundary boundary, float boundaryPosition,
+                int boundaryPositionPx, float horizontalCenter, float x);
+        void onCropDragComplete();
     }
 
     static class SavedState extends BaseSavedState {
diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/MagnifierView.java b/packages/SystemUI/src/com/android/systemui/screenshot/MagnifierView.java
index 08cd91c..34b40f7 100644
--- a/packages/SystemUI/src/com/android/systemui/screenshot/MagnifierView.java
+++ b/packages/SystemUI/src/com/android/systemui/screenshot/MagnifierView.java
@@ -28,7 +28,6 @@
 import android.graphics.Rect;
 import android.graphics.drawable.Drawable;
 import android.util.AttributeSet;
-import android.view.MotionEvent;
 import android.view.View;
 import android.view.ViewPropertyAnimator;
 
@@ -148,49 +147,51 @@
     }
 
     @Override
-    public void onCropMotionEvent(MotionEvent event, CropView.CropBoundary boundary,
-            float cropPosition, int cropPositionPx, float horizontalCenter) {
+    public void onCropDragStarted(CropView.CropBoundary boundary, float boundaryPosition,
+            int boundaryPositionPx, float horizontalCenter, float x) {
         mCropBoundary = boundary;
         mLastCenter = horizontalCenter;
-        boolean touchOnRight = event.getX() > getParentWidth() / 2;
+        boolean touchOnRight = x > getParentWidth() / 2;
         float translateXTarget = touchOnRight ? 0 : getParentWidth() - getWidth();
-        switch (event.getAction()) {
-            case MotionEvent.ACTION_DOWN:
-                mLastCropPosition = cropPosition;
-                setTranslationY(cropPositionPx - getHeight() / 2);
-                setPivotX(getWidth() / 2);
-                setPivotY(getHeight() / 2);
-                setScaleX(0.2f);
-                setScaleY(0.2f);
-                setAlpha(0f);
-                setTranslationX((getParentWidth() - getWidth()) / 2);
-                setVisibility(View.VISIBLE);
-                mTranslationAnimator =
-                        animate().alpha(1f).translationX(translateXTarget).scaleX(1f).scaleY(1f);
-                mTranslationAnimator.setListener(mTranslationAnimatorListener);
-                mTranslationAnimator.start();
-                break;
-            case MotionEvent.ACTION_MOVE:
-                // The touch is near the middle if it's within 10% of the center point.
-                // We don't want to animate horizontally if the touch is near the middle.
-                boolean nearMiddle = Math.abs(event.getX() - getParentWidth() / 2)
-                        < getParentWidth() / 10f;
-                boolean viewOnLeft = getTranslationX() < (getParentWidth() - getWidth()) / 2;
-                if (!nearMiddle && viewOnLeft != touchOnRight && mTranslationAnimator == null) {
-                    mTranslationAnimator = animate().translationX(translateXTarget);
-                    mTranslationAnimator.setListener(mTranslationAnimatorListener);
-                    mTranslationAnimator.start();
-                }
-                mLastCropPosition = cropPosition;
-                setTranslationY(cropPositionPx - getHeight() / 2);
-                invalidate();
-                break;
-            case MotionEvent.ACTION_CANCEL:
-            case MotionEvent.ACTION_UP:
-                animate().alpha(0).translationX((getParentWidth() - getWidth()) / 2).scaleX(0.2f)
-                        .scaleY(0.2f).withEndAction(() -> setVisibility(View.INVISIBLE)).start();
-                break;
+        mLastCropPosition = boundaryPosition;
+        setTranslationY(boundaryPositionPx - getHeight() / 2);
+        setPivotX(getWidth() / 2);
+        setPivotY(getHeight() / 2);
+        setScaleX(0.2f);
+        setScaleY(0.2f);
+        setAlpha(0f);
+        setTranslationX((getParentWidth() - getWidth()) / 2);
+        setVisibility(View.VISIBLE);
+        mTranslationAnimator =
+                animate().alpha(1f).translationX(translateXTarget).scaleX(1f).scaleY(1f);
+        mTranslationAnimator.setListener(mTranslationAnimatorListener);
+        mTranslationAnimator.start();
+    }
+
+    @Override
+    public void onCropDragMoved(CropView.CropBoundary boundary, float boundaryPosition,
+            int boundaryPositionPx, float horizontalCenter, float x) {
+        boolean touchOnRight = x > getParentWidth() / 2;
+        float translateXTarget = touchOnRight ? 0 : getParentWidth() - getWidth();
+        // The touch is near the middle if it's within 10% of the center point.
+        // We don't want to animate horizontally if the touch is near the middle.
+        boolean nearMiddle = Math.abs(x - getParentWidth() / 2)
+                < getParentWidth() / 10f;
+        boolean viewOnLeft = getTranslationX() < (getParentWidth() - getWidth()) / 2;
+        if (!nearMiddle && viewOnLeft != touchOnRight && mTranslationAnimator == null) {
+            mTranslationAnimator = animate().translationX(translateXTarget);
+            mTranslationAnimator.setListener(mTranslationAnimatorListener);
+            mTranslationAnimator.start();
         }
+        mLastCropPosition = boundaryPosition;
+        setTranslationY(boundaryPositionPx - getHeight() / 2);
+        invalidate();
+    }
+
+    @Override
+    public void onCropDragComplete() {
+        animate().alpha(0).translationX((getParentWidth() - getWidth()) / 2).scaleX(0.2f)
+                .scaleY(0.2f).withEndAction(() -> setVisibility(View.INVISIBLE)).start();
     }
 
     private Path generateCheckerboard() {
diff --git a/packages/SystemUI/src/com/android/systemui/settings/brightness/BrightnessDialog.java b/packages/SystemUI/src/com/android/systemui/settings/brightness/BrightnessDialog.java
index 1961bfc..3ba4646 100644
--- a/packages/SystemUI/src/com/android/systemui/settings/brightness/BrightnessDialog.java
+++ b/packages/SystemUI/src/com/android/systemui/settings/brightness/BrightnessDialog.java
@@ -25,6 +25,7 @@
 
 import com.android.internal.logging.MetricsLogger;
 import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
+import com.android.systemui.R;
 import com.android.systemui.broadcast.BroadcastDispatcher;
 
 import javax.inject.Inject;
@@ -61,10 +62,10 @@
         window.setLayout(
                 WindowManager.LayoutParams.MATCH_PARENT, WindowManager.LayoutParams.WRAP_CONTENT);
 
-
         BrightnessSlider controller = mToggleSliderFactory.create(this, null);
         controller.init();
         setContentView(controller.getRootView());
+        controller.getRootView().setBackgroundResource(R.drawable.brightness_mirror_background);
         mBrightnessController = new BrightnessController(this, controller, mBroadcastDispatcher);
     }
 
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 019f7e0..6b864c9 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconAreaController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconAreaController.java
@@ -161,15 +161,14 @@
     /**
      * Called by the Keyguard*ViewController whose view contains the aod icons.
      */
-    public void setupAodIcons(@NonNull NotificationIconContainer aodIcons,
-            int lockScreenMode) {
+    public void setupAodIcons(@NonNull NotificationIconContainer aodIcons) {
         boolean changed = mAodIcons != null;
         if (changed) {
             mAodIcons.setAnimationsEnabled(false);
             mAodIcons.removeAllViews();
         }
         mAodIcons = aodIcons;
-        mAodIcons.setOnLockScreen(true, lockScreenMode);
+        mAodIcons.setOnLockScreen(true);
         updateAodIconsVisibility(false /* animate */);
         updateAnimations();
         if (changed) {
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 52f656f..c09c485 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconContainer.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconContainer.java
@@ -35,7 +35,6 @@
 import androidx.collection.ArrayMap;
 
 import com.android.internal.statusbar.StatusBarIcon;
-import com.android.keyguard.KeyguardUpdateMonitor;
 import com.android.settingslib.Utils;
 import com.android.systemui.R;
 import com.android.systemui.animation.Interpolators;
@@ -151,7 +150,6 @@
     private float mActualPaddingStart = NO_VALUE;
     private boolean mDozing;
     private boolean mOnLockScreen;
-    private int mLockScreenMode = KeyguardUpdateMonitor.LOCK_SCREEN_MODE_NORMAL;
     private boolean mInNotificationIconShelf;
     private boolean mChangingViewPositions;
     private int mAddAnimationStartIndex = -1;
@@ -464,33 +462,6 @@
             mFirstVisibleIconState = mIconStates.get(getChildAt(0));
         }
 
-        boolean center = mOnLockScreen
-                && mLockScreenMode == KeyguardUpdateMonitor.LOCK_SCREEN_MODE_NORMAL;
-        if (center && translationX < getLayoutEnd()) {
-            float initialTranslation =
-                    mFirstVisibleIconState == null ? 0 : mFirstVisibleIconState.xTranslation;
-
-            float contentWidth = 0;
-            if (mLastVisibleIconState != null) {
-                contentWidth = mLastVisibleIconState.xTranslation + mIconSize;
-                contentWidth = Math.min(getWidth(), contentWidth) - initialTranslation;
-            }
-            float availableSpace = getLayoutEnd() - getActualPaddingStart();
-            float delta = (availableSpace - contentWidth) / 2;
-
-            if (firstOverflowIndex != -1) {
-                // If we have an overflow, only count those half for centering because the dots
-                // don't have a lot of visual weight.
-                float deltaIgnoringOverflow = (getLayoutEnd() - mVisualOverflowStart) / 2;
-                delta = (deltaIgnoringOverflow + delta) / 2;
-            }
-            for (int i = 0; i < childCount; i++) {
-                View view = getChildAt(i);
-                IconState iconState = mIconStates.get(view);
-                iconState.xTranslation += delta;
-            }
-        }
-
         if (isLayoutRtl()) {
             for (int i = 0; i < childCount; i++) {
                 View view = getChildAt(i);
@@ -698,9 +669,8 @@
      * Set whether the device is on the lockscreen and which lockscreen mode the device is
      * configured to. Depending on these values, the layout of the AOD icons change.
      */
-    public void setOnLockScreen(boolean onLockScreen, int lockScreenMode) {
+    public void setOnLockScreen(boolean onLockScreen) {
         mOnLockScreen = onLockScreen;
-        mLockScreenMode = lockScreenMode;
     }
 
     public void setInNotificationIconShelf(boolean inShelf) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelViewController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelViewController.java
index 6af2990..7032aef 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelViewController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelViewController.java
@@ -76,7 +76,6 @@
 import com.android.internal.logging.MetricsLogger;
 import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
 import com.android.internal.util.LatencyTracker;
-import com.android.keyguard.KeyguardClockSwitchController;
 import com.android.keyguard.KeyguardStatusView;
 import com.android.keyguard.KeyguardStatusViewController;
 import com.android.keyguard.KeyguardUpdateMonitor;
@@ -363,6 +362,7 @@
     private float mDownX;
     private float mDownY;
     private int mDisplayCutoutTopInset = 0; // in pixels
+    private int mSplitShadeNotificationsTopPadding;
 
     private final KeyguardClockPositionAlgorithm
             mClockPositionAlgorithm =
@@ -798,11 +798,6 @@
                 statusBarViewComponent.getKeyguardStatusBarViewController();
         mKeyguarStatusBarViewController.init();
 
-        // Re-associate the clock container with the keyguard clock switch.
-        KeyguardClockSwitchController keyguardClockSwitchController =
-                statusViewComponent.getKeyguardClockSwitchController();
-        keyguardClockSwitchController.setBigClockContainer(mBigClockContainer);
-
         if (mKeyguardUserSwitcherController != null) {
             // Try to close the switcher so that callbacks are triggered if necessary.
             // Otherwise, NPV can get into a state where some of the views are still hidden
@@ -847,6 +842,8 @@
     }
 
     public void updateResources() {
+        mSplitShadeNotificationsTopPadding =
+                mResources.getDimensionPixelSize(R.dimen.notifications_top_padding_split_shade);
         int qsWidth = mResources.getDimensionPixelSize(R.dimen.qs_panel_width);
         int panelWidth = mResources.getDimensionPixelSize(R.dimen.notification_panel_width);
         mShouldUseSplitNotificationShade =
@@ -2019,10 +2016,9 @@
         }
     }
 
-    private float calculateQsTopPadding() {
-        // in split shade mode we want notifications to be directly below status bar
+    private float calculateNotificationsTopPadding() {
         if (mShouldUseSplitNotificationShade && !mKeyguardShowing) {
-            return 0f;
+            return mSplitShadeNotificationsTopPadding;
         }
         if (mKeyguardShowing && (mQsExpandImmediate
                 || mIsExpanding && mQsExpandedWhenExpandingStarted)) {
@@ -2076,7 +2072,8 @@
 
 
     protected void requestScrollerTopPaddingUpdate(boolean animate) {
-        mNotificationStackScrollLayoutController.updateTopPadding(calculateQsTopPadding(), animate);
+        mNotificationStackScrollLayoutController.updateTopPadding(
+                calculateNotificationsTopPadding(), animate);
         if (mKeyguardShowing && mKeyguardBypassController.getBypassEnabled()) {
             // update the position of the header
             updateQsExpansion();
@@ -4056,7 +4053,8 @@
                     calculatePanelHeightShade(), p);
             p.setColor(Color.MAGENTA);
             canvas.drawLine(
-                    0, calculateQsTopPadding(), mView.getWidth(), calculateQsTopPadding(), p);
+                    0, calculateNotificationsTopPadding(), mView.getWidth(),
+                    calculateNotificationsTopPadding(), p);
             p.setColor(Color.CYAN);
             canvas.drawLine(0, mClockPositionResult.stackScrollerPadding, mView.getWidth(),
                     mNotificationStackScrollLayoutController.getTopPadding(), p);
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 adde4d8..58488ef 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java
@@ -497,7 +497,7 @@
             return;
         }
         shiftNotificationsScrim(qsPanelBottomY);
-        updateNotificationsScrimAlpha(qsPanelBottomY);
+        updateNotificationsScrimAlpha(expansionFraction, qsPanelBottomY);
         if (mQsExpansion != expansionFraction) {
             mQsExpansion = expansionFraction;
             boolean relevantState = (mState == ScrimState.SHADE_LOCKED
@@ -519,14 +519,14 @@
         }
     }
 
-    private void updateNotificationsScrimAlpha(int qsPanelBottomY) {
+    private void updateNotificationsScrimAlpha(float qsExpansion, int qsPanelBottomY) {
         float newAlpha = 0;
         if (qsPanelBottomY > 0) {
             float interpolator = 0;
             if (mState == ScrimState.UNLOCKED || mState == ScrimState.SHADE_LOCKED) {
                 interpolator = getInterpolatedFraction();
             } else {
-                interpolator = mQsExpansion;
+                interpolator = qsExpansion;
             }
             newAlpha = MathUtils.lerp(0, 1, interpolator);
         }
diff --git a/packages/SystemUI/src/com/android/systemui/wmshell/BubblesManager.java b/packages/SystemUI/src/com/android/systemui/wmshell/BubblesManager.java
index afeda967..55b80dd 100644
--- a/packages/SystemUI/src/com/android/systemui/wmshell/BubblesManager.java
+++ b/packages/SystemUI/src/com/android/systemui/wmshell/BubblesManager.java
@@ -38,7 +38,6 @@
 import android.app.NotificationManager;
 import android.content.Context;
 import android.content.res.Configuration;
-import android.os.Looper;
 import android.os.RemoteException;
 import android.os.ServiceManager;
 import android.service.notification.NotificationListenerService.RankingMap;
@@ -85,16 +84,13 @@
 
 import java.io.FileDescriptor;
 import java.io.PrintWriter;
-import java.lang.reflect.Array;
 import java.util.ArrayList;
 import java.util.HashMap;
 import java.util.List;
 import java.util.Optional;
-import java.util.concurrent.CountDownLatch;
 import java.util.concurrent.Executor;
 import java.util.function.Consumer;
 import java.util.function.IntConsumer;
-import java.util.function.Supplier;
 
 /**
  * The SysUi side bubbles manager which communicate with other SysUi components.
@@ -252,6 +248,13 @@
 
         mSysuiProxy = new Bubbles.SysuiProxy() {
             @Override
+            public void isNotificationShadeExpand(Consumer<Boolean> callback) {
+                sysuiMainExecutor.execute(() -> {
+                    callback.accept(mNotificationShadeWindowController.getPanelExpanded());
+                });
+            }
+
+            @Override
             public void getPendingOrActiveEntry(String key, Consumer<BubbleEntry> callback) {
                 sysuiMainExecutor.execute(() -> {
                     NotificationEntry entry =
diff --git a/packages/SystemUI/src/com/android/systemui/wmshell/WMShellBaseModule.java b/packages/SystemUI/src/com/android/systemui/wmshell/WMShellBaseModule.java
index 45b0b59..98833eb 100644
--- a/packages/SystemUI/src/com/android/systemui/wmshell/WMShellBaseModule.java
+++ b/packages/SystemUI/src/com/android/systemui/wmshell/WMShellBaseModule.java
@@ -186,14 +186,15 @@
             WindowManager windowManager,
             WindowManagerShellWrapper windowManagerShellWrapper,
             LauncherApps launcherApps,
+            TaskStackListenerImpl taskStackListener,
             UiEventLogger uiEventLogger,
             ShellTaskOrganizer organizer,
             @ShellMainThread ShellExecutor mainExecutor,
             @ShellMainThread Handler mainHandler) {
         return Optional.of(BubbleController.create(context, null /* synchronizer */,
                 floatingContentCoordinator, statusBarService, windowManager,
-                windowManagerShellWrapper, launcherApps, uiEventLogger, organizer,
-                mainExecutor, mainHandler));
+                windowManagerShellWrapper, launcherApps, taskStackListener,
+                uiEventLogger, organizer, mainExecutor, mainHandler));
     }
 
     //
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardClockSwitchControllerTest.java b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardClockSwitchControllerTest.java
index 0fcd79b..9017dd2 100644
--- a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardClockSwitchControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardClockSwitchControllerTest.java
@@ -31,8 +31,6 @@
 import android.testing.AndroidTestingRunner;
 import android.util.AttributeSet;
 import android.view.View;
-import android.view.ViewGroup;
-import android.widget.FrameLayout;
 import android.widget.RelativeLayout;
 
 import com.android.internal.colorextraction.ColorExtractor;
@@ -49,6 +47,7 @@
 import com.android.systemui.statusbar.StatusBarState;
 import com.android.systemui.statusbar.phone.NotificationIconAreaController;
 import com.android.systemui.statusbar.phone.NotificationIconContainer;
+import com.android.systemui.statusbar.policy.BatteryController;
 
 import org.junit.Before;
 import org.junit.Test;
@@ -94,6 +93,12 @@
     private FeatureFlags mFeatureFlags;
     @Mock
     private Executor mExecutor;
+    @Mock
+    private AnimatableClockView mClockView;
+    @Mock
+    private AnimatableClockView mLargeClockView;
+    @Mock
+    BatteryController mBatteryController;
 
     private KeyguardClockSwitchController mController;
 
@@ -101,9 +106,15 @@
     public void setup() {
         MockitoAnnotations.initMocks(this);
 
-        when(mView.findViewById(com.android.systemui.R.id.left_aligned_notification_icon_container))
+        when(mView.findViewById(R.id.left_aligned_notification_icon_container))
                 .thenReturn(mNotificationIcons);
         when(mView.getContext()).thenReturn(getContext());
+
+        when(mView.findViewById(R.id.animatable_clock_view)).thenReturn(mClockView);
+        when(mView.findViewById(R.id.animatable_clock_view_large)).thenReturn(mLargeClockView);
+        when(mClockView.getContext()).thenReturn(getContext());
+        when(mLargeClockView.getContext()).thenReturn(getContext());
+
         when(mFeatureFlags.isSmartspaceEnabled()).thenReturn(true);
         when(mView.isAttachedToWindow()).thenReturn(true);
         when(mResources.getString(anyInt())).thenReturn("h:mm");
@@ -119,7 +130,8 @@
                 mBroadcastDispatcher,
                 mPluginManager,
                 mFeatureFlags,
-                mExecutor);
+                mExecutor,
+                mBatteryController);
 
         when(mStatusBarStateController.getState()).thenReturn(StatusBarState.SHADE);
         when(mColorExtractor.getColors(anyInt())).thenReturn(mGradientColors);
@@ -165,33 +177,11 @@
 
         listenerArgumentCaptor.getValue().onViewDetachedFromWindow(mView);
 
-        verify(mStatusBarStateController).removeCallback(
-                any(StatusBarStateController.StateListener.class));
         verify(mColorExtractor).removeOnColorsChangedListener(
                 any(ColorExtractor.OnColorsChangedListener.class));
     }
 
     @Test
-    public void testBigClockPassesStatusBarState() {
-        ViewGroup testView = new FrameLayout(mContext);
-
-        mController.init();
-        when(mStatusBarStateController.getState()).thenReturn(StatusBarState.SHADE);
-        mController.setBigClockContainer(testView);
-        verify(mView).setBigClockContainer(testView, StatusBarState.SHADE);
-
-
-        when(mStatusBarStateController.getState()).thenReturn(StatusBarState.KEYGUARD);
-        mController.setBigClockContainer(testView);
-        verify(mView).setBigClockContainer(testView, StatusBarState.KEYGUARD);
-
-
-        when(mStatusBarStateController.getState()).thenReturn(StatusBarState.SHADE_LOCKED);
-        mController.setBigClockContainer(testView);
-        verify(mView).setBigClockContainer(testView, StatusBarState.SHADE_LOCKED);
-    }
-
-    @Test
     public void testPluginPassesStatusBarState() {
         ArgumentCaptor<ClockManager.ClockChangedListener> listenerArgumentCaptor =
                 ArgumentCaptor.forClass(ClockManager.ClockChangedListener.class);
@@ -245,8 +235,6 @@
     private void verifyAttachment(VerificationMode times) {
         verify(mClockManager, times).addOnClockChangedListener(
                 any(ClockManager.ClockChangedListener.class));
-        verify(mStatusBarStateController, times).addCallback(
-                any(StatusBarStateController.StateListener.class));
         verify(mColorExtractor, times).addOnColorsChangedListener(
                 any(ColorExtractor.OnColorsChangedListener.class));
         verify(mView, times).updateColors(mGradientColors);
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardClockSwitchTest.java b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardClockSwitchTest.java
index e793079..10ed1d7 100644
--- a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardClockSwitchTest.java
+++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardClockSwitchTest.java
@@ -21,9 +21,7 @@
 
 import static com.google.common.truth.Truth.assertThat;
 
-import static org.mockito.Mockito.doReturn;
 import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.never;
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
 
@@ -33,7 +31,6 @@
 import android.test.suitebuilder.annotation.SmallTest;
 import android.testing.AndroidTestingRunner;
 import android.testing.TestableLooper.RunWithLooper;
-import android.text.TextPaint;
 import android.util.AttributeSet;
 import android.view.LayoutInflater;
 import android.view.View;
@@ -48,8 +45,6 @@
 import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
-import org.mockito.InjectMocks;
-import org.mockito.Mock;
 import org.mockito.MockitoAnnotations;
 
 @SmallTest
@@ -59,14 +54,13 @@
 // the keyguard_clcok_switch layout is inflated.
 @RunWithLooper(setAsMainLooper = true)
 public class KeyguardClockSwitchTest extends SysuiTestCase {
-    private FrameLayout mClockContainer;
-    private FrameLayout mBigClockContainer;
+    private FrameLayout mClockFrame;
+    private FrameLayout mLargeClockFrame;
     private TextClock mBigClock;
 
-    @Mock
-    TextClock mClockView;
+    private AnimatableClockView mClockView;
+    private AnimatableClockView mLargeClockView;
     View mMockKeyguardSliceView;
-    @InjectMocks
     KeyguardClockSwitch mKeyguardClockSwitch;
 
     @Before
@@ -95,11 +89,12 @@
         });
         mKeyguardClockSwitch =
                 (KeyguardClockSwitch) layoutInflater.inflate(R.layout.keyguard_clock_switch, null);
-        mClockContainer = mKeyguardClockSwitch.findViewById(R.id.clock_view);
-        mBigClockContainer = new FrameLayout(getContext());
+        mClockFrame = mKeyguardClockSwitch.findViewById(R.id.lockscreen_clock_view);
+        mClockView = mKeyguardClockSwitch.findViewById(R.id.animatable_clock_view);
+        mLargeClockFrame = mKeyguardClockSwitch.findViewById(R.id.lockscreen_clock_view_large);
+        mLargeClockView = mKeyguardClockSwitch.findViewById(R.id.animatable_clock_view_large);
         mBigClock = new TextClock(getContext());
         MockitoAnnotations.initMocks(this);
-        when(mClockView.getPaint()).thenReturn(mock(TextPaint.class));
     }
 
     @Test
@@ -110,33 +105,28 @@
 
         mKeyguardClockSwitch.setClockPlugin(plugin, StatusBarState.KEYGUARD);
 
-        verify(mClockView).setVisibility(GONE);
-        assertThat(plugin.getView().getParent()).isEqualTo(mClockContainer);
+        assertThat(mClockView.getVisibility()).isEqualTo(GONE);
+        assertThat(plugin.getView().getParent()).isEqualTo(mClockFrame);
     }
 
     @Test
     public void onPluginConnected_showPluginBigClock() {
-        // GIVEN that the container for the big clock has visibility GONE
-        mBigClockContainer.setVisibility(GONE);
-        mKeyguardClockSwitch.setBigClockContainer(mBigClockContainer, StatusBarState.KEYGUARD);
-        // AND the plugin returns a view for the big clock
+        // GIVEN the plugin returns a view for the big clock
         ClockPlugin plugin = mock(ClockPlugin.class);
         when(plugin.getBigClockView()).thenReturn(mBigClock);
-        // AND in the keyguard state
-        mKeyguardClockSwitch.updateBigClockVisibility(StatusBarState.KEYGUARD);
         // WHEN the plugin is connected
         mKeyguardClockSwitch.setClockPlugin(plugin, StatusBarState.KEYGUARD);
         // THEN the big clock container is visible and it is the parent of the
         // big clock view.
-        assertThat(mBigClockContainer.getVisibility()).isEqualTo(View.VISIBLE);
-        assertThat(mBigClock.getParent()).isEqualTo(mBigClockContainer);
+        assertThat(mLargeClockView.getVisibility()).isEqualTo(View.GONE);
+        assertThat(mBigClock.getParent()).isEqualTo(mLargeClockFrame);
     }
 
     @Test
     public void onPluginConnected_nullView() {
         ClockPlugin plugin = mock(ClockPlugin.class);
         mKeyguardClockSwitch.setClockPlugin(plugin, StatusBarState.KEYGUARD);
-        verify(mClockView, never()).setVisibility(GONE);
+        assertThat(mClockView.getVisibility()).isEqualTo(VISIBLE);
     }
 
     @Test
@@ -150,7 +140,7 @@
         when(plugin2.getView()).thenReturn(new TextClock(getContext()));
         mKeyguardClockSwitch.setClockPlugin(plugin2, StatusBarState.KEYGUARD);
         // THEN only the view from the second plugin should be a child of KeyguardClockSwitch.
-        assertThat(plugin2.getView().getParent()).isEqualTo(mClockContainer);
+        assertThat(plugin2.getView().getParent()).isEqualTo(mClockFrame);
         assertThat(plugin1.getView().getParent()).isNull();
     }
 
@@ -170,33 +160,28 @@
         ClockPlugin plugin = mock(ClockPlugin.class);
         TextClock pluginView = new TextClock(getContext());
         when(plugin.getView()).thenReturn(pluginView);
-        mClockView.setVisibility(GONE);
 
         mKeyguardClockSwitch.setClockPlugin(plugin, StatusBarState.KEYGUARD);
-        mKeyguardClockSwitch.setClockPlugin(null, StatusBarState.KEYGUARD);
+        assertThat(mClockView.getVisibility()).isEqualTo(GONE);
 
-        verify(mClockView).setVisibility(VISIBLE);
+        mKeyguardClockSwitch.setClockPlugin(null, StatusBarState.KEYGUARD);
+        assertThat(mClockView.getVisibility()).isEqualTo(VISIBLE);
+
         assertThat(plugin.getView().getParent()).isNull();
     }
 
     @Test
     public void onPluginDisconnected_hidePluginBigClock() {
-        // GIVEN that the big clock container is visible
-        FrameLayout bigClockContainer = new FrameLayout(getContext());
-        bigClockContainer.setVisibility(VISIBLE);
-        mKeyguardClockSwitch.setBigClockContainer(bigClockContainer, StatusBarState.KEYGUARD);
-        // AND the plugin returns a view for the big clock
+        // GIVEN the plugin returns a view for the big clock
         ClockPlugin plugin = mock(ClockPlugin.class);
         TextClock pluginView = new TextClock(getContext());
         when(plugin.getBigClockView()).thenReturn(pluginView);
-        // AND in the keyguard state
-        mKeyguardClockSwitch.updateBigClockVisibility(StatusBarState.KEYGUARD);
         // WHEN the plugin is connected and then disconnected
         mKeyguardClockSwitch.setClockPlugin(plugin, StatusBarState.KEYGUARD);
         mKeyguardClockSwitch.setClockPlugin(null, StatusBarState.KEYGUARD);
         // THEN the big lock container is GONE and the big clock view doesn't have
         // a parent.
-        assertThat(bigClockContainer.getVisibility()).isEqualTo(GONE);
+        assertThat(mLargeClockView.getVisibility()).isEqualTo(VISIBLE);
         assertThat(pluginView.getParent()).isNull();
     }
 
@@ -205,7 +190,7 @@
         ClockPlugin plugin = mock(ClockPlugin.class);
         mKeyguardClockSwitch.setClockPlugin(plugin, StatusBarState.KEYGUARD);
         mKeyguardClockSwitch.setClockPlugin(null, StatusBarState.KEYGUARD);
-        verify(mClockView, never()).setVisibility(GONE);
+        assertThat(mClockView.getVisibility()).isEqualTo(VISIBLE);
     }
 
     @Test
@@ -220,7 +205,7 @@
         // WHEN the second plugin is disconnected
         mKeyguardClockSwitch.setClockPlugin(null, StatusBarState.KEYGUARD);
         // THEN the default clock should be shown.
-        verify(mClockView).setVisibility(VISIBLE);
+        assertThat(mClockView.getVisibility()).isEqualTo(VISIBLE);
         assertThat(plugin1.getView().getParent()).isNull();
         assertThat(plugin2.getView().getParent()).isNull();
     }
@@ -238,13 +223,6 @@
     }
 
     @Test
-    public void setTextColor_defaultClockSetTextColor() {
-        mKeyguardClockSwitch.setTextColor(Color.YELLOW);
-
-        verify(mClockView).setTextColor(Color.YELLOW);
-    }
-
-    @Test
     public void setTextColor_pluginClockSetTextColor() {
         ClockPlugin plugin = mock(ClockPlugin.class);
         TextClock pluginView = new TextClock(getContext());
@@ -256,16 +234,6 @@
         verify(plugin).setTextColor(Color.WHITE);
     }
 
-    @Test
-    public void setStyle_defaultClockSetStyle() {
-        TextPaint paint = mock(TextPaint.class);
-        Style style = mock(Style.class);
-        doReturn(paint).when(mClockView).getPaint();
-
-        mKeyguardClockSwitch.setStyle(style);
-
-        verify(paint).setStyle(style);
-    }
 
     @Test
     public void setStyle_pluginClockSetStyle() {
@@ -279,98 +247,4 @@
 
         verify(plugin).setStyle(style);
     }
-
-    @Test
-    public void onStateChanged_GoneInShade() {
-        // GIVEN that the big clock container is visible
-        mBigClockContainer.setVisibility(View.VISIBLE);
-        mKeyguardClockSwitch.setBigClockContainer(mBigClockContainer, StatusBarState.KEYGUARD);
-        // WHEN transitioned to SHADE state
-        mKeyguardClockSwitch.updateBigClockVisibility(StatusBarState.SHADE);
-        // THEN the container is gone.
-        assertThat(mBigClockContainer.getVisibility()).isEqualTo(View.GONE);
-    }
-
-    @Test
-    public void onStateChanged_VisibleInKeyguard() {
-        // GIVEN that the big clock container is gone
-        mBigClockContainer.setVisibility(View.GONE);
-        mKeyguardClockSwitch.setBigClockContainer(mBigClockContainer, StatusBarState.KEYGUARD);
-        // AND GIVEN that a plugin is active.
-        ClockPlugin plugin = mock(ClockPlugin.class);
-        when(plugin.getBigClockView()).thenReturn(mBigClock);
-        mKeyguardClockSwitch.setClockPlugin(plugin, StatusBarState.KEYGUARD);
-        // WHEN transitioned to KEYGUARD state
-        mKeyguardClockSwitch.updateBigClockVisibility(StatusBarState.KEYGUARD);
-        // THEN the container is visible.
-        assertThat(mBigClockContainer.getVisibility()).isEqualTo(View.VISIBLE);
-    }
-
-    @Test
-    public void setBigClockContainer_visible() {
-        // GIVEN that the big clock container is visible
-        mBigClockContainer.setVisibility(View.VISIBLE);
-        // AND GIVEN that a plugin is active.
-        ClockPlugin plugin = mock(ClockPlugin.class);
-        when(plugin.getBigClockView()).thenReturn(mBigClock);
-        mKeyguardClockSwitch.setClockPlugin(plugin, StatusBarState.KEYGUARD);
-        // AND in the keyguard state
-        mKeyguardClockSwitch.updateBigClockVisibility(StatusBarState.KEYGUARD);
-        // WHEN the container is associated with the clock switch
-        mKeyguardClockSwitch.setBigClockContainer(mBigClockContainer, StatusBarState.KEYGUARD);
-        // THEN the container remains visible.
-        assertThat(mBigClockContainer.getVisibility()).isEqualTo(View.VISIBLE);
-    }
-
-    @Test
-    public void setBigClockContainer_gone() {
-        // GIVEN that the big clock container is gone
-        mBigClockContainer.setVisibility(View.GONE);
-        // AND GIVEN that a plugin is active.
-        ClockPlugin plugin = mock(ClockPlugin.class);
-        when(plugin.getBigClockView()).thenReturn(mBigClock);
-        mKeyguardClockSwitch.setClockPlugin(plugin, StatusBarState.KEYGUARD);
-        // AND in the keyguard state
-        mKeyguardClockSwitch.updateBigClockVisibility(StatusBarState.KEYGUARD);
-        // WHEN the container is associated with the clock switch
-        mKeyguardClockSwitch.setBigClockContainer(mBigClockContainer, StatusBarState.KEYGUARD);
-        // THEN the container is made visible.
-        assertThat(mBigClockContainer.getVisibility()).isEqualTo(View.VISIBLE);
-    }
-
-    @Test
-    public void setKeyguardHidingBigClock_gone() {
-        // GIVEN that the container for the big clock has visibility GONE
-        mBigClockContainer.setVisibility(GONE);
-        mKeyguardClockSwitch.setBigClockContainer(mBigClockContainer, StatusBarState.KEYGUARD);
-        // AND the plugin returns a view for the big clock
-        ClockPlugin plugin = mock(ClockPlugin.class);
-        when(plugin.getBigClockView()).thenReturn(mBigClock);
-        // AND in the keyguard state
-        mKeyguardClockSwitch.updateBigClockVisibility(StatusBarState.KEYGUARD);
-        // WHEN the plugin is connected
-        mKeyguardClockSwitch.setClockPlugin(plugin, StatusBarState.KEYGUARD);
-        // WHEN the container set hiding clock as true
-        mKeyguardClockSwitch.setKeyguardHidingBigClock(true);
-        // THEN the container is gone.
-        assertThat(mBigClockContainer.getVisibility()).isEqualTo(View.GONE);
-    }
-
-    @Test
-    public void setKeyguardHidingBigClock_visible() {
-        // GIVEN that the container for the big clock has visibility GONE
-        mBigClockContainer.setVisibility(GONE);
-        mKeyguardClockSwitch.setBigClockContainer(mBigClockContainer, StatusBarState.KEYGUARD);
-        // AND the plugin returns a view for the big clock
-        ClockPlugin plugin = mock(ClockPlugin.class);
-        when(plugin.getBigClockView()).thenReturn(mBigClock);
-        // AND in the keyguard state
-        mKeyguardClockSwitch.updateBigClockVisibility(StatusBarState.KEYGUARD);
-        // WHEN the plugin is connected
-        mKeyguardClockSwitch.setClockPlugin(plugin, StatusBarState.KEYGUARD);
-        // WHEN the container set hiding clock as false
-        mKeyguardClockSwitch.setKeyguardHidingBigClock(false);
-        // THEN the container is made visible.
-        assertThat(mBigClockContainer.getVisibility()).isEqualTo(View.VISIBLE);
-    }
 }
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardStatusViewControllerTest.java b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardStatusViewControllerTest.java
index 0074dbe..49f1655 100644
--- a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardStatusViewControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardStatusViewControllerTest.java
@@ -23,7 +23,6 @@
 
 import com.android.systemui.SysuiTestCase;
 import com.android.systemui.statusbar.phone.DozeParameters;
-import com.android.systemui.statusbar.phone.NotificationIconAreaController;
 import com.android.systemui.statusbar.policy.ConfigurationController;
 import com.android.systemui.statusbar.policy.KeyguardStateController;
 
@@ -50,8 +49,6 @@
     @Mock
     ConfigurationController mConfigurationController;
     @Mock
-    NotificationIconAreaController mNotificationIconAreaController;
-    @Mock
     DozeParameters mDozeParameters;
 
     private KeyguardStatusViewController mController;
@@ -67,7 +64,6 @@
                 mKeyguardStateController,
                 mKeyguardUpdateMonitor,
                 mConfigurationController,
-                mNotificationIconAreaController,
                 mDozeParameters);
     }
 
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/TextAnimatorTest.kt b/packages/SystemUI/tests/src/com/android/keyguard/TextAnimatorTest.kt
index 7b4f14d..ad7f0cb 100644
--- a/packages/SystemUI/tests/src/com/android/keyguard/TextAnimatorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/keyguard/TextAnimatorTest.kt
@@ -16,6 +16,7 @@
 
 package com.android.keyguard
 
+import android.animation.AnimatorListenerAdapter
 import android.animation.ValueAnimator
 import android.testing.AndroidTestingRunner
 import android.text.Layout
@@ -25,7 +26,9 @@
 import com.android.systemui.SysuiTestCase
 import org.junit.Test
 import org.junit.runner.RunWith
+import org.mockito.ArgumentCaptor
 import org.mockito.Mockito.`when`
+import org.mockito.Mockito.eq
 import org.mockito.Mockito.inOrder
 import org.mockito.Mockito.mock
 import org.mockito.Mockito.never
@@ -107,4 +110,34 @@
         // Then, animation start should not be called.
         verify(valueAnimator, never()).start()
     }
+
+    @Test
+    fun testAnimationEnded() {
+        val layout = makeLayout("Hello, World", PAINT)
+        val valueAnimator = mock(ValueAnimator::class.java)
+        val textInterpolator = mock(TextInterpolator::class.java)
+        val paint = mock(TextPaint::class.java)
+        `when`(textInterpolator.targetPaint).thenReturn(paint)
+        val animationEndCallback = mock(Runnable::class.java)
+
+        val textAnimator = TextAnimator(layout, {}).apply {
+            this.textInterpolator = textInterpolator
+            this.animator = valueAnimator
+        }
+
+        textAnimator.setTextStyle(
+                weight = 400,
+                animate = true,
+                onAnimationEnd = animationEndCallback
+        )
+
+        // Verify animationEnd callback has been added.
+        val captor = ArgumentCaptor.forClass(AnimatorListenerAdapter::class.java)
+        verify(valueAnimator).addListener(captor.capture())
+        captor.value.onAnimationEnd(valueAnimator)
+
+        // Verify animationEnd callback has been invoked and removed.
+        verify(animationEndCallback).run()
+        verify(valueAnimator).removeListener(eq(captor.value))
+    }
 }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/privacy/PrivacyDialogTest.kt b/packages/SystemUI/tests/src/com/android/systemui/privacy/PrivacyDialogTest.kt
index 28b44d9..1baaf6b 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/privacy/PrivacyDialogTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/privacy/PrivacyDialogTest.kt
@@ -234,6 +234,27 @@
     }
 
     @Test
+    fun testPhoneCallNotClickable() {
+        val element = PrivacyDialog.PrivacyElement(
+                PrivacyType.TYPE_MICROPHONE,
+                TEST_PACKAGE_NAME,
+                TEST_USER_ID,
+                "App",
+                null,
+                0L,
+                false,
+                false,
+                true
+        )
+
+        val list = listOf(element)
+        dialog = PrivacyDialog(context, list, starter)
+        dialog.show()
+        assertThat(dialog.requireViewById<View>(R.id.privacy_item).isClickable).isFalse()
+        assertThat(dialog.requireViewById<View>(R.id.chevron).visibility).isEqualTo(View.GONE)
+    }
+
+    @Test
     fun testAttribution() {
         val element = PrivacyDialog.PrivacyElement(
                 PrivacyType.TYPE_MICROPHONE,
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/QSSecurityFooterTest.java b/packages/SystemUI/tests/src/com/android/systemui/qs/QSSecurityFooterTest.java
index e4b95af..4ee639b 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/QSSecurityFooterTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/QSSecurityFooterTest.java
@@ -102,7 +102,7 @@
         mRootView = (ViewGroup) new LayoutInflaterBuilder(mContext)
                 .replace("ImageView", TestableImageView.class)
                 .build().inflate(R.layout.quick_settings_footer, null, false);
-        mFooter = new QSSecurityFooter(mRootView, mContext, mUserTracker, new Handler(looper),
+        mFooter = new QSSecurityFooter(mRootView, mUserTracker, new Handler(looper),
                 mActivityStarter, mSecurityController, looper);
         mFooterText = mRootView.findViewById(R.id.footer_text);
         mFooterIcon = mRootView.findViewById(R.id.footer_icon);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationIconAreaControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationIconAreaControllerTest.java
index 858227f..5f8eb9e 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationIconAreaControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationIconAreaControllerTest.java
@@ -25,7 +25,6 @@
 
 import androidx.test.filters.SmallTest;
 
-import com.android.keyguard.KeyguardUpdateMonitor;
 import com.android.systemui.SysuiTestCase;
 import com.android.systemui.demomode.DemoModeController;
 import com.android.systemui.plugins.DarkIconDispatcher;
@@ -107,9 +106,7 @@
 
     @Test
     public void testAppearResetsTranslation() {
-        mController.setupAodIcons(
-                mAodIcons,
-                KeyguardUpdateMonitor.LOCK_SCREEN_MODE_NORMAL);
+        mController.setupAodIcons(mAodIcons);
         when(mDozeParameters.shouldControlScreenOff()).thenReturn(false);
         mController.appearAodIcons();
         verify(mAodIcons).setTranslationY(0);
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 123e4ef..8633eb4 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
@@ -70,6 +70,7 @@
 import java.util.Arrays;
 import java.util.Collections;
 import java.util.HashSet;
+import java.util.Map;
 
 @RunWith(AndroidTestingRunner.class)
 @TestableLooper.RunWithLooper
@@ -245,13 +246,14 @@
         mScrimController.transitionTo(ScrimState.KEYGUARD);
         finishAnimationsImmediately();
 
-        assertScrimAlpha(TRANSPARENT /* front */,
-                SEMI_TRANSPARENT /* back */,
-                TRANSPARENT /* bubble */);
+        assertScrimAlpha(Map.of(
+                mScrimInFront, TRANSPARENT,
+                mScrimBehind, SEMI_TRANSPARENT));
 
-        assertScrimTint(true /* front */,
-                true /* behind */,
-                false /* bubble */);
+        assertScrimTinted(Map.of(
+                mScrimInFront, true,
+                mScrimBehind, true,
+                mScrimForBubble, false));
     }
 
     @Test
@@ -259,13 +261,15 @@
         mScrimController.transitionTo(ScrimState.SHADE_LOCKED);
         finishAnimationsImmediately();
 
-        assertScrimAlpha(TRANSPARENT /* front */,
-                OPAQUE /* back */,
-                TRANSPARENT /* bubble */);
+        assertScrimAlpha(Map.of(
+                mScrimInFront, TRANSPARENT,
+                mScrimBehind, OPAQUE));
 
-        assertScrimTint(false /* front */,
-                true /* behind */,
-                false /* bubble */);
+        assertScrimTinted(Map.of(
+                mScrimInFront, false,
+                mScrimBehind, true,
+                mScrimForBubble, false
+        ));
     }
 
     @Test
@@ -273,13 +277,15 @@
         mScrimController.transitionTo(ScrimState.OFF);
         finishAnimationsImmediately();
 
-        assertScrimAlpha(OPAQUE /* front */,
-                OPAQUE /* back */,
-                TRANSPARENT /* bubble */);
+        assertScrimAlpha(Map.of(
+                mScrimInFront, OPAQUE,
+                mScrimBehind, OPAQUE));
 
-        assertScrimTint(true /* front */,
-                true /* behind */,
-                false /* bubble */);
+        assertScrimTinted(Map.of(
+                mScrimInFront, true,
+                mScrimBehind, true,
+                mScrimForBubble, false
+        ));
     }
 
     @Test
@@ -287,13 +293,16 @@
         mScrimController.transitionTo(ScrimState.AOD);
         finishAnimationsImmediately();
 
-        assertScrimAlpha(TRANSPARENT /* front */,
-                OPAQUE /* back */,
-                TRANSPARENT /* bubble */);
+        assertScrimAlpha(Map.of(
+                mScrimInFront, TRANSPARENT,
+                mScrimBehind, OPAQUE,
+                mNotificationsScrim, TRANSPARENT));
 
-        assertScrimTint(true /* front */,
-                true /* behind */,
-                false /* bubble */);
+        assertScrimTinted(Map.of(
+                mScrimInFront, true,
+                mScrimBehind, true,
+                mScrimForBubble, false
+        ));
     }
 
     @Test
@@ -302,17 +311,17 @@
         mScrimController.transitionTo(ScrimState.AOD);
         finishAnimationsImmediately();
 
-        assertScrimAlpha(TRANSPARENT /* front */,
-                TRANSPARENT /* back */,
-                TRANSPARENT /* bubble */);
+        assertScrimAlpha(Map.of(
+                mScrimInFront, TRANSPARENT,
+                mScrimBehind, TRANSPARENT));
 
         // Pulsing notification should conserve AOD wallpaper.
         mScrimController.transitionTo(ScrimState.PULSING);
         finishAnimationsImmediately();
 
-        assertScrimAlpha(TRANSPARENT /* front */,
-                TRANSPARENT /* back */,
-                TRANSPARENT /* bubble */);
+        assertScrimAlpha(Map.of(
+                mScrimInFront, TRANSPARENT,
+                mScrimBehind, TRANSPARENT));
     }
 
     @Test
@@ -322,13 +331,15 @@
         mScrimController.transitionTo(ScrimState.AOD);
         finishAnimationsImmediately();
 
-        assertScrimAlpha(TRANSPARENT /* front */,
-                OPAQUE /* back */,
-                TRANSPARENT /* bubble */);
+        assertScrimAlpha(Map.of(
+                mScrimInFront, TRANSPARENT,
+                mScrimBehind, OPAQUE));
 
-        assertScrimTint(true /* front */,
-                true /* behind */,
-                false /* bubble */);
+        assertScrimTinted(Map.of(
+                mScrimInFront, true,
+                mScrimBehind, true,
+                mScrimForBubble, false
+        ));
     }
 
     @Test
@@ -339,13 +350,15 @@
         mScrimController.setHasBackdrop(true);
         finishAnimationsImmediately();
 
-        assertScrimAlpha(TRANSPARENT /* front */,
-                OPAQUE /* back */,
-                TRANSPARENT /* bubble */);
+        assertScrimAlpha(Map.of(
+                mScrimInFront, TRANSPARENT,
+                mScrimBehind, OPAQUE));
 
-        assertScrimTint(true /* front */,
-                true /* behind */,
-                false /* bubble */);
+        assertScrimTinted(Map.of(
+                mScrimInFront, true,
+                mScrimBehind, true,
+                mScrimForBubble, false
+        ));
     }
 
     @Test
@@ -355,31 +368,31 @@
         mScrimController.setAodFrontScrimAlpha(0.5f);
         finishAnimationsImmediately();
 
-        assertScrimAlpha(TRANSPARENT /* front */,
-                SEMI_TRANSPARENT /* back */,
-                TRANSPARENT /* bubble */);
+        assertScrimAlpha(Map.of(
+                mScrimInFront, TRANSPARENT,
+                mScrimBehind, SEMI_TRANSPARENT));
 
         // ... but that it does take effect once we enter the AOD state.
         mScrimController.transitionTo(ScrimState.AOD);
         finishAnimationsImmediately();
-        assertScrimAlpha(SEMI_TRANSPARENT /* front */,
-                OPAQUE /* back */,
-                TRANSPARENT /* bubble */);
+        assertScrimAlpha(Map.of(
+                mScrimInFront, SEMI_TRANSPARENT,
+                mScrimBehind, OPAQUE));
 
         // ... and that if we set it while we're in AOD, it does take immediate effect.
         mScrimController.setAodFrontScrimAlpha(1f);
-        assertScrimAlpha(OPAQUE /* front */,
-                OPAQUE /* back */,
-                TRANSPARENT /* bubble */);
+        assertScrimAlpha(Map.of(
+                mScrimInFront, OPAQUE,
+                mScrimBehind, OPAQUE));
 
         // ... and make sure we recall the previous front scrim alpha even if we transition away
         // for a bit.
         mScrimController.transitionTo(ScrimState.UNLOCKED);
         mScrimController.transitionTo(ScrimState.AOD);
         finishAnimationsImmediately();
-        assertScrimAlpha(OPAQUE /* front */,
-                OPAQUE /* back */,
-                TRANSPARENT /* bubble */);
+        assertScrimAlpha(Map.of(
+                mScrimInFront, OPAQUE,
+                mScrimBehind, OPAQUE));
 
         // ... and alpha updates should be completely ignored if always_on is off.
         // Passing it forward would mess up the wake-up transition.
@@ -402,17 +415,17 @@
         mScrimController.setAodFrontScrimAlpha(0.5f);
         finishAnimationsImmediately();
 
-        assertScrimAlpha(TRANSPARENT /* front */,
-                SEMI_TRANSPARENT /* back */,
-                TRANSPARENT /* bubble */);
+        assertScrimAlpha(Map.of(
+                mScrimInFront, TRANSPARENT,
+                mScrimBehind, SEMI_TRANSPARENT));
 
         // ... and doesn't take effect when disabled always_on
         mAlwaysOnEnabled = false;
         mScrimController.transitionTo(ScrimState.AOD);
         finishAnimationsImmediately();
-        assertScrimAlpha(OPAQUE /* front */,
-                OPAQUE /* back */,
-                TRANSPARENT /* bubble */);
+        assertScrimAlpha(Map.of(
+                mScrimInFront, OPAQUE,
+                mScrimBehind, OPAQUE));
 
         // ... but will take effect after docked
         when(mDockManager.isDocked()).thenReturn(true);
@@ -420,15 +433,15 @@
         mScrimController.setAodFrontScrimAlpha(0.5f);
         mScrimController.transitionTo(ScrimState.AOD);
 
-        assertScrimAlpha(SEMI_TRANSPARENT /* front */,
-                OPAQUE /* back */,
-                TRANSPARENT /* bubble */);
+        assertScrimAlpha(Map.of(
+                mScrimInFront, SEMI_TRANSPARENT,
+                mScrimBehind, OPAQUE));
 
         // ... and that if we set it while we're in AOD, it does take immediate effect after docked.
         mScrimController.setAodFrontScrimAlpha(1f);
-        assertScrimAlpha(OPAQUE /* front */,
-                OPAQUE /* back */,
-                TRANSPARENT /* bubble */);
+        assertScrimAlpha(Map.of(
+                mScrimInFront, OPAQUE,
+                mScrimBehind, OPAQUE));
 
         // Reset value since enums are static.
         mScrimController.setAodFrontScrimAlpha(0f);
@@ -442,36 +455,38 @@
         mScrimController.setWallpaperSupportsAmbientMode(false);
         mScrimController.transitionTo(ScrimState.AOD);
         finishAnimationsImmediately();
-        assertScrimAlpha(TRANSPARENT /* front */,
-                OPAQUE /* back */,
-                TRANSPARENT /* bubble */);
+        assertScrimAlpha(Map.of(
+                mScrimInFront, TRANSPARENT,
+                mScrimBehind, OPAQUE));
 
         mScrimController.transitionTo(ScrimState.PULSING);
         finishAnimationsImmediately();
         // 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
-        assertScrimAlpha(TRANSPARENT /* front */,
-                OPAQUE /* back */,
-                TRANSPARENT /* bubble */);
+        assertScrimAlpha(Map.of(
+                mScrimInFront, TRANSPARENT,
+                mScrimBehind, OPAQUE));
 
-        assertScrimTint(true /* front */,
-                true /* behind */,
-                false /* bubble */);
+        assertScrimTinted(Map.of(
+                mScrimInFront, true,
+                mScrimBehind, true,
+                mScrimForBubble, false
+        ));
 
         // ... and when ambient goes dark, front scrim should be semi-transparent
         mScrimController.setAodFrontScrimAlpha(0.5f);
         finishAnimationsImmediately();
         // Front scrim should be semi-transparent
-        assertScrimAlpha(SEMI_TRANSPARENT /* front */,
-                OPAQUE /* back */,
-                TRANSPARENT /* bubble */);
+        assertScrimAlpha(Map.of(
+                mScrimInFront, SEMI_TRANSPARENT,
+                mScrimBehind, OPAQUE));
 
         mScrimController.setWakeLockScreenSensorActive(true);
         finishAnimationsImmediately();
-        assertScrimAlpha(SEMI_TRANSPARENT /* front */,
-                SEMI_TRANSPARENT /* back */,
-                TRANSPARENT /* bubble */);
+        assertScrimAlpha(Map.of(
+                mScrimInFront, SEMI_TRANSPARENT,
+                mScrimBehind, SEMI_TRANSPARENT));
 
         // Reset value since enums are static.
         mScrimController.setAodFrontScrimAlpha(0f);
@@ -483,27 +498,29 @@
         finishAnimationsImmediately();
         // Front scrim should be transparent
         // Back scrim should be visible without tint
-        assertScrimAlpha(TRANSPARENT /* front */,
-                OPAQUE /* back */,
-                TRANSPARENT /* bubble */);
+        assertScrimAlpha(Map.of(
+                mScrimInFront, TRANSPARENT,
+                mScrimBehind, OPAQUE));
 
-        assertScrimTint(false /* front */,
-                false /* behind */,
-                false /* bubble */);
+        assertScrimTinted(Map.of(
+                mScrimInFront, false,
+                mScrimBehind, false,
+                mScrimForBubble, false
+        ));
     }
 
     @Test
     public void transitionToBouncer() {
         mScrimController.transitionTo(ScrimState.BOUNCER_SCRIMMED);
         finishAnimationsImmediately();
-        // Front scrim should be transparent
-        // Back scrim should be visible without tint
-        assertScrimAlpha(OPAQUE /* front */,
-                TRANSPARENT /* back */,
-                TRANSPARENT /* bubble */);
-        assertScrimTint(false /* front */,
-                false /* behind */,
-                false /* bubble */);
+        assertScrimAlpha(Map.of(
+                mScrimInFront, OPAQUE,
+                mScrimBehind, TRANSPARENT));
+        assertScrimTinted(Map.of(
+                mScrimInFront, false,
+                mScrimBehind, false,
+                mScrimForBubble, false
+        ));
     }
 
     @Test
@@ -511,19 +528,21 @@
         mScrimController.setPanelExpansion(0f);
         mScrimController.transitionTo(ScrimState.UNLOCKED);
         finishAnimationsImmediately();
-        assertScrimAlpha(TRANSPARENT /* front */,
-                TRANSPARENT /* back */,
-                TRANSPARENT /* bubble */);
+        assertScrimAlpha(Map.of(
+                mScrimInFront, TRANSPARENT,
+                mScrimBehind, TRANSPARENT));
 
-        assertScrimTint(false /* front */,
-                true /* behind */,
-                false /* bubble */);
+        assertScrimTinted(Map.of(
+                mScrimInFront, false,
+                mScrimBehind, true,
+                mScrimForBubble, false
+        ));
 
         // Back scrim should be visible after start dragging
         mScrimController.setPanelExpansion(0.5f);
-        assertScrimAlpha(TRANSPARENT /* front */,
-                SEMI_TRANSPARENT /* back */,
-                TRANSPARENT /* bubble */);
+        assertScrimAlpha(Map.of(
+                mScrimInFront, TRANSPARENT,
+                mScrimBehind, SEMI_TRANSPARENT));
     }
 
     @Test
@@ -531,9 +550,11 @@
         mScrimController.transitionTo(ScrimState.BUBBLE_EXPANDED);
         finishAnimationsImmediately();
 
-        assertScrimTint(false /* front */,
-                false /* behind */,
-                false /* bubble */);
+        assertScrimTinted(Map.of(
+                mScrimInFront, false,
+                mScrimBehind, false,
+                mScrimForBubble, false
+        ));
 
         // Front scrim should be transparent
         Assert.assertEquals(ScrimController.TRANSPARENT,
@@ -589,7 +610,10 @@
         mScrimController.setQsPosition(1f, 999 /* value doesn't matter */);
         finishAnimationsImmediately();
 
-        assertScrimAlpha(TRANSPARENT, OPAQUE, TRANSPARENT);
+        assertScrimAlpha(Map.of(
+                mScrimInFront, TRANSPARENT,
+                mScrimBehind, OPAQUE,
+                mNotificationsScrim, OPAQUE));
     }
 
     @Test
@@ -623,21 +647,26 @@
         mScrimController.transitionTo(ScrimState.UNLOCKED);
 
         // Immediately tinted black after the transition starts
-        assertScrimTint(true /* front */,
-                true /* behind */,
-                true  /* bubble */);
+        assertScrimTinted(Map.of(
+                mScrimInFront, true,
+                mScrimBehind, true,
+                mScrimForBubble, true
+        ));
 
         finishAnimationsImmediately();
 
         // All scrims should be transparent at the end of fade transition.
-        assertScrimAlpha(TRANSPARENT /* front */,
-                TRANSPARENT /* behind */,
-                TRANSPARENT /* bubble */);
+        assertScrimAlpha(Map.of(
+                mScrimInFront, TRANSPARENT,
+                mScrimBehind, TRANSPARENT,
+                mScrimForBubble, TRANSPARENT));
 
         // Make sure at the very end of the animation, we're reset to transparent
-        assertScrimTint(false /* front */,
-                true /* behind */,
-                false  /* bubble */);
+        assertScrimTinted(Map.of(
+                mScrimInFront, false,
+                mScrimBehind, true,
+                mScrimForBubble, false
+        ));
     }
 
     @Test
@@ -652,9 +681,11 @@
                         // Front scrim should be black in the middle of the transition
                         Assert.assertTrue("Scrim should be visible during transition. Alpha: "
                                 + mScrimInFront.getViewAlpha(), mScrimInFront.getViewAlpha() > 0);
-                        assertScrimTint(true /* front */,
-                                true /* behind */,
-                                true /* bubble */);
+                        assertScrimTinted(Map.of(
+                                mScrimInFront, true,
+                                mScrimBehind, true,
+                                mScrimForBubble, true
+                        ));
                         Assert.assertSame("Scrim should be visible during transition.",
                                 mScrimVisibility, OPAQUE);
                     }
@@ -843,15 +874,15 @@
         mScrimController.setKeyguardOccluded(true);
         mScrimController.transitionTo(ScrimState.AOD);
         finishAnimationsImmediately();
-        assertScrimAlpha(TRANSPARENT /* front */,
-                OPAQUE /* behind */,
-                TRANSPARENT /* bubble */);
+        assertScrimAlpha(Map.of(
+                mScrimInFront, TRANSPARENT,
+                mScrimBehind, OPAQUE));
 
         mScrimController.transitionTo(ScrimState.PULSING);
         finishAnimationsImmediately();
-        assertScrimAlpha(TRANSPARENT /* front */,
-                OPAQUE /* behind */,
-                TRANSPARENT /* bubble */);
+        assertScrimAlpha(Map.of(
+                mScrimInFront, TRANSPARENT,
+                mScrimBehind, OPAQUE));
     }
 
     @Test
@@ -859,15 +890,15 @@
         mScrimController.setWallpaperSupportsAmbientMode(true);
         mScrimController.transitionTo(ScrimState.AOD);
         finishAnimationsImmediately();
-        assertScrimAlpha(TRANSPARENT /* front */,
-                TRANSPARENT /* behind */,
-                TRANSPARENT /* bubble */);
+        assertScrimAlpha(Map.of(
+                mScrimInFront, TRANSPARENT,
+                mScrimBehind, TRANSPARENT));
 
         mScrimController.setKeyguardOccluded(true);
         finishAnimationsImmediately();
-        assertScrimAlpha(TRANSPARENT /* front */,
-                OPAQUE /* behind */,
-                TRANSPARENT /* bubble */);
+        assertScrimAlpha(Map.of(
+                mScrimInFront, TRANSPARENT,
+                mScrimBehind, OPAQUE));
     }
 
     @Test
@@ -926,21 +957,67 @@
         }
     }
 
-    private void assertScrimTint(boolean front, boolean behind, boolean bubble) {
-        Assert.assertEquals("Tint test failed at state " + mScrimController.getState()
-                        + " with scrim: " + getScrimName(mScrimInFront) + " and tint: "
-                        + Integer.toHexString(mScrimInFront.getTint()),
-                front, mScrimInFront.getTint() != Color.TRANSPARENT);
+    @Test
+    public void testScrimsOpaque_whenShadeFullyExpanded() {
+        mScrimController.transitionTo(ScrimState.UNLOCKED);
+        mScrimController.setPanelExpansion(1);
+        // notifications scrim alpha change require calling setQsPosition
+        mScrimController.setQsPosition(0, 300);
+        finishAnimationsImmediately();
 
-        Assert.assertEquals("Tint test failed at state " + mScrimController.getState()
-                        + " with scrim: " + getScrimName(mScrimBehind) + " and tint: "
-                        + Integer.toHexString(mScrimBehind.getTint()),
-                behind, mScrimBehind.getTint() != Color.TRANSPARENT);
+        Assert.assertEquals("Behind scrim should be opaque",
+                mScrimBehind.getViewAlpha(), 1, 0.0);
+        Assert.assertEquals("Notifications scrim should be opaque",
+                mNotificationsScrim.getViewAlpha(), 1, 0.0);
+    }
 
-        Assert.assertEquals("Tint test failed at state " + mScrimController.getState()
-                        + " with scrim: " + getScrimName(mScrimForBubble) + " and tint: "
-                        + Integer.toHexString(mScrimForBubble.getTint()),
-                bubble, mScrimForBubble.getTint() != Color.TRANSPARENT);
+    @Test
+    public void testScrimsVisible_whenShadeVisible() {
+        mScrimController.transitionTo(ScrimState.UNLOCKED);
+        mScrimController.setPanelExpansion(0.5f);
+        // notifications scrim alpha change require calling setQsPosition
+        mScrimController.setQsPosition(0, 300);
+
+        assertScrimAlpha(Map.of(
+                mScrimBehind, SEMI_TRANSPARENT,
+                mNotificationsScrim, SEMI_TRANSPARENT,
+                mScrimInFront, TRANSPARENT));
+    }
+
+    @Test
+    public void testScrimsVisible_whenShadeVisibleOnLockscreen() {
+        mScrimController.transitionTo(ScrimState.KEYGUARD);
+        mScrimController.setQsPosition(0.5f, 300);
+
+        assertScrimAlpha(Map.of(
+                mScrimBehind, SEMI_TRANSPARENT,
+                mNotificationsScrim, SEMI_TRANSPARENT,
+                mScrimInFront, TRANSPARENT));
+    }
+
+    @Test
+    public void testNotificationScrimTransparent_whenOnLockscreen() {
+        mScrimController.transitionTo(ScrimState.KEYGUARD);
+        // even if shade is not pulled down, panel has expansion of 1 on the lockscreen
+        mScrimController.setPanelExpansion(1);
+        mScrimController.setQsPosition(0f, /*qs panel bottom*/ 0);
+
+        assertScrimAlpha(Map.of(
+                mScrimBehind, SEMI_TRANSPARENT,
+                mNotificationsScrim, TRANSPARENT));
+    }
+
+    private void assertScrimTinted(Map<ScrimView, Boolean> scrimToTint) {
+        // notifications scrim should have always transparent tint
+        assertScrimTint(mNotificationsScrim, false);
+        scrimToTint.forEach((scrim, hasTint) -> assertScrimTint(scrim, hasTint));
+    }
+
+    private void assertScrimTint(ScrimView scrim, boolean hasTint) {
+        String message = "Tint test failed at state " + mScrimController.getState()
+                + " with scrim: " + getScrimName(scrim) + " and tint: "
+                + Integer.toHexString(scrim.getTint());
+        Assert.assertEquals(message, hasTint, scrim.getTint() != Color.TRANSPARENT);
     }
 
     private String getScrimName(ScrimView scrim) {
@@ -956,29 +1033,25 @@
         return "unknown_scrim";
     }
 
-    private void assertScrimAlpha(int front, int behind, int bubble) {
+    /**
+     * If {@link #mScrimForBubble} or {@link #mNotificationsScrim} is not passed in the map
+     * we assume it must be transparent
+     */
+    private void assertScrimAlpha(Map<ScrimView, Integer> scrimToAlpha) {
         // Check single scrim visibility.
-        Assert.assertEquals("Unexpected front scrim alpha: "
-                        + mScrimInFront.getViewAlpha(),
-                front != TRANSPARENT /* expected */,
-                mScrimInFront.getViewAlpha() > TRANSPARENT /* actual */);
-
-        Assert.assertEquals("Unexpected back scrim alpha: "
-                        + mScrimBehind.getViewAlpha(),
-                behind != TRANSPARENT /* expected */,
-                mScrimBehind.getViewAlpha() > TRANSPARENT /* actual */);
-
-        Assert.assertEquals(
-                "Unexpected bubble scrim alpha: "
-                        + mScrimForBubble.getViewAlpha(), /* message */
-                bubble != TRANSPARENT /* expected */,
-                mScrimForBubble.getViewAlpha() > TRANSPARENT /* actual */);
+        if (!scrimToAlpha.containsKey(mScrimForBubble)) {
+            assertScrimAlpha(mScrimForBubble, TRANSPARENT);
+        }
+        if (!scrimToAlpha.containsKey(mNotificationsScrim)) {
+            assertScrimAlpha(mNotificationsScrim, TRANSPARENT);
+        }
+        scrimToAlpha.forEach((scrimView, alpha) -> assertScrimAlpha(scrimView, alpha));
 
         // Check combined scrim visibility.
         final int visibility;
-        if (front == OPAQUE || behind == OPAQUE || bubble == OPAQUE) {
+        if (scrimToAlpha.values().contains(OPAQUE)) {
             visibility = OPAQUE;
-        } else if (front > TRANSPARENT || behind > TRANSPARENT || bubble > TRANSPARENT) {
+        } else if (scrimToAlpha.values().contains(SEMI_TRANSPARENT)) {
             visibility = SEMI_TRANSPARENT;
         } else {
             visibility = TRANSPARENT;
@@ -987,4 +1060,11 @@
                 visibility /* expected */,
                 mScrimVisibility);
     }
+
+    private void assertScrimAlpha(ScrimView scrim, int expectedAlpha) {
+        Assert.assertEquals("Unexpected " + getScrimName(scrim) + " scrim alpha: "
+                        + scrim.getViewAlpha(),
+                expectedAlpha != TRANSPARENT /* expected */,
+                scrim.getViewAlpha() > TRANSPARENT /* actual */);
+    }
 }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/wmshell/BubblesTest.java b/packages/SystemUI/tests/src/com/android/systemui/wmshell/BubblesTest.java
index 9b9937b..abc8da2 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/wmshell/BubblesTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/wmshell/BubblesTest.java
@@ -101,6 +101,7 @@
 import com.android.wm.shell.bubbles.Bubbles;
 import com.android.wm.shell.common.FloatingContentCoordinator;
 import com.android.wm.shell.common.ShellExecutor;
+import com.android.wm.shell.common.TaskStackListenerImpl;
 
 import com.google.common.collect.ImmutableList;
 
@@ -206,6 +207,8 @@
     @Mock
     private BubbleLogger mBubbleLogger;
     @Mock
+    private TaskStackListenerImpl mTaskStackListener;
+    @Mock
     private ShellTaskOrganizer mShellTaskOrganizer;
 
     private TestableBubblePositioner mPositioner;
@@ -287,6 +290,7 @@
                 mWindowManagerShellWrapper,
                 mLauncherApps,
                 mBubbleLogger,
+                mTaskStackListener,
                 mShellTaskOrganizer,
                 mPositioner,
                 syncExecutor,
diff --git a/packages/SystemUI/tests/src/com/android/systemui/wmshell/NewNotifPipelineBubblesTest.java b/packages/SystemUI/tests/src/com/android/systemui/wmshell/NewNotifPipelineBubblesTest.java
index b0ec628..1ba7f8a 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/wmshell/NewNotifPipelineBubblesTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/wmshell/NewNotifPipelineBubblesTest.java
@@ -94,6 +94,7 @@
 import com.android.wm.shell.bubbles.Bubbles;
 import com.android.wm.shell.common.FloatingContentCoordinator;
 import com.android.wm.shell.common.ShellExecutor;
+import com.android.wm.shell.common.TaskStackListenerImpl;
 
 import org.junit.Before;
 import org.junit.Ignore;
@@ -187,6 +188,8 @@
     @Mock
     private BubbleLogger mBubbleLogger;
     @Mock
+    private TaskStackListenerImpl mTaskStackListener;
+    @Mock
     private ShellTaskOrganizer mShellTaskOrganizer;
 
     private TestableBubblePositioner mPositioner;
@@ -253,6 +256,7 @@
                 mWindowManagerShellWrapper,
                 mLauncherApps,
                 mBubbleLogger,
+                mTaskStackListener,
                 mShellTaskOrganizer,
                 mPositioner,
                 syncExecutor,
diff --git a/packages/SystemUI/tests/src/com/android/systemui/wmshell/TestableBubbleController.java b/packages/SystemUI/tests/src/com/android/systemui/wmshell/TestableBubbleController.java
index a1adb2c..a9a558d 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/wmshell/TestableBubbleController.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/wmshell/TestableBubbleController.java
@@ -31,6 +31,7 @@
 import com.android.wm.shell.bubbles.BubblePositioner;
 import com.android.wm.shell.common.FloatingContentCoordinator;
 import com.android.wm.shell.common.ShellExecutor;
+import com.android.wm.shell.common.TaskStackListenerImpl;
 
 /**
  * Testable BubbleController subclass that immediately synchronizes surfaces.
@@ -47,13 +48,15 @@
             WindowManagerShellWrapper windowManagerShellWrapper,
             LauncherApps launcherApps,
             BubbleLogger bubbleLogger,
+            TaskStackListenerImpl taskStackListener,
             ShellTaskOrganizer shellTaskOrganizer,
             BubblePositioner positioner,
             ShellExecutor shellMainExecutor,
             Handler shellMainHandler) {
         super(context, data, Runnable::run, floatingContentCoordinator, dataRepository,
                 statusBarService, windowManager, windowManagerShellWrapper, launcherApps,
-                bubbleLogger, shellTaskOrganizer, positioner, shellMainExecutor, shellMainHandler);
+                bubbleLogger, taskStackListener, shellTaskOrganizer, positioner, shellMainExecutor,
+                shellMainHandler);
         setInflateSynchronously(true);
         initialize();
     }
diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java
index 09687d3..8246ca3 100644
--- a/services/core/java/com/android/server/ConnectivityService.java
+++ b/services/core/java/com/android/server/ConnectivityService.java
@@ -2279,7 +2279,9 @@
                 netId = nai.network.getNetId();
             }
             boolean ok = addLegacyRouteToHost(lp, addr, netId, uid);
-            if (DBG) log("requestRouteToHostAddress ok=" + ok);
+            if (DBG) {
+                log("requestRouteToHostAddress " + addr + nai.toShortString() + " ok=" + ok);
+            }
             return ok;
         } finally {
             Binder.restoreCallingIdentity(token);
@@ -4229,7 +4231,7 @@
             // network, we should respect the user's option and don't need to popup the
             // PARTIAL_CONNECTIVITY notification to user again.
             nai.networkAgentConfig.acceptPartialConnectivity = accept;
-            nai.updateScoreForNetworkAgentConfigUpdate();
+            nai.updateScoreForNetworkAgentUpdate();
             rematchAllNetworksAndRequests();
         }
 
@@ -4297,6 +4299,7 @@
         }
         if (!nai.avoidUnvalidated) {
             nai.avoidUnvalidated = true;
+            nai.updateScoreForNetworkAgentUpdate();
             rematchAllNetworksAndRequests();
         }
     }
@@ -4404,7 +4407,7 @@
 
     private void updateAvoidBadWifi() {
         for (final NetworkAgentInfo nai : mNetworkAgentInfos) {
-            nai.updateScoreForNetworkAgentConfigUpdate();
+            nai.updateScoreForNetworkAgentUpdate();
         }
         rematchAllNetworksAndRequests();
     }
@@ -7170,6 +7173,7 @@
         final NetworkCapabilities prevNc = nai.getAndSetNetworkCapabilities(newNc);
 
         updateUids(nai, prevNc, newNc);
+        nai.updateScoreForNetworkAgentUpdate();
 
         if (nai.getCurrentScore() == oldScore && newNc.equalRequestableCapabilities(prevNc)) {
             // If the requestable capabilities haven't changed, and the score hasn't changed, then
diff --git a/services/core/java/com/android/server/connectivity/FullScore.java b/services/core/java/com/android/server/connectivity/FullScore.java
index a8a83fc..52da566 100644
--- a/services/core/java/com/android/server/connectivity/FullScore.java
+++ b/services/core/java/com/android/server/connectivity/FullScore.java
@@ -91,17 +91,26 @@
     /** @hide */
     public static final int POLICY_IS_INVINCIBLE = 58;
 
+    // This network has been validated at least once since it was connected, but not explicitly
+    // avoided in UI.
+    // TODO : remove setAvoidUnvalidated and instead disconnect the network when the user
+    // chooses to move away from this network, and remove this flag.
+    /** @hide */
+    public static final int POLICY_EVER_VALIDATED_NOT_AVOIDED_WHEN_BAD = 57;
+
     // To help iterate when printing
     @VisibleForTesting
-    static final int MIN_CS_MANAGED_POLICY = POLICY_IS_INVINCIBLE;
+    static final int MIN_CS_MANAGED_POLICY = POLICY_EVER_VALIDATED_NOT_AVOIDED_WHEN_BAD;
     @VisibleForTesting
     static final int MAX_CS_MANAGED_POLICY = POLICY_IS_VALIDATED;
 
     // Mask for policies in NetworkScore. This should have all bits managed by NetworkScore set
     // and all bits managed by FullScore unset. As bits are handled from 0 up in NetworkScore and
-    // from 63 down in FullScore, cut at the 32rd bit for simplicity, but change this if some day
+    // from 63 down in FullScore, cut at the 32nd bit for simplicity, but change this if some day
     // there are more than 32 bits handled on either side.
-    private static final int EXTERNAL_POLICIES_MASK = 0x0000FFFF;
+    // YIELD_TO_BAD_WIFI is temporarily handled by ConnectivityService.
+    private static final long EXTERNAL_POLICIES_MASK =
+            0x00000000FFFFFFFFL & ~(1L << POLICY_YIELD_TO_BAD_WIFI);
 
     @VisibleForTesting
     static @NonNull String policyNameOf(final int policy) {
@@ -115,6 +124,7 @@
             case POLICY_TRANSPORT_PRIMARY: return "TRANSPORT_PRIMARY";
             case POLICY_EXITING: return "EXITING";
             case POLICY_IS_INVINCIBLE: return "INVINCIBLE";
+            case POLICY_EVER_VALIDATED_NOT_AVOIDED_WHEN_BAD: return "EVER_VALIDATED";
         }
         throw new IllegalArgumentException("Unknown policy : " + policy);
     }
@@ -137,6 +147,7 @@
      * @param score the score supplied by the agent
      * @param caps the NetworkCapabilities of the network
      * @param config the NetworkAgentConfig of the network
+     * @param everValidated whether this network has ever validated
      * @param yieldToBadWiFi whether this network yields to a previously validated wifi gone bad
      * @return a FullScore that is appropriate to use for ranking.
      */
@@ -145,12 +156,13 @@
     // connectivity for backward compatibility.
     public static FullScore fromNetworkScore(@NonNull final NetworkScore score,
             @NonNull final NetworkCapabilities caps, @NonNull final NetworkAgentConfig config,
-            final boolean yieldToBadWiFi) {
+            final boolean everValidated, final boolean yieldToBadWiFi) {
         return withPolicies(score.getLegacyInt(), score.getPolicies(),
                 score.getKeepConnectedReason(),
                 caps.hasCapability(NET_CAPABILITY_VALIDATED),
                 caps.hasTransport(TRANSPORT_VPN),
                 caps.hasCapability(NET_CAPABILITY_NOT_METERED),
+                everValidated,
                 config.explicitlySelected,
                 config.acceptUnvalidated,
                 yieldToBadWiFi,
@@ -179,6 +191,8 @@
         // Prospective scores are always unmetered, because unmetered networks are stronger
         // than metered networks, and it's not known in advance whether the network is metered.
         final boolean unmetered = true;
+        // If the offer may validate, then it should be considered to have validated at some point
+        final boolean everValidated = mayValidate;
         // The network hasn't been chosen by the user (yet, at least).
         final boolean everUserSelected = false;
         // Don't assume the user will accept unvalidated connectivity.
@@ -189,8 +203,8 @@
         // score.
         final boolean invincible = score.getLegacyInt() > NetworkRanker.LEGACY_INT_MAX;
         return withPolicies(score.getLegacyInt(), score.getPolicies(), KEEP_CONNECTED_NONE,
-                mayValidate, vpn, unmetered, everUserSelected, acceptUnvalidated, yieldToBadWiFi,
-                invincible);
+                mayValidate, vpn, unmetered, everValidated, everUserSelected, acceptUnvalidated,
+                yieldToBadWiFi, invincible);
     }
 
     /**
@@ -204,11 +218,14 @@
     // telephony factory, so that it depends on the carrier. For now this is handled by
     // connectivity for backward compatibility.
     public FullScore mixInScore(@NonNull final NetworkCapabilities caps,
-            @NonNull final NetworkAgentConfig config, final boolean yieldToBadWifi) {
+            @NonNull final NetworkAgentConfig config,
+            final boolean everValidated,
+            final boolean yieldToBadWifi) {
         return withPolicies(mLegacyInt, mPolicies, mKeepConnectedReason,
                 caps.hasCapability(NET_CAPABILITY_VALIDATED),
                 caps.hasTransport(TRANSPORT_VPN),
                 caps.hasCapability(NET_CAPABILITY_NOT_METERED),
+                everValidated,
                 config.explicitlySelected,
                 config.acceptUnvalidated,
                 yieldToBadWifi,
@@ -224,6 +241,7 @@
             final boolean isValidated,
             final boolean isVpn,
             final boolean isUnmetered,
+            final boolean everValidated,
             final boolean everUserSelected,
             final boolean acceptUnvalidated,
             final boolean yieldToBadWiFi,
@@ -232,6 +250,7 @@
                 | (isValidated       ? 1L << POLICY_IS_VALIDATED : 0)
                 | (isVpn             ? 1L << POLICY_IS_VPN : 0)
                 | (isUnmetered       ? 1L << POLICY_IS_UNMETERED : 0)
+                | (everValidated     ? 1L << POLICY_EVER_VALIDATED_NOT_AVOIDED_WHEN_BAD : 0)
                 | (everUserSelected  ? 1L << POLICY_EVER_USER_SELECTED : 0)
                 | (acceptUnvalidated ? 1L << POLICY_ACCEPT_UNVALIDATED : 0)
                 | (yieldToBadWiFi    ? 1L << POLICY_YIELD_TO_BAD_WIFI : 0)
diff --git a/services/core/java/com/android/server/connectivity/NetworkAgentInfo.java b/services/core/java/com/android/server/connectivity/NetworkAgentInfo.java
index 5d793fd..4d310cb 100644
--- a/services/core/java/com/android/server/connectivity/NetworkAgentInfo.java
+++ b/services/core/java/com/android/server/connectivity/NetworkAgentInfo.java
@@ -707,7 +707,8 @@
             @NonNull final NetworkCapabilities nc) {
         final NetworkCapabilities oldNc = networkCapabilities;
         networkCapabilities = nc;
-        mScore = mScore.mixInScore(networkCapabilities, networkAgentConfig, yieldToBadWiFi());
+        mScore = mScore.mixInScore(networkCapabilities, networkAgentConfig, everValidatedForYield(),
+                yieldToBadWiFi());
         final NetworkMonitorManager nm = mNetworkMonitor;
         if (nm != null) {
             nm.notifyNetworkCapabilitiesChanged(nc);
@@ -893,7 +894,7 @@
     // Caller must not mutate. This method is called frequently and making a defensive copy
     // would be too expensive. This is used by NetworkRanker.Scoreable, so it can be compared
     // against other scoreables.
-    @Override public NetworkCapabilities getCaps() {
+    @Override public NetworkCapabilities getCapsNoCopy() {
         return networkCapabilities;
     }
 
@@ -919,7 +920,7 @@
      */
     public void setScore(final NetworkScore score) {
         mScore = FullScore.fromNetworkScore(score, networkCapabilities, networkAgentConfig,
-                yieldToBadWiFi());
+                everValidatedForYield(), yieldToBadWiFi());
     }
 
     /**
@@ -927,8 +928,13 @@
      *
      * Call this after updating the network agent config.
      */
-    public void updateScoreForNetworkAgentConfigUpdate() {
-        mScore = mScore.mixInScore(networkCapabilities, networkAgentConfig, yieldToBadWiFi());
+    public void updateScoreForNetworkAgentUpdate() {
+        mScore = mScore.mixInScore(networkCapabilities, networkAgentConfig,
+                everValidatedForYield(), yieldToBadWiFi());
+    }
+
+    private boolean everValidatedForYield() {
+        return everValidated && !avoidUnvalidated;
     }
 
     /**
diff --git a/services/core/java/com/android/server/connectivity/NetworkOffer.java b/services/core/java/com/android/server/connectivity/NetworkOffer.java
index 5336593..2bad596 100644
--- a/services/core/java/com/android/server/connectivity/NetworkOffer.java
+++ b/services/core/java/com/android/server/connectivity/NetworkOffer.java
@@ -76,7 +76,7 @@
     /**
      * Get the capabilities filter of this offer
      */
-    @Override @NonNull public NetworkCapabilities getCaps() {
+    @Override @NonNull public NetworkCapabilities getCapsNoCopy() {
         return caps;
     }
 
diff --git a/services/core/java/com/android/server/connectivity/NetworkRanker.java b/services/core/java/com/android/server/connectivity/NetworkRanker.java
index 3aaff59..c123ea7 100644
--- a/services/core/java/com/android/server/connectivity/NetworkRanker.java
+++ b/services/core/java/com/android/server/connectivity/NetworkRanker.java
@@ -26,6 +26,7 @@
 
 import static com.android.server.connectivity.FullScore.POLICY_ACCEPT_UNVALIDATED;
 import static com.android.server.connectivity.FullScore.POLICY_EVER_USER_SELECTED;
+import static com.android.server.connectivity.FullScore.POLICY_EVER_VALIDATED_NOT_AVOIDED_WHEN_BAD;
 import static com.android.server.connectivity.FullScore.POLICY_IS_INVINCIBLE;
 import static com.android.server.connectivity.FullScore.POLICY_IS_VALIDATED;
 import static com.android.server.connectivity.FullScore.POLICY_IS_VPN;
@@ -58,7 +59,7 @@
         /** Get score of this scoreable */
         FullScore getScore();
         /** Get capabilities of this scoreable */
-        NetworkCapabilities getCaps();
+        NetworkCapabilities getCapsNoCopy();
     }
 
     private static final boolean USE_POLICY_RANKING = false;
@@ -158,11 +159,12 @@
         if (accepted.size() == 1) return accepted.get(0);
         if (accepted.size() > 0 && rejected.size() > 0) candidates = new ArrayList<>(accepted);
 
-        // Yield to bad wifi policy : if any wifi has ever been validated, keep only networks
-        // that don't yield to such a wifi network.
+        // Yield to bad wifi policy : if any wifi has ever been validated (even if it's now
+        // unvalidated), and unless it's been explicitly avoided when bad in UI, then keep only
+        // networks that don't yield to such a wifi network.
         final boolean anyWiFiEverValidated = CollectionUtils.any(candidates,
-                nai -> nai.getScore().hasPolicy(POLICY_EVER_USER_SELECTED)
-                        && nai.getCaps().hasTransport(TRANSPORT_WIFI));
+                nai -> nai.getScore().hasPolicy(POLICY_EVER_VALIDATED_NOT_AVOIDED_WHEN_BAD)
+                        && nai.getCapsNoCopy().hasTransport(TRANSPORT_WIFI));
         if (anyWiFiEverValidated) {
             partitionInto(candidates, nai -> !nai.getScore().hasPolicy(POLICY_YIELD_TO_BAD_WIFI),
                     accepted, rejected);
@@ -206,18 +208,18 @@
         for (final Scoreable defaultSubNai : accepted) {
             // Remove all networks without the DEFAULT_SUBSCRIPTION policy and the same transports
             // as a network that has it.
-            final int[] transports = defaultSubNai.getCaps().getTransportTypes();
+            final int[] transports = defaultSubNai.getCapsNoCopy().getTransportTypes();
             candidates.removeIf(nai -> !nai.getScore().hasPolicy(POLICY_TRANSPORT_PRIMARY)
-                    && Arrays.equals(transports, nai.getCaps().getTransportTypes()));
+                    && Arrays.equals(transports, nai.getCapsNoCopy().getTransportTypes()));
         }
         if (1 == candidates.size()) return candidates.get(0);
-        // It's guaranteed candidates.size() > 0 because there is at least one with DEFAULT_SUB
-        // policy and only those without it were removed.
+        // It's guaranteed candidates.size() > 0 because there is at least one with the
+        // TRANSPORT_PRIMARY policy and only those without it were removed.
 
         // If some of the networks have a better transport than others, keep only the ones with
         // the best transports.
         for (final int transport : PREFERRED_TRANSPORTS_ORDER) {
-            partitionInto(candidates, nai -> nai.getCaps().hasTransport(transport),
+            partitionInto(candidates, nai -> nai.getCapsNoCopy().hasTransport(transport),
                     accepted, rejected);
             if (accepted.size() == 1) return accepted.get(0);
             if (accepted.size() > 0 && rejected.size() > 0) {
diff --git a/services/core/java/com/android/server/display/DisplayPowerController.java b/services/core/java/com/android/server/display/DisplayPowerController.java
index cb8541e..5cd0534 100644
--- a/services/core/java/com/android/server/display/DisplayPowerController.java
+++ b/services/core/java/com/android/server/display/DisplayPowerController.java
@@ -140,6 +140,7 @@
     private static final int RAMP_STATE_SKIP_INITIAL = 1;
     private static final int RAMP_STATE_SKIP_AUTOBRIGHT = 2;
 
+    private static final int REPORTED_TO_POLICY_UNREPORTED = -1;
     private static final int REPORTED_TO_POLICY_SCREEN_OFF = 0;
     private static final int REPORTED_TO_POLICY_SCREEN_TURNING_ON = 1;
     private static final int REPORTED_TO_POLICY_SCREEN_ON = 2;
@@ -311,8 +312,8 @@
     private long mScreenOnBlockStartRealTime;
     private long mScreenOffBlockStartRealTime;
 
-    // Screen state we reported to policy. Must be one of REPORTED_TO_POLICY_SCREEN_* fields.
-    private int mReportedScreenStateToPolicy;
+    // Screen state we reported to policy. Must be one of REPORTED_TO_POLICY_* fields.
+    private int mReportedScreenStateToPolicy = REPORTED_TO_POLICY_UNREPORTED;
 
     // If the last recorded screen state was dozing or not.
     private boolean mDozing;
@@ -1440,12 +1441,14 @@
 
     private boolean setScreenState(int state, boolean reportOnly) {
         final boolean isOff = (state == Display.STATE_OFF);
-        if (mPowerState.getScreenState() != state) {
 
+        if (mPowerState.getScreenState() != state
+                || mReportedScreenStateToPolicy == REPORTED_TO_POLICY_UNREPORTED) {
             // If we are trying to turn screen off, give policy a chance to do something before we
             // actually turn the screen off.
             if (isOff && !mScreenOffBecauseOfProximity) {
-                if (mReportedScreenStateToPolicy == REPORTED_TO_POLICY_SCREEN_ON) {
+                if (mReportedScreenStateToPolicy == REPORTED_TO_POLICY_SCREEN_ON
+                        || mReportedScreenStateToPolicy == REPORTED_TO_POLICY_UNREPORTED) {
                     setReportedScreenState(REPORTED_TO_POLICY_SCREEN_TURNING_OFF);
                     blockScreenOff();
                     mWindowManagerPolicy.screenTurningOff(mDisplayId, mPendingScreenOffUnblocker);
@@ -1456,7 +1459,7 @@
                 }
             }
 
-            if (!reportOnly) {
+            if (!reportOnly && mPowerState.getScreenState() != state) {
                 Trace.traceCounter(Trace.TRACE_TAG_POWER, "ScreenState", state);
                 // TODO(b/153319140) remove when we can get this from the above trace invocation
                 SystemProperties.set("debug.tracing.screen_state", String.valueOf(state));
@@ -1486,7 +1489,9 @@
             mWindowManagerPolicy.screenTurnedOff(mDisplayId);
             setReportedScreenState(REPORTED_TO_POLICY_SCREEN_OFF);
         }
-        if (!isOff && mReportedScreenStateToPolicy == REPORTED_TO_POLICY_SCREEN_OFF) {
+        if (!isOff
+                && (mReportedScreenStateToPolicy == REPORTED_TO_POLICY_SCREEN_OFF
+                        || mReportedScreenStateToPolicy == REPORTED_TO_POLICY_UNREPORTED)) {
             setReportedScreenState(REPORTED_TO_POLICY_SCREEN_TURNING_ON);
             if (mPowerState.getColorFadeLevel() == 0.0f) {
                 blockScreenOn();
diff --git a/services/core/java/com/android/server/pm/LauncherAppsService.java b/services/core/java/com/android/server/pm/LauncherAppsService.java
index 27e0ffc..91a66ac 100644
--- a/services/core/java/com/android/server/pm/LauncherAppsService.java
+++ b/services/core/java/com/android/server/pm/LauncherAppsService.java
@@ -978,7 +978,6 @@
                 // Flag for bubble to make behaviour match documentLaunchMode=always.
                 intents[0].addFlags(FLAG_ACTIVITY_NEW_DOCUMENT);
                 intents[0].addFlags(FLAG_ACTIVITY_MULTIPLE_TASK);
-                intents[0].putExtra(Intent.EXTRA_IS_BUBBLED, true);
             }
 
             intents[0].addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
diff --git a/services/core/java/com/android/server/policy/PhoneWindowManager.java b/services/core/java/com/android/server/policy/PhoneWindowManager.java
index c7789ee..45e6cdc 100644
--- a/services/core/java/com/android/server/policy/PhoneWindowManager.java
+++ b/services/core/java/com/android/server/policy/PhoneWindowManager.java
@@ -405,6 +405,7 @@
     private boolean mEnableCarDockHomeCapture = true;
 
     boolean mBootMessageNeedsHiding;
+    volatile boolean mBootAnimationDismissable;
     private KeyguardServiceDelegate mKeyguardDelegate;
     private boolean mKeyguardBound;
     final Runnable mWindowManagerDrawCallback = new Runnable() {
@@ -4305,6 +4306,7 @@
                     0 /* cookie */);
             updateScreenOffSleepToken(false);
             mDefaultDisplayPolicy.screenTurnedOn(screenOnListener);
+            mBootAnimationDismissable = false;
 
             synchronized (mLock) {
                 if (mKeyguardDelegate != null && mKeyguardDelegate.hasKeyguard()) {
@@ -4379,6 +4381,10 @@
         }
         Trace.asyncTraceEnd(Trace.TRACE_TAG_WINDOW_MANAGER, "screenTurningOn", 0 /* cookie */);
 
+        enableScreen(listener, true /* report */);
+    }
+
+    private void enableScreen(ScreenOnListener listener, boolean report) {
         final boolean enableScreen;
         final boolean awake = mDefaultDisplayPolicy.isAwake();
         synchronized (mLock) {
@@ -4396,17 +4402,19 @@
             }
         }
 
-        if (listener != null) {
-            listener.onScreenOn();
-        }
-
-        for (int i = mScreenOnListeners.size() - 1; i >= 0; i--) {
-            final ScreenOnListener screenOnListener = mScreenOnListeners.valueAt(i);
-            if (screenOnListener != null) {
-                screenOnListener.onScreenOn();
+        if (report) {
+            if (listener != null) {
+                listener.onScreenOn();
             }
+
+            for (int i = mScreenOnListeners.size() - 1; i >= 0; i--) {
+                final ScreenOnListener screenOnListener = mScreenOnListeners.valueAt(i);
+                if (screenOnListener != null) {
+                    screenOnListener.onScreenOn();
+                }
+            }
+            mScreenOnListeners.clear();
         }
-        mScreenOnListeners.clear();
 
         if (enableScreen) {
             try {
@@ -4614,13 +4622,28 @@
         }
         startedWakingUp(PowerManager.WAKE_REASON_UNKNOWN);
         finishedWakingUp(PowerManager.WAKE_REASON_UNKNOWN);
-        screenTurningOn(DEFAULT_DISPLAY, mDefaultDisplayPolicy.getScreenOnListener());
-        screenTurnedOn(DEFAULT_DISPLAY);
+
+        int defaultDisplayState = mDisplayManager.getDisplay(DEFAULT_DISPLAY).getState();
+        boolean defaultDisplayOn = defaultDisplayState == Display.STATE_ON;
+        boolean defaultScreenTurningOn = mDefaultDisplayPolicy.getScreenOnListener() != null;
+        if (defaultDisplayOn || defaultScreenTurningOn) {
+            // Now that system is booted, wait for keyguard and windows to be drawn before
+            // updating the orientation listener, stopping the boot animation and enabling screen.
+            screenTurningOn(DEFAULT_DISPLAY, mDefaultDisplayPolicy.getScreenOnListener());
+            screenTurnedOn(DEFAULT_DISPLAY);
+        } else {
+            // We're not turning the screen on, so don't wait for keyguard to be drawn
+            // to dismiss the boot animation and finish booting
+            mBootAnimationDismissable = true;
+            enableScreen(null, false /* report */);
+        }
     }
 
     @Override
     public boolean canDismissBootAnimation() {
-        return mDefaultDisplayPolicy.isKeyguardDrawComplete();
+        // Allow to dismiss the boot animation if the keyguard has finished drawing,
+        // or mBootAnimationDismissable has been set
+        return mDefaultDisplayPolicy.isKeyguardDrawComplete() || mBootAnimationDismissable;
     }
 
     ProgressDialog mBootMsgDialog = null;
diff --git a/services/core/java/com/android/server/vibrator/VibrationThread.java b/services/core/java/com/android/server/vibrator/VibrationThread.java
index df85e26..b4a95c4 100644
--- a/services/core/java/com/android/server/vibrator/VibrationThread.java
+++ b/services/core/java/com/android/server/vibrator/VibrationThread.java
@@ -255,9 +255,6 @@
     @Nullable
     private SingleVibratorStep nextVibrateStep(long startTime, VibratorController controller,
             VibrationEffect.Composed effect, int segmentIndex, long vibratorOffTimeout) {
-        // Some steps should only start after the vibrator has finished the previous vibration, so
-        // make sure we take the latest between both timings.
-        long latestStartTime = Math.max(startTime, vibratorOffTimeout);
         if (segmentIndex >= effect.getSegments().size()) {
             segmentIndex = effect.getRepeatIndex();
         }
@@ -272,15 +269,14 @@
 
         VibrationEffectSegment segment = effect.getSegments().get(segmentIndex);
         if (segment instanceof PrebakedSegment) {
-            return new PerformStep(latestStartTime, controller, effect, segmentIndex,
-                    vibratorOffTimeout);
+            return new PerformStep(startTime, controller, effect, segmentIndex, vibratorOffTimeout);
         }
         if (segment instanceof PrimitiveSegment) {
-            return new ComposePrimitivesStep(latestStartTime, controller, effect, segmentIndex,
+            return new ComposePrimitivesStep(startTime, controller, effect, segmentIndex,
                     vibratorOffTimeout);
         }
         if (segment instanceof RampSegment) {
-            return new ComposePwleStep(latestStartTime, controller, effect, segmentIndex,
+            return new ComposePwleStep(startTime, controller, effect, segmentIndex,
                     vibratorOffTimeout);
         }
         return new AmplitudeStep(startTime, controller, effect, segmentIndex, vibratorOffTimeout);
@@ -572,7 +568,7 @@
 
         private long startVibrating(SingleVibratorStep step, List<Step> nextSteps) {
             nextSteps.addAll(step.play());
-            long stepDuration = step.getOnResult();
+            long stepDuration = step.getVibratorOnDuration();
             if (stepDuration < 0) {
                 // Step failed, so return negative duration to propagate failure.
                 return stepDuration;
@@ -649,14 +645,13 @@
         }
 
         /**
-         * Return the result a call to {@link VibratorController#on} method triggered by
-         * {@link #play()}.
+         * Return the duration the vibrator was turned on when this step was played.
          *
          * @return A positive duration that the vibrator was turned on for by this step;
-         * Zero if the segment is not supported or vibrator was never turned on;
-         * A negative value if the vibrator call has failed.
+         * Zero if the segment is not supported, the step was not played yet or vibrator was never
+         * turned on by this step; A negative value if the vibrator call has failed.
          */
-        public long getOnResult() {
+        public long getVibratorOnDuration() {
             return mVibratorOnResult;
         }
 
@@ -690,7 +685,7 @@
 
         /**
          * Return the {@link #nextVibrateStep} with same start and off timings calculated from
-         * {@link #getOnResult()}, jumping all played segments.
+         * {@link #getVibratorOnDuration()}, jumping all played segments.
          *
          * <p>This method has same behavior as {@link #skipToNextSteps(int)} when the vibrator
          * result is non-positive, meaning the vibrator has either ignored or failed to turn on.
@@ -730,7 +725,10 @@
 
         PerformStep(long startTime, VibratorController controller,
                 VibrationEffect.Composed effect, int index, long vibratorOffTimeout) {
-            super(startTime, controller, effect, index, vibratorOffTimeout);
+            // This step should wait for the last vibration to finish (with the timeout) and for the
+            // intended step start time (to respect the effect delays).
+            super(Math.max(startTime, vibratorOffTimeout), controller, effect, index,
+                    vibratorOffTimeout);
         }
 
         @Override
@@ -765,7 +763,7 @@
                     List<Step> fallbackResult = fallbackStep.play();
                     // Update the result with the fallback result so this step is seamlessly
                     // replaced by the fallback to any outer application of this.
-                    mVibratorOnResult = fallbackStep.getOnResult();
+                    mVibratorOnResult = fallbackStep.getVibratorOnDuration();
                     return fallbackResult;
                 }
 
@@ -802,7 +800,10 @@
 
         ComposePrimitivesStep(long startTime, VibratorController controller,
                 VibrationEffect.Composed effect, int index, long vibratorOffTimeout) {
-            super(startTime, controller, effect, index, vibratorOffTimeout);
+            // This step should wait for the last vibration to finish (with the timeout) and for the
+            // intended step start time (to respect the effect delays).
+            super(Math.max(startTime, vibratorOffTimeout), controller, effect, index,
+                    vibratorOffTimeout);
         }
 
         @Override
@@ -851,7 +852,10 @@
 
         ComposePwleStep(long startTime, VibratorController controller,
                 VibrationEffect.Composed effect, int index, long vibratorOffTimeout) {
-            super(startTime, controller, effect, index, vibratorOffTimeout);
+            // This step should wait for the last vibration to finish (with the timeout) and for the
+            // intended step start time (to respect the effect delays).
+            super(Math.max(startTime, vibratorOffTimeout), controller, effect, index,
+                    vibratorOffTimeout);
         }
 
         @Override
@@ -924,6 +928,7 @@
 
         AmplitudeStep(long startTime, VibratorController controller,
                 VibrationEffect.Composed effect, int index, long vibratorOffTimeout) {
+            // This step has a fixed startTime coming from the timings of the waveform it's playing.
             super(startTime, controller, effect, index, vibratorOffTimeout);
             mNextOffTime = vibratorOffTimeout;
         }
diff --git a/services/core/java/com/android/server/vibrator/VibratorManagerService.java b/services/core/java/com/android/server/vibrator/VibratorManagerService.java
index b1d6050..6bd7198 100644
--- a/services/core/java/com/android/server/vibrator/VibratorManagerService.java
+++ b/services/core/java/com/android/server/vibrator/VibratorManagerService.java
@@ -603,11 +603,20 @@
             // Repeating vibrations always take precedence.
             return null;
         }
-        if (mCurrentVibration != null && mCurrentVibration.getVibration().isRepeating()) {
-            if (DEBUG) {
-                Slog.d(TAG, "Ignoring incoming vibration in favor of previous alarm vibration");
+        if (mCurrentVibration != null) {
+            if (mCurrentVibration.getVibration().attrs.getUsage()
+                    == VibrationAttributes.USAGE_ALARM) {
+                if (DEBUG) {
+                    Slog.d(TAG, "Ignoring incoming vibration in favor of alarm vibration");
+                }
+                return Vibration.Status.IGNORED_FOR_ALARM;
             }
-            return Vibration.Status.IGNORED_FOR_ALARM;
+            if (mCurrentVibration.getVibration().isRepeating()) {
+                if (DEBUG) {
+                    Slog.d(TAG, "Ignoring incoming vibration in favor of repeating vibration");
+                }
+                return Vibration.Status.IGNORED_FOR_ONGOING;
+            }
         }
         return null;
     }
diff --git a/services/core/java/com/android/server/wm/ActivityRecord.java b/services/core/java/com/android/server/wm/ActivityRecord.java
index 631d866..e0724fd 100644
--- a/services/core/java/com/android/server/wm/ActivityRecord.java
+++ b/services/core/java/com/android/server/wm/ActivityRecord.java
@@ -561,6 +561,9 @@
     // The locusId associated with this activity, if set.
     private LocusId mLocusId;
 
+    // Whether the activity was launched from a bubble.
+    private boolean mLaunchedFromBubble;
+
     private SizeConfigurationBuckets mSizeConfigurations;
 
     /**
@@ -4218,7 +4221,12 @@
         }
     }
 
+    boolean getLaunchedFromBubble() {
+        return mLaunchedFromBubble;
+    }
+
     private void setOptions(@NonNull ActivityOptions options) {
+        mLaunchedFromBubble = options.getLaunchedFromBubble();
         mPendingOptions = options;
         if (options.getAnimationType() == ANIM_REMOTE_ANIMATION) {
             mPendingRemoteAnimation = options.getRemoteAnimationAdapter();
diff --git a/services/core/java/com/android/server/wm/ActivityStarter.java b/services/core/java/com/android/server/wm/ActivityStarter.java
index aa1f42e..75a188e 100644
--- a/services/core/java/com/android/server/wm/ActivityStarter.java
+++ b/services/core/java/com/android/server/wm/ActivityStarter.java
@@ -2633,6 +2633,12 @@
                 mOptions = null;
             }
         }
+
+        if (mPreferredWindowingMode != WINDOWING_MODE_UNDEFINED
+                && intentTask.getWindowingMode() != mPreferredWindowingMode) {
+            intentTask.setWindowingMode(mPreferredWindowingMode);
+        }
+
         // Need to update mTargetRootTask because if task was moved out of it, the original root
         // task may be destroyed.
         mTargetRootTask = intentActivity.getRootTask();
diff --git a/services/core/java/com/android/server/wm/ActivityTaskSupervisor.java b/services/core/java/com/android/server/wm/ActivityTaskSupervisor.java
index bfbc10a..bdde369 100644
--- a/services/core/java/com/android/server/wm/ActivityTaskSupervisor.java
+++ b/services/core/java/com/android/server/wm/ActivityTaskSupervisor.java
@@ -826,7 +826,8 @@
                         r.getSavedState(), r.getPersistentSavedState(), results, newIntents,
                         r.takeOptions(), dc.isNextTransitionForward(),
                         proc.createProfilerInfoIfNeeded(), r.assistToken, activityClientController,
-                        r.createFixedRotationAdjustmentsIfNeeded(), r.shareableActivityToken));
+                        r.createFixedRotationAdjustmentsIfNeeded(), r.shareableActivityToken,
+                        r.getLaunchedFromBubble()));
 
                 // Set desired final state.
                 final ActivityLifecycleItem lifecycleItem;
diff --git a/services/core/java/com/android/server/wm/InsetsSourceProvider.java b/services/core/java/com/android/server/wm/InsetsSourceProvider.java
index 0732314..7daebff 100644
--- a/services/core/java/com/android/server/wm/InsetsSourceProvider.java
+++ b/services/core/java/com/android/server/wm/InsetsSourceProvider.java
@@ -84,6 +84,7 @@
     private TriConsumer<DisplayFrames, WindowState, Rect> mImeFrameProvider;
     private final Rect mImeOverrideFrame = new Rect();
     private boolean mIsLeashReadyForDispatching;
+    private final Rect mLastSourceFrame = new Rect();
 
     private final Consumer<Transaction> mSetLeashPositionConsumer = t -> {
         if (mControl != null) {
@@ -268,11 +269,14 @@
                     mSetLeashPositionConsumer.accept(mWin.getPendingTransaction());
                 }
             }
-            final Insets insetsHint = mSource.calculateInsets(
-                    mWin.getBounds(), true /* ignoreVisibility */);
-            if (!insetsHint.equals(mControl.getInsetsHint())) {
-                changed = true;
-                mControl.setInsetsHint(insetsHint);
+            if (mServerVisible && !mLastSourceFrame.equals(mSource.getFrame())) {
+                final Insets insetsHint = mSource.calculateInsets(
+                        mWin.getBounds(), true /* ignoreVisibility */);
+                if (!insetsHint.equals(mControl.getInsetsHint())) {
+                    changed = true;
+                    mControl.setInsetsHint(insetsHint);
+                }
+                mLastSourceFrame.set(mSource.getFrame());
             }
             if (changed) {
                 mStateController.notifyControlChanged(mControlTarget);
diff --git a/services/core/java/com/android/server/wm/SafeActivityOptions.java b/services/core/java/com/android/server/wm/SafeActivityOptions.java
index 6567195..c9d5fa4 100644
--- a/services/core/java/com/android/server/wm/SafeActivityOptions.java
+++ b/services/core/java/com/android/server/wm/SafeActivityOptions.java
@@ -18,6 +18,7 @@
 
 import static android.Manifest.permission.CONTROL_REMOTE_APP_TRANSITION_ANIMATIONS;
 import static android.Manifest.permission.START_TASKS_FROM_RECENTS;
+import static android.Manifest.permission.STATUS_BAR_SERVICE;
 import static android.app.ActivityTaskManager.INVALID_TASK_ID;
 import static android.content.pm.PackageManager.PERMISSION_DENIED;
 import static android.content.pm.PackageManager.PERMISSION_GRANTED;
@@ -278,6 +279,19 @@
             Slog.w(TAG, msg);
             throw new SecurityException(msg);
         }
+
+        // If launched from bubble is specified, then ensure that the caller is system or sysui.
+        if (options.getLaunchedFromBubble() && callingUid != Process.SYSTEM_UID) {
+            final int statusBarPerm = ActivityTaskManagerService.checkPermission(
+                    STATUS_BAR_SERVICE, callingPid, callingUid);
+            if (statusBarPerm == PERMISSION_DENIED) {
+                final String msg = "Permission Denial: starting " + getIntentString(intent)
+                        + " from " + callerApp + " (pid=" + callingPid
+                        + ", uid=" + callingUid + ") with launchedFromBubble=true";
+                Slog.w(TAG, msg);
+                throw new SecurityException(msg);
+            }
+        }
     }
 
     private String getIntentString(Intent intent) {
diff --git a/services/core/jni/com_android_server_vibrator_VibratorController.cpp b/services/core/jni/com_android_server_vibrator_VibratorController.cpp
index cf64a68..b7fa796 100644
--- a/services/core/jni/com_android_server_vibrator_VibratorController.cpp
+++ b/services/core/jni/com_android_server_vibrator_VibratorController.cpp
@@ -199,7 +199,7 @@
         ALOGE("vibratorIsAvailable failed because native wrapper was not initialized");
         return JNI_FALSE;
     }
-    auto pingFn = [](std::shared_ptr<vibrator::HalWrapper> hal) { return hal->ping(); };
+    auto pingFn = [](vibrator::HalWrapper* hal) { return hal->ping(); };
     return wrapper->halCall<void>(pingFn, "ping").isOk() ? JNI_TRUE : JNI_FALSE;
 }
 
@@ -211,7 +211,7 @@
         return -1;
     }
     auto callback = wrapper->createCallback(vibrationId);
-    auto onFn = [&](std::shared_ptr<vibrator::HalWrapper> hal) {
+    auto onFn = [timeoutMs, &callback](vibrator::HalWrapper* hal) {
         return hal->on(std::chrono::milliseconds(timeoutMs), callback);
     };
     auto result = wrapper->halCall<void>(onFn, "on");
@@ -224,7 +224,7 @@
         ALOGE("vibratorOff failed because native wrapper was not initialized");
         return;
     }
-    auto offFn = [](std::shared_ptr<vibrator::HalWrapper> hal) { return hal->off(); };
+    auto offFn = [](vibrator::HalWrapper* hal) { return hal->off(); };
     wrapper->halCall<void>(offFn, "off");
 }
 
@@ -234,7 +234,7 @@
         ALOGE("vibratorSetAmplitude failed because native wrapper was not initialized");
         return;
     }
-    auto setAmplitudeFn = [&](std::shared_ptr<vibrator::HalWrapper> hal) {
+    auto setAmplitudeFn = [amplitude](vibrator::HalWrapper* hal) {
         return hal->setAmplitude(static_cast<float>(amplitude));
     };
     wrapper->halCall<void>(setAmplitudeFn, "setAmplitude");
@@ -247,7 +247,7 @@
         ALOGE("vibratorSetExternalControl failed because native wrapper was not initialized");
         return;
     }
-    auto setExternalControlFn = [&](std::shared_ptr<vibrator::HalWrapper> hal) {
+    auto setExternalControlFn = [enabled](vibrator::HalWrapper* hal) {
         return hal->setExternalControl(enabled);
     };
     wrapper->halCall<void>(setExternalControlFn, "setExternalControl");
@@ -263,7 +263,7 @@
     aidl::Effect effectType = static_cast<aidl::Effect>(effect);
     aidl::EffectStrength effectStrength = static_cast<aidl::EffectStrength>(strength);
     auto callback = wrapper->createCallback(vibrationId);
-    auto performEffectFn = [&](std::shared_ptr<vibrator::HalWrapper> hal) {
+    auto performEffectFn = [effectType, effectStrength, &callback](vibrator::HalWrapper* hal) {
         return hal->performEffect(effectType, effectStrength, callback);
     };
     auto result = wrapper->halCall<std::chrono::milliseconds>(performEffectFn, "performEffect");
@@ -284,7 +284,7 @@
         effects.push_back(effectFromJavaPrimitive(env, element));
     }
     auto callback = wrapper->createCallback(vibrationId);
-    auto performComposedEffectFn = [&](std::shared_ptr<vibrator::HalWrapper> hal) {
+    auto performComposedEffectFn = [&effects, &callback](vibrator::HalWrapper* hal) {
         return hal->performComposedEffect(effects, callback);
     };
     auto result = wrapper->halCall<std::chrono::milliseconds>(performComposedEffectFn,
@@ -319,7 +319,7 @@
     }
 
     auto callback = wrapper->createCallback(vibrationId);
-    auto performPwleEffectFn = [&](std::shared_ptr<vibrator::HalWrapper> hal) {
+    auto performPwleEffectFn = [&primitives, &callback](vibrator::HalWrapper* hal) {
         return hal->performPwleEffect(primitives, callback);
     };
     auto result = wrapper->halCall<void>(performPwleEffectFn, "performPwleEffect");
@@ -333,7 +333,7 @@
         ALOGE("vibratorAlwaysOnEnable failed because native wrapper was not initialized");
         return;
     }
-    auto alwaysOnEnableFn = [&](std::shared_ptr<vibrator::HalWrapper> hal) {
+    auto alwaysOnEnableFn = [id, effect, strength](vibrator::HalWrapper* hal) {
         return hal->alwaysOnEnable(static_cast<int32_t>(id), static_cast<aidl::Effect>(effect),
                                    static_cast<aidl::EffectStrength>(strength));
     };
@@ -346,7 +346,7 @@
         ALOGE("vibratorAlwaysOnDisable failed because native wrapper was not initialized");
         return;
     }
-    auto alwaysOnDisableFn = [&](std::shared_ptr<vibrator::HalWrapper> hal) {
+    auto alwaysOnDisableFn = [id](vibrator::HalWrapper* hal) {
         return hal->alwaysOnDisable(static_cast<int32_t>(id));
     };
     wrapper->halCall<void>(alwaysOnDisableFn, "alwaysOnDisable");
@@ -446,11 +446,11 @@
     sRampClassInfo.duration = GetFieldIDOrDie(env, rampClass, "mDuration", "I");
 
     jclass frequencyMappingClass = FindClassOrDie(env, "android/os/VibratorInfo$FrequencyMapping");
-    sFrequencyMappingClass = (jclass)env->NewGlobalRef(frequencyMappingClass);
+    sFrequencyMappingClass = static_cast<jclass>(env->NewGlobalRef(frequencyMappingClass));
     sFrequencyMappingCtor = GetMethodIDOrDie(env, sFrequencyMappingClass, "<init>", "(FFFF[F)V");
 
     jclass vibratorInfoClass = FindClassOrDie(env, "android/os/VibratorInfo");
-    sVibratorInfoClass = (jclass)env->NewGlobalRef(vibratorInfoClass);
+    sVibratorInfoClass = static_cast<jclass>(env->NewGlobalRef(vibratorInfoClass));
     sVibratorInfoCtor = GetMethodIDOrDie(env, sVibratorInfoClass, "<init>",
                                          "(IJ[I[I[IFLandroid/os/VibratorInfo$FrequencyMapping;)V");
 
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/ActiveAdmin.java b/services/devicepolicy/java/com/android/server/devicepolicy/ActiveAdmin.java
index fb0265e..ff7514a 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/ActiveAdmin.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/ActiveAdmin.java
@@ -144,13 +144,13 @@
     private static final String TAG_ENROLLMENT_SPECIFIC_ID = "enrollment-specific-id";
     private static final String TAG_ADMIN_CAN_GRANT_SENSORS_PERMISSIONS =
             "admin-can-grant-sensors-permissions";
-    private static final String TAG_ENTERPRISE_NETWORK_PREFERENCE_ENABLED =
-            "enterprise-network-preference-enabled";
+    private static final String TAG_PREFERENTIAL_NETWORK_SERVICE_ENABLED =
+            "preferential-network-service-enabled";
     private static final String TAG_USB_DATA_SIGNALING = "usb-data-signaling";
     private static final String ATTR_VALUE = "value";
     private static final String ATTR_LAST_NETWORK_LOGGING_NOTIFICATION = "last-notification";
     private static final String ATTR_NUM_NETWORK_LOGGING_NOTIFICATIONS = "num-notifications";
-    private static final boolean ENTERPRISE_NETWORK_PREFERENCE_ENABLED_DEFAULT = true;
+    private static final boolean PREFERENTIAL_NETWORK_SERVICE_ENABLED_DEFAULT = true;
 
     DeviceAdminInfo info;
 
@@ -296,8 +296,8 @@
     public String mOrganizationId;
     public String mEnrollmentSpecificId;
     public boolean mAdminCanGrantSensorsPermissions;
-    public boolean mEnterpriseNetworkPreferenceEnabled =
-            ENTERPRISE_NETWORK_PREFERENCE_ENABLED_DEFAULT;
+    public boolean mPreferentialNetworkServiceEnabled =
+            PREFERENTIAL_NETWORK_SERVICE_ENABLED_DEFAULT;
 
     private static final boolean USB_DATA_SIGNALING_ENABLED_DEFAULT = true;
     boolean mUsbDataSignalingEnabled = USB_DATA_SIGNALING_ENABLED_DEFAULT;
@@ -576,9 +576,9 @@
         }
         writeAttributeValueToXml(out, TAG_ADMIN_CAN_GRANT_SENSORS_PERMISSIONS,
                 mAdminCanGrantSensorsPermissions);
-        if (mEnterpriseNetworkPreferenceEnabled != ENTERPRISE_NETWORK_PREFERENCE_ENABLED_DEFAULT) {
-            writeAttributeValueToXml(out, TAG_ENTERPRISE_NETWORK_PREFERENCE_ENABLED,
-                    mEnterpriseNetworkPreferenceEnabled);
+        if (mPreferentialNetworkServiceEnabled != PREFERENTIAL_NETWORK_SERVICE_ENABLED_DEFAULT) {
+            writeAttributeValueToXml(out, TAG_PREFERENTIAL_NETWORK_SERVICE_ENABLED,
+                    mPreferentialNetworkServiceEnabled);
         }
         if (mUsbDataSignalingEnabled != USB_DATA_SIGNALING_ENABLED_DEFAULT) {
             writeAttributeValueToXml(out, TAG_USB_DATA_SIGNALING, mUsbDataSignalingEnabled);
@@ -806,9 +806,9 @@
                 mAlwaysOnVpnPackage = parser.getAttributeValue(null, ATTR_VALUE);
             } else if (TAG_ALWAYS_ON_VPN_LOCKDOWN.equals(tag)) {
                 mAlwaysOnVpnLockdown = parser.getAttributeBoolean(null, ATTR_VALUE, false);
-            } else if (TAG_ENTERPRISE_NETWORK_PREFERENCE_ENABLED.equals(tag)) {
-                mEnterpriseNetworkPreferenceEnabled = parser.getAttributeBoolean(
-                        null, ATTR_VALUE, ENTERPRISE_NETWORK_PREFERENCE_ENABLED_DEFAULT);
+            } else if (TAG_PREFERENTIAL_NETWORK_SERVICE_ENABLED.equals(tag)) {
+                mPreferentialNetworkServiceEnabled = parser.getAttributeBoolean(
+                        null, ATTR_VALUE, PREFERENTIAL_NETWORK_SERVICE_ENABLED_DEFAULT);
             } else if (TAG_COMMON_CRITERIA_MODE.equals(tag)) {
                 mCommonCriteriaMode = parser.getAttributeBoolean(null, ATTR_VALUE, false);
             } else if (TAG_PASSWORD_COMPLEXITY.equals(tag)) {
@@ -1168,8 +1168,8 @@
         pw.print("mAlwaysOnVpnLockdown=");
         pw.println(mAlwaysOnVpnLockdown);
 
-        pw.print("mEnterpriseNetworkPreferenceEnabled=");
-        pw.println(mEnterpriseNetworkPreferenceEnabled);
+        pw.print("mPreferentialNetworkServiceEnabled=");
+        pw.println(mPreferentialNetworkServiceEnabled);
 
         pw.print("mCommonCriteriaMode=");
         pw.println(mCommonCriteriaMode);
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
index 20a88af..66e640d6 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
@@ -3123,13 +3123,13 @@
         updatePermissionPolicyCache(userId);
         updateAdminCanGrantSensorsPermissionCache(userId);
 
-        boolean enableEnterpriseNetworkPreferenceEnabled = true;
+        boolean preferentialNetworkServiceEnabled = true;
         synchronized (getLockObject()) {
             ActiveAdmin owner = getDeviceOrProfileOwnerAdminLocked(userId);
-            enableEnterpriseNetworkPreferenceEnabled = owner != null
-                    ? owner.mEnterpriseNetworkPreferenceEnabled : true;
+            preferentialNetworkServiceEnabled = owner != null
+                    ? owner.mPreferentialNetworkServiceEnabled : true;
         }
-        updateNetworkPreferenceForUser(userId, enableEnterpriseNetworkPreferenceEnabled);
+        updateNetworkPreferenceForUser(userId, preferentialNetworkServiceEnabled);
 
         startOwnerService(userId, "start-user");
     }
@@ -11616,32 +11616,32 @@
     }
 
     @Override
-    public void setEnterpriseNetworkPreferenceEnabled(boolean enabled) {
+    public void setPreferentialNetworkServiceEnabled(boolean enabled) {
         if (!mHasFeature) {
             return;
         }
         final CallerIdentity caller = getCallerIdentity();
         Preconditions.checkCallAuthorization(isProfileOwner(caller),
                 "Caller is not profile owner;"
-                        + " only profile owner may control the enterprise network preference");
+                        + " only profile owner may control the preferntial network service");
         synchronized (getLockObject()) {
             final ActiveAdmin requiredAdmin = getProfileOwnerAdminLocked(
                     caller.getUserId());
             if (requiredAdmin != null
-                    && requiredAdmin.mEnterpriseNetworkPreferenceEnabled != enabled) {
-                requiredAdmin.mEnterpriseNetworkPreferenceEnabled = enabled;
+                    && requiredAdmin.mPreferentialNetworkServiceEnabled != enabled) {
+                requiredAdmin.mPreferentialNetworkServiceEnabled = enabled;
                 saveSettingsLocked(caller.getUserId());
             }
         }
         updateNetworkPreferenceForUser(caller.getUserId(), enabled);
         DevicePolicyEventLogger
-                .createEvent(DevicePolicyEnums.SET_ENTERPRISE_NETWORK_PREFERENCE_ENABLED)
+                .createEvent(DevicePolicyEnums.SET_PREFERENTIAL_NETWORK_SERVICE_ENABLED)
                 .setBoolean(enabled)
                 .write();
     }
 
     @Override
-    public boolean isEnterpriseNetworkPreferenceEnabled(int userHandle) {
+    public boolean isPreferentialNetworkServiceEnabled(int userHandle) {
         if (!mHasFeature) {
             return false;
         }
@@ -11652,7 +11652,7 @@
         synchronized (getLockObject()) {
             final ActiveAdmin requiredAdmin = getProfileOwnerAdminLocked(userHandle);
             if (requiredAdmin != null) {
-                return requiredAdmin.mEnterpriseNetworkPreferenceEnabled;
+                return requiredAdmin.mPreferentialNetworkServiceEnabled;
             } else {
                 return false;
             }
@@ -17227,11 +17227,11 @@
     }
 
     private void updateNetworkPreferenceForUser(int userId,
-            boolean enableEnterpriseNetworkPreferenceEnabled) {
+            boolean preferentialNetworkServiceEnabled) {
         if (!isManagedProfile(userId)) {
             return;
         }
-        int networkPreference = enableEnterpriseNetworkPreferenceEnabled
+        int networkPreference = preferentialNetworkServiceEnabled
                 ? PROFILE_NETWORK_PREFERENCE_ENTERPRISE : PROFILE_NETWORK_PREFERENCE_DEFAULT;
         mInjector.binderWithCleanCallingIdentity(() ->
                 mInjector.getConnectivityManager().setProfileNetworkPreference(
diff --git a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java
index 486d2b3..78e2dee 100644
--- a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java
+++ b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java
@@ -4032,20 +4032,20 @@
     }
 
     @Test
-    public void testGetSetEnterpriseNetworkPreference() throws Exception {
+    public void testGetSetPreferentialNetworkService() throws Exception {
         assertExpectException(SecurityException.class, null,
-                () -> dpm.setEnterpriseNetworkPreferenceEnabled(false));
+                () -> dpm.setPreferentialNetworkServiceEnabled(false));
 
         assertExpectException(SecurityException.class, null,
-                () -> dpm.isEnterpriseNetworkPreferenceEnabled());
+                () -> dpm.isPreferentialNetworkServiceEnabled());
 
         final int managedProfileUserId = 15;
         final int managedProfileAdminUid = UserHandle.getUid(managedProfileUserId, 19436);
         addManagedProfile(admin1, managedProfileAdminUid, admin1);
         mContext.binder.callingUid = managedProfileAdminUid;
 
-        dpm.setEnterpriseNetworkPreferenceEnabled(false);
-        assertThat(dpm.isEnterpriseNetworkPreferenceEnabled()).isFalse();
+        dpm.setPreferentialNetworkServiceEnabled(false);
+        assertThat(dpm.isPreferentialNetworkServiceEnabled()).isFalse();
         verify(getServices().connectivityManager, times(1)).setProfileNetworkPreference(
                 eq(UserHandle.of(managedProfileUserId)),
                 eq(ConnectivityManager.PROFILE_NETWORK_PREFERENCE_DEFAULT),
@@ -4053,8 +4053,8 @@
                 any()
         );
 
-        dpm.setEnterpriseNetworkPreferenceEnabled(true);
-        assertThat(dpm.isEnterpriseNetworkPreferenceEnabled()).isTrue();
+        dpm.setPreferentialNetworkServiceEnabled(true);
+        assertThat(dpm.isPreferentialNetworkServiceEnabled()).isTrue();
         verify(getServices().connectivityManager, times(1)).setProfileNetworkPreference(
                 eq(UserHandle.of(managedProfileUserId)),
                 eq(ConnectivityManager.PROFILE_NETWORK_PREFERENCE_ENTERPRISE),
diff --git a/services/tests/servicestests/src/com/android/server/vibrator/VibratorManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/vibrator/VibratorManagerServiceTest.java
index 12ced38..b0e8ef0b 100644
--- a/services/tests/servicestests/src/com/android/server/vibrator/VibratorManagerServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/vibrator/VibratorManagerServiceTest.java
@@ -566,6 +566,54 @@
     }
 
     @Test
+    public void vibrate_withOngoingRepeatingVibration_ignoresEffect() throws Exception {
+        mockVibrators(1);
+        mVibratorProviders.get(1).setCapabilities(IVibrator.CAP_AMPLITUDE_CONTROL);
+        VibratorManagerService service = createSystemReadyService();
+
+        VibrationEffect repeatingEffect = VibrationEffect.createWaveform(
+                new long[]{10_000, 10_000}, new int[]{128, 255}, 1);
+        vibrate(service, repeatingEffect, new VibrationAttributes.Builder().setUsage(
+                VibrationAttributes.USAGE_UNKNOWN).build());
+
+        // VibrationThread will start this vibration async, so wait before checking it started.
+        assertTrue(waitUntil(s -> !mVibratorProviders.get(1).getEffectSegments().isEmpty(),
+                service, TEST_TIMEOUT_MILLIS));
+
+        vibrate(service, VibrationEffect.get(VibrationEffect.EFFECT_CLICK),
+                new VibrationAttributes.Builder().setUsage(
+                        VibrationAttributes.USAGE_TOUCH).build());
+
+        // Wait before checking it never played a second effect.
+        assertFalse(waitUntil(s -> mVibratorProviders.get(1).getEffectSegments().size() > 1,
+                service, /* timeout= */ 50));
+    }
+
+    @Test
+    public void vibrate_withOngoingAlarmVibration_ignoresEffect() throws Exception {
+        mockVibrators(1);
+        mVibratorProviders.get(1).setCapabilities(IVibrator.CAP_AMPLITUDE_CONTROL);
+        VibratorManagerService service = createSystemReadyService();
+
+        VibrationEffect alarmEffect = VibrationEffect.createWaveform(
+                new long[]{10_000, 10_000}, new int[]{128, 255}, -1);
+        vibrate(service, alarmEffect, new VibrationAttributes.Builder().setUsage(
+                VibrationAttributes.USAGE_ALARM).build());
+
+        // VibrationThread will start this vibration async, so wait before checking it started.
+        assertTrue(waitUntil(s -> !mVibratorProviders.get(1).getEffectSegments().isEmpty(),
+                service, TEST_TIMEOUT_MILLIS));
+
+        vibrate(service, VibrationEffect.get(VibrationEffect.EFFECT_CLICK),
+                new VibrationAttributes.Builder().setUsage(
+                        VibrationAttributes.USAGE_TOUCH).build());
+
+        // Wait before checking it never played a second effect.
+        assertFalse(waitUntil(s -> mVibratorProviders.get(1).getEffectSegments().size() > 1,
+                service, /* timeout= */ 50));
+    }
+
+    @Test
     public void vibrate_withInputDevices_vibratesInputDevices() throws Exception {
         mockVibrators(1);
         mVibratorProviders.get(1).setCapabilities(IVibrator.CAP_COMPOSE_EFFECTS);
@@ -761,22 +809,22 @@
         fakeVibrator.setSupportedEffects(VibrationEffect.EFFECT_CLICK);
         VibratorManagerService service = createSystemReadyService();
 
-        vibrate(service, CombinedVibrationEffect.startSynced()
-                .addVibrator(1, VibrationEffect.get(VibrationEffect.EFFECT_CLICK))
-                .combine(), ALARM_ATTRS);
-        assertTrue(waitUntil(s -> fakeVibrator.getEffectSegments().size() == 1,
-                service, TEST_TIMEOUT_MILLIS));
-
         vibrate(service, CombinedVibrationEffect.startSequential()
                 .addNext(1, VibrationEffect.createOneShot(20, 100))
                 .combine(), NOTIFICATION_ATTRS);
-        assertTrue(waitUntil(s -> fakeVibrator.getEffectSegments().size() == 2,
+        assertTrue(waitUntil(s -> fakeVibrator.getEffectSegments().size() == 1,
                 service, TEST_TIMEOUT_MILLIS));
 
         vibrate(service, VibrationEffect.startComposition()
                 .addPrimitive(VibrationEffect.Composition.PRIMITIVE_CLICK, 1f)
                 .addPrimitive(VibrationEffect.Composition.PRIMITIVE_TICK, 0.5f)
                 .compose(), HAPTIC_FEEDBACK_ATTRS);
+        assertTrue(waitUntil(s -> fakeVibrator.getEffectSegments().size() == 3,
+                service, TEST_TIMEOUT_MILLIS));
+
+        vibrate(service, CombinedVibrationEffect.startSynced()
+                .addVibrator(1, VibrationEffect.get(VibrationEffect.EFFECT_CLICK))
+                .combine(), ALARM_ATTRS);
         assertTrue(waitUntil(s -> fakeVibrator.getEffectSegments().size() == 4,
                 service, TEST_TIMEOUT_MILLIS));
 
@@ -785,17 +833,17 @@
         assertEquals(4, fakeVibrator.getEffectSegments().size());
         assertEquals(1, fakeVibrator.getAmplitudes().size());
 
-        // Alarm vibration is always VIBRATION_INTENSITY_HIGH.
-        PrebakedSegment expected = new PrebakedSegment(
-                VibrationEffect.EFFECT_CLICK, false, VibrationEffect.EFFECT_STRENGTH_STRONG);
-        assertEquals(expected, fakeVibrator.getEffectSegments().get(0));
-
         // Notification vibrations will be scaled with SCALE_VERY_HIGH.
         assertTrue(0.6 < fakeVibrator.getAmplitudes().get(0));
 
         // Haptic feedback vibrations will be scaled with SCALE_LOW.
-        assertTrue(0.5 < ((PrimitiveSegment) fakeVibrator.getEffectSegments().get(2)).getScale());
-        assertTrue(0.5 > ((PrimitiveSegment) fakeVibrator.getEffectSegments().get(3)).getScale());
+        assertTrue(0.5 < ((PrimitiveSegment) fakeVibrator.getEffectSegments().get(1)).getScale());
+        assertTrue(0.5 > ((PrimitiveSegment) fakeVibrator.getEffectSegments().get(2)).getScale());
+
+        // Alarm vibration is always VIBRATION_INTENSITY_HIGH.
+        PrebakedSegment expected = new PrebakedSegment(
+                VibrationEffect.EFFECT_CLICK, false, VibrationEffect.EFFECT_STRENGTH_STRONG);
+        assertEquals(expected, fakeVibrator.getEffectSegments().get(3));
 
         // Ring vibrations have intensity OFF and are not played.
     }
diff --git a/tests/net/common/java/android/net/NetworkAgentConfigTest.kt b/tests/net/common/java/android/net/NetworkAgentConfigTest.kt
index 1e54093..db939f9 100644
--- a/tests/net/common/java/android/net/NetworkAgentConfigTest.kt
+++ b/tests/net/common/java/android/net/NetworkAgentConfigTest.kt
@@ -63,8 +63,8 @@
             setPartialConnectivityAcceptable(false)
             setUnvalidatedConnectivityAcceptable(true)
             setLegacyTypeName("TEST_NETWORK")
-            disableNat64Detection()
-            disableProvisioningNotification()
+            setNat64DetectionEnabled(false)
+            setProvisioningNotificationEnabled(false)
         }.build()
 
         assertTrue(config.isExplicitlySelected())
diff --git a/tests/net/java/com/android/server/connectivity/FullScoreTest.kt b/tests/net/java/com/android/server/connectivity/FullScoreTest.kt
index f0d7d86..45b575a 100644
--- a/tests/net/java/com/android/server/connectivity/FullScoreTest.kt
+++ b/tests/net/java/com/android/server/connectivity/FullScoreTest.kt
@@ -56,7 +56,7 @@
             if (vpn) addTransportType(NetworkCapabilities.TRANSPORT_VPN)
             if (validated) addCapability(NetworkCapabilities.NET_CAPABILITY_VALIDATED)
         }.build()
-        return mixInScore(nc, nac, false /* avoidBadWifi */)
+        return mixInScore(nc, nac, validated, false /* yieldToBadWifi */)
     }
 
     @Test