Merge "Remove translation service feature." 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 682ee1b..e2bfda6 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/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/admin/PasswordPolicy.java b/core/java/android/app/admin/PasswordPolicy.java
index 13f11ad..0544a36 100644
--- a/core/java/android/app/admin/PasswordPolicy.java
+++ b/core/java/android/app/admin/PasswordPolicy.java
@@ -20,6 +20,7 @@
 import static android.app.admin.DevicePolicyManager.PASSWORD_QUALITY_ALPHANUMERIC;
 import static android.app.admin.DevicePolicyManager.PASSWORD_QUALITY_BIOMETRIC_WEAK;
 import static android.app.admin.DevicePolicyManager.PASSWORD_QUALITY_COMPLEX;
+import static android.app.admin.DevicePolicyManager.PASSWORD_QUALITY_NUMERIC;
 import static android.app.admin.DevicePolicyManager.PASSWORD_QUALITY_NUMERIC_COMPLEX;
 import static android.app.admin.DevicePolicyManager.PASSWORD_QUALITY_SOMETHING;
 import static android.app.admin.DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED;
@@ -27,6 +28,7 @@
 import static com.android.internal.widget.LockPatternUtils.CREDENTIAL_TYPE_NONE;
 import static com.android.internal.widget.LockPatternUtils.CREDENTIAL_TYPE_PASSWORD;
 import static com.android.internal.widget.LockPatternUtils.CREDENTIAL_TYPE_PATTERN;
+import static com.android.internal.widget.LockPatternUtils.CREDENTIAL_TYPE_PIN;
 
 /**
  * {@hide}
@@ -58,14 +60,20 @@
         } else if (quality == PASSWORD_QUALITY_BIOMETRIC_WEAK
                 || quality == PASSWORD_QUALITY_SOMETHING) {
             return new PasswordMetrics(CREDENTIAL_TYPE_PATTERN);
-        } // quality is NUMERIC or stronger.
+        } else if (quality == PASSWORD_QUALITY_NUMERIC
+                || quality == PASSWORD_QUALITY_NUMERIC_COMPLEX) {
+            PasswordMetrics result = new PasswordMetrics(CREDENTIAL_TYPE_PIN);
+            result.length = length;
+            if (quality == PASSWORD_QUALITY_NUMERIC_COMPLEX) {
+                result.seqLength = PasswordMetrics.MAX_ALLOWED_SEQUENCE;
+            }
+            return result;
+        } // quality is ALPHABETIC or stronger.
 
         PasswordMetrics result = new PasswordMetrics(CREDENTIAL_TYPE_PASSWORD);
         result.length = length;
 
-        if (quality == PASSWORD_QUALITY_NUMERIC_COMPLEX) {
-            result.seqLength = PasswordMetrics.MAX_ALLOWED_SEQUENCE;
-        } else if (quality == PASSWORD_QUALITY_ALPHABETIC) {
+        if (quality == PASSWORD_QUALITY_ALPHABETIC) {
             result.nonNumeric = 1;
         } else if (quality == PASSWORD_QUALITY_ALPHANUMERIC) {
             result.numeric = 1;
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/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/res/res/values/strings.xml b/core/res/res/values/strings.xml
index 9736c4b..93a0e25 100644
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -4983,10 +4983,10 @@
     <string name="confirm_battery_saver">OK</string>
 
     <!-- [CHAR_LIMIT=NONE] Battery saver: Feature description, with a "learn more" link. -->
-    <string name="battery_saver_description_with_learn_more">To extend battery life, Battery Saver:\n\n\u2022 Turns on Dark theme\n\u2022 Turns off or restricts background activity, some visual effects, and other features like \u201cHey Google\u201d\n\n<annotation id="url">Learn more</annotation></string>
+    <string name="battery_saver_description_with_learn_more">Battery Saver turns on Dark theme and limits or turns off background activity, some visual effects, and features like \u201cHey Google\u201d\n\n<annotation id="url">Learn more</annotation></string>
 
     <!-- [CHAR_LIMIT=NONE] Battery saver: Feature description, without a "learn more" link. -->
-    <string name="battery_saver_description">To extend battery life, Battery Saver:\n\n\u2022 Turns on Dark theme\n\u2022 Turns off or restricts background activity, some visual effects, and other features like \u201cHey Google\u201d</string>
+    <string name="battery_saver_description">Battery Saver turns on Dark theme and limits or turns off background activity, some visual effects, and features like \u201cHey Google\u201d.</string>
 
     <!-- [CHAR_LIMIT=NONE] Data saver: Feature description -->
     <string name="data_saver_description">To help reduce data usage, Data Saver prevents some apps from sending or receiving data in the background. An app you’re currently using can access data, but may do so less frequently. This may mean, for example, that images don’t display until you tap them.</string>
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/admin/PasswordPolicyTest.java b/core/tests/coretests/src/android/app/admin/PasswordPolicyTest.java
index e951054..f1be173 100644
--- a/core/tests/coretests/src/android/app/admin/PasswordPolicyTest.java
+++ b/core/tests/coretests/src/android/app/admin/PasswordPolicyTest.java
@@ -28,6 +28,7 @@
 import static com.android.internal.widget.LockPatternUtils.CREDENTIAL_TYPE_NONE;
 import static com.android.internal.widget.LockPatternUtils.CREDENTIAL_TYPE_PASSWORD;
 import static com.android.internal.widget.LockPatternUtils.CREDENTIAL_TYPE_PATTERN;
+import static com.android.internal.widget.LockPatternUtils.CREDENTIAL_TYPE_PIN;
 
 import static org.junit.Assert.assertEquals;
 
@@ -80,7 +81,7 @@
     public void testGetMinMetrics_numeric() {
         PasswordPolicy policy = testPolicy(PASSWORD_QUALITY_NUMERIC);
         PasswordMetrics minMetrics = policy.getMinMetrics();
-        assertEquals(CREDENTIAL_TYPE_PASSWORD, minMetrics.credType);
+        assertEquals(CREDENTIAL_TYPE_PIN, minMetrics.credType);
         assertEquals(TEST_VALUE, minMetrics.length);
         assertEquals(0, minMetrics.numeric); // numeric can doesn't really require digits.
         assertEquals(0, minMetrics.letters);
@@ -104,7 +105,7 @@
     public void testGetMinMetrics_numericComplex() {
         PasswordPolicy policy = testPolicy(PASSWORD_QUALITY_NUMERIC_COMPLEX);
         PasswordMetrics minMetrics = policy.getMinMetrics();
-        assertEquals(CREDENTIAL_TYPE_PASSWORD, minMetrics.credType);
+        assertEquals(CREDENTIAL_TYPE_PIN, minMetrics.credType);
         assertEquals(TEST_VALUE, minMetrics.length);
         assertEquals(0, minMetrics.numeric);
         assertEquals(0, minMetrics.letters);
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/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/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/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/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