Merge "AudioDeviceInventory: fix purge of device role cache." into udc-dev
diff --git a/core/java/android/animation/AnimatorInflater.java b/core/java/android/animation/AnimatorInflater.java
index 2198fcd..f67c68e 100644
--- a/core/java/android/animation/AnimatorInflater.java
+++ b/core/java/android/animation/AnimatorInflater.java
@@ -111,20 +111,20 @@
             float pathErrorScale) throws NotFoundException {
         final ConfigurationBoundResourceCache<Animator> animatorCache = resources
                 .getAnimatorCache();
-        ConfigurationBoundResourceCache.Entry<Animator> animatorEntry =
-                animatorCache.getInstance(id, resources, theme);
-        if (animatorEntry.hasValue()) {
+        Animator animator = animatorCache.getInstance(id, resources, theme);
+        if (animator != null) {
             if (DBG_ANIMATOR_INFLATER) {
                 Log.d(TAG, "loaded animator from cache, " + resources.getResourceName(id));
             }
-            return animatorEntry.getValue();
+            return animator;
         } else if (DBG_ANIMATOR_INFLATER) {
             Log.d(TAG, "cache miss for animator " + resources.getResourceName(id));
         }
+        int cacheGeneration = animatorCache.getGeneration();
         XmlResourceParser parser = null;
         try {
             parser = resources.getAnimation(id);
-            Animator animator = createAnimatorFromXml(resources, theme, parser, pathErrorScale);
+            animator = createAnimatorFromXml(resources, theme, parser, pathErrorScale);
             if (animator != null) {
                 animator.appendChangingConfigurations(getChangingConfigs(resources, id));
                 final ConstantState<Animator> constantState = animator.createConstantState();
@@ -132,7 +132,7 @@
                     if (DBG_ANIMATOR_INFLATER) {
                         Log.d(TAG, "caching animator for res " + resources.getResourceName(id));
                     }
-                    animatorCache.put(id, theme, constantState, animatorEntry.getGeneration());
+                    animatorCache.put(id, theme, constantState, cacheGeneration);
                     // create a new animator so that cached version is never used by the user
                     animator = constantState.newInstance(resources, theme);
                 }
@@ -161,22 +161,22 @@
         final ConfigurationBoundResourceCache<StateListAnimator> cache = resources
                 .getStateListAnimatorCache();
         final Theme theme = context.getTheme();
-        ConfigurationBoundResourceCache.Entry<StateListAnimator> animatorEntry =
-                cache.getInstance(id, resources, theme);
-        if (animatorEntry.hasValue()) {
-            return animatorEntry.getValue();
+        StateListAnimator animator = cache.getInstance(id, resources, theme);
+        if (animator != null) {
+            return animator;
         }
+        int cacheGeneration = cache.getGeneration();
         XmlResourceParser parser = null;
         try {
             parser = resources.getAnimation(id);
-            StateListAnimator animator =
+            animator =
                     createStateListAnimatorFromXml(context, parser, Xml.asAttributeSet(parser));
             if (animator != null) {
                 animator.appendChangingConfigurations(getChangingConfigs(resources, id));
                 final ConstantState<StateListAnimator> constantState = animator
                         .createConstantState();
                 if (constantState != null) {
-                    cache.put(id, theme, constantState, animatorEntry.getGeneration());
+                    cache.put(id, theme, constantState, cacheGeneration);
                     // return a clone so that the animator in constant state is never used.
                     animator = constantState.newInstance(resources, theme);
                 }
diff --git a/core/java/android/app/admin/WifiSsidPolicy.java b/core/java/android/app/admin/WifiSsidPolicy.java
index ed53967..ffc4480 100644
--- a/core/java/android/app/admin/WifiSsidPolicy.java
+++ b/core/java/android/app/admin/WifiSsidPolicy.java
@@ -136,7 +136,7 @@
     }
 
     /**
-     * Two instances of WifiSsidPolicy is considered equal if they have
+     * Two instances of WifiSsidPolicy are considered equal if they have
      * the same WifiSsidPolicyType and the same set of WifiSsids
      */
     @Override
diff --git a/core/java/android/content/pm/PackageParser.java b/core/java/android/content/pm/PackageParser.java
index 960d10a..048289f 100644
--- a/core/java/android/content/pm/PackageParser.java
+++ b/core/java/android/content/pm/PackageParser.java
@@ -2628,15 +2628,6 @@
             return Build.VERSION_CODES.CUR_DEVELOPMENT;
         }
 
-        // STOPSHIP: hack for the pre-release SDK
-        if (platformSdkCodenames.length == 0
-                && Build.VERSION.KNOWN_CODENAMES.stream().max(String::compareTo).orElse("").equals(
-                targetCode)) {
-            Slog.w(TAG, "Package requires development platform " + targetCode
-                    + ", returning current version " + Build.VERSION.SDK_INT);
-            return Build.VERSION.SDK_INT;
-        }
-
         // Otherwise, we're looking at an incompatible pre-release SDK.
         if (platformSdkCodenames.length > 0) {
             outError[0] = "Requires development platform " + targetCode
@@ -2708,15 +2699,6 @@
             return Build.VERSION_CODES.CUR_DEVELOPMENT;
         }
 
-        // STOPSHIP: hack for the pre-release SDK
-        if (platformSdkCodenames.length == 0
-                && Build.VERSION.KNOWN_CODENAMES.stream().max(String::compareTo).orElse("").equals(
-                minCode)) {
-            Slog.w(TAG, "Package requires min development platform " + minCode
-                    + ", returning current version " + Build.VERSION.SDK_INT);
-            return Build.VERSION.SDK_INT;
-        }
-
         // Otherwise, we're looking at an incompatible pre-release SDK.
         if (platformSdkCodenames.length > 0) {
             outError[0] = "Requires development platform " + minCode
diff --git a/core/java/android/content/pm/parsing/FrameworkParsingPackageUtils.java b/core/java/android/content/pm/parsing/FrameworkParsingPackageUtils.java
index 8cc4cdb..3e1c5bb 100644
--- a/core/java/android/content/pm/parsing/FrameworkParsingPackageUtils.java
+++ b/core/java/android/content/pm/parsing/FrameworkParsingPackageUtils.java
@@ -316,15 +316,6 @@
             return input.success(Build.VERSION_CODES.CUR_DEVELOPMENT);
         }
 
-        // STOPSHIP: hack for the pre-release SDK
-        if (platformSdkCodenames.length == 0
-                && Build.VERSION.KNOWN_CODENAMES.stream().max(String::compareTo).orElse("").equals(
-                        minCode)) {
-            Slog.w(TAG, "Parsed package requires min development platform " + minCode
-                    + ", returning current version " + Build.VERSION.SDK_INT);
-            return input.success(Build.VERSION.SDK_INT);
-        }
-
         // Otherwise, we're looking at an incompatible pre-release SDK.
         if (platformSdkCodenames.length > 0) {
             return input.error(PackageManager.INSTALL_FAILED_OLDER_SDK,
@@ -377,27 +368,19 @@
             return input.success(targetVers);
         }
 
-        // If it's a pre-release SDK and the codename matches this platform, it
-        // definitely targets this SDK.
-        if (matchTargetCode(platformSdkCodenames, targetCode)) {
-            return input.success(Build.VERSION_CODES.CUR_DEVELOPMENT);
-        }
-
-        // STOPSHIP: hack for the pre-release SDK
-        if (platformSdkCodenames.length == 0
-                && Build.VERSION.KNOWN_CODENAMES.stream().max(String::compareTo).orElse("").equals(
-                        targetCode)) {
-            Slog.w(TAG, "Parsed package requires development platform " + targetCode
-                    + ", returning current version " + Build.VERSION.SDK_INT);
-            return input.success(Build.VERSION.SDK_INT);
-        }
-
         try {
             if (allowUnknownCodenames && UnboundedSdkLevel.isAtMost(targetCode)) {
                 return input.success(Build.VERSION_CODES.CUR_DEVELOPMENT);
             }
         } catch (IllegalArgumentException e) {
-            return input.error(PackageManager.INSTALL_FAILED_OLDER_SDK, "Bad package SDK");
+            // isAtMost() throws it when encountering an older SDK codename
+            return input.error(PackageManager.INSTALL_FAILED_OLDER_SDK, e.getMessage());
+        }
+
+        // If it's a pre-release SDK and the codename matches this platform, it
+        // definitely targets this SDK.
+        if (matchTargetCode(platformSdkCodenames, targetCode)) {
+            return input.success(Build.VERSION_CODES.CUR_DEVELOPMENT);
         }
 
         // Otherwise, we're looking at an incompatible pre-release SDK.
diff --git a/core/java/android/content/res/ConfigurationBoundResourceCache.java b/core/java/android/content/res/ConfigurationBoundResourceCache.java
index 4da3c18..5e10a57 100644
--- a/core/java/android/content/res/ConfigurationBoundResourceCache.java
+++ b/core/java/android/content/res/ConfigurationBoundResourceCache.java
@@ -37,16 +37,16 @@
      * @param key a key that uniquely identifies the drawable resource
      * @param resources a Resources object from which to create new instances.
      * @param theme the theme where the resource will be used
-     * @return an Entry wrapping a new instance of the resource, or {@code null} if not in
+     * @return a new instance of the resource, or {@code null} if not in
      *         the cache
      */
-    public Entry<T> getInstance(long key, Resources resources, Resources.Theme theme) {
-        final Entry<ConstantState<T>> e = get(key, theme);
-        if (e.hasValue()) {
-            return new Entry<>(e.getValue().newInstance(resources, theme), e.getGeneration());
+    public T getInstance(long key, Resources resources, Resources.Theme theme) {
+        final ConstantState<T> entry = get(key, theme);
+        if (entry != null) {
+            return entry.newInstance(resources, theme);
         }
 
-        return new Entry<>(null, e.getGeneration());
+        return null;
     }
 
     @Override
diff --git a/core/java/android/content/res/DrawableCache.java b/core/java/android/content/res/DrawableCache.java
index b51d14a..d0ebe33 100644
--- a/core/java/android/content/res/DrawableCache.java
+++ b/core/java/android/content/res/DrawableCache.java
@@ -40,32 +40,14 @@
      */
     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
     public Drawable getInstance(long key, Resources resources, Resources.Theme theme) {
-        final Entry<Drawable.ConstantState> entry = get(key, theme);
-        if (entry.getValue() != null) {
-            return entry.getValue().newDrawable(resources, theme);
+        final Drawable.ConstantState entry = get(key, theme);
+        if (entry != null) {
+            return entry.newDrawable(resources, theme);
         }
 
         return null;
     }
 
-    /**
-     * If the resource is cached, creates and returns a new instance of it.
-     *
-     * @param key a key that uniquely identifies the drawable resource
-     * @param resources a Resources object from which to create new instances.
-     * @param theme the theme where the resource will be used
-     * @return an Entry wrapping a a new instance of the resource, or {@code null} if not in
-     *         the cache
-     */
-    public Entry<Drawable> getDrawable(long key, Resources resources, Resources.Theme theme) {
-        final Entry<Drawable.ConstantState> e = get(key, theme);
-        if (e.hasValue()) {
-            return new Entry<>(e.getValue().newDrawable(resources, theme), e.getGeneration());
-        }
-
-        return new Entry<>(null, e.getGeneration());
-    }
-
     @Override
     public boolean shouldInvalidateEntry(Drawable.ConstantState entry, int configChanges) {
         return Configuration.needNewResources(configChanges, entry.getChangingConfigurations());
diff --git a/core/java/android/content/res/ResourcesImpl.java b/core/java/android/content/res/ResourcesImpl.java
index 25154d5..1fdfcd0 100644
--- a/core/java/android/content/res/ResourcesImpl.java
+++ b/core/java/android/content/res/ResourcesImpl.java
@@ -650,21 +650,16 @@
                 key = (((long) value.assetCookie) << 32) | value.data;
             }
 
-            int cacheGeneration;
+            int cacheGeneration = caches.getGeneration();
             // First, check whether we have a cached version of this drawable
             // that was inflated against the specified theme. Skip the cache if
             // we're currently preloading or we're not using the cache.
             if (!mPreloading && useCache) {
-                final ThemedResourceCache.Entry<Drawable> cachedDrawable =
-                        caches.getDrawable(key, wrapper, theme);
-                if (cachedDrawable.hasValue()) {
-                    cachedDrawable.getValue().setChangingConfigurations(
-                            value.changingConfigurations);
-                    return cachedDrawable.getValue();
+                Drawable cachedDrawable = caches.getInstance(key, wrapper, theme);
+                if (cachedDrawable != null) {
+                    cachedDrawable.setChangingConfigurations(value.changingConfigurations);
+                    return cachedDrawable;
                 }
-                cacheGeneration = cachedDrawable.getGeneration();
-            } else {
-                cacheGeneration = ThemedResourceCache.UNDEFINED_GENERATION;
             }
 
             // Next, check preloaded drawables. Preloaded drawables may contain
@@ -1009,16 +1004,15 @@
             TypedValue value, int id) {
         final long key = (((long) value.assetCookie) << 32) | value.data;
         final ConfigurationBoundResourceCache<ComplexColor> cache = mComplexColorCache;
-        ThemedResourceCache.Entry<ComplexColor> complexColorEntry =
-                cache.getInstance(key, wrapper, theme);
-        if (complexColorEntry.hasValue()) {
-            return complexColorEntry.getValue();
+        ComplexColor complexColor = cache.getInstance(key, wrapper, theme);
+        if (complexColor != null) {
+            return complexColor;
         }
+        int cacheGeneration = cache.getGeneration();
 
         final android.content.res.ConstantState<ComplexColor> factory =
                 sPreloadedComplexColors.get(key);
 
-        ComplexColor complexColor = null;
         if (factory != null) {
             complexColor = factory.newInstance(wrapper, theme);
         }
@@ -1035,8 +1029,7 @@
                     sPreloadedComplexColors.put(key, complexColor.getConstantState());
                 }
             } else {
-                cache.put(key, theme, complexColor.getConstantState(),
-                        complexColorEntry.getGeneration());
+                cache.put(key, theme, complexColor.getConstantState(), cacheGeneration);
             }
         }
         return complexColor;
diff --git a/core/java/android/content/res/ThemedResourceCache.java b/core/java/android/content/res/ThemedResourceCache.java
index e7fd275..a7cd168 100644
--- a/core/java/android/content/res/ThemedResourceCache.java
+++ b/core/java/android/content/res/ThemedResourceCache.java
@@ -41,29 +41,6 @@
 
     private int mGeneration;
 
-    public static class Entry<S> {
-        private S mValue;
-        private int mGeneration;
-
-
-        public S getValue() {
-            return mValue;
-        }
-
-        public boolean hasValue() {
-            return mValue != null;
-        }
-
-        public int getGeneration() {
-            return mGeneration;
-        }
-
-        Entry(S value, int generation) {
-            this.mValue = value;
-            this.mGeneration = generation;
-        }
-    }
-
     /**
      * Adds a new theme-dependent entry to the cache.
      *
@@ -109,6 +86,15 @@
     }
 
     /**
+     * Returns the current generation of the cache
+     *
+     * @return The current generation
+     */
+    public int getGeneration() {
+        return mGeneration;
+    }
+
+    /**
      * Returns an entry from the cache.
      *
      * @param key a key that uniquely identifies the entry
@@ -116,7 +102,7 @@
      * @return a cached entry, or {@code null} if not in the cache
      */
     @Nullable
-    public Entry get(long key, @Nullable Theme theme) {
+    public T get(long key, @Nullable Theme theme) {
         // The themed (includes null-themed) and unthemed caches are mutually
         // exclusive, so we'll give priority to whichever one we think we'll
         // hit first. Since most of the framework drawables are themed, that's
@@ -126,7 +112,7 @@
             if (themedEntries != null) {
                 final WeakReference<T> themedEntry = themedEntries.get(key);
                 if (themedEntry != null) {
-                    return new Entry(themedEntry.get(), mGeneration);
+                    return themedEntry.get();
                 }
             }
 
@@ -134,14 +120,15 @@
             if (unthemedEntries != null) {
                 final WeakReference<T> unthemedEntry = unthemedEntries.get(key);
                 if (unthemedEntry != null) {
-                    return new Entry(unthemedEntry.get(), mGeneration);
+                    return unthemedEntry.get();
                 }
             }
         }
 
-        return new Entry(null, mGeneration);
+        return null;
     }
 
+
     /**
      * Prunes cache entries that have been invalidated by a configuration
      * change.
diff --git a/core/java/android/hardware/camera2/impl/CameraAdvancedExtensionSessionImpl.java b/core/java/android/hardware/camera2/impl/CameraAdvancedExtensionSessionImpl.java
index d87226c..65d4b43 100644
--- a/core/java/android/hardware/camera2/impl/CameraAdvancedExtensionSessionImpl.java
+++ b/core/java/android/hardware/camera2/impl/CameraAdvancedExtensionSessionImpl.java
@@ -77,18 +77,18 @@
     private static final String TAG = "CameraAdvancedExtensionSessionImpl";
 
     private final Executor mExecutor;
-    private final CameraDevice mCameraDevice;
+    private CameraDevice mCameraDevice;
     private final Map<String, CameraMetadataNative> mCharacteristicsMap;
     private final long mExtensionClientId;
     private final Handler mHandler;
     private final HandlerThread mHandlerThread;
     private final CameraExtensionSession.StateCallback mCallbacks;
-    private final IAdvancedExtenderImpl mAdvancedExtender;
+    private IAdvancedExtenderImpl mAdvancedExtender;
     // maps registered camera surfaces to extension output configs
     private final HashMap<Surface, CameraOutputConfig> mCameraConfigMap = new HashMap<>();
     // maps camera extension output ids to camera registered image readers
     private final HashMap<Integer, ImageReader> mReaderMap = new HashMap<>();
-    private final RequestProcessor mRequestProcessor = new RequestProcessor();
+    private RequestProcessor mRequestProcessor = new RequestProcessor();
     private final int mSessionId;
 
     private Surface mClientRepeatingRequestSurface;
@@ -100,7 +100,7 @@
     private final ExtensionSessionStatsAggregator mStatsAggregator;
 
     private boolean mInitialized;
-
+    private boolean mSessionClosed;
 
     // Lock to synchronize cross-thread access to device public interface
     final Object mInterfaceLock;
@@ -237,6 +237,7 @@
         mHandlerThread.start();
         mHandler = new Handler(mHandlerThread.getLooper());
         mInitialized = false;
+        mSessionClosed = false;
         mInitializeHandler = new InitializeSessionHandler();
         mSessionId = sessionId;
         mInterfaceLock = cameraDevice.mInterfaceLock;
@@ -424,7 +425,7 @@
                 mSessionProcessor.setParameters(request);
 
                 seqId = mSessionProcessor.startRepeating(new RequestCallbackHandler(request,
-                        executor, listener));
+                        executor, listener, mCameraDevice.getId()));
             } catch (RemoteException e) {
                 throw new CameraAccessException(CameraAccessException.CAMERA_ERROR,
                         "Failed to enable repeating request, extension service failed to respond!");
@@ -452,7 +453,7 @@
                     mSessionProcessor.setParameters(request);
 
                     seqId = mSessionProcessor.startCapture(new RequestCallbackHandler(request,
-                            executor, listener), isPostviewRequested);
+                            executor, listener, mCameraDevice.getId()), isPostviewRequested);
                 } catch (RemoteException e) {
                     throw new CameraAccessException(CameraAccessException.CAMERA_ERROR, "Failed " +
                             " to submit capture request, extension service failed to respond!");
@@ -460,8 +461,8 @@
             } else if ((mClientRepeatingRequestSurface != null) &&
                     request.containsTarget(mClientRepeatingRequestSurface)) {
                 try {
-                    seqId = mSessionProcessor.startTrigger(request,
-                            new RequestCallbackHandler(request, executor, listener));
+                    seqId = mSessionProcessor.startTrigger(request, new RequestCallbackHandler(
+                            request, executor, listener, mCameraDevice.getId()));
                 } catch (RemoteException e) {
                     throw new CameraAccessException(CameraAccessException.CAMERA_ERROR, "Failed " +
                             " to submit trigger request, extension service failed to respond!");
@@ -528,6 +529,7 @@
                     mCaptureSession.stopRepeating();
                     mSessionProcessor.stopRepeating();
                     mSessionProcessor.onCaptureSessionEnd();
+                    mSessionClosed = true;
                 } catch (RemoteException e) {
                     Log.e(TAG, "Failed to stop the repeating request or end the session,"
                             + " , extension service does not respond!") ;
@@ -560,6 +562,9 @@
 
             if (mSessionProcessor != null) {
                 try {
+                    if (!mSessionClosed) {
+                        mSessionProcessor.onCaptureSessionEnd();
+                    }
                     mSessionProcessor.deInitSession();
                 } catch (RemoteException e) {
                     Log.e(TAG, "Failed to de-initialize session processor, extension service"
@@ -584,6 +589,10 @@
 
             mClientRepeatingRequestSurface = null;
             mClientCaptureSurface = null;
+            mCaptureSession = null;
+            mRequestProcessor = null;
+            mCameraDevice = null;
+            mAdvancedExtender = null;
         }
 
         if (notifyClose && !skipCloseNotification) {
@@ -706,13 +715,16 @@
         private final CaptureRequest mClientRequest;
         private final Executor mClientExecutor;
         private final ExtensionCaptureCallback mClientCallbacks;
+        private final String mCameraId;
 
         private RequestCallbackHandler(@NonNull CaptureRequest clientRequest,
                 @NonNull Executor clientExecutor,
-                @NonNull ExtensionCaptureCallback clientCallbacks) {
+                @NonNull ExtensionCaptureCallback clientCallbacks,
+                @NonNull String cameraId) {
             mClientRequest = clientRequest;
             mClientExecutor = clientExecutor;
             mClientCallbacks = clientCallbacks;
+            mCameraId = cameraId;
         }
 
         @Override
@@ -784,7 +796,7 @@
             }
 
             result.set(CaptureResult.SENSOR_TIMESTAMP, timestamp);
-            TotalCaptureResult totalResult = new TotalCaptureResult(mCameraDevice.getId(), result,
+            TotalCaptureResult totalResult = new TotalCaptureResult(mCameraId, result,
                     mClientRequest, requestId, timestamp, new ArrayList<>(), mSessionId,
                     new PhysicalCaptureResultInfo[0]);
             final long ident = Binder.clearCallingIdentity();
@@ -1036,14 +1048,20 @@
         public int submitBurst(List<Request> requests, IRequestCallback callback) {
             int seqId = -1;
             try {
-                CaptureCallbackHandler captureCallback = new CaptureCallbackHandler(callback);
-                ArrayList<CaptureRequest> captureRequests = new ArrayList<>();
-                for (Request request : requests) {
-                    captureRequests.add(initializeCaptureRequest(mCameraDevice, request,
-                            mCameraConfigMap));
+                synchronized (mInterfaceLock) {
+                    if (!mInitialized) {
+                        return seqId;
+                    }
+
+                    CaptureCallbackHandler captureCallback = new CaptureCallbackHandler(callback);
+                    ArrayList<CaptureRequest> captureRequests = new ArrayList<>();
+                    for (Request request : requests) {
+                        captureRequests.add(initializeCaptureRequest(mCameraDevice, request,
+                                mCameraConfigMap));
+                    }
+                    seqId = mCaptureSession.captureBurstRequests(captureRequests,
+                            new CameraExtensionUtils.HandlerExecutor(mHandler), captureCallback);
                 }
-                seqId = mCaptureSession.captureBurstRequests(captureRequests,
-                        new CameraExtensionUtils.HandlerExecutor(mHandler), captureCallback);
             } catch (CameraAccessException e) {
                 Log.e(TAG, "Failed to submit capture requests!");
             } catch (IllegalStateException e) {
@@ -1057,11 +1075,17 @@
         public int setRepeating(Request request, IRequestCallback callback) {
             int seqId = -1;
             try {
-                CaptureRequest repeatingRequest = initializeCaptureRequest(mCameraDevice,
+                synchronized (mInterfaceLock) {
+                    if (!mInitialized) {
+                        return seqId;
+                    }
+
+                    CaptureRequest repeatingRequest = initializeCaptureRequest(mCameraDevice,
                             request, mCameraConfigMap);
-                CaptureCallbackHandler captureCallback = new CaptureCallbackHandler(callback);
-                seqId = mCaptureSession.setSingleRepeatingRequest(repeatingRequest,
-                        new CameraExtensionUtils.HandlerExecutor(mHandler), captureCallback);
+                    CaptureCallbackHandler captureCallback = new CaptureCallbackHandler(callback);
+                    seqId = mCaptureSession.setSingleRepeatingRequest(repeatingRequest,
+                            new CameraExtensionUtils.HandlerExecutor(mHandler), captureCallback);
+                }
             } catch (CameraAccessException e) {
                 Log.e(TAG, "Failed to enable repeating request!");
             } catch (IllegalStateException e) {
@@ -1074,7 +1098,13 @@
         @Override
         public void abortCaptures() {
             try {
-                mCaptureSession.abortCaptures();
+                synchronized (mInterfaceLock) {
+                    if (!mInitialized) {
+                        return;
+                    }
+
+                    mCaptureSession.abortCaptures();
+                }
             } catch (CameraAccessException e) {
                 Log.e(TAG, "Failed during capture abort!");
             } catch (IllegalStateException e) {
@@ -1085,7 +1115,13 @@
         @Override
         public void stopRepeating() {
             try {
-                mCaptureSession.stopRepeating();
+                synchronized (mInterfaceLock) {
+                    if (!mInitialized) {
+                        return;
+                    }
+
+                    mCaptureSession.stopRepeating();
+                }
             } catch (CameraAccessException e) {
                 Log.e(TAG, "Failed during repeating capture stop!");
             } catch (IllegalStateException e) {
diff --git a/core/java/android/service/dreams/DreamOverlayService.java b/core/java/android/service/dreams/DreamOverlayService.java
index 5469916..9a02b74b 100644
--- a/core/java/android/service/dreams/DreamOverlayService.java
+++ b/core/java/android/service/dreams/DreamOverlayService.java
@@ -71,13 +71,7 @@
 
         @Override
         public void wakeUp() {
-            mService.wakeUp(this, () -> {
-                try {
-                    mDreamOverlayCallback.onWakeUpComplete();
-                } catch (RemoteException e) {
-                    Log.e(TAG, "Could not notify dream of wakeUp", e);
-                }
-            });
+            mService.wakeUp(this);
         }
 
         @Override
@@ -125,14 +119,14 @@
         mCurrentClient = null;
     }
 
-    private void wakeUp(OverlayClient client, Runnable callback) {
+    private void wakeUp(OverlayClient client) {
         // Run on executor as this is a binder call from OverlayClient.
         mExecutor.execute(() -> {
             if (mCurrentClient != client) {
                 return;
             }
 
-            onWakeUp(callback);
+            onWakeUp();
         });
     }
 
@@ -190,19 +184,10 @@
 
     /**
      * This method is overridden by implementations to handle when the dream has been requested
-     * to wakeup. This allows any overlay animations to run. By default, the method will invoke
-     * the callback immediately.
-     *
-     * This callback will be run on the {@link Executor} provided in the constructor if provided, or
-     * on the main executor if none was provided.
-     *
-     * @param onCompleteCallback The callback to trigger to notify the dream service that the
-     *                           overlay has completed waking up.
+     * to wakeup.
      * @hide
      */
-    public void onWakeUp(@NonNull Runnable onCompleteCallback) {
-        onCompleteCallback.run();
-    }
+    public void onWakeUp() {}
 
     /**
      * This method is overridden by implementations to handle when the dream has ended. There may
diff --git a/core/java/android/service/dreams/DreamService.java b/core/java/android/service/dreams/DreamService.java
index 3a32352..cd57de5 100644
--- a/core/java/android/service/dreams/DreamService.java
+++ b/core/java/android/service/dreams/DreamService.java
@@ -249,13 +249,6 @@
             // Simply finish dream when exit is requested.
             mHandler.post(() -> finish());
         }
-
-        @Override
-        public void onWakeUpComplete() {
-            // Finish the dream once overlay animations are complete. Execute on handler since
-            // this is coming in on the overlay binder.
-            mHandler.post(() -> finish());
-        }
     };
 
 
@@ -923,6 +916,7 @@
                     overlay.wakeUp();
                 } catch (RemoteException e) {
                     Slog.e(TAG, "Error waking the overlay service", e);
+                } finally {
                     finish();
                 }
             });
diff --git a/core/java/android/service/dreams/IDreamOverlayCallback.aidl b/core/java/android/service/dreams/IDreamOverlayCallback.aidl
index 4ad63f1..ec76a33 100644
--- a/core/java/android/service/dreams/IDreamOverlayCallback.aidl
+++ b/core/java/android/service/dreams/IDreamOverlayCallback.aidl
@@ -28,7 +28,4 @@
     * Invoked to request the dream exit.
     */
     void onExitRequested();
-
-    /** Invoked when the dream overlay wakeUp animation is complete. */
-    void onWakeUpComplete();
 }
\ No newline at end of file
diff --git a/core/java/android/service/wallpaper/WallpaperService.java b/core/java/android/service/wallpaper/WallpaperService.java
index 4e086c2..dbc1be1 100644
--- a/core/java/android/service/wallpaper/WallpaperService.java
+++ b/core/java/android/service/wallpaper/WallpaperService.java
@@ -44,6 +44,7 @@
 import android.compat.annotation.UnsupportedAppUsage;
 import android.content.Context;
 import android.content.Intent;
+import android.content.pm.PackageManager;
 import android.content.res.Configuration;
 import android.graphics.BLASTBufferQueue;
 import android.graphics.Bitmap;
@@ -190,6 +191,9 @@
     private Handler mBackgroundHandler;
     private HandlerThread mBackgroundThread;
 
+    // TODO (b/287037772) remove this flag and the forceReport argument in reportVisibility
+    private boolean mIsWearOs;
+
     static final class WallpaperCommand {
         String action;
         int x;
@@ -2282,7 +2286,8 @@
                     @Override
                     public void onDisplayChanged(int displayId) {
                         if (mDisplay.getDisplayId() == displayId) {
-                            boolean forceReport = mDisplay.getState() != Display.STATE_DOZE_SUSPEND;
+                            boolean forceReport = mIsWearOs
+                                    && mDisplay.getState() != Display.STATE_DOZE_SUSPEND;
                             reportVisibility(forceReport);
                         }
                     }
@@ -2734,6 +2739,7 @@
         mBackgroundThread = new HandlerThread("DefaultWallpaperLocalColorExtractor");
         mBackgroundThread.start();
         mBackgroundHandler = new Handler(mBackgroundThread.getLooper());
+        mIsWearOs = getPackageManager().hasSystemFeature(PackageManager.FEATURE_WATCH);
         super.onCreate();
         Trace.endSection();
     }
diff --git a/core/java/android/view/InsetsState.java b/core/java/android/view/InsetsState.java
index 5b974cd..b55d25a 100644
--- a/core/java/android/view/InsetsState.java
+++ b/core/java/android/view/InsetsState.java
@@ -177,7 +177,8 @@
         if ((legacyWindowFlags & FLAG_FULLSCREEN) != 0) {
             compatInsetsTypes &= ~statusBars();
         }
-        if (clearsCompatInsets(windowType, legacyWindowFlags, windowingMode)) {
+        if (clearsCompatInsets(windowType, legacyWindowFlags, windowingMode)
+                && !alwaysConsumeSystemBars) {
             compatInsetsTypes = 0;
         }
 
diff --git a/core/java/com/android/internal/policy/DecorView.java b/core/java/com/android/internal/policy/DecorView.java
index 15f70f3..af1fdd7 100644
--- a/core/java/com/android/internal/policy/DecorView.java
+++ b/core/java/com/android/internal/policy/DecorView.java
@@ -1111,8 +1111,13 @@
                     : controller.getSystemBarsAppearance();
 
             if (insets != null) {
-                final boolean clearsCompatInsets = clearsCompatInsets(attrs.type, attrs.flags,
-                        getResources().getConfiguration().windowConfiguration.getWindowingMode());
+                mLastShouldAlwaysConsumeSystemBars = insets.shouldAlwaysConsumeSystemBars();
+
+                final boolean clearsCompatInsets =
+                        clearsCompatInsets(attrs.type, attrs.flags,
+                                getResources().getConfiguration().windowConfiguration
+                                        .getWindowingMode())
+                        && !mLastShouldAlwaysConsumeSystemBars;
                 final Insets stableBarInsets = insets.getInsetsIgnoringVisibility(
                         WindowInsets.Type.systemBars());
                 final Insets systemInsets = clearsCompatInsets
@@ -1143,7 +1148,6 @@
                 disallowAnimate |= (hasLeftStableInset != mLastHasLeftStableInset);
                 mLastHasLeftStableInset = hasLeftStableInset;
 
-                mLastShouldAlwaysConsumeSystemBars = insets.shouldAlwaysConsumeSystemBars();
                 mLastSuppressScrimTypes = insets.getSuppressScrimTypes();
             }
 
diff --git a/core/tests/coretests/src/android/content/res/ConfigurationBoundResourceCacheTest.java b/core/tests/coretests/src/android/content/res/ConfigurationBoundResourceCacheTest.java
index b5f18c2..6ffdee1 100644
--- a/core/tests/coretests/src/android/content/res/ConfigurationBoundResourceCacheTest.java
+++ b/core/tests/coretests/src/android/content/res/ConfigurationBoundResourceCacheTest.java
@@ -45,7 +45,7 @@
     @SmallTest
     public void testGetEmpty() {
         final Resources res = getActivity().getResources();
-        assertNull(mCache.getInstance(-1, res, null).getValue());
+        assertNull(mCache.getInstance(-1, res, null));
     }
 
     @SmallTest
@@ -53,9 +53,9 @@
         mCache.put(1, null, new DummyFloatConstantState(5f),
                 ThemedResourceCache.UNDEFINED_GENERATION);
         final Resources res = getActivity().getResources();
-        assertEquals(5f, mCache.getInstance(1, res, null).getValue());
-        assertNotSame(5f, mCache.getInstance(1, res, null).getValue());
-        assertEquals(false, mCache.getInstance(1, res, getActivity().getTheme()).hasValue());
+        assertEquals(5f, mCache.getInstance(1, res, null));
+        assertNotSame(5f, mCache.getInstance(1, res, null));
+        assertEquals(null, mCache.getInstance(1, res, getActivity().getTheme()));
     }
 
     @SmallTest
@@ -63,9 +63,9 @@
         mCache.put(1, getActivity().getTheme(), new DummyFloatConstantState(5f),
                 ThemedResourceCache.UNDEFINED_GENERATION);
         final Resources res = getActivity().getResources();
-        assertEquals(false, mCache.getInstance(1, res, null).hasValue());
-        assertEquals(5f, mCache.getInstance(1, res, getActivity().getTheme()).getValue());
-        assertNotSame(5f, mCache.getInstance(1, res, getActivity().getTheme()).getValue());
+        assertEquals(null, mCache.getInstance(1, res, null));
+        assertEquals(5f, mCache.getInstance(1, res, getActivity().getTheme()));
+        assertNotSame(5f, mCache.getInstance(1, res, getActivity().getTheme()));
     }
 
     @SmallTest
@@ -75,10 +75,10 @@
         mCache.put(1, null, new DummyFloatConstantState(10f),
                 ThemedResourceCache.UNDEFINED_GENERATION);
         final Resources res = getActivity().getResources();
-        assertEquals(10f, mCache.getInstance(1, res, null).getValue());
-        assertNotSame(10f, mCache.getInstance(1, res, null).getValue());
-        assertEquals(5f, mCache.getInstance(1, res, getActivity().getTheme()).getValue());
-        assertNotSame(5f, mCache.getInstance(1, res, getActivity().getTheme()).getValue());
+        assertEquals(10f, mCache.getInstance(1, res, null));
+        assertNotSame(10f, mCache.getInstance(1, res, null));
+        assertEquals(5f, mCache.getInstance(1, res, getActivity().getTheme()));
+        assertNotSame(5f, mCache.getInstance(1, res, getActivity().getTheme()));
     }
 
     @SmallTest
@@ -98,9 +98,9 @@
                 Configuration.ORIENTATION_PORTRAIT
                 : Configuration.ORIENTATION_LANDSCAPE;
         int changes = calcConfigChanges(res, newCnf);
-        assertEquals(staticDim, mCache.getInstance(key, res, getActivity().getTheme()).getValue());
+        assertEquals(staticDim, mCache.getInstance(key, res, getActivity().getTheme()));
         mCache.onConfigurationChange(changes);
-        assertEquals(staticDim, mCache.getInstance(key, res, getActivity().getTheme()).getValue());
+        assertEquals(staticDim, mCache.getInstance(key, res, getActivity().getTheme()));
     }
 
     @SmallTest
@@ -123,9 +123,9 @@
                 : Configuration.ORIENTATION_LANDSCAPE;
         int changes = calcConfigChanges(res, newCnf);
         assertEquals(changingDim,
-                mCache.getInstance(key, res, getActivity().getTheme()).getValue());
+                mCache.getInstance(key, res, getActivity().getTheme()));
         mCache.onConfigurationChange(changes);
-        assertNull(mCache.get(key, getActivity().getTheme()).getValue());
+        assertNull(mCache.get(key, getActivity().getTheme()));
     }
 
     @SmallTest
@@ -152,15 +152,15 @@
                 : Configuration.ORIENTATION_LANDSCAPE;
         int changes = calcConfigChanges(res, newCnf);
         assertEquals(staticDim, mCache.getInstance(R.dimen.resource_cache_test_generic, res,
-                getActivity().getTheme()).getValue());
+                getActivity().getTheme()));
         assertEquals(changingDim,
                 mCache.getInstance(R.dimen.resource_cache_test_orientation_dependent, res,
-                        getActivity().getTheme()).getValue());
+                        getActivity().getTheme()));
         mCache.onConfigurationChange(changes);
         assertEquals(staticDim, mCache.getInstance(R.dimen.resource_cache_test_generic, res,
-                getActivity().getTheme()).getValue());
+                getActivity().getTheme()));
         assertNull(mCache.getInstance(R.dimen.resource_cache_test_orientation_dependent, res,
-                getActivity().getTheme()).getValue());
+                getActivity().getTheme()));
     }
 
     @SmallTest
@@ -198,18 +198,18 @@
         for (int i = 0; i < 2; i++) {
             final Resources.Theme theme = i == 0 ? getActivity().getTheme() : null;
             assertEquals(staticDim,
-                    mCache.getInstance(R.dimen.resource_cache_test_generic, res, theme).getValue());
+                    mCache.getInstance(R.dimen.resource_cache_test_generic, res, theme));
             assertEquals(changingDim,
                     mCache.getInstance(R.dimen.resource_cache_test_orientation_dependent, res,
-                            theme).getValue());
+                            theme));
         }
         mCache.onConfigurationChange(changes);
         for (int i = 0; i < 2; i++) {
             final Resources.Theme theme = i == 0 ? getActivity().getTheme() : null;
             assertEquals(staticDim,
-                    mCache.getInstance(R.dimen.resource_cache_test_generic, res, theme).getValue());
+                    mCache.getInstance(R.dimen.resource_cache_test_generic, res, theme));
             assertNull(mCache.getInstance(R.dimen.resource_cache_test_orientation_dependent, res,
-                    theme).getValue());
+                    theme));
         }
     }
 
diff --git a/data/keyboards/Vendor_0957_Product_0001.kl b/data/keyboards/Vendor_0957_Product_0001.kl
index 54f8808..5d7fd85 100644
--- a/data/keyboards/Vendor_0957_Product_0001.kl
+++ b/data/keyboards/Vendor_0957_Product_0001.kl
@@ -45,6 +45,7 @@
 
 # custom keys
 key usage 0x000c01BB    TV_INPUT
+key usage 0x000c0186    MACRO_1
 
 key usage 0x000c0185    TV_TELETEXT
 key usage 0x000c0061    CAPTIONS
@@ -77,4 +78,4 @@
 key usage 0x000c0077    BUTTON_3     WAKE #YouTube
 key usage 0x000c0078    BUTTON_4     WAKE #Netflix
 key usage 0x000c0079    BUTTON_6     WAKE
-key usage 0x000c007A    BUTTON_7     WAKE
\ No newline at end of file
+key usage 0x000c007A    BUTTON_7     WAKE
diff --git a/libs/WindowManager/Jetpack/src/androidx/window/extensions/area/WindowAreaComponentImpl.java b/libs/WindowManager/Jetpack/src/androidx/window/extensions/area/WindowAreaComponentImpl.java
index 96190c4b..1e6e503 100644
--- a/libs/WindowManager/Jetpack/src/androidx/window/extensions/area/WindowAreaComponentImpl.java
+++ b/libs/WindowManager/Jetpack/src/androidx/window/extensions/area/WindowAreaComponentImpl.java
@@ -28,6 +28,7 @@
 import android.util.Pair;
 import android.view.Display;
 import android.view.DisplayAddress;
+import android.view.Surface;
 
 import androidx.annotation.NonNull;
 import androidx.annotation.Nullable;
@@ -36,6 +37,7 @@
 
 import com.android.internal.R;
 import com.android.internal.annotations.GuardedBy;
+import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.util.ArrayUtils;
 
 import java.util.Objects;
@@ -229,27 +231,43 @@
      * @since {@link WindowExtensions#VENDOR_API_LEVEL_3}
      */
     @Override
+    @NonNull
     public DisplayMetrics getRearDisplayMetrics() {
-        DisplayMetrics metrics = null;
+        DisplayMetrics rearDisplayMetrics = null;
 
         // DISPLAY_CATEGORY_REAR displays are only available when you are in the concurrent
         // display state, so we have to look through all displays to match the address
-        Display[] displays = mDisplayManager.getDisplays(
+        final Display[] displays = mDisplayManager.getDisplays(
                 DisplayManager.DISPLAY_CATEGORY_ALL_INCLUDING_DISABLED);
+
+
         for (int i = 0; i < displays.length; i++) {
             DisplayAddress.Physical address =
                     (DisplayAddress.Physical) displays[i].getAddress();
             if (mRearDisplayAddress == address.getPhysicalDisplayId()) {
-                metrics = new DisplayMetrics();
-                displays[i].getRealMetrics(metrics);
+                rearDisplayMetrics = new DisplayMetrics();
+                final Display rearDisplay = displays[i];
+
+                // We must always retrieve the metrics for the rear display regardless of if it is
+                // the default display or not.
+                rearDisplay.getRealMetrics(rearDisplayMetrics);
+
+                // TODO(b/287170025): This should be something like if (!rearDisplay.isEnabled)
+                //  instead. Currently when the rear display is disabled, its state is STATE_OFF.
+                if (rearDisplay.getDisplayId() != Display.DEFAULT_DISPLAY) {
+                    final Display defaultDisplay = mDisplayManager
+                            .getDisplay(Display.DEFAULT_DISPLAY);
+                    rotateRearDisplayMetricsIfNeeded(defaultDisplay.getRotation(),
+                            rearDisplay.getRotation(), rearDisplayMetrics);
+                }
                 break;
             }
         }
 
         synchronized (mLock) {
             // Update the rear display metrics with our latest value if one was received
-            if (metrics != null) {
-                mRearDisplayMetrics = metrics;
+            if (rearDisplayMetrics != null) {
+                mRearDisplayMetrics = rearDisplayMetrics;
             }
 
             return Objects.requireNonNullElseGet(mRearDisplayMetrics, DisplayMetrics::new);
@@ -540,6 +558,34 @@
         return mLastReportedRearDisplayPresentationStatus;
     }
 
+    @VisibleForTesting
+    static void rotateRearDisplayMetricsIfNeeded(
+            @Surface.Rotation int defaultDisplayRotation,
+            @Surface.Rotation int rearDisplayRotation,
+            @NonNull DisplayMetrics inOutMetrics) {
+        // If the rear display has a non-zero rotation, it means the backing DisplayContent /
+        // DisplayRotation is fresh.
+        if (rearDisplayRotation != Surface.ROTATION_0) {
+            return;
+        }
+
+        // If the default display is 0 or 180, the rear display must also be 0 or 180.
+        if (defaultDisplayRotation == Surface.ROTATION_0
+                || defaultDisplayRotation == Surface.ROTATION_180) {
+            return;
+        }
+
+        final int heightPixels = inOutMetrics.heightPixels;
+        final int widthPixels = inOutMetrics.widthPixels;
+        inOutMetrics.widthPixels = heightPixels;
+        inOutMetrics.heightPixels = widthPixels;
+
+        final int noncompatHeightPixels = inOutMetrics.noncompatHeightPixels;
+        final int noncompatWidthPixels = inOutMetrics.noncompatWidthPixels;
+        inOutMetrics.noncompatWidthPixels = noncompatHeightPixels;
+        inOutMetrics.noncompatHeightPixels = noncompatWidthPixels;
+    }
+
     /**
      * Callback for the {@link DeviceStateRequest} to be notified of when the request has been
      * activated or cancelled. This callback provides information to the client library
diff --git a/libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/area/WindowAreaComponentImplTests.java b/libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/area/WindowAreaComponentImplTests.java
new file mode 100644
index 0000000..ccb4ebe
--- /dev/null
+++ b/libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/area/WindowAreaComponentImplTests.java
@@ -0,0 +1,96 @@
+/*
+ * Copyright (C) 2023 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 androidx.window.extensions.area;
+
+import static org.junit.Assert.assertEquals;
+
+import android.platform.test.annotations.Presubmit;
+import android.util.DisplayMetrics;
+import android.view.Surface;
+
+import androidx.test.ext.junit.runners.AndroidJUnit4;
+import androidx.test.filters.SmallTest;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@Presubmit
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class WindowAreaComponentImplTests {
+
+    private final DisplayMetrics mTestDisplayMetrics = new DisplayMetrics();
+
+    @Before
+    public void setup() {
+        mTestDisplayMetrics.widthPixels = 1;
+        mTestDisplayMetrics.heightPixels = 2;
+        mTestDisplayMetrics.noncompatWidthPixels = 3;
+        mTestDisplayMetrics.noncompatHeightPixels = 4;
+    }
+
+    /**
+     * Cases where the rear display metrics does not need to be transformed.
+     */
+    @Test
+    public void testRotateRearDisplayMetrics_noTransformNeeded() {
+        final DisplayMetrics originalMetrics = new DisplayMetrics();
+        originalMetrics.setTo(mTestDisplayMetrics);
+
+        WindowAreaComponentImpl.rotateRearDisplayMetricsIfNeeded(
+                Surface.ROTATION_0, Surface.ROTATION_0, mTestDisplayMetrics);
+        assertEquals(originalMetrics, mTestDisplayMetrics);
+
+        WindowAreaComponentImpl.rotateRearDisplayMetricsIfNeeded(
+                Surface.ROTATION_180, Surface.ROTATION_180, mTestDisplayMetrics);
+        assertEquals(originalMetrics, mTestDisplayMetrics);
+
+        WindowAreaComponentImpl.rotateRearDisplayMetricsIfNeeded(
+                Surface.ROTATION_0, Surface.ROTATION_180, mTestDisplayMetrics);
+        assertEquals(originalMetrics, mTestDisplayMetrics);
+
+        WindowAreaComponentImpl.rotateRearDisplayMetricsIfNeeded(
+                Surface.ROTATION_180, Surface.ROTATION_0, mTestDisplayMetrics);
+        assertEquals(originalMetrics, mTestDisplayMetrics);
+    }
+
+    /**
+     * Cases where the rear display metrics need to be transformed.
+     */
+    @Test
+    public void testRotateRearDisplayMetrics_transformNeeded() {
+        DisplayMetrics originalMetrics = new DisplayMetrics();
+        originalMetrics.setTo(mTestDisplayMetrics);
+
+        DisplayMetrics expectedMetrics = new DisplayMetrics();
+        expectedMetrics.setTo(mTestDisplayMetrics);
+        expectedMetrics.widthPixels = mTestDisplayMetrics.heightPixels;
+        expectedMetrics.heightPixels = mTestDisplayMetrics.widthPixels;
+        expectedMetrics.noncompatWidthPixels = mTestDisplayMetrics.noncompatHeightPixels;
+        expectedMetrics.noncompatHeightPixels = mTestDisplayMetrics.noncompatWidthPixels;
+
+        WindowAreaComponentImpl.rotateRearDisplayMetricsIfNeeded(
+                Surface.ROTATION_90, Surface.ROTATION_0, mTestDisplayMetrics);
+        assertEquals(expectedMetrics, mTestDisplayMetrics);
+
+        mTestDisplayMetrics.setTo(originalMetrics);
+        WindowAreaComponentImpl.rotateRearDisplayMetricsIfNeeded(
+                Surface.ROTATION_270, Surface.ROTATION_0, mTestDisplayMetrics);
+        assertEquals(expectedMetrics, mTestDisplayMetrics);
+    }
+}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellModule.java b/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellModule.java
index 4980e49..cff3172 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellModule.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellModule.java
@@ -61,7 +61,6 @@
 import com.android.wm.shell.freeform.FreeformTaskTransitionHandler;
 import com.android.wm.shell.freeform.FreeformTaskTransitionObserver;
 import com.android.wm.shell.keyguard.KeyguardTransitionHandler;
-import com.android.wm.shell.kidsmode.KidsModeTaskOrganizer;
 import com.android.wm.shell.onehanded.OneHandedController;
 import com.android.wm.shell.pip.Pip;
 import com.android.wm.shell.pip.PipAnimationController;
@@ -536,9 +535,11 @@
             Optional<PipTouchHandler> pipTouchHandlerOptional,
             Optional<RecentsTransitionHandler> recentsTransitionHandler,
             KeyguardTransitionHandler keyguardTransitionHandler,
+            Optional<UnfoldTransitionHandler> unfoldHandler,
             Transitions transitions) {
         return new DefaultMixedHandler(shellInit, transitions, splitScreenOptional,
-                pipTouchHandlerOptional, recentsTransitionHandler, keyguardTransitionHandler);
+                pipTouchHandlerOptional, recentsTransitionHandler, keyguardTransitionHandler,
+                unfoldHandler);
     }
 
     @WMSingleton
@@ -711,28 +712,6 @@
     }
 
     //
-    // Kids mode
-    //
-    @WMSingleton
-    @Provides
-    static KidsModeTaskOrganizer provideKidsModeTaskOrganizer(
-            Context context,
-            ShellInit shellInit,
-            ShellCommandHandler shellCommandHandler,
-            SyncTransactionQueue syncTransactionQueue,
-            DisplayController displayController,
-            DisplayInsetsController displayInsetsController,
-            Optional<UnfoldAnimationController> unfoldAnimationController,
-            Optional<RecentTasksController> recentTasksOptional,
-            @ShellMainThread ShellExecutor mainExecutor,
-            @ShellMainThread Handler mainHandler
-    ) {
-        return new KidsModeTaskOrganizer(context, shellInit, shellCommandHandler,
-                syncTransactionQueue, displayController, displayInsetsController,
-                unfoldAnimationController, recentTasksOptional, mainExecutor, mainHandler);
-    }
-
-    //
     // Misc
     //
 
@@ -743,7 +722,6 @@
     @Provides
     static Object provideIndependentShellComponentsToCreate(
             DefaultMixedHandler defaultMixedHandler,
-            KidsModeTaskOrganizer kidsModeTaskOrganizer,
             Optional<DesktopModeController> desktopModeController) {
         return new Object();
     }
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/kidsmode/KidsModeSettingsObserver.java b/libs/WindowManager/Shell/src/com/android/wm/shell/kidsmode/KidsModeSettingsObserver.java
deleted file mode 100644
index 65cb7ac..0000000
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/kidsmode/KidsModeSettingsObserver.java
+++ /dev/null
@@ -1,92 +0,0 @@
-/*
- * Copyright (C) 2022 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.wm.shell.kidsmode;
-
-import android.annotation.NonNull;
-import android.app.ActivityManager;
-import android.content.ContentResolver;
-import android.content.Context;
-import android.database.ContentObserver;
-import android.net.Uri;
-import android.os.Handler;
-import android.os.UserHandle;
-import android.provider.Settings;
-
-import java.util.Collection;
-
-/**
- * A ContentObserver for listening kids mode relative setting keys:
- *  - {@link Settings.Secure#NAVIGATION_MODE}
- *  - {@link Settings.Secure#NAV_BAR_KIDS_MODE}
- *
- * @hide
- */
-public class KidsModeSettingsObserver extends ContentObserver {
-    private Context mContext;
-    private Runnable mOnChangeRunnable;
-
-    public KidsModeSettingsObserver(Handler handler, Context context) {
-        super(handler);
-        mContext = context;
-    }
-
-    public void setOnChangeRunnable(Runnable r) {
-        mOnChangeRunnable = r;
-    }
-
-    /**
-     * Registers the observer.
-     */
-    public void register() {
-        final ContentResolver r = mContext.getContentResolver();
-        r.registerContentObserver(
-                Settings.Secure.getUriFor(Settings.Secure.NAVIGATION_MODE),
-                false, this, UserHandle.USER_ALL);
-        r.registerContentObserver(
-                Settings.Secure.getUriFor(Settings.Secure.NAV_BAR_KIDS_MODE),
-                false, this, UserHandle.USER_ALL);
-    }
-
-    /**
-     * Unregisters the observer.
-     */
-    public void unregister() {
-        mContext.getContentResolver().unregisterContentObserver(this);
-    }
-
-    @Override
-    public void onChange(boolean selfChange, @NonNull Collection<Uri> uris, int flags, int userId) {
-        if (userId != ActivityManager.getCurrentUser()) {
-            return;
-        }
-
-        if (mOnChangeRunnable != null) {
-            mOnChangeRunnable.run();
-        }
-    }
-
-    /**
-     * Returns true only when it's in three button nav mode and the kid nav bar mode is enabled.
-     * Otherwise, return false.
-     */
-    public boolean isEnabled() {
-        return Settings.Secure.getIntForUser(mContext.getContentResolver(),
-                Settings.Secure.NAVIGATION_MODE, 0, UserHandle.USER_CURRENT) == 0
-                && Settings.Secure.getIntForUser(mContext.getContentResolver(),
-                Settings.Secure.NAV_BAR_KIDS_MODE, 0, UserHandle.USER_CURRENT) == 1;
-    }
-}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/kidsmode/KidsModeTaskOrganizer.java b/libs/WindowManager/Shell/src/com/android/wm/shell/kidsmode/KidsModeTaskOrganizer.java
deleted file mode 100644
index 6d46a9c..0000000
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/kidsmode/KidsModeTaskOrganizer.java
+++ /dev/null
@@ -1,436 +0,0 @@
-/*
- * Copyright (C) 2022 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.wm.shell.kidsmode;
-
-import static android.app.WindowConfiguration.ACTIVITY_TYPE_HOME;
-import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD;
-import static android.app.WindowConfiguration.ACTIVITY_TYPE_UNDEFINED;
-import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
-import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED;
-import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE;
-import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_REVERSE_LANDSCAPE;
-import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_SENSOR_LANDSCAPE;
-import static android.view.Display.DEFAULT_DISPLAY;
-
-import android.app.ActivityManager;
-import android.content.BroadcastReceiver;
-import android.content.Context;
-import android.content.Intent;
-import android.content.IntentFilter;
-import android.content.res.Configuration;
-import android.graphics.Rect;
-import android.os.Binder;
-import android.os.Handler;
-import android.os.IBinder;
-import android.view.Display;
-import android.view.InsetsSource;
-import android.view.InsetsState;
-import android.view.SurfaceControl;
-import android.view.WindowInsets;
-import android.window.ITaskOrganizerController;
-import android.window.TaskAppearedInfo;
-import android.window.WindowContainerToken;
-import android.window.WindowContainerTransaction;
-
-import androidx.annotation.NonNull;
-
-import com.android.internal.R;
-import com.android.internal.annotations.VisibleForTesting;
-import com.android.wm.shell.ShellTaskOrganizer;
-import com.android.wm.shell.common.DisplayController;
-import com.android.wm.shell.common.DisplayInsetsController;
-import com.android.wm.shell.common.DisplayLayout;
-import com.android.wm.shell.common.ShellExecutor;
-import com.android.wm.shell.common.SyncTransactionQueue;
-import com.android.wm.shell.recents.RecentTasksController;
-import com.android.wm.shell.sysui.ShellCommandHandler;
-import com.android.wm.shell.sysui.ShellInit;
-import com.android.wm.shell.unfold.UnfoldAnimationController;
-
-import java.io.PrintWriter;
-import java.util.List;
-import java.util.Optional;
-
-/**
- * A dedicated task organizer when kids mode is enabled.
- *  - Creates a root task with bounds that exclude the navigation bar area
- *  - Launch all task into the root task except for Launcher
- */
-public class KidsModeTaskOrganizer extends ShellTaskOrganizer {
-    private static final String TAG = "KidsModeTaskOrganizer";
-
-    private static final int[] CONTROLLED_ACTIVITY_TYPES =
-            {ACTIVITY_TYPE_UNDEFINED, ACTIVITY_TYPE_STANDARD, ACTIVITY_TYPE_HOME};
-    private static final int[] CONTROLLED_WINDOWING_MODES =
-            {WINDOWING_MODE_FULLSCREEN, WINDOWING_MODE_UNDEFINED};
-
-    private final Handler mMainHandler;
-    private final Context mContext;
-    private final ShellCommandHandler mShellCommandHandler;
-    private final SyncTransactionQueue mSyncQueue;
-    private final DisplayController mDisplayController;
-    private final DisplayInsetsController mDisplayInsetsController;
-
-    /**
-     * The value of the {@link R.bool.config_reverseDefaultRotation} property which defines how
-     * {@link Display#getRotation} values are mapped to screen orientations
-     */
-    private final boolean mReverseDefaultRotationEnabled;
-
-    @VisibleForTesting
-    ActivityManager.RunningTaskInfo mLaunchRootTask;
-    @VisibleForTesting
-    SurfaceControl mLaunchRootLeash;
-    @VisibleForTesting
-    final IBinder mCookie = new Binder();
-
-    private final InsetsState mInsetsState = new InsetsState();
-    private int mDisplayWidth;
-    private int mDisplayHeight;
-
-    private KidsModeSettingsObserver mKidsModeSettingsObserver;
-    private boolean mEnabled;
-
-    private ActivityManager.RunningTaskInfo mHomeTask;
-
-    private final BroadcastReceiver mUserSwitchIntentReceiver = new BroadcastReceiver() {
-        @Override
-        public void onReceive(Context context, Intent intent) {
-            updateKidsModeState();
-        }
-    };
-
-    DisplayController.OnDisplaysChangedListener mOnDisplaysChangedListener =
-            new DisplayController.OnDisplaysChangedListener() {
-        @Override
-        public void onDisplayConfigurationChanged(int displayId, Configuration newConfig) {
-            if (displayId != DEFAULT_DISPLAY) {
-                return;
-            }
-            final DisplayLayout displayLayout =
-                    mDisplayController.getDisplayLayout(DEFAULT_DISPLAY);
-            if (displayLayout == null) {
-                return;
-            }
-            final int displayWidth = displayLayout.width();
-            final int displayHeight = displayLayout.height();
-            if (displayWidth == mDisplayWidth || displayHeight == mDisplayHeight) {
-                return;
-            }
-            mDisplayWidth = displayWidth;
-            mDisplayHeight = displayHeight;
-            updateBounds();
-        }
-    };
-
-    DisplayInsetsController.OnInsetsChangedListener mOnInsetsChangedListener =
-            new DisplayInsetsController.OnInsetsChangedListener() {
-        @Override
-        public void insetsChanged(InsetsState insetsState) {
-            final boolean[] navigationBarChanged = {false};
-            InsetsState.traverse(insetsState, mInsetsState, new InsetsState.OnTraverseCallbacks() {
-                @Override
-                public void onIdMatch(InsetsSource source1, InsetsSource source2) {
-                    if (source1.getType() == WindowInsets.Type.navigationBars()
-                            && !source1.equals(source2)) {
-                        navigationBarChanged[0] = true;
-                    }
-                }
-
-                @Override
-                public void onIdNotFoundInState1(int index2, InsetsSource source2) {
-                    if (source2.getType() == WindowInsets.Type.navigationBars()) {
-                        navigationBarChanged[0] = true;
-                    }
-                }
-
-                @Override
-                public void onIdNotFoundInState2(int index1, InsetsSource source1) {
-                    if (source1.getType() == WindowInsets.Type.navigationBars()) {
-                        navigationBarChanged[0] = true;
-                    }
-                }
-            });
-            if (!navigationBarChanged[0]) {
-                return;
-            }
-            // Update bounds only when the insets of navigation bar or task bar is changed.
-            mInsetsState.set(insetsState);
-            updateBounds();
-        }
-    };
-
-    @VisibleForTesting
-    KidsModeTaskOrganizer(
-            Context context,
-            ShellInit shellInit,
-            ShellCommandHandler shellCommandHandler,
-            ITaskOrganizerController taskOrganizerController,
-            SyncTransactionQueue syncTransactionQueue,
-            DisplayController displayController,
-            DisplayInsetsController displayInsetsController,
-            Optional<UnfoldAnimationController> unfoldAnimationController,
-            Optional<RecentTasksController> recentTasks,
-            KidsModeSettingsObserver kidsModeSettingsObserver,
-            ShellExecutor mainExecutor,
-            Handler mainHandler) {
-        // Note: we don't call super with the shell init because we will be initializing manually
-        super(/* shellInit= */ null, /* shellCommandHandler= */ null, taskOrganizerController,
-                /* compatUI= */ null, unfoldAnimationController, recentTasks, mainExecutor);
-        mContext = context;
-        mShellCommandHandler = shellCommandHandler;
-        mMainHandler = mainHandler;
-        mSyncQueue = syncTransactionQueue;
-        mDisplayController = displayController;
-        mDisplayInsetsController = displayInsetsController;
-        mKidsModeSettingsObserver = kidsModeSettingsObserver;
-        shellInit.addInitCallback(this::onInit, this);
-        mReverseDefaultRotationEnabled = context.getResources().getBoolean(
-                R.bool.config_reverseDefaultRotation);
-    }
-
-    public KidsModeTaskOrganizer(
-            Context context,
-            ShellInit shellInit,
-            ShellCommandHandler shellCommandHandler,
-            SyncTransactionQueue syncTransactionQueue,
-            DisplayController displayController,
-            DisplayInsetsController displayInsetsController,
-            Optional<UnfoldAnimationController> unfoldAnimationController,
-            Optional<RecentTasksController> recentTasks,
-            ShellExecutor mainExecutor,
-            Handler mainHandler) {
-        // Note: we don't call super with the shell init because we will be initializing manually
-        super(/* shellInit= */ null, /* taskOrganizerController= */ null, /* compatUI= */ null,
-                unfoldAnimationController, recentTasks, mainExecutor);
-        mContext = context;
-        mShellCommandHandler = shellCommandHandler;
-        mMainHandler = mainHandler;
-        mSyncQueue = syncTransactionQueue;
-        mDisplayController = displayController;
-        mDisplayInsetsController = displayInsetsController;
-        shellInit.addInitCallback(this::onInit, this);
-        mReverseDefaultRotationEnabled = context.getResources().getBoolean(
-                R.bool.config_reverseDefaultRotation);
-    }
-
-    /**
-     * Initializes kids mode status.
-     */
-    public void onInit() {
-        if (mShellCommandHandler != null) {
-            mShellCommandHandler.addDumpCallback(this::dump, this);
-        }
-        if (mKidsModeSettingsObserver == null) {
-            mKidsModeSettingsObserver = new KidsModeSettingsObserver(mMainHandler, mContext);
-        }
-        mKidsModeSettingsObserver.setOnChangeRunnable(() -> updateKidsModeState());
-        updateKidsModeState();
-        mKidsModeSettingsObserver.register();
-
-        final IntentFilter filter = new IntentFilter();
-        filter.addAction(Intent.ACTION_USER_SWITCHED);
-        mContext.registerReceiverForAllUsers(mUserSwitchIntentReceiver, filter, null, mMainHandler);
-    }
-
-    @Override
-    public void onTaskAppeared(ActivityManager.RunningTaskInfo taskInfo, SurfaceControl leash) {
-        if (mEnabled && mLaunchRootTask == null && taskInfo.launchCookies != null
-                && taskInfo.launchCookies.contains(mCookie)) {
-            mLaunchRootTask = taskInfo;
-            mLaunchRootLeash = leash;
-            updateTask();
-        }
-        super.onTaskAppeared(taskInfo, leash);
-
-        // Only allow home to draw under system bars.
-        if (taskInfo.getActivityType() == ACTIVITY_TYPE_HOME) {
-            final WindowContainerTransaction wct = getWindowContainerTransaction();
-            wct.setBounds(taskInfo.token, new Rect(0, 0, mDisplayWidth, mDisplayHeight));
-            mSyncQueue.queue(wct);
-            mHomeTask = taskInfo;
-        }
-        mSyncQueue.runInSync(t -> {
-            // Reset several properties back to fullscreen (PiP, for example, leaves all these
-            // properties in a bad state).
-            t.setCrop(leash, null);
-            t.setPosition(leash, 0, 0);
-            t.setAlpha(leash, 1f);
-            t.setMatrix(leash, 1, 0, 0, 1);
-            t.show(leash);
-        });
-    }
-
-    @Override
-    public void onTaskInfoChanged(ActivityManager.RunningTaskInfo taskInfo) {
-        if (mLaunchRootTask != null && mLaunchRootTask.taskId == taskInfo.taskId
-                && !taskInfo.equals(mLaunchRootTask)) {
-            mLaunchRootTask = taskInfo;
-        }
-
-        if (mHomeTask != null && mHomeTask.taskId == taskInfo.taskId
-                && !taskInfo.equals(mHomeTask)) {
-            mHomeTask = taskInfo;
-        }
-
-        super.onTaskInfoChanged(taskInfo);
-    }
-
-    @VisibleForTesting
-    void updateKidsModeState() {
-        final boolean enabled = mKidsModeSettingsObserver.isEnabled();
-        if (mEnabled == enabled) {
-            return;
-        }
-        mEnabled = enabled;
-        if (mEnabled) {
-            enable();
-        } else {
-            disable();
-        }
-    }
-
-    @VisibleForTesting
-    void enable() {
-        // Needed since many Kids apps aren't optimised to support both orientations and it will be
-        // hard for kids to understand the app compat mode.
-        // TODO(229961548): Remove ignoreOrientationRequest exception for Kids Mode once possible.
-        if (mReverseDefaultRotationEnabled) {
-            setOrientationRequestPolicy(/* isIgnoreOrientationRequestDisabled */ true,
-                    /* fromOrientations */
-                    new int[]{SCREEN_ORIENTATION_LANDSCAPE, SCREEN_ORIENTATION_REVERSE_LANDSCAPE},
-                    /* toOrientations */
-                    new int[]{SCREEN_ORIENTATION_SENSOR_LANDSCAPE,
-                            SCREEN_ORIENTATION_SENSOR_LANDSCAPE});
-        } else {
-            setOrientationRequestPolicy(/* isIgnoreOrientationRequestDisabled */ true,
-                    /* fromOrientations */ null, /* toOrientations */ null);
-        }
-        final DisplayLayout displayLayout = mDisplayController.getDisplayLayout(DEFAULT_DISPLAY);
-        if (displayLayout != null) {
-            mDisplayWidth = displayLayout.width();
-            mDisplayHeight = displayLayout.height();
-        }
-        mInsetsState.set(mDisplayController.getInsetsState(DEFAULT_DISPLAY));
-        mDisplayInsetsController.addInsetsChangedListener(DEFAULT_DISPLAY,
-                mOnInsetsChangedListener);
-        mDisplayController.addDisplayWindowListener(mOnDisplaysChangedListener);
-        List<TaskAppearedInfo> taskAppearedInfos = registerOrganizer();
-        for (int i = 0; i < taskAppearedInfos.size(); i++) {
-            final TaskAppearedInfo info = taskAppearedInfos.get(i);
-            onTaskAppeared(info.getTaskInfo(), info.getLeash());
-        }
-        createRootTask(DEFAULT_DISPLAY, WINDOWING_MODE_FULLSCREEN, mCookie);
-        updateTask();
-    }
-
-    @VisibleForTesting
-    void disable() {
-        setOrientationRequestPolicy(/* isIgnoreOrientationRequestDisabled */ false,
-                /* fromOrientations */ null, /* toOrientations */ null);
-        mDisplayInsetsController.removeInsetsChangedListener(DEFAULT_DISPLAY,
-                mOnInsetsChangedListener);
-        mDisplayController.removeDisplayWindowListener(mOnDisplaysChangedListener);
-        updateTask();
-        final WindowContainerToken token = mLaunchRootTask.token;
-        if (token != null) {
-            deleteRootTask(token);
-        }
-        mLaunchRootTask = null;
-        mLaunchRootLeash = null;
-        if (mHomeTask != null && mHomeTask.token != null) {
-            final WindowContainerToken homeToken = mHomeTask.token;
-            final WindowContainerTransaction wct = getWindowContainerTransaction();
-            wct.setBounds(homeToken, null);
-            mSyncQueue.queue(wct);
-        }
-        mHomeTask = null;
-        unregisterOrganizer();
-    }
-
-    private void updateTask() {
-        updateTask(getWindowContainerTransaction());
-    }
-
-    private void updateTask(WindowContainerTransaction wct) {
-        if (mLaunchRootTask == null || mLaunchRootLeash == null) {
-            return;
-        }
-        final Rect taskBounds = calculateBounds();
-        final WindowContainerToken rootToken = mLaunchRootTask.token;
-        wct.setBounds(rootToken, mEnabled ? taskBounds : null);
-        wct.setLaunchRoot(rootToken,
-                mEnabled ? CONTROLLED_WINDOWING_MODES : null,
-                mEnabled ? CONTROLLED_ACTIVITY_TYPES : null);
-        wct.reparentTasks(
-                mEnabled ? null : rootToken /* currentParent */,
-                mEnabled ? rootToken : null /* newParent */,
-                CONTROLLED_WINDOWING_MODES,
-                CONTROLLED_ACTIVITY_TYPES,
-                true /* onTop */);
-        wct.reorder(rootToken, mEnabled /* onTop */);
-        mSyncQueue.queue(wct);
-        if (mEnabled) {
-            final SurfaceControl rootLeash = mLaunchRootLeash;
-            mSyncQueue.runInSync(t -> {
-                t.setPosition(rootLeash, taskBounds.left, taskBounds.top);
-                t.setWindowCrop(rootLeash, mDisplayWidth, mDisplayHeight);
-            });
-        }
-    }
-
-    private Rect calculateBounds() {
-        final Rect bounds = new Rect(0, 0, mDisplayWidth, mDisplayHeight);
-        bounds.inset(mInsetsState.calculateInsets(
-                bounds, WindowInsets.Type.navigationBars(), false /* ignoreVisibility */));
-        return bounds;
-    }
-
-    private void updateBounds() {
-        if (mLaunchRootTask == null) {
-            return;
-        }
-        final WindowContainerTransaction wct = getWindowContainerTransaction();
-        final Rect taskBounds = calculateBounds();
-        wct.setBounds(mLaunchRootTask.token, taskBounds);
-        wct.setBounds(mHomeTask.token, new Rect(0, 0, mDisplayWidth, mDisplayHeight));
-        mSyncQueue.queue(wct);
-        final SurfaceControl finalLeash = mLaunchRootLeash;
-        mSyncQueue.runInSync(t -> {
-            t.setPosition(finalLeash, taskBounds.left, taskBounds.top);
-            t.setWindowCrop(finalLeash, mDisplayWidth, mDisplayHeight);
-        });
-    }
-
-    @VisibleForTesting
-    WindowContainerTransaction getWindowContainerTransaction() {
-        return new WindowContainerTransaction();
-    }
-
-    @Override
-    public void dump(@NonNull PrintWriter pw, String prefix) {
-        final String innerPrefix = prefix + "  ";
-        pw.println(prefix + TAG);
-        pw.println(innerPrefix + " mEnabled=" + mEnabled);
-        pw.println(innerPrefix + " mLaunchRootTask=" + mLaunchRootTask);
-        pw.println(innerPrefix + " mLaunchRootLeash=" + mLaunchRootLeash);
-        pw.println(innerPrefix + " mDisplayWidth=" + mDisplayWidth);
-        pw.println(innerPrefix + " mDisplayHeight=" + mDisplayHeight);
-        pw.println(innerPrefix + " mInsetsState=" + mInsetsState);
-        super.dump(pw, innerPrefix);
-    }
-}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/recents/RecentsTransitionHandler.java b/libs/WindowManager/Shell/src/com/android/wm/shell/recents/RecentsTransitionHandler.java
index 8024a4c..843e5af 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/recents/RecentsTransitionHandler.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/recents/RecentsTransitionHandler.java
@@ -424,6 +424,7 @@
             // the change count). This lets us categorize things into above/below/between
             // while maintaining their relative ordering.
             final int belowLayers = info.getChanges().size();
+            final int middleLayers = info.getChanges().size() * 2;
             final int aboveLayers = info.getChanges().size() * 3;
             for (int i = 0; i < info.getChanges().size(); ++i) {
                 final TransitionInfo.Change change = info.getChanges().get(i);
@@ -441,14 +442,19 @@
                             belowLayers - i, info, t, mLeashMap);
                     apps.add(target);
                     if (TransitionUtil.isClosingType(change.getMode())) {
-                        ProtoLog.v(ShellProtoLogGroup.WM_SHELL_RECENTS_TRANSITION,
-                                "  adding pausing leaf taskId=%d", taskInfo.taskId);
-                        // raise closing (pausing) task to "above" layer so it isn't covered
-                        t.setLayer(target.leash, aboveLayers - i);
                         mPausingTasks.add(new TaskState(change, target.leash));
                         if (taskInfo.topActivityType == ACTIVITY_TYPE_HOME) {
+                            ProtoLog.v(ShellProtoLogGroup.WM_SHELL_RECENTS_TRANSITION,
+                                    "  adding pausing leaf home taskId=%d", taskInfo.taskId);
                             // This can only happen if we have a separate recents/home (3p launcher)
                             mPausingSeparateHome = true;
+                        } else {
+                            final int layer = aboveLayers - i;
+                            ProtoLog.v(ShellProtoLogGroup.WM_SHELL_RECENTS_TRANSITION,
+                                    "  adding pausing leaf taskId=%d at layer=%d",
+                                    taskInfo.taskId, layer);
+                            // raise closing (pausing) task to "above" layer so it isn't covered
+                            t.setLayer(target.leash, layer);
                         }
                         if (taskInfo.pictureInPictureParams != null
                                 && taskInfo.pictureInPictureParams.isAutoEnterEnabled()) {
@@ -456,8 +462,12 @@
                         }
                     } else if (taskInfo != null
                             && taskInfo.topActivityType == ACTIVITY_TYPE_RECENTS) {
-                        // There's a 3p launcher, so make sure recents goes above that.
-                        t.setLayer(target.leash, aboveLayers - i);
+                        final int layer = middleLayers - i;
+                        ProtoLog.v(ShellProtoLogGroup.WM_SHELL_RECENTS_TRANSITION,
+                                "  setting recents activity layer=%d", layer);
+                        // There's a 3p launcher, so make sure recents goes above that, but under
+                        // the pausing apps.
+                        t.setLayer(target.leash, layer);
                     } else if (taskInfo != null && taskInfo.topActivityType == ACTIVITY_TYPE_HOME) {
                         // do nothing
                     } else if (TransitionUtil.isOpeningType(change.getMode())) {
@@ -468,16 +478,18 @@
                 } else if (taskInfo != null && TransitionInfo.isIndependent(change, info)) {
                     // Root tasks
                     if (TransitionUtil.isClosingType(change.getMode())) {
+                        final int layer = aboveLayers - i;
                         ProtoLog.v(ShellProtoLogGroup.WM_SHELL_RECENTS_TRANSITION,
-                                "  adding pausing taskId=%d", taskInfo.taskId);
+                                "  adding pausing taskId=%d at layer=%d", taskInfo.taskId, layer);
                         // raise closing (pausing) task to "above" layer so it isn't covered
-                        t.setLayer(change.getLeash(), aboveLayers - i);
+                        t.setLayer(change.getLeash(), layer);
                         mPausingTasks.add(new TaskState(change, null /* leash */));
                     } else if (TransitionUtil.isOpeningType(change.getMode())) {
+                        final int layer = belowLayers - i;
                         ProtoLog.v(ShellProtoLogGroup.WM_SHELL_RECENTS_TRANSITION,
-                                "  adding opening taskId=%d", taskInfo.taskId);
+                                "  adding opening taskId=%d at layer=%d", taskInfo.taskId, layer);
                         // Put into the "below" layer space.
-                        t.setLayer(change.getLeash(), belowLayers - i);
+                        t.setLayer(change.getLeash(), layer);
                         mOpeningTasks.add(new TaskState(change, null /* leash */));
                     }
                 } else if (TransitionUtil.isDividerBar(change)) {
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageCoordinator.java b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageCoordinator.java
index da14d03..d38c381 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageCoordinator.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageCoordinator.java
@@ -2365,6 +2365,11 @@
                     prepareExitSplitScreen(STAGE_TYPE_UNDEFINED, out);
                 }
             }
+
+            // When split in the background, it should be only opening/dismissing transition and
+            // would keep out not empty. Prevent intercepting all transitions for split screen when
+            // it is in the background and not identify to handle it.
+            return (!out.isEmpty() || isSplitScreenVisible()) ? out : null;
         } else {
             if (isOpening && getStageOfTask(triggerTask) != null) {
                 // One task is appearing into split, prepare to enter split screen.
@@ -2373,8 +2378,8 @@
                 mSplitTransitions.setEnterTransition(transition, request.getRemoteTransition(),
                         TRANSIT_SPLIT_SCREEN_PAIR_OPEN, !mIsDropEntering);
             }
+            return out;
         }
-        return out;
     }
 
     /**
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/DefaultMixedHandler.java b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/DefaultMixedHandler.java
index 18c5a2a..3059e85 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/DefaultMixedHandler.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/DefaultMixedHandler.java
@@ -51,6 +51,7 @@
 import com.android.wm.shell.splitscreen.SplitScreenController;
 import com.android.wm.shell.splitscreen.StageCoordinator;
 import com.android.wm.shell.sysui.ShellInit;
+import com.android.wm.shell.unfold.UnfoldTransitionHandler;
 import com.android.wm.shell.util.TransitionUtil;
 
 import java.util.ArrayList;
@@ -68,6 +69,7 @@
     private RecentsTransitionHandler mRecentsHandler;
     private StageCoordinator mSplitHandler;
     private final KeyguardTransitionHandler mKeyguardHandler;
+    private UnfoldTransitionHandler mUnfoldHandler;
 
     private static class MixedTransition {
         static final int TYPE_ENTER_PIP_FROM_SPLIT = 1;
@@ -84,6 +86,9 @@
         /** Keyguard exit/occlude/unocclude transition. */
         static final int TYPE_KEYGUARD = 5;
 
+        /** Fuld/Unfold transition. */
+        static final int TYPE_UNFOLD = 6;
+
         /** The default animation for this mixed transition. */
         static final int ANIM_TYPE_DEFAULT = 0;
 
@@ -135,7 +140,8 @@
             Optional<SplitScreenController> splitScreenControllerOptional,
             Optional<PipTouchHandler> pipTouchHandlerOptional,
             Optional<RecentsTransitionHandler> recentsHandlerOptional,
-            KeyguardTransitionHandler keyguardHandler) {
+            KeyguardTransitionHandler keyguardHandler,
+            Optional<UnfoldTransitionHandler> unfoldHandler) {
         mPlayer = player;
         mKeyguardHandler = keyguardHandler;
         if (Transitions.ENABLE_SHELL_TRANSITIONS && pipTouchHandlerOptional.isPresent()
@@ -152,6 +158,7 @@
                 if (mRecentsHandler != null) {
                     mRecentsHandler.addMixer(this);
                 }
+                mUnfoldHandler = unfoldHandler.orElse(null);
             }, this);
         }
     }
@@ -215,6 +222,16 @@
             mixed.mLeftoversHandler = handler.first;
             mActiveTransitions.add(mixed);
             return handler.second;
+        } else if (mUnfoldHandler != null && mUnfoldHandler.hasUnfold(request)) {
+            final WindowContainerTransaction wct =
+                    mUnfoldHandler.handleRequest(transition, request);
+            if (wct != null) {
+                final MixedTransition mixed = new MixedTransition(
+                        MixedTransition.TYPE_UNFOLD, transition);
+                mixed.mLeftoversHandler = mUnfoldHandler;
+                mActiveTransitions.add(mixed);
+            }
+            return wct;
         }
         return null;
     }
@@ -322,6 +339,8 @@
         } else if (mixed.mType == MixedTransition.TYPE_KEYGUARD) {
             return animateKeyguard(mixed, info, startTransaction, finishTransaction,
                     finishCallback);
+        } else if (mixed.mType == MixedTransition.TYPE_UNFOLD) {
+            return animateUnfold(mixed, info, startTransaction, finishTransaction, finishCallback);
         } else {
             mActiveTransitions.remove(mixed);
             throw new IllegalStateException("Starting mixed animation without a known mixed type? "
@@ -606,6 +625,33 @@
         return true;
     }
 
+    private boolean animateUnfold(@NonNull final MixedTransition mixed,
+            @NonNull TransitionInfo info,
+            @NonNull SurfaceControl.Transaction startTransaction,
+            @NonNull SurfaceControl.Transaction finishTransaction,
+            @NonNull Transitions.TransitionFinishCallback finishCallback) {
+        final Transitions.TransitionFinishCallback finishCB = (wct, wctCB) -> {
+            mixed.mInFlightSubAnimations--;
+            if (mixed.mInFlightSubAnimations > 0) return;
+            mActiveTransitions.remove(mixed);
+            finishCallback.onTransitionFinished(wct, wctCB);
+        };
+        mixed.mInFlightSubAnimations = 1;
+        if (!mUnfoldHandler.startAnimation(
+                mixed.mTransition, info, startTransaction, finishTransaction, finishCB)) {
+            return false;
+        }
+        // Sync pip state.
+        if (mPipHandler != null) {
+            // We don't know when to apply `startTransaction` so use a separate transaction here.
+            // This should be fine because these surface properties are independent.
+            final SurfaceControl.Transaction t = new SurfaceControl.Transaction();
+            mPipHandler.syncPipSurfaceState(info, t, finishTransaction);
+            t.apply();
+        }
+        return true;
+    }
+
     /** Use to when split use intent to enter, check if this enter transition should be mixed or
      * not.*/
     public boolean shouldSplitEnterMixed(PendingIntent intent) {
@@ -665,6 +711,8 @@
                         finishCallback);
             } else if (mixed.mType == MixedTransition.TYPE_KEYGUARD) {
                 mKeyguardHandler.mergeAnimation(transition, info, t, mergeTarget, finishCallback);
+            } else if (mixed.mType == MixedTransition.TYPE_UNFOLD) {
+                mUnfoldHandler.mergeAnimation(transition, info, t, mergeTarget, finishCallback);
             } else {
                 throw new IllegalStateException("Playing a mixed transition with unknown type? "
                         + mixed.mType);
@@ -690,6 +738,8 @@
             mixed.mLeftoversHandler.onTransitionConsumed(transition, aborted, finishT);
         } else if (mixed.mType == MixedTransition.TYPE_KEYGUARD) {
             mKeyguardHandler.onTransitionConsumed(transition, aborted, finishT);
+        } else if (mixed.mType == MixedTransition.TYPE_UNFOLD) {
+            mUnfoldHandler.onTransitionConsumed(transition, aborted, finishT);
         }
     }
 }
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/unfold/UnfoldTransitionHandler.java b/libs/WindowManager/Shell/src/com/android/wm/shell/unfold/UnfoldTransitionHandler.java
index e1d58a4..f148412 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/unfold/UnfoldTransitionHandler.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/unfold/UnfoldTransitionHandler.java
@@ -197,12 +197,18 @@
         }
     }
 
+    /** Whether `request` contains an unfold action. */
+    public boolean hasUnfold(@NonNull TransitionRequestInfo request) {
+        return (request.getType() == TRANSIT_CHANGE
+                && request.getDisplayChange() != null
+                && request.getDisplayChange().isPhysicalDisplayChanged());
+    }
+
     @Nullable
     @Override
     public WindowContainerTransaction handleRequest(@NonNull IBinder transition,
             @NonNull TransitionRequestInfo request) {
-        if (request.getType() == TRANSIT_CHANGE && request.getDisplayChange() != null
-                && request.getDisplayChange().isPhysicalDisplayChanged()) {
+        if (hasUnfold(request)) {
             mTransition = transition;
             return new WindowContainerTransaction();
         }
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/kidsmode/KidsModeTaskOrganizerTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/kidsmode/KidsModeTaskOrganizerTest.java
deleted file mode 100644
index 58e91cb..0000000
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/kidsmode/KidsModeTaskOrganizerTest.java
+++ /dev/null
@@ -1,163 +0,0 @@
-/*
- * Copyright (C) 2022 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.wm.shell.kidsmode;
-
-import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
-import static android.view.Display.DEFAULT_DISPLAY;
-
-import static com.google.common.truth.Truth.assertThat;
-
-import static org.mockito.ArgumentMatchers.any;
-import static org.mockito.ArgumentMatchers.eq;
-import static org.mockito.Mockito.doReturn;
-import static org.mockito.Mockito.spy;
-import static org.mockito.Mockito.times;
-import static org.mockito.Mockito.verify;
-
-import android.app.ActivityManager;
-import android.content.Context;
-import android.content.pm.ParceledListSlice;
-import android.content.res.Resources;
-import android.os.Handler;
-import android.os.IBinder;
-import android.os.RemoteException;
-import android.view.InsetsState;
-import android.view.SurfaceControl;
-import android.window.ITaskOrganizerController;
-import android.window.TaskAppearedInfo;
-import android.window.WindowContainerToken;
-import android.window.WindowContainerTransaction;
-
-import androidx.test.ext.junit.runners.AndroidJUnit4;
-import androidx.test.filters.SmallTest;
-
-import com.android.wm.shell.ShellTestCase;
-import com.android.wm.shell.common.DisplayController;
-import com.android.wm.shell.common.DisplayInsetsController;
-import com.android.wm.shell.common.ShellExecutor;
-import com.android.wm.shell.common.SyncTransactionQueue;
-import com.android.wm.shell.sysui.ShellCommandHandler;
-import com.android.wm.shell.sysui.ShellInit;
-
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.mockito.Mock;
-import org.mockito.MockitoAnnotations;
-
-import java.util.ArrayList;
-import java.util.Optional;
-
-@SmallTest
-@RunWith(AndroidJUnit4.class)
-public class KidsModeTaskOrganizerTest extends ShellTestCase {
-    @Mock private ITaskOrganizerController mTaskOrganizerController;
-    @Mock private Context mContext;
-    @Mock private Handler mHandler;
-    @Mock private SyncTransactionQueue mSyncTransactionQueue;
-    @Mock private ShellExecutor mTestExecutor;
-    @Mock private DisplayController mDisplayController;
-    @Mock private SurfaceControl mLeash;
-    @Mock private WindowContainerToken mToken;
-    @Mock private WindowContainerTransaction mTransaction;
-    @Mock private KidsModeSettingsObserver mObserver;
-    @Mock private ShellInit mShellInit;
-    @Mock private ShellCommandHandler mShellCommandHandler;
-    @Mock private DisplayInsetsController mDisplayInsetsController;
-    @Mock private Resources mResources;
-
-    KidsModeTaskOrganizer mOrganizer;
-
-    @Before
-    public void setUp() {
-        MockitoAnnotations.initMocks(this);
-        try {
-            doReturn(ParceledListSlice.<TaskAppearedInfo>emptyList())
-                    .when(mTaskOrganizerController).registerTaskOrganizer(any());
-        } catch (RemoteException e) {
-        }
-        // NOTE: KidsModeTaskOrganizer should have a null CompatUIController.
-        doReturn(mResources).when(mContext).getResources();
-        final KidsModeTaskOrganizer kidsModeTaskOrganizer = new KidsModeTaskOrganizer(mContext,
-                mShellInit, mShellCommandHandler, mTaskOrganizerController, mSyncTransactionQueue,
-                mDisplayController, mDisplayInsetsController, Optional.empty(), Optional.empty(),
-                mObserver, mTestExecutor, mHandler);
-        mOrganizer = spy(kidsModeTaskOrganizer);
-        doReturn(mTransaction).when(mOrganizer).getWindowContainerTransaction();
-        doReturn(new InsetsState()).when(mDisplayController).getInsetsState(DEFAULT_DISPLAY);
-    }
-
-    @Test
-    public void instantiateController_addInitCallback() {
-        verify(mShellInit, times(1)).addInitCallback(any(), any());
-    }
-
-    @Test
-    public void testKidsModeOn() {
-        doReturn(true).when(mObserver).isEnabled();
-
-        mOrganizer.updateKidsModeState();
-
-        verify(mOrganizer, times(1)).enable();
-        verify(mOrganizer, times(1)).registerOrganizer();
-        verify(mOrganizer, times(1)).createRootTask(
-                eq(DEFAULT_DISPLAY), eq(WINDOWING_MODE_FULLSCREEN), eq(mOrganizer.mCookie));
-        verify(mOrganizer, times(1))
-                .setOrientationRequestPolicy(eq(true), any(), any());
-
-        final ActivityManager.RunningTaskInfo rootTask = createTaskInfo(12,
-                WINDOWING_MODE_FULLSCREEN, mOrganizer.mCookie);
-        mOrganizer.onTaskAppeared(rootTask, mLeash);
-
-        assertThat(mOrganizer.mLaunchRootLeash).isEqualTo(mLeash);
-        assertThat(mOrganizer.mLaunchRootTask).isEqualTo(rootTask);
-    }
-
-    @Test
-    public void testKidsModeOff() {
-        doReturn(true).when(mObserver).isEnabled();
-        mOrganizer.updateKidsModeState();
-        final ActivityManager.RunningTaskInfo rootTask = createTaskInfo(12,
-                WINDOWING_MODE_FULLSCREEN, mOrganizer.mCookie);
-        mOrganizer.onTaskAppeared(rootTask, mLeash);
-
-        doReturn(false).when(mObserver).isEnabled();
-        mOrganizer.updateKidsModeState();
-
-        verify(mOrganizer, times(1)).disable();
-        verify(mOrganizer, times(1)).unregisterOrganizer();
-        verify(mOrganizer, times(1)).deleteRootTask(rootTask.token);
-        verify(mOrganizer, times(1))
-                .setOrientationRequestPolicy(eq(false), any(), any());
-        assertThat(mOrganizer.mLaunchRootLeash).isNull();
-        assertThat(mOrganizer.mLaunchRootTask).isNull();
-    }
-
-    private ActivityManager.RunningTaskInfo createTaskInfo(
-            int taskId, int windowingMode, IBinder cookies) {
-        ActivityManager.RunningTaskInfo taskInfo = new ActivityManager.RunningTaskInfo();
-        taskInfo.taskId = taskId;
-        taskInfo.token = mToken;
-        taskInfo.configuration.windowConfiguration.setWindowingMode(windowingMode);
-        final ArrayList<IBinder> launchCookies = new ArrayList<>();
-        if (cookies != null) {
-            launchCookies.add(cookies);
-        }
-        taskInfo.launchCookies = launchCookies;
-        return taskInfo;
-    }
-}
diff --git a/location/java/android/location/Location.java b/location/java/android/location/Location.java
index 9be7728..0eb657a 100644
--- a/location/java/android/location/Location.java
+++ b/location/java/android/location/Location.java
@@ -709,7 +709,7 @@
     /**
      * Returns the Mean Sea Level altitude of this location in meters.
      *
-     * <p>This is only valid if {@link #hasMslAltitude()} is true.
+     * @throws IllegalStateException if {@link #hasMslAltitude()} is false.
      */
     public @FloatRange double getMslAltitudeMeters() {
         Preconditions.checkState(hasMslAltitude(),
@@ -744,7 +744,7 @@
      * percentile confidence level. This means that there is 68% chance that the true Mean Sea Level
      * altitude of this location falls within {@link #getMslAltitudeMeters()} +/- this uncertainty.
      *
-     * <p>This is only valid if {@link #hasMslAltitudeAccuracy()} is true.
+     * @throws IllegalStateException if {@link #hasMslAltitudeAccuracy()} is false.
      */
     public @FloatRange(from = 0.0) float getMslAltitudeAccuracyMeters() {
         Preconditions.checkState(hasMslAltitudeAccuracy(),
diff --git a/packages/SystemUI/res/values-land/dimens.xml b/packages/SystemUI/res/values-land/dimens.xml
index f277e8a..da4547b 100644
--- a/packages/SystemUI/res/values-land/dimens.xml
+++ b/packages/SystemUI/res/values-land/dimens.xml
@@ -76,4 +76,10 @@
     <!-- Bouncer user switcher margins -->
     <dimen name="bouncer_user_switcher_view_mode_user_switcher_bottom_margin">0dp</dimen>
     <dimen name="bouncer_user_switcher_view_mode_view_flipper_bottom_margin">0dp</dimen>
+
+    <!-- Power Menu Lite -->
+    <!-- These values are for small screen landscape. For larger landscape screens, they are
+         overlaid -->
+    <dimen name="global_actions_button_size">72dp</dimen>
+    <dimen name="global_actions_button_padding">26dp</dimen>
 </resources>
diff --git a/packages/SystemUI/res/values-sw410dp-land/dimens.xml b/packages/SystemUI/res/values-sw410dp-land/dimens.xml
index c4d9b9b..6045606 100644
--- a/packages/SystemUI/res/values-sw410dp-land/dimens.xml
+++ b/packages/SystemUI/res/values-sw410dp-land/dimens.xml
@@ -18,4 +18,8 @@
     <!-- Lock pattern view size, align sysui biometric_auth_pattern_view_size -->
     <dimen name="biometric_auth_pattern_view_size">248dp</dimen>
     <dimen name="biometric_auth_pattern_view_max_size">348dp</dimen>
+
+    <!-- Power Menu Lite -->
+    <dimen name="global_actions_button_size">96dp</dimen>
+    <dimen name="global_actions_button_padding">38dp</dimen>
 </resources>
\ No newline at end of file
diff --git a/packages/SystemUI/src/com/android/keyguard/CarrierTextManager.java b/packages/SystemUI/src/com/android/keyguard/CarrierTextManager.java
index a724514..b52ee01 100644
--- a/packages/SystemUI/src/com/android/keyguard/CarrierTextManager.java
+++ b/packages/SystemUI/src/com/android/keyguard/CarrierTextManager.java
@@ -148,7 +148,8 @@
     /**
      * The status of this lock screen. Primarily used for widgets on LockScreen.
      */
-    private enum StatusMode {
+    @VisibleForTesting
+    protected enum StatusMode {
         Normal, // Normal case (sim card present, it's not locked)
         NetworkLocked, // SIM card is 'network locked'.
         SimMissing, // SIM card is missing.
@@ -158,6 +159,7 @@
         SimPermDisabled, // SIM card is permanently disabled due to PUK unlock failure
         SimNotReady, // SIM is not ready yet. May never be on devices w/o a SIM.
         SimIoError, // SIM card is faulty
+        SimRestricted, // SIM Card restricted, present but not usable due to carrier restrictions.
         SimUnknown // SIM card is unknown
     }
 
@@ -493,6 +495,7 @@
                         getContext().getText(R.string.keyguard_sim_error_message_short),
                         text);
                 break;
+            case SimRestricted: // fall through
             case SimUnknown:
                 carrierText = null;
                 break;
@@ -535,19 +538,19 @@
     /**
      * Determine the current status of the lock screen given the SIM state and other stuff.
      */
-    private CarrierTextManager.StatusMode getStatusForIccState(int simState) {
-        final boolean missingAndNotProvisioned =
-                !mKeyguardUpdateMonitor.isDeviceProvisioned()
-                        && (simState == TelephonyManager.SIM_STATE_ABSENT
-                        || simState == TelephonyManager.SIM_STATE_PERM_DISABLED);
+    @VisibleForTesting
+    protected CarrierTextManager.StatusMode getStatusForIccState(int simState) {
+        if (!mKeyguardUpdateMonitor.isDeviceProvisioned()
+                && (simState == TelephonyManager.SIM_STATE_ABSENT
+                        || simState == TelephonyManager.SIM_STATE_PERM_DISABLED)) {
+            return CarrierTextManager.StatusMode.SimMissingLocked;
+        }
 
-        // Assume we're NETWORK_LOCKED if not provisioned
-        simState = missingAndNotProvisioned ? TelephonyManager.SIM_STATE_NETWORK_LOCKED : simState;
         switch (simState) {
             case TelephonyManager.SIM_STATE_ABSENT:
                 return CarrierTextManager.StatusMode.SimMissing;
             case TelephonyManager.SIM_STATE_NETWORK_LOCKED:
-                return CarrierTextManager.StatusMode.SimMissingLocked;
+                return CarrierTextManager.StatusMode.NetworkLocked;
             case TelephonyManager.SIM_STATE_NOT_READY:
                 return CarrierTextManager.StatusMode.SimNotReady;
             case TelephonyManager.SIM_STATE_PIN_REQUIRED:
@@ -562,6 +565,8 @@
                 return CarrierTextManager.StatusMode.SimUnknown;
             case TelephonyManager.SIM_STATE_CARD_IO_ERROR:
                 return CarrierTextManager.StatusMode.SimIoError;
+            case TelephonyManager.SIM_STATE_CARD_RESTRICTED:
+                return CarrierTextManager.StatusMode.SimRestricted;
         }
         return CarrierTextManager.StatusMode.SimUnknown;
     }
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardPasswordView.java b/packages/SystemUI/src/com/android/keyguard/KeyguardPasswordView.java
index 1d7c35d..7a0a24a 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardPasswordView.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardPasswordView.java
@@ -104,7 +104,7 @@
             case PROMPT_REASON_DEVICE_ADMIN:
                 return R.string.kg_prompt_reason_device_admin;
             case PROMPT_REASON_USER_REQUEST:
-                return R.string.kg_prompt_reason_user_request;
+                return R.string.kg_prompt_after_user_lockdown_password;
             case PROMPT_REASON_PREPARE_FOR_UPDATE:
                 return R.string.kg_prompt_reason_timeout_password;
             case PROMPT_REASON_NON_STRONG_BIOMETRIC_TIMEOUT:
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardPatternViewController.java b/packages/SystemUI/src/com/android/keyguard/KeyguardPatternViewController.java
index 64b1c50..be42376 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardPatternViewController.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardPatternViewController.java
@@ -311,7 +311,7 @@
                 resId = R.string.kg_prompt_reason_device_admin;
                 break;
             case PROMPT_REASON_USER_REQUEST:
-                resId = R.string.kg_prompt_reason_user_request;
+                resId = R.string.kg_prompt_after_user_lockdown_pattern;
                 break;
             case PROMPT_REASON_PREPARE_FOR_UPDATE:
                 resId = R.string.kg_prompt_reason_timeout_pattern;
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardPinBasedInputView.java b/packages/SystemUI/src/com/android/keyguard/KeyguardPinBasedInputView.java
index 5cb2c5c..687436c 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardPinBasedInputView.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardPinBasedInputView.java
@@ -118,7 +118,7 @@
             case PROMPT_REASON_DEVICE_ADMIN:
                 return R.string.kg_prompt_reason_device_admin;
             case PROMPT_REASON_USER_REQUEST:
-                return R.string.kg_prompt_reason_user_request;
+                return R.string.kg_prompt_after_user_lockdown_pin;
             case PROMPT_REASON_PREPARE_FOR_UPDATE:
                 return R.string.kg_prompt_reason_timeout_pin;
             case PROMPT_REASON_NON_STRONG_BIOMETRIC_TIMEOUT:
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
index 2bf8fb3..ae061c0 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
@@ -2045,11 +2045,47 @@
     private final HashMap<Integer, Boolean> mIsUnlockWithFingerprintPossible = new HashMap<>();
 
     /**
-     * When we receive a
-     * {@link com.android.internal.telephony.TelephonyIntents#ACTION_SIM_STATE_CHANGED} broadcast,
+     * When we receive a {@link android.content.Intent#ACTION_SIM_STATE_CHANGED} broadcast,
      * and then pass a result via our handler to {@link KeyguardUpdateMonitor#handleSimStateChange},
      * we need a single object to pass to the handler.  This class helps decode
      * the intent and provide a {@link SimData} result.
+     *
+     * Below is the Sim state mapping matrixs:
+     * +---+-----------------------------------------------------+----------------------------+
+     * |   |Telephony FWK broadcast with action                  |SystemUI mapping SIM state  |
+     * |   |android.content.Intent#ACTION_SIM_STATE_CHANGED      |refer to android.telephony. |
+     * |NO.+-------------------------+---------------------------+TelephonyManager#getSimState|
+     * |   |EXTRA_SIM_STATE          |EXTRA_SIM_LOCKED_REASON    |                            |
+     * |   |(Intent#XXX)             |(Intent#XXX)               |TelephonyManager#SimState   |
+     * +===+=====================================================+============================+
+     * |1  |SIM_STATE_UNKNOWN        |always null                |SIM_STATE_UNKNOWN           |
+     * +---+-------------------------+---------------------------+----------------------------+
+     * |2  |SIM_STATE_ABSENT         |always null                |SIM_STATE_ABSENT            |
+     * +---+-------------------------+---------------------------+----------------------------+
+     * |3  |SIM_STATE_CARD_IO_ERROR  |SIM_STATE_CARD_IO_ERROR    |SIM_STATE_CARD_IO_ERROR     |
+     * +---+-------------------------+---------------------------+----------------------------+
+     * |4  |SIM_STATE_CARD_RESTRICTED|SIM_STATE_CARD_RESTRICTED  |SIM_STATE_CARD_RESTRICTED   |
+     * +---+-------------------------+---------------------------+----------------------------+
+     * |5  |SIM_STATE_LOCKED         |SIM_LOCKED_ON_PIN          |SIM_STATE_PIN_REQUIRED      |
+     * +---+-------------------------+---------------------------+----------------------------+
+     * |6  |SIM_STATE_LOCKED         |SIM_LOCKED_ON_PUK          |SIM_STATE_PUK_REQUIRED      |
+     * +---+-------------------------+---------------------------+----------------------------+
+     * |7  |SIM_STATE_LOCKED         |SIM_LOCKED_NETWORK         |SIM_STATE_NETWORK_LOCKED    |
+     * +---+-------------------------+---------------------------+----------------------------+
+     * |8  |SIM_STATE_LOCKED         |SIM_ABSENT_ON_PERM_DISABLED|SIM_STATE_PERM_DISABLED     |
+     * +---+-------------------------+---------------------------+----------------------------+
+     * |9  |SIM_STATE_NOT_READY      |always null                |SIM_STATE_NOT_READY         |
+     * +---+-------------------------+---------------------------+----------------------------+
+     * |10 |SIM_STATE_IMSI           |always null                |SIM_STATE_READY             |
+     * +---+-------------------------+---------------------------+----------------------------+
+     * |11 |SIM_STATE_READY          |always null                |SIM_STATE_READY             |
+     * +---+-------------------------+---------------------------+----------------------------+
+     * |12 |SIM_STATE_LOADED         |always null                |SIM_STATE_READY             |
+     * +---+-------------------------+---------------------------+----------------------------+
+     *
+     * Note that, it seems #10 imsi ready case(i.e. SIM_STATE_IMSI) is never triggered from
+     * Android Pie(telephony FWK doesn't trigger this broadcast any more), but it is still
+     * OK keep this mapping logic.
      */
     private static class SimData {
         public int simState;
@@ -2063,26 +2099,16 @@
         }
 
         static SimData fromIntent(Intent intent) {
-            int state;
             if (!Intent.ACTION_SIM_STATE_CHANGED.equals(intent.getAction())) {
                 throw new IllegalArgumentException("only handles intent ACTION_SIM_STATE_CHANGED");
             }
+            int state = TelephonyManager.SIM_STATE_UNKNOWN;
             String stateExtra = intent.getStringExtra(Intent.EXTRA_SIM_STATE);
             int slotId = intent.getIntExtra(SubscriptionManager.EXTRA_SLOT_INDEX, 0);
             int subId = intent.getIntExtra(SubscriptionManager.EXTRA_SUBSCRIPTION_INDEX,
                     SubscriptionManager.INVALID_SUBSCRIPTION_ID);
             if (Intent.SIM_STATE_ABSENT.equals(stateExtra)) {
-                final String absentReason = intent
-                        .getStringExtra(Intent.EXTRA_SIM_LOCKED_REASON);
-
-                if (Intent.SIM_ABSENT_ON_PERM_DISABLED.equals(
-                        absentReason)) {
-                    state = TelephonyManager.SIM_STATE_PERM_DISABLED;
-                } else {
-                    state = TelephonyManager.SIM_STATE_ABSENT;
-                }
-            } else if (Intent.SIM_STATE_READY.equals(stateExtra)) {
-                state = TelephonyManager.SIM_STATE_READY;
+                state = TelephonyManager.SIM_STATE_ABSENT;
             } else if (Intent.SIM_STATE_LOCKED.equals(stateExtra)) {
                 final String lockedReason = intent
                         .getStringExtra(Intent.EXTRA_SIM_LOCKED_REASON);
@@ -2090,20 +2116,24 @@
                     state = TelephonyManager.SIM_STATE_PIN_REQUIRED;
                 } else if (Intent.SIM_LOCKED_ON_PUK.equals(lockedReason)) {
                     state = TelephonyManager.SIM_STATE_PUK_REQUIRED;
-                } else {
-                    state = TelephonyManager.SIM_STATE_UNKNOWN;
+                } else if (Intent.SIM_LOCKED_NETWORK.equals(lockedReason)) {
+                    state = TelephonyManager.SIM_STATE_NETWORK_LOCKED;
+                } else if (Intent.SIM_ABSENT_ON_PERM_DISABLED.equals(lockedReason)) {
+                    state = TelephonyManager.SIM_STATE_PERM_DISABLED;
                 }
-            } else if (Intent.SIM_LOCKED_NETWORK.equals(stateExtra)) {
-                state = TelephonyManager.SIM_STATE_NETWORK_LOCKED;
             } else if (Intent.SIM_STATE_CARD_IO_ERROR.equals(stateExtra)) {
                 state = TelephonyManager.SIM_STATE_CARD_IO_ERROR;
-            } else if (Intent.SIM_STATE_LOADED.equals(stateExtra)
+            } else if (Intent.SIM_STATE_CARD_RESTRICTED.equals(stateExtra)) {
+                state = TelephonyManager.SIM_STATE_CARD_RESTRICTED;
+            } else if (Intent.SIM_STATE_NOT_READY.equals(stateExtra)) {
+                state = TelephonyManager.SIM_STATE_NOT_READY;
+            } else if (Intent.SIM_STATE_READY.equals(stateExtra)
+                    || Intent.SIM_STATE_LOADED.equals(stateExtra)
                     || Intent.SIM_STATE_IMSI.equals(stateExtra)) {
-                // This is required because telephony doesn't return to "READY" after
+                // Mapping SIM_STATE_LOADED and SIM_STATE_IMSI to SIM_STATE_READY is required
+                // because telephony doesn't return to "READY" after
                 // these state transitions. See bug 7197471.
                 state = TelephonyManager.SIM_STATE_READY;
-            } else {
-                state = TelephonyManager.SIM_STATE_UNKNOWN;
             }
             return new SimData(state, slotId, subId);
         }
diff --git a/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayAnimationsController.kt b/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayAnimationsController.kt
index c5e7e0d..ee046c2 100644
--- a/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayAnimationsController.kt
+++ b/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayAnimationsController.kt
@@ -34,13 +34,11 @@
 import com.android.systemui.complication.ComplicationLayoutParams.Position
 import com.android.systemui.dreams.dagger.DreamOverlayModule
 import com.android.systemui.keyguard.ui.viewmodel.DreamingToLockscreenTransitionViewModel
-import com.android.systemui.keyguard.ui.viewmodel.DreamingToLockscreenTransitionViewModel.Companion.DREAM_ANIMATION_DURATION
 import com.android.systemui.lifecycle.repeatWhenAttached
 import com.android.systemui.statusbar.BlurUtils
 import com.android.systemui.statusbar.CrossFadeHelper
 import com.android.systemui.statusbar.policy.ConfigurationController
 import com.android.systemui.statusbar.policy.ConfigurationController.ConfigurationListener
-import com.android.systemui.util.concurrency.DelayableExecutor
 import javax.inject.Inject
 import javax.inject.Named
 import kotlinx.coroutines.flow.MutableStateFlow
@@ -129,6 +127,12 @@
                         )
                     }
                 }
+
+                launch {
+                    transitionViewModel.transitionEnded.collect { _ ->
+                        mOverlayStateController.setExitAnimationsRunning(false)
+                    }
+                }
             }
 
             configController.removeCallback(configCallback)
@@ -251,9 +255,9 @@
     }
 
     /** Starts the dream content and dream overlay exit animations. */
-    fun wakeUp(doneCallback: Runnable, executor: DelayableExecutor) {
+    fun wakeUp() {
         cancelAnimations()
-        executor.executeDelayed(doneCallback, DREAM_ANIMATION_DURATION.inWholeMilliseconds)
+        mOverlayStateController.setExitAnimationsRunning(true)
     }
 
     /** Cancels the dream content and dream overlay animations, if they're currently running. */
diff --git a/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayContainerViewController.java b/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayContainerViewController.java
index c22019e..ff07bb6 100644
--- a/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayContainerViewController.java
+++ b/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayContainerViewController.java
@@ -31,8 +31,6 @@
 import android.view.View;
 import android.view.ViewGroup;
 
-import androidx.annotation.NonNull;
-
 import com.android.app.animation.Interpolators;
 import com.android.dream.lowlight.LowLightTransitionCoordinator;
 import com.android.systemui.R;
@@ -46,7 +44,6 @@
 import com.android.systemui.shade.ShadeExpansionChangeEvent;
 import com.android.systemui.statusbar.BlurUtils;
 import com.android.systemui.util.ViewController;
-import com.android.systemui.util.concurrency.DelayableExecutor;
 
 import java.util.Arrays;
 
@@ -302,20 +299,15 @@
 
     /**
      * Handle the dream waking up and run any necessary animations.
-     *
-     * @param onAnimationEnd Callback to trigger once animations are finished.
-     * @param callbackExecutor Executor to execute the callback on.
      */
-    public void wakeUp(@NonNull Runnable onAnimationEnd,
-            @NonNull DelayableExecutor callbackExecutor) {
+    public void wakeUp() {
         // When swiping causes wakeup, do not run any animations as the dream should exit as soon
         // as possible.
         if (mWakingUpFromSwipe) {
-            onAnimationEnd.run();
             return;
         }
 
-        mDreamOverlayAnimationsController.wakeUp(onAnimationEnd, callbackExecutor);
+        mDreamOverlayAnimationsController.wakeUp();
     }
 
     @Override
diff --git a/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayService.java b/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayService.java
index 1da7900..d509015 100644
--- a/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayService.java
+++ b/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayService.java
@@ -116,6 +116,17 @@
                 }
             };
 
+    private final DreamOverlayStateController.Callback mExitAnimationFinishedCallback =
+            new DreamOverlayStateController.Callback() {
+                @Override
+                public void onStateChanged() {
+                    if (!mStateController.areExitAnimationsRunning()) {
+                        mStateController.removeCallback(mExitAnimationFinishedCallback);
+                        resetCurrentDreamOverlayLocked();
+                    }
+                }
+            };
+
     private final DreamOverlayStateController mStateController;
 
     @VisibleForTesting
@@ -257,10 +268,10 @@
     }
 
     @Override
-    public void onWakeUp(@NonNull Runnable onCompletedCallback) {
+    public void onWakeUp() {
         if (mDreamOverlayContainerViewController != null) {
             mDreamOverlayCallbackController.onWakeUp();
-            mDreamOverlayContainerViewController.wakeUp(onCompletedCallback, mExecutor);
+            mDreamOverlayContainerViewController.wakeUp();
         }
     }
 
@@ -329,6 +340,11 @@
     }
 
     private void resetCurrentDreamOverlayLocked() {
+        if (mStateController.areExitAnimationsRunning()) {
+            mStateController.addCallback(mExitAnimationFinishedCallback);
+            return;
+        }
+
         if (mStarted && mWindow != null) {
             try {
                 mWindowManager.removeView(mWindow.getDecorView());
diff --git a/packages/SystemUI/src/com/android/systemui/flags/Flags.kt b/packages/SystemUI/src/com/android/systemui/flags/Flags.kt
index f3403f7..3f20540 100644
--- a/packages/SystemUI/src/com/android/systemui/flags/Flags.kt
+++ b/packages/SystemUI/src/com/android/systemui/flags/Flags.kt
@@ -266,7 +266,7 @@
     /** Flag meant to guard the talkback fix for the KeyguardIndicationTextView */
     // TODO(b/286563884): Tracking bug
     @JvmField
-    val KEYGUARD_TALKBACK_FIX = unreleasedFlag(238, "keyguard_talkback_fix")
+    val KEYGUARD_TALKBACK_FIX = releasedFlag(238, "keyguard_talkback_fix")
 
     // 300 - power menu
     // TODO(b/254512600): Tracking Bug
@@ -748,4 +748,10 @@
     @JvmField
     val BIGPICTURE_NOTIFICATION_LAZY_LOADING =
             unreleasedFlag(283447257, "bigpicture_notification_lazy_loading")
+
+    // 2900 - CentralSurfaces-related flags
+
+    // TODO(b/285174336): Tracking Bug
+    @JvmField
+    val USE_REPOS_FOR_BOUNCER_SHOWING = unreleasedFlag(2900, "use_repos_for_bouncer_showing")
 }
diff --git a/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialogLite.java b/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialogLite.java
index 2807107..76322ad 100644
--- a/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialogLite.java
+++ b/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialogLite.java
@@ -249,6 +249,7 @@
     private int mDialogPressDelay = DIALOG_PRESS_DELAY; // ms
     protected Handler mMainHandler;
     private int mSmallestScreenWidthDp;
+    private int mOrientation;
     private final Optional<CentralSurfaces> mCentralSurfacesOptional;
     private final KeyguardUpdateMonitor mKeyguardUpdateMonitor;
     private final DialogLaunchAnimator mDialogLaunchAnimator;
@@ -391,6 +392,7 @@
         mRingerModeTracker = ringerModeTracker;
         mMainHandler = handler;
         mSmallestScreenWidthDp = resources.getConfiguration().smallestScreenWidthDp;
+        mOrientation = resources.getConfiguration().orientation;
         mCentralSurfacesOptional = centralSurfacesOptional;
         mKeyguardUpdateMonitor = keyguardUpdateMonitor;
         mDialogLaunchAnimator = dialogLaunchAnimator;
@@ -744,8 +746,10 @@
     @Override
     public void onConfigChanged(Configuration newConfig) {
         if (mDialog != null && mDialog.isShowing()
-                && (newConfig.smallestScreenWidthDp != mSmallestScreenWidthDp)) {
+                && (newConfig.smallestScreenWidthDp != mSmallestScreenWidthDp
+                || newConfig.orientation != mOrientation)) {
             mSmallestScreenWidthDp = newConfig.smallestScreenWidthDp;
+            mOrientation = newConfig.orientation;
             mDialog.refreshDialog();
         }
     }
@@ -2303,6 +2307,8 @@
         @Override
         protected void onCreate(Bundle savedInstanceState) {
             super.onCreate(savedInstanceState);
+            getWindow().setTitle(getContext().getString(
+                    com.android.systemui.R.string.accessibility_quick_settings_power_menu));
             initializeLayout();
             mWindowDimAmount = getWindow().getAttributes().dimAmount;
             getOnBackInvokedDispatcher().registerOnBackInvokedCallback(
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardService.java b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardService.java
index 94227bc..a2c940b 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardService.java
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardService.java
@@ -187,10 +187,10 @@
         final IRemoteAnimationRunner runner, final boolean lockscreenLiveWallpaperEnabled) {
         return new IRemoteTransition.Stub() {
 
+            @GuardedBy("mLeashMap")
             private final ArrayMap<SurfaceControl, SurfaceControl> mLeashMap = new ArrayMap<>();
             private final CounterRotator mCounterRotator = new CounterRotator();
 
-
             @GuardedBy("mLeashMap")
             private IRemoteTransitionFinishedCallback mFinishCallback = null;
 
@@ -200,40 +200,38 @@
                     throws RemoteException {
                 Slog.d(TAG, "Starts IRemoteAnimationRunner: info=" + info);
 
+                final RemoteAnimationTarget[] apps;
+                final RemoteAnimationTarget[] wallpapers;
+                final RemoteAnimationTarget[] nonApps = new RemoteAnimationTarget[0];
                 synchronized (mLeashMap) {
-                    final RemoteAnimationTarget[] apps =
-                            wrap(info, false /* wallpapers */, t, mLeashMap, mCounterRotator);
-                    final RemoteAnimationTarget[] wallpapers =
-                            wrap(info, true /* wallpapers */, t, mLeashMap, mCounterRotator);
-                    final RemoteAnimationTarget[] nonApps = new RemoteAnimationTarget[0];
-
-                    // Set alpha back to 1 for the independent changes because we will be animating
-                    // children instead.
-                    for (TransitionInfo.Change chg : info.getChanges()) {
-                        if (TransitionInfo.isIndependent(chg, info)) {
-                            t.setAlpha(chg.getLeash(), 1.f);
-                        }
-                    }
-                    initAlphaForAnimationTargets(t, apps);
-                    if (lockscreenLiveWallpaperEnabled) {
-                        initAlphaForAnimationTargets(t, wallpapers);
-                    }
-                    t.apply();
+                    apps = wrap(info, false /* wallpapers */, t, mLeashMap, mCounterRotator);
+                    wallpapers = wrap(info, true /* wallpapers */, t, mLeashMap, mCounterRotator);
                     mFinishCallback = finishCallback;
-                    runner.onAnimationStart(
-                            getTransitionOldType(info.getType(), info.getFlags(), apps),
-                            apps, wallpapers, nonApps,
-                            new IRemoteAnimationFinishedCallback.Stub() {
-                                @Override
-                                public void onAnimationFinished() throws RemoteException {
-                                    synchronized (mLeashMap) {
-                                        Slog.d(TAG, "Finish IRemoteAnimationRunner.");
-                                        finish();
-                                    }
-                                }
-                            }
-                    );
                 }
+
+                // Set alpha back to 1 for the independent changes because we will be animating
+                // children instead.
+                for (TransitionInfo.Change chg : info.getChanges()) {
+                    if (TransitionInfo.isIndependent(chg, info)) {
+                        t.setAlpha(chg.getLeash(), 1.f);
+                    }
+                }
+                initAlphaForAnimationTargets(t, apps);
+                if (lockscreenLiveWallpaperEnabled) {
+                    initAlphaForAnimationTargets(t, wallpapers);
+                }
+                t.apply();
+
+                runner.onAnimationStart(
+                        getTransitionOldType(info.getType(), info.getFlags(), apps),
+                        apps, wallpapers, nonApps,
+                        new IRemoteAnimationFinishedCallback.Stub() {
+                            @Override
+                            public void onAnimationFinished() throws RemoteException {
+                                Slog.d(TAG, "Finish IRemoteAnimationRunner.");
+                                finish();
+                            }
+                        });
             }
 
             public void mergeAnimation(IBinder candidateTransition, TransitionInfo candidateInfo,
@@ -247,10 +245,8 @@
                 }
 
                 try {
-                    synchronized (mLeashMap) {
-                        runner.onAnimationCancelled();
-                        finish();
-                    }
+                    runner.onAnimationCancelled();
+                    finish();
                 } catch (RemoteException e) {
                     // nothing, we'll just let it finish on its own I guess.
                 }
@@ -264,18 +260,22 @@
                 }
             }
 
-            @GuardedBy("mLeashMap")
             private void finish() throws RemoteException {
+                IRemoteTransitionFinishedCallback finishCallback = null;
                 SurfaceControl.Transaction finishTransaction = null;
-                if (mCounterRotator.getSurface() != null
-                        && mCounterRotator.getSurface().isValid()) {
-                    finishTransaction = new SurfaceControl.Transaction();
-                    mCounterRotator.cleanUp(finishTransaction);
-                }
-                mLeashMap.clear();
-                final IRemoteTransitionFinishedCallback finishCallback = mFinishCallback;
-                if (finishCallback != null) {
+
+                synchronized (mLeashMap) {
+                    if (mCounterRotator.getSurface() != null
+                            && mCounterRotator.getSurface().isValid()) {
+                        finishTransaction = new SurfaceControl.Transaction();
+                        mCounterRotator.cleanUp(finishTransaction);
+                    }
+                    mLeashMap.clear();
+                    finishCallback = mFinishCallback;
                     mFinishCallback = null;
+                }
+
+                if (finishCallback != null) {
                     finishCallback.onTransitionFinished(null /* wct */, finishTransaction);
                 } else if (finishTransaction != null) {
                     finishTransaction.apply();
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
index 0e0cf74..5bf56a1 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
@@ -18,6 +18,7 @@
 
 import static android.app.StatusBarManager.SESSION_KEYGUARD;
 import static android.provider.Settings.System.SCREEN_OFF_TIMEOUT;
+import static android.view.RemoteAnimationTarget.MODE_OPENING;
 import static android.view.WindowManagerPolicyConstants.KEYGUARD_GOING_AWAY_FLAG_NO_WINDOW_ANIMATIONS;
 import static android.view.WindowManagerPolicyConstants.KEYGUARD_GOING_AWAY_FLAG_TO_LAUNCHER_CLEAR_SNAPSHOT;
 import static android.view.WindowManagerPolicyConstants.KEYGUARD_GOING_AWAY_FLAG_WITH_WALLPAPER;
@@ -32,10 +33,11 @@
 import static com.android.internal.widget.LockPatternUtils.StrongAuthTracker.STRONG_AUTH_REQUIRED_AFTER_LOCKOUT;
 import static com.android.internal.widget.LockPatternUtils.StrongAuthTracker.STRONG_AUTH_REQUIRED_AFTER_NON_STRONG_BIOMETRICS_TIMEOUT;
 import static com.android.internal.widget.LockPatternUtils.StrongAuthTracker.STRONG_AUTH_REQUIRED_AFTER_TIMEOUT;
+import static com.android.internal.widget.LockPatternUtils.StrongAuthTracker.STRONG_AUTH_REQUIRED_AFTER_USER_LOCKDOWN;
 import static com.android.internal.widget.LockPatternUtils.StrongAuthTracker.STRONG_AUTH_REQUIRED_FOR_UNATTENDED_UPDATE;
 import static com.android.systemui.DejankUtils.whitelistIpcs;
-import static com.android.systemui.keyguard.ui.viewmodel.DreamingToLockscreenTransitionViewModel.LOCKSCREEN_ANIMATION_DURATION_MS;
 import static com.android.systemui.keyguard.ui.viewmodel.LockscreenToDreamingTransitionViewModel.DREAMING_ANIMATION_DURATION_MS;
+import static com.android.systemui.util.kotlin.JavaAdapterKt.collectFlow;
 
 import android.animation.Animator;
 import android.animation.AnimatorListenerAdapter;
@@ -87,9 +89,11 @@
 import android.view.IRemoteAnimationFinishedCallback;
 import android.view.IRemoteAnimationRunner;
 import android.view.RemoteAnimationTarget;
+import android.view.SurfaceControl.Transaction;
 import android.view.SyncRtSurfaceTransactionApplier;
 import android.view.View;
 import android.view.ViewGroup;
+import android.view.ViewRootImpl;
 import android.view.WindowManager;
 import android.view.WindowManagerPolicyConstants;
 import android.view.animation.Animation;
@@ -127,12 +131,14 @@
 import com.android.systemui.animation.LaunchAnimator;
 import com.android.systemui.broadcast.BroadcastDispatcher;
 import com.android.systemui.classifier.FalsingCollector;
+import com.android.systemui.dagger.qualifiers.Main;
 import com.android.systemui.dagger.qualifiers.UiBackground;
 import com.android.systemui.dreams.DreamOverlayStateController;
 import com.android.systemui.dump.DumpManager;
 import com.android.systemui.flags.FeatureFlags;
 import com.android.systemui.flags.Flags;
 import com.android.systemui.keyguard.dagger.KeyguardModule;
+import com.android.systemui.keyguard.ui.viewmodel.DreamingToLockscreenTransitionViewModel;
 import com.android.systemui.log.SessionTracker;
 import com.android.systemui.navigationbar.NavigationModeController;
 import com.android.systemui.plugins.statusbar.StatusBarStateController;
@@ -162,6 +168,9 @@
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.concurrent.Executor;
+import java.util.function.Consumer;
+
+import kotlinx.coroutines.CoroutineDispatcher;
 
 /**
  * Mediates requests related to the keyguard.  This includes queries about the
@@ -435,11 +444,6 @@
     private final int mDreamOpenAnimationDuration;
 
     /**
-     * The duration in milliseconds of the dream close animation.
-     */
-    private final int mDreamCloseAnimationDuration;
-
-    /**
      * The animation used for hiding keyguard. This is used to fetch the animation timings if
      * WindowManager is not providing us with them.
      */
@@ -845,6 +849,8 @@
                 return KeyguardSecurityView.PROMPT_REASON_RESTART;
             } else if (any && (strongAuth & STRONG_AUTH_REQUIRED_AFTER_TIMEOUT) != 0) {
                 return KeyguardSecurityView.PROMPT_REASON_TIMEOUT;
+            } else if (any && (strongAuth & STRONG_AUTH_REQUIRED_AFTER_USER_LOCKDOWN) != 0) {
+                return KeyguardSecurityView.PROMPT_REASON_USER_REQUEST;
             } else if ((strongAuth & STRONG_AUTH_REQUIRED_AFTER_DPM_LOCK_NOW) != 0) {
                 return KeyguardSecurityView.PROMPT_REASON_DEVICE_ADMIN;
             } else if (trustAgentsEnabled
@@ -1128,49 +1134,57 @@
                         return;
                     }
 
-                    final RemoteAnimationTarget primary = apps[0];
+                    mRemoteAnimationTarget = apps[0];
                     final boolean isDream = (apps[0].taskInfo != null
                             && apps[0].taskInfo.topActivityType
                             == WindowConfiguration.ACTIVITY_TYPE_DREAM);
 
-                    final SyncRtSurfaceTransactionApplier applier =
-                            new SyncRtSurfaceTransactionApplier(
-                                    mKeyguardViewControllerLazy.get().getViewRootImpl().getView());
 
+                    final View localView = mKeyguardViewControllerLazy.get()
+                            .getViewRootImpl().getView();
+                    final SyncRtSurfaceTransactionApplier applier =
+                            new SyncRtSurfaceTransactionApplier(localView);
 
                     mContext.getMainExecutor().execute(() -> {
                         if (mUnoccludeAnimator != null) {
                             mUnoccludeAnimator.cancel();
                         }
 
+                        if (isDream) {
+                            initAlphaForAnimationTargets(wallpapers);
+                            getRemoteSurfaceAlphaApplier().accept(0.0f);
+                            mDreamingToLockscreenTransitionViewModel.get()
+                                    .startTransition();
+                            return;
+                        }
+
                         mUnoccludeAnimator = ValueAnimator.ofFloat(1f, 0f);
-                        mUnoccludeAnimator.setDuration(isDream ? mDreamCloseAnimationDuration
-                                : UNOCCLUDE_ANIMATION_DURATION);
+                        mUnoccludeAnimator.setDuration(UNOCCLUDE_ANIMATION_DURATION);
                         mUnoccludeAnimator.setInterpolator(Interpolators.TOUCH_RESPONSE);
                         mUnoccludeAnimator.addUpdateListener(
                                 animation -> {
                                     final float animatedValue =
                                             (float) animation.getAnimatedValue();
 
-                                    final float surfaceHeight = primary.screenSpaceBounds.height();
+                                    final float surfaceHeight =
+                                            mRemoteAnimationTarget.screenSpaceBounds.height();
 
                                     // Fade for all types of activities.
                                     SyncRtSurfaceTransactionApplier.SurfaceParams.Builder
                                             paramsBuilder =
                                             new SyncRtSurfaceTransactionApplier.SurfaceParams
-                                                    .Builder(primary.leash)
+                                                    .Builder(mRemoteAnimationTarget.leash)
                                                     .withAlpha(animatedValue);
-                                    // Set translate if the occluding activity isn't Dream.
-                                    if (!isDream) {
-                                        mUnoccludeMatrix.setTranslate(
-                                                0f,
-                                                (1f - animatedValue)
-                                                        * surfaceHeight
-                                                        * UNOCCLUDE_TRANSLATE_DISTANCE_PERCENT);
 
-                                        paramsBuilder.withMatrix(mUnoccludeMatrix).withCornerRadius(
-                                                mWindowCornerRadius);
-                                    }
+                                    mUnoccludeMatrix.setTranslate(
+                                            0f,
+                                            (1f - animatedValue)
+                                                    * surfaceHeight
+                                                    * UNOCCLUDE_TRANSLATE_DISTANCE_PERCENT);
+
+                                    paramsBuilder.withMatrix(mUnoccludeMatrix).withCornerRadius(
+                                            mWindowCornerRadius);
+
                                     applier.scheduleApply(paramsBuilder.build());
                                 });
                         mUnoccludeAnimator.addListener(new AnimatorListenerAdapter() {
@@ -1192,6 +1206,34 @@
                 }
             };
 
+    private static void initAlphaForAnimationTargets(
+            @android.annotation.NonNull RemoteAnimationTarget[] targets
+    ) {
+        for (RemoteAnimationTarget target : targets) {
+            if (target.mode != MODE_OPENING) continue;
+
+            try (Transaction t = new Transaction()) {
+                t.setAlpha(target.leash, 1.f);
+                t.apply();
+            }
+        }
+    }
+
+    private Consumer<Float> getRemoteSurfaceAlphaApplier() {
+        return (Float alpha) -> {
+            if (mRemoteAnimationTarget == null) return;
+            final View localView = mKeyguardViewControllerLazy.get().getViewRootImpl().getView();
+            final SyncRtSurfaceTransactionApplier applier =
+                    new SyncRtSurfaceTransactionApplier(localView);
+            SyncRtSurfaceTransactionApplier.SurfaceParams
+                    params =
+                    new SyncRtSurfaceTransactionApplier.SurfaceParams
+                            .Builder(mRemoteAnimationTarget.leash)
+                            .withAlpha(alpha).build();
+            applier.scheduleApply(params);
+        };
+    }
+
     private DeviceConfigProxy mDeviceConfig;
     private DozeParameters mDozeParameters;
 
@@ -1221,6 +1263,10 @@
     private FeatureFlags mFeatureFlags;
     private final UiEventLogger mUiEventLogger;
     private final SessionTracker mSessionTracker;
+    private final CoroutineDispatcher mMainDispatcher;
+    private final Lazy<DreamingToLockscreenTransitionViewModel>
+            mDreamingToLockscreenTransitionViewModel;
+    private RemoteAnimationTarget mRemoteAnimationTarget;
 
     /**
      * Injected constructor. See {@link KeyguardModule}.
@@ -1256,7 +1302,9 @@
             Lazy<NotificationShadeWindowController> notificationShadeWindowControllerLazy,
             Lazy<ActivityLaunchAnimator> activityLaunchAnimator,
             Lazy<ScrimController> scrimControllerLazy,
-            FeatureFlags featureFlags) {
+            FeatureFlags featureFlags,
+            @Main CoroutineDispatcher mainDispatcher,
+            Lazy<DreamingToLockscreenTransitionViewModel> dreamingToLockscreenTransitionViewModel) {
         mContext = context;
         mUserTracker = userTracker;
         mFalsingCollector = falsingCollector;
@@ -1311,11 +1359,13 @@
         mWindowCornerRadius = ScreenDecorationsUtils.getWindowCornerRadius(context);
 
         mDreamOpenAnimationDuration = (int) DREAMING_ANIMATION_DURATION_MS;
-        mDreamCloseAnimationDuration = (int) LOCKSCREEN_ANIMATION_DURATION_MS;
 
         mFeatureFlags = featureFlags;
         mUiEventLogger = uiEventLogger;
         mSessionTracker = sessionTracker;
+
+        mMainDispatcher = mainDispatcher;
+        mDreamingToLockscreenTransitionViewModel = dreamingToLockscreenTransitionViewModel;
     }
 
     public void userActivity() {
@@ -1434,6 +1484,13 @@
             mUpdateMonitor.registerCallback(mUpdateCallback);
             adjustStatusBarLocked();
             mDreamOverlayStateController.addCallback(mDreamOverlayStateCallback);
+
+            ViewRootImpl viewRootImpl = mKeyguardViewControllerLazy.get().getViewRootImpl();
+            if (viewRootImpl != null) {
+                collectFlow(viewRootImpl.getView(),
+                        mDreamingToLockscreenTransitionViewModel.get().getDreamOverlayAlpha(),
+                        getRemoteSurfaceAlphaApplier(), mMainDispatcher);
+            }
         }
         // Most services aren't available until the system reaches the ready state, so we
         // send it here when the device first boots.
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/dagger/KeyguardModule.java b/packages/SystemUI/src/com/android/systemui/keyguard/dagger/KeyguardModule.java
index d7c039d..ab79c80 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/dagger/KeyguardModule.java
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/dagger/KeyguardModule.java
@@ -37,6 +37,7 @@
 import com.android.systemui.classifier.FalsingCollector;
 import com.android.systemui.classifier.FalsingModule;
 import com.android.systemui.dagger.SysUISingleton;
+import com.android.systemui.dagger.qualifiers.Main;
 import com.android.systemui.dagger.qualifiers.UiBackground;
 import com.android.systemui.dreams.DreamOverlayStateController;
 import com.android.systemui.dump.DumpManager;
@@ -51,6 +52,7 @@
 import com.android.systemui.keyguard.domain.quickaffordance.KeyguardQuickAffordanceModule;
 import com.android.systemui.keyguard.shared.quickaffordance.KeyguardQuickAffordancesMetricsLogger;
 import com.android.systemui.keyguard.shared.quickaffordance.KeyguardQuickAffordancesMetricsLoggerImpl;
+import com.android.systemui.keyguard.ui.viewmodel.DreamingToLockscreenTransitionViewModel;
 import com.android.systemui.log.SessionTracker;
 import com.android.systemui.navigationbar.NavigationModeController;
 import com.android.systemui.settings.UserTracker;
@@ -72,6 +74,8 @@
 
 import java.util.concurrent.Executor;
 
+import kotlinx.coroutines.CoroutineDispatcher;
+
 /**
  * Dagger Module providing keyguard.
  */
@@ -128,7 +132,9 @@
             Lazy<NotificationShadeWindowController> notificationShadeWindowController,
             Lazy<ActivityLaunchAnimator> activityLaunchAnimator,
             Lazy<ScrimController> scrimControllerLazy,
-            FeatureFlags featureFlags) {
+            FeatureFlags featureFlags,
+            @Main CoroutineDispatcher mainDispatcher,
+            Lazy<DreamingToLockscreenTransitionViewModel> dreamingToLockscreenTransitionViewModel) {
         return new KeyguardViewMediator(
                 context,
                 uiEventLogger,
@@ -162,7 +168,9 @@
                 notificationShadeWindowController,
                 activityLaunchAnimator,
                 scrimControllerLazy,
-                featureFlags);
+                featureFlags,
+                mainDispatcher,
+                dreamingToLockscreenTransitionViewModel);
     }
 
     /** */
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/KeyguardTransitionRepository.kt b/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/KeyguardTransitionRepository.kt
index 100bc59..358ab01 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/KeyguardTransitionRepository.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/KeyguardTransitionRepository.kt
@@ -160,35 +160,28 @@
             // An animator was provided, so use it to run the transition
             animator.setFloatValues(startingValue, 1f)
             animator.duration = ((1f - startingValue) * animator.duration).toLong()
-            val updateListener =
-                object : AnimatorUpdateListener {
-                    override fun onAnimationUpdate(animation: ValueAnimator) {
-                        emitTransition(
-                            TransitionStep(
-                                info,
-                                (animation.getAnimatedValue() as Float),
-                                TransitionState.RUNNING
-                            )
-                        )
-                    }
-                }
+            val updateListener = AnimatorUpdateListener { animation ->
+                emitTransition(
+                    TransitionStep(
+                        info,
+                        (animation.animatedValue as Float),
+                        TransitionState.RUNNING
+                    )
+                )
+            }
             val adapter =
                 object : AnimatorListenerAdapter() {
                     override fun onAnimationStart(animation: Animator) {
                         emitTransition(TransitionStep(info, startingValue, TransitionState.STARTED))
                     }
                     override fun onAnimationCancel(animation: Animator) {
-                        endAnimation(animation, lastStep.value, TransitionState.CANCELED)
+                        endAnimation(lastStep.value, TransitionState.CANCELED)
                     }
                     override fun onAnimationEnd(animation: Animator) {
-                        endAnimation(animation, 1f, TransitionState.FINISHED)
+                        endAnimation(1f, TransitionState.FINISHED)
                     }
 
-                    private fun endAnimation(
-                        animation: Animator,
-                        value: Float,
-                        state: TransitionState
-                    ) {
+                    private fun endAnimation(value: Float, state: TransitionState) {
                         emitTransition(TransitionStep(info, value, state))
                         animator.removeListener(this)
                         animator.removeUpdateListener(updateListener)
@@ -201,7 +194,7 @@
             return@startTransition null
         }
             ?: run {
-                emitTransition(TransitionStep(info, 0f, TransitionState.STARTED))
+                emitTransition(TransitionStep(info, startingValue, TransitionState.STARTED))
 
                 // No animator, so it's manual. Provide a mechanism to callback
                 updateTransitionId = UUID.randomUUID()
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromDozingTransitionInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromDozingTransitionInteractor.kt
index 323fc31..ee2c2df 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromDozingTransitionInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromDozingTransitionInteractor.kt
@@ -52,7 +52,7 @@
                 .sample(keyguardTransitionInteractor.startedKeyguardTransitionStep, ::Pair)
                 .collect { (wakefulnessModel, lastStartedTransition) ->
                     if (
-                        wakefulnessModel.isStartingToWake() &&
+                        wakefulnessModel.isStartingToWakeOrAwake() &&
                             lastStartedTransition.to == KeyguardState.DOZING
                     ) {
                         keyguardTransitionRepository.startTransition(
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromDreamingTransitionInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromDreamingTransitionInteractor.kt
index 36c8eb1..ccf4bc1 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromDreamingTransitionInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromDreamingTransitionInteractor.kt
@@ -23,7 +23,6 @@
 import com.android.systemui.keyguard.data.repository.KeyguardTransitionRepository
 import com.android.systemui.keyguard.shared.model.BiometricUnlockModel
 import com.android.systemui.keyguard.shared.model.DozeStateModel
-import com.android.systemui.keyguard.shared.model.DozeStateModel.Companion.isDozeOff
 import com.android.systemui.keyguard.shared.model.KeyguardState
 import com.android.systemui.keyguard.shared.model.TransitionInfo
 import com.android.systemui.util.kotlin.Utils.Companion.toTriple
@@ -48,39 +47,23 @@
 ) : TransitionInteractor(FromDreamingTransitionInteractor::class.simpleName!!) {
 
     override fun start() {
-        listenForDreamingToLockscreen()
         listenForDreamingToOccluded()
         listenForDreamingToGone()
         listenForDreamingToDozing()
     }
 
-    private fun listenForDreamingToLockscreen() {
+    fun startToLockscreenTransition() {
         scope.launch {
-            keyguardInteractor.isAbleToDream
-                .sample(
-                    combine(
-                        keyguardInteractor.dozeTransitionModel,
-                        keyguardTransitionInteractor.startedKeyguardTransitionStep,
-                        ::Pair
-                    ),
-                    ::toTriple
+            if (keyguardTransitionInteractor.startedKeyguardState.value == KeyguardState.DREAMING) {
+                keyguardTransitionRepository.startTransition(
+                    TransitionInfo(
+                        name,
+                        KeyguardState.DREAMING,
+                        KeyguardState.LOCKSCREEN,
+                        getAnimator(TO_LOCKSCREEN_DURATION),
+                    )
                 )
-                .collect { (isDreaming, dozeTransitionModel, lastStartedTransition) ->
-                    if (
-                        !isDreaming &&
-                            isDozeOff(dozeTransitionModel.to) &&
-                            lastStartedTransition.to == KeyguardState.DREAMING
-                    ) {
-                        keyguardTransitionRepository.startTransition(
-                            TransitionInfo(
-                                name,
-                                KeyguardState.DREAMING,
-                                KeyguardState.LOCKSCREEN,
-                                getAnimator(TO_LOCKSCREEN_DURATION),
-                            )
-                        )
-                    }
-                }
+            }
         }
     }
 
@@ -173,6 +156,6 @@
 
     companion object {
         private val DEFAULT_DURATION = 500.milliseconds
-        val TO_LOCKSCREEN_DURATION = 1183.milliseconds
+        val TO_LOCKSCREEN_DURATION = 1167.milliseconds
     }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardInteractor.kt
index 3cf9a9e..c44435e 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardInteractor.kt
@@ -111,7 +111,7 @@
                 isDreaming && isDozeOff(dozeTransitionModel.to)
             }
             .sample(wakefulnessModel) { isAbleToDream, wakefulnessModel ->
-                isAbleToDream && wakefulnessModel.isStartingToWake()
+                isAbleToDream && wakefulnessModel.isStartingToWakeOrAwake()
             }
             .flatMapLatest { isAbleToDream ->
                 flow {
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionInteractor.kt
index da0ada1..42f12f8 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionInteractor.kt
@@ -18,6 +18,7 @@
 package com.android.systemui.keyguard.domain.interactor
 
 import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.dagger.qualifiers.Application
 import com.android.systemui.keyguard.data.repository.KeyguardTransitionRepository
 import com.android.systemui.keyguard.shared.model.KeyguardState
 import com.android.systemui.keyguard.shared.model.KeyguardState.AOD
@@ -29,10 +30,14 @@
 import com.android.systemui.keyguard.shared.model.TransitionState
 import com.android.systemui.keyguard.shared.model.TransitionStep
 import javax.inject.Inject
+import kotlinx.coroutines.CoroutineScope
 import kotlinx.coroutines.flow.Flow
+import kotlinx.coroutines.flow.SharingStarted
+import kotlinx.coroutines.flow.StateFlow
 import kotlinx.coroutines.flow.filter
 import kotlinx.coroutines.flow.map
 import kotlinx.coroutines.flow.merge
+import kotlinx.coroutines.flow.stateIn
 
 /** Encapsulates business-logic related to the keyguard transitions. */
 @SysUISingleton
@@ -40,6 +45,7 @@
 @Inject
 constructor(
     private val repository: KeyguardTransitionRepository,
+    @Application val scope: CoroutineScope,
 ) {
     /** (any)->GONE transition information */
     val anyStateToGoneTransition: Flow<TransitionStep> =
@@ -108,10 +114,17 @@
     val finishedKeyguardTransitionStep: Flow<TransitionStep> =
         repository.transitions.filter { step -> step.transitionState == TransitionState.FINISHED }
 
-    /** The last completed [KeyguardState] transition */
-    val finishedKeyguardState: Flow<KeyguardState> =
-        finishedKeyguardTransitionStep.map { step -> step.to }
+    /** The destination state of the last started transition */
+    val startedKeyguardState: StateFlow<KeyguardState> =
+        startedKeyguardTransitionStep
+            .map { step -> step.to }
+            .stateIn(scope, SharingStarted.Eagerly, KeyguardState.OFF)
 
+    /** The last completed [KeyguardState] transition */
+    val finishedKeyguardState: StateFlow<KeyguardState> =
+        finishedKeyguardTransitionStep
+            .map { step -> step.to }
+            .stateIn(scope, SharingStarted.Eagerly, LOCKSCREEN)
     /**
      * The amount of transition into or out of the given [KeyguardState].
      *
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/shared/model/WakefulnessModel.kt b/packages/SystemUI/src/com/android/systemui/keyguard/shared/model/WakefulnessModel.kt
index 7ca90ba..52e15be 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/shared/model/WakefulnessModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/shared/model/WakefulnessModel.kt
@@ -29,6 +29,8 @@
 
     fun isStartingToSleepOrAsleep() = isStartingToSleep() || state == WakefulnessState.ASLEEP
 
+    fun isStartingToWakeOrAwake() = isStartingToWake() || state == WakefulnessState.AWAKE
+
     fun isStartingToSleepFromPowerButton() =
         isStartingToSleep() && lastWakeReason == WakeSleepReason.POWER_BUTTON
 
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/DreamingToLockscreenTransitionViewModel.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/DreamingToLockscreenTransitionViewModel.kt
index 2c9a9b3..9ca4bd6 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/DreamingToLockscreenTransitionViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/DreamingToLockscreenTransitionViewModel.kt
@@ -16,15 +16,17 @@
 
 package com.android.systemui.keyguard.ui.viewmodel
 
-import com.android.app.animation.Interpolators.EMPHASIZED_ACCELERATE
-import com.android.app.animation.Interpolators.EMPHASIZED_DECELERATE
+import com.android.app.animation.Interpolators.EMPHASIZED
 import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.keyguard.domain.interactor.FromDreamingTransitionInteractor
 import com.android.systemui.keyguard.domain.interactor.FromDreamingTransitionInteractor.Companion.TO_LOCKSCREEN_DURATION
 import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractor
+import com.android.systemui.keyguard.shared.model.TransitionState
 import com.android.systemui.keyguard.ui.KeyguardTransitionAnimationFlow
 import javax.inject.Inject
 import kotlin.time.Duration.Companion.milliseconds
 import kotlinx.coroutines.flow.Flow
+import kotlinx.coroutines.flow.filter
 
 /**
  * Breaks down DREAMING->LOCKSCREEN transition into discrete steps for corresponding views to
@@ -34,22 +36,32 @@
 class DreamingToLockscreenTransitionViewModel
 @Inject
 constructor(
-    private val interactor: KeyguardTransitionInteractor,
+    keyguardTransitionInteractor: KeyguardTransitionInteractor,
+    private val fromDreamingTransitionInteractor: FromDreamingTransitionInteractor
 ) {
+    fun startTransition() = fromDreamingTransitionInteractor.startToLockscreenTransition()
+
     private val transitionAnimation =
         KeyguardTransitionAnimationFlow(
             transitionDuration = TO_LOCKSCREEN_DURATION,
-            transitionFlow = interactor.dreamingToLockscreenTransition,
+            transitionFlow = keyguardTransitionInteractor.dreamingToLockscreenTransition,
         )
 
+    val transitionEnded =
+        keyguardTransitionInteractor.dreamingToLockscreenTransition.filter { step ->
+            step.transitionState == TransitionState.FINISHED ||
+                step.transitionState == TransitionState.CANCELED
+        }
+
     /** Dream overlay y-translation on exit */
     fun dreamOverlayTranslationY(translatePx: Int): Flow<Float> {
         return transitionAnimation.createFlow(
-            duration = 600.milliseconds,
+            duration = TO_LOCKSCREEN_DURATION,
             onStep = { it * translatePx },
-            interpolator = EMPHASIZED_ACCELERATE,
+            interpolator = EMPHASIZED,
         )
     }
+
     /** Dream overlay views alpha - fade out */
     val dreamOverlayAlpha: Flow<Float> =
         transitionAnimation.createFlow(
@@ -65,7 +77,7 @@
             // Reset on cancel or finish
             onFinish = { 0f },
             onCancel = { 0f },
-            interpolator = EMPHASIZED_DECELERATE,
+            interpolator = EMPHASIZED,
         )
     }
 
@@ -76,12 +88,4 @@
             duration = 250.milliseconds,
             onStep = { it },
         )
-
-    companion object {
-        /* Length of time before ending the dream activity, in order to start unoccluding */
-        val DREAM_ANIMATION_DURATION = 250.milliseconds
-        @JvmField
-        val LOCKSCREEN_ANIMATION_DURATION_MS =
-            (TO_LOCKSCREEN_DURATION - DREAM_ANIMATION_DURATION).inWholeMilliseconds
-    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenToDreamingTransitionViewModel.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenToDreamingTransitionViewModel.kt
index c6187dd..a3ae67d 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenToDreamingTransitionViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenToDreamingTransitionViewModel.kt
@@ -33,7 +33,7 @@
 class LockscreenToDreamingTransitionViewModel
 @Inject
 constructor(
-    private val interactor: KeyguardTransitionInteractor,
+    interactor: KeyguardTransitionInteractor,
 ) {
     private val transitionAnimation =
         KeyguardTransitionAnimationFlow(
diff --git a/packages/SystemUI/src/com/android/systemui/navigationbar/TaskbarDelegate.java b/packages/SystemUI/src/com/android/systemui/navigationbar/TaskbarDelegate.java
index b96ca7a..3b32313e 100644
--- a/packages/SystemUI/src/com/android/systemui/navigationbar/TaskbarDelegate.java
+++ b/packages/SystemUI/src/com/android/systemui/navigationbar/TaskbarDelegate.java
@@ -224,7 +224,6 @@
                         return LightBarTransitionsController.DEFAULT_TINT_ANIMATION_DURATION;
                     }
                 });
-        controller.overrideIconTintForNavMode(true);
 
         return controller;
     }
diff --git a/packages/SystemUI/src/com/android/systemui/shade/QsBatteryModeController.kt b/packages/SystemUI/src/com/android/systemui/shade/QsBatteryModeController.kt
index 3eec7fa0e..ff57a73 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/QsBatteryModeController.kt
+++ b/packages/SystemUI/src/com/android/systemui/shade/QsBatteryModeController.kt
@@ -39,19 +39,12 @@
      * [cutout]. We don't show battery estimation in qqs header on the devices with center cutout.
      * The result might be null when the battery icon is invisible during the qs-qqs transition
      * animation.
+     *
+     * Note: short-circuiting this value until a comprehensive fix for b/282044659 is finished.
      */
     @BatteryMeterView.BatteryPercentMode
     fun getBatteryMode(cutout: DisplayCutout?, qsExpandedFraction: Float): Int? =
-        when {
-            qsExpandedFraction > fadeInStartFraction -> BatteryMeterView.MODE_ESTIMATE
-            qsExpandedFraction < fadeOutCompleteFraction ->
-                if (hasCenterCutout(cutout)) {
-                    BatteryMeterView.MODE_ON
-                } else {
-                    BatteryMeterView.MODE_ESTIMATE
-                }
-            else -> null
-        }
+        BatteryMeterView.MODE_ON
 
     fun updateResources() {
         fadeInStartFraction =
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesImpl.java
index 1cd0f08..648ece5 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesImpl.java
@@ -475,6 +475,13 @@
      */
     private boolean mShouldDelayWakeUpAnimation = false;
 
+    /**
+     * Whether we should delay the AOD->Lockscreen animation.
+     * If false, the animation will start in onStartedWakingUp().
+     * If true, the animation will start in onFinishedWakingUp().
+     */
+    private boolean mShouldDelayLockscreenTransitionFromAod = false;
+
     private final Object mQueueLock = new Object();
 
     private final PulseExpansionHandler mPulseExpansionHandler;
@@ -3242,7 +3249,10 @@
 
                 updateVisibleToUser();
                 updateIsKeyguard();
-                if (!mFeatureFlags.isEnabled(Flags.ZJ_285570694_LOCKSCREEN_TRANSITION_FROM_AOD)) {
+                mShouldDelayLockscreenTransitionFromAod = mDozeParameters.getAlwaysOn()
+                        && mFeatureFlags.isEnabled(
+                                Flags.ZJ_285570694_LOCKSCREEN_TRANSITION_FROM_AOD);
+                if (!mShouldDelayLockscreenTransitionFromAod) {
                     startLockscreenTransitionFromAod();
                 }
             });
@@ -3251,8 +3261,7 @@
 
         /**
          * Private helper for starting the LOCKSCREEN_TRANSITION_FROM_AOD animation - only necessary
-         * so we can start it from either onFinishedWakingUp() or onFinishedWakingUp() depending
-         * on a flag value.
+         * so we can start it from either onFinishedWakingUp() or onFinishedWakingUp().
          */
         private void startLockscreenTransitionFromAod() {
             // stopDozing() starts the LOCKSCREEN_TRANSITION_FROM_AOD animation.
@@ -3273,7 +3282,7 @@
 
         @Override
         public void onFinishedWakingUp() {
-            if (mFeatureFlags.isEnabled(Flags.ZJ_285570694_LOCKSCREEN_TRANSITION_FROM_AOD)) {
+            if (mShouldDelayLockscreenTransitionFromAod) {
                 mNotificationShadeWindowController.batchApplyWindowLayoutParams(
                         this::startLockscreenTransitionFromAod);
             }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/LightBarTransitionsController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/LightBarTransitionsController.java
index 7bc4fc3..ae70384 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/LightBarTransitionsController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/LightBarTransitionsController.java
@@ -115,7 +115,6 @@
     };
 
     private final Context mContext;
-    private Boolean mOverrideIconTintForNavMode;
 
     @AssistedInject
     public LightBarTransitionsController(
@@ -276,19 +275,11 @@
     }
 
     /**
-     * Specify an override value to return for {@link #overrideIconTintForNavMode(boolean)}.
-     */
-    public void overrideIconTintForNavMode(boolean overrideValue) {
-        mOverrideIconTintForNavMode = overrideValue;
-    }
-    /**
      * Return whether to use the tint calculated in this class for nav icons.
      */
     public boolean supportsIconTintForNavMode(int navigationMode) {
         // In gesture mode, we already do region sampling to update tint based on content beneath.
-        return mOverrideIconTintForNavMode != null
-                ? mOverrideIconTintForNavMode
-                : !QuickStepContract.isGesturalMode(navigationMode);
+        return !QuickStepContract.isGesturalMode(navigationMode);
     }
 
     /**
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/BaseUserSwitcherAdapter.kt b/packages/SystemUI/src/com/android/systemui/statusbar/policy/BaseUserSwitcherAdapter.kt
index 2b4f51c..4c6374b 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/BaseUserSwitcherAdapter.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/BaseUserSwitcherAdapter.kt
@@ -35,7 +35,10 @@
 ) : BaseAdapter() {
 
     protected open val users: List<UserRecord>
-        get() = controller.users.filter { !controller.isKeyguardShowing || !it.isRestricted }
+        get() = controller.users.filter {
+            (!controller.isKeyguardShowing || !it.isRestricted) &&
+                (controller.isUserSwitcherEnabled || it.isCurrent)
+        }
 
     init {
         controller.addAdapter(WeakReference(this))
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/UserSwitcherController.kt b/packages/SystemUI/src/com/android/systemui/statusbar/policy/UserSwitcherController.kt
index 1e223b1..f88339a 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/UserSwitcherController.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/UserSwitcherController.kt
@@ -67,6 +67,9 @@
     val isSimpleUserSwitcher: Boolean
         get() = userInteractor.isSimpleUserSwitcher
 
+    val isUserSwitcherEnabled: Boolean
+        get() = userInteractor.isUserSwitcherEnabled
+
     /** The [UserRecord] of the current user or `null` when none. */
     val currentUserRecord: UserRecord?
         get() = userInteractor.selectedUserRecord.value
diff --git a/packages/SystemUI/src/com/android/systemui/user/data/repository/UserRepository.kt b/packages/SystemUI/src/com/android/systemui/user/data/repository/UserRepository.kt
index a0b56aa..3de75ca 100644
--- a/packages/SystemUI/src/com/android/systemui/user/data/repository/UserRepository.kt
+++ b/packages/SystemUI/src/com/android/systemui/user/data/repository/UserRepository.kt
@@ -105,6 +105,8 @@
     fun getSelectedUserInfo(): UserInfo
 
     fun isSimpleUserSwitcher(): Boolean
+
+    fun isUserSwitcherEnabled(): Boolean
 }
 
 @SysUISingleton
@@ -206,6 +208,10 @@
         return _userSwitcherSettings.value.isSimpleUserSwitcher
     }
 
+    override fun isUserSwitcherEnabled(): Boolean {
+        return _userSwitcherSettings.value.isUserSwitcherEnabled
+    }
+
     private fun observeUserSwitching() {
         conflatedCallbackFlow {
                 val callback =
diff --git a/packages/SystemUI/src/com/android/systemui/user/domain/interactor/UserInteractor.kt b/packages/SystemUI/src/com/android/systemui/user/domain/interactor/UserInteractor.kt
index 27c348b..a487f53 100644
--- a/packages/SystemUI/src/com/android/systemui/user/domain/interactor/UserInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/user/domain/interactor/UserInteractor.kt
@@ -294,6 +294,10 @@
 
     val isSimpleUserSwitcher: Boolean
         get() = repository.isSimpleUserSwitcher()
+
+    val isUserSwitcherEnabled: Boolean
+        get() = repository.isUserSwitcherEnabled()
+
     val keyguardUpdateMonitorCallback =
         object : KeyguardUpdateMonitorCallback() {
             override fun onKeyguardGoingAway() {
@@ -370,6 +374,7 @@
         }
 
         pw.println("isSimpleUserSwitcher=$isSimpleUserSwitcher")
+        pw.println("isUserSwitcherEnabled=$isUserSwitcherEnabled")
         pw.println("isGuestUserAutoCreated=$isGuestUserAutoCreated")
     }
 
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/CarrierTextManagerTest.java b/packages/SystemUI/tests/src/com/android/keyguard/CarrierTextManagerTest.java
index 48a8d1b..e7d420b 100644
--- a/packages/SystemUI/tests/src/com/android/keyguard/CarrierTextManagerTest.java
+++ b/packages/SystemUI/tests/src/com/android/keyguard/CarrierTextManagerTest.java
@@ -561,6 +561,66 @@
                 captor.getValue().carrierText);
     }
 
+    @Test
+    public void testGetStatusForIccState() {
+        when(mKeyguardUpdateMonitor.isDeviceProvisioned()).thenReturn(false);
+        assertEquals(CarrierTextManager.StatusMode.SimMissingLocked,
+                mCarrierTextManager.getStatusForIccState(TelephonyManager.SIM_STATE_ABSENT));
+        assertEquals(CarrierTextManager.StatusMode.NetworkLocked,
+                mCarrierTextManager.getStatusForIccState(
+                        TelephonyManager.SIM_STATE_NETWORK_LOCKED));
+        assertEquals(CarrierTextManager.StatusMode.SimNotReady,
+                mCarrierTextManager.getStatusForIccState(TelephonyManager.SIM_STATE_NOT_READY));
+        assertEquals(CarrierTextManager.StatusMode.SimLocked,
+                mCarrierTextManager.getStatusForIccState(
+                        TelephonyManager.SIM_STATE_PIN_REQUIRED));
+        assertEquals(CarrierTextManager.StatusMode.SimPukLocked,
+                mCarrierTextManager.getStatusForIccState(
+                        TelephonyManager.SIM_STATE_PUK_REQUIRED));
+        assertEquals(CarrierTextManager.StatusMode.Normal,
+                mCarrierTextManager.getStatusForIccState(TelephonyManager.SIM_STATE_READY));
+        assertEquals(CarrierTextManager.StatusMode.SimMissingLocked,
+                mCarrierTextManager.getStatusForIccState(
+                        TelephonyManager.SIM_STATE_PERM_DISABLED));
+        assertEquals(CarrierTextManager.StatusMode.SimUnknown,
+                mCarrierTextManager.getStatusForIccState(TelephonyManager.SIM_STATE_UNKNOWN));
+        assertEquals(CarrierTextManager.StatusMode.SimIoError,
+                mCarrierTextManager.getStatusForIccState(
+                        TelephonyManager.SIM_STATE_CARD_IO_ERROR));
+        assertEquals(CarrierTextManager.StatusMode.SimRestricted,
+                mCarrierTextManager.getStatusForIccState(
+                        TelephonyManager.SIM_STATE_CARD_RESTRICTED));
+
+        when(mKeyguardUpdateMonitor.isDeviceProvisioned()).thenReturn(true);
+        assertEquals(CarrierTextManager.StatusMode.SimMissing,
+                mCarrierTextManager.getStatusForIccState(TelephonyManager.SIM_STATE_ABSENT));
+        assertEquals(CarrierTextManager.StatusMode.NetworkLocked,
+                mCarrierTextManager.getStatusForIccState(
+                        TelephonyManager.SIM_STATE_NETWORK_LOCKED));
+        assertEquals(CarrierTextManager.StatusMode.SimNotReady,
+                mCarrierTextManager.getStatusForIccState(
+                        TelephonyManager.SIM_STATE_NOT_READY));
+        assertEquals(CarrierTextManager.StatusMode.SimLocked,
+                mCarrierTextManager.getStatusForIccState(
+                        TelephonyManager.SIM_STATE_PIN_REQUIRED));
+        assertEquals(CarrierTextManager.StatusMode.SimPukLocked,
+                mCarrierTextManager.getStatusForIccState(
+                        TelephonyManager.SIM_STATE_PUK_REQUIRED));
+        assertEquals(CarrierTextManager.StatusMode.Normal,
+                mCarrierTextManager.getStatusForIccState(TelephonyManager.SIM_STATE_READY));
+        assertEquals(CarrierTextManager.StatusMode.SimPermDisabled,
+                mCarrierTextManager.getStatusForIccState(
+                        TelephonyManager.SIM_STATE_PERM_DISABLED));
+        assertEquals(CarrierTextManager.StatusMode.SimUnknown,
+                mCarrierTextManager.getStatusForIccState(TelephonyManager.SIM_STATE_UNKNOWN));
+        assertEquals(CarrierTextManager.StatusMode.SimIoError,
+                mCarrierTextManager.getStatusForIccState(
+                        TelephonyManager.SIM_STATE_CARD_IO_ERROR));
+        assertEquals(CarrierTextManager.StatusMode.SimRestricted,
+                mCarrierTextManager.getStatusForIccState(
+                        TelephonyManager.SIM_STATE_CARD_RESTRICTED));
+    }
+
     private Context getContextSpyForStickyBroadcast(Intent returnVal) {
         Context contextSpy = spy(mContext);
         doReturn(returnVal).when(contextSpy).registerReceiver(eq(null), any(IntentFilter.class));
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/ClockEventControllerTest.kt b/packages/SystemUI/tests/src/com/android/keyguard/ClockEventControllerTest.kt
index 3f1560b..e9a9f3a 100644
--- a/packages/SystemUI/tests/src/com/android/keyguard/ClockEventControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/keyguard/ClockEventControllerTest.kt
@@ -47,6 +47,7 @@
 import com.android.systemui.util.mockito.mock
 import kotlinx.coroutines.Dispatchers
 import kotlinx.coroutines.runBlocking
+import kotlinx.coroutines.test.TestScope
 import kotlinx.coroutines.yield
 import org.junit.Assert.assertEquals
 import org.junit.Before
@@ -118,7 +119,7 @@
                 featureFlags = featureFlags,
                 bouncerRepository = bouncerRepository,
             ),
-            KeyguardTransitionInteractor(repository = transitionRepository),
+            KeyguardTransitionInteractor(transitionRepository, TestScope().backgroundScope),
             broadcastDispatcher,
             batteryController,
             keyguardUpdateMonitor,
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardUpdateMonitorTest.java b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardUpdateMonitorTest.java
index de306d6..1e675f8 100644
--- a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardUpdateMonitorTest.java
+++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardUpdateMonitorTest.java
@@ -167,6 +167,7 @@
 import java.util.concurrent.CountDownLatch;
 import java.util.concurrent.Executor;
 import java.util.concurrent.atomic.AtomicBoolean;
+import java.util.concurrent.atomic.AtomicInteger;
 
 @SmallTest
 @RunWith(AndroidTestingRunner.class)
@@ -672,6 +673,130 @@
     }
 
     @Test
+    public void testHandleSimStateChange_Unknown() {
+        Intent intent = new Intent(Intent.ACTION_SIM_STATE_CHANGED);
+        intent.putExtra(Intent.EXTRA_SIM_STATE, Intent.SIM_STATE_UNKNOWN);
+        mKeyguardUpdateMonitor.mBroadcastReceiver.onReceive(getContext(),
+                putPhoneInfo(intent, null, false));
+        mTestableLooper.processAllMessages();
+        Assert.assertEquals(TelephonyManager.SIM_STATE_UNKNOWN,
+                mKeyguardUpdateMonitor.getCachedSimState());
+    }
+
+    @Test
+    public void testHandleSimStateChange_Absent() {
+        Intent intent = new Intent(Intent.ACTION_SIM_STATE_CHANGED);
+        intent.putExtra(Intent.EXTRA_SIM_STATE, Intent.SIM_STATE_ABSENT);
+        mKeyguardUpdateMonitor.mBroadcastReceiver.onReceive(getContext(),
+                putPhoneInfo(intent, null, false));
+        mTestableLooper.processAllMessages();
+        Assert.assertEquals(TelephonyManager.SIM_STATE_ABSENT,
+                mKeyguardUpdateMonitor.getCachedSimState());
+    }
+
+    @Test
+    public void testHandleSimStateChange_CardIOError() {
+        Intent intent = new Intent(Intent.ACTION_SIM_STATE_CHANGED);
+        intent.putExtra(Intent.EXTRA_SIM_STATE, Intent.SIM_STATE_CARD_IO_ERROR);
+        intent.putExtra(Intent.EXTRA_SIM_LOCKED_REASON, Intent.SIM_STATE_CARD_IO_ERROR);
+        mKeyguardUpdateMonitor.mBroadcastReceiver.onReceive(getContext(),
+                putPhoneInfo(intent, null, false));
+        mTestableLooper.processAllMessages();
+        Assert.assertEquals(TelephonyManager.SIM_STATE_CARD_IO_ERROR,
+                mKeyguardUpdateMonitor.getCachedSimState());
+    }
+
+    @Test
+    public void testHandleSimStateChange_CardRestricted() {
+        Intent intent = new Intent(Intent.ACTION_SIM_STATE_CHANGED);
+        intent.putExtra(Intent.EXTRA_SIM_STATE, Intent.SIM_STATE_CARD_RESTRICTED);
+        intent.putExtra(Intent.EXTRA_SIM_LOCKED_REASON, Intent.SIM_STATE_CARD_RESTRICTED);
+        mKeyguardUpdateMonitor.mBroadcastReceiver.onReceive(getContext(),
+                putPhoneInfo(intent, null, false));
+        mTestableLooper.processAllMessages();
+        Assert.assertEquals(TelephonyManager.SIM_STATE_CARD_RESTRICTED,
+                mKeyguardUpdateMonitor.getCachedSimState());
+    }
+
+    @Test
+    public void testHandleSimStateChange_Locked() {
+        Intent intent = new Intent(Intent.ACTION_SIM_STATE_CHANGED);
+        intent.putExtra(Intent.EXTRA_SIM_STATE, Intent.SIM_STATE_LOCKED);
+
+        // locked on PIN1
+        intent.putExtra(Intent.EXTRA_SIM_LOCKED_REASON, Intent.SIM_LOCKED_ON_PIN);
+        mKeyguardUpdateMonitor.mBroadcastReceiver.onReceive(getContext(),
+                putPhoneInfo(intent, null, true));
+        mTestableLooper.processAllMessages();
+        Assert.assertEquals(TelephonyManager.SIM_STATE_PIN_REQUIRED,
+                mKeyguardUpdateMonitor.getCachedSimState());
+
+        // locked on PUK1
+        intent.putExtra(Intent.EXTRA_SIM_LOCKED_REASON, Intent.SIM_LOCKED_ON_PUK);
+        mKeyguardUpdateMonitor.mBroadcastReceiver.onReceive(getContext(),
+                putPhoneInfo(intent, null, true));
+        mTestableLooper.processAllMessages();
+        Assert.assertEquals(TelephonyManager.SIM_STATE_PUK_REQUIRED,
+                mKeyguardUpdateMonitor.getCachedSimState());
+
+        // locked on network personalization
+        intent.putExtra(Intent.EXTRA_SIM_LOCKED_REASON, Intent.SIM_LOCKED_NETWORK);
+        mKeyguardUpdateMonitor.mBroadcastReceiver.onReceive(getContext(),
+                putPhoneInfo(intent, null, true));
+        mTestableLooper.processAllMessages();
+        Assert.assertEquals(TelephonyManager.SIM_STATE_NETWORK_LOCKED,
+                mKeyguardUpdateMonitor.getCachedSimState());
+
+        // permanently disabled due to puk fails
+        intent.putExtra(Intent.EXTRA_SIM_LOCKED_REASON, Intent.SIM_ABSENT_ON_PERM_DISABLED);
+        mKeyguardUpdateMonitor.mBroadcastReceiver.onReceive(getContext(),
+                putPhoneInfo(intent, null, true));
+        mTestableLooper.processAllMessages();
+        Assert.assertEquals(TelephonyManager.SIM_STATE_PERM_DISABLED,
+                mKeyguardUpdateMonitor.getCachedSimState());
+    }
+
+    @Test
+    public void testHandleSimStateChange_NotReady() {
+        Intent intent = new Intent(Intent.ACTION_SIM_STATE_CHANGED);
+        intent.putExtra(Intent.EXTRA_SIM_STATE, Intent.SIM_STATE_NOT_READY);
+        mKeyguardUpdateMonitor.mBroadcastReceiver.onReceive(getContext(),
+                putPhoneInfo(intent, null, false));
+        mTestableLooper.processAllMessages();
+        Assert.assertEquals(TelephonyManager.SIM_STATE_NOT_READY,
+                mKeyguardUpdateMonitor.getCachedSimState());
+    }
+
+    @Test
+    public void testHandleSimStateChange_Ready() {
+        Intent intent = new Intent(Intent.ACTION_SIM_STATE_CHANGED);
+
+        // ICC IMSI is ready in property
+        intent.putExtra(Intent.EXTRA_SIM_STATE, Intent.SIM_STATE_IMSI);
+        mKeyguardUpdateMonitor.mBroadcastReceiver.onReceive(getContext(),
+                putPhoneInfo(intent, null, false));
+        mTestableLooper.processAllMessages();
+        Assert.assertEquals(TelephonyManager.SIM_STATE_READY,
+                mKeyguardUpdateMonitor.getCachedSimState());
+
+        // ICC is ready to access
+        intent.putExtra(Intent.EXTRA_SIM_STATE, Intent.SIM_STATE_READY);
+        mKeyguardUpdateMonitor.mBroadcastReceiver.onReceive(getContext(),
+                putPhoneInfo(intent, null, false));
+        mTestableLooper.processAllMessages();
+        Assert.assertEquals(TelephonyManager.SIM_STATE_READY,
+                mKeyguardUpdateMonitor.getCachedSimState());
+
+        // all ICC records, including IMSI, are loaded
+        intent.putExtra(Intent.EXTRA_SIM_STATE, Intent.SIM_STATE_LOADED);
+        mKeyguardUpdateMonitor.mBroadcastReceiver.onReceive(getContext(),
+                putPhoneInfo(intent, null, true));
+        mTestableLooper.processAllMessages();
+        Assert.assertEquals(TelephonyManager.SIM_STATE_READY,
+                mKeyguardUpdateMonitor.getCachedSimState());
+    }
+
+    @Test
     public void testTriesToAuthenticateFingerprint_whenKeyguard() {
         mKeyguardUpdateMonitor.dispatchStartedGoingToSleep(0 /* why */);
         mTestableLooper.processAllMessages();
@@ -3122,6 +3247,7 @@
 
     private class TestableKeyguardUpdateMonitor extends KeyguardUpdateMonitor {
         AtomicBoolean mSimStateChanged = new AtomicBoolean(false);
+        AtomicInteger mCachedSimState = new AtomicInteger(-1);
 
         protected TestableKeyguardUpdateMonitor(Context context) {
             super(context, mUserTracker,
@@ -3144,9 +3270,14 @@
             return mSimStateChanged.getAndSet(false);
         }
 
+        public int getCachedSimState() {
+            return mCachedSimState.getAndSet(-1);
+        }
+
         @Override
         protected void handleSimStateChange(int subId, int slotId, int state) {
             mSimStateChanged.set(true);
+            mCachedSimState.set(state);
             super.handleSimStateChange(subId, slotId, state);
         }
 
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/LockIconViewControllerBaseTest.java b/packages/SystemUI/tests/src/com/android/keyguard/LockIconViewControllerBaseTest.java
index 456702b..84e58be 100644
--- a/packages/SystemUI/tests/src/com/android/keyguard/LockIconViewControllerBaseTest.java
+++ b/packages/SystemUI/tests/src/com/android/keyguard/LockIconViewControllerBaseTest.java
@@ -159,7 +159,8 @@
                 mVibrator,
                 mAuthRippleController,
                 mResources,
-                new KeyguardTransitionInteractor(mTransitionRepository),
+                new KeyguardTransitionInteractor(mTransitionRepository,
+                        TestScopeProvider.getTestScope().getBackgroundScope()),
                 new KeyguardInteractor(
                         new FakeKeyguardRepository(),
                         mCommandQueue,
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/TestScopeProvider.kt b/packages/SystemUI/tests/src/com/android/keyguard/TestScopeProvider.kt
new file mode 100644
index 0000000..073c7fe
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/keyguard/TestScopeProvider.kt
@@ -0,0 +1,25 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package com.android.keyguard
+
+import kotlinx.coroutines.test.TestScope
+
+class TestScopeProvider {
+    companion object {
+        @JvmStatic fun getTestScope() = TestScope()
+    }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/biometrics/domain/interactor/LogContextInteractorImplTest.kt b/packages/SystemUI/tests/src/com/android/systemui/biometrics/domain/interactor/LogContextInteractorImplTest.kt
index 1f2b64d..263ce1a 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/biometrics/domain/interactor/LogContextInteractorImplTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/domain/interactor/LogContextInteractorImplTest.kt
@@ -56,6 +56,7 @@
                 foldProvider,
                 KeyguardTransitionInteractor(
                     keyguardTransitionRepository,
+                    testScope.backgroundScope
                 ),
             )
     }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/dreams/DreamOverlayAnimationsControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/dreams/DreamOverlayAnimationsControllerTest.kt
index 039682c..a00e545 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/dreams/DreamOverlayAnimationsControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/dreams/DreamOverlayAnimationsControllerTest.kt
@@ -11,7 +11,6 @@
 import com.android.systemui.keyguard.ui.viewmodel.DreamingToLockscreenTransitionViewModel
 import com.android.systemui.statusbar.BlurUtils
 import com.android.systemui.statusbar.policy.ConfigurationController
-import com.android.systemui.util.concurrency.DelayableExecutor
 import com.android.systemui.util.mockito.argumentCaptor
 import com.android.systemui.util.mockito.mock
 import com.android.systemui.util.mockito.whenever
@@ -23,9 +22,7 @@
 import org.junit.runner.RunWith
 import org.mockito.ArgumentCaptor
 import org.mockito.Mock
-import org.mockito.Mockito.anyLong
 import org.mockito.Mockito.atLeastOnce
-import org.mockito.Mockito.eq
 import org.mockito.Mockito.never
 import org.mockito.Mockito.times
 import org.mockito.Mockito.verify
@@ -92,16 +89,10 @@
     }
 
     @Test
-    fun testWakeUpCallsExecutor() {
-        val mockExecutor: DelayableExecutor = mock()
-        val mockCallback: Runnable = mock()
+    fun testWakeUpSetsExitAnimationsRunning() {
+        controller.wakeUp()
 
-        controller.wakeUp(
-            doneCallback = mockCallback,
-            executor = mockExecutor,
-        )
-
-        verify(mockExecutor).executeDelayed(eq(mockCallback), anyLong())
+        verify(stateController).setExitAnimationsRunning(true)
     }
 
     @Test
@@ -112,10 +103,7 @@
 
         verify(mockStartAnimator, never()).cancel()
 
-        controller.wakeUp(
-            doneCallback = mock(),
-            executor = mock(),
-        )
+        controller.wakeUp()
 
         // Verify that we cancelled the start animator in favor of the exit
         // animator.
diff --git a/packages/SystemUI/tests/src/com/android/systemui/dreams/DreamOverlayServiceTest.java b/packages/SystemUI/tests/src/com/android/systemui/dreams/DreamOverlayServiceTest.java
index cfd51e3..d0d348d 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/dreams/DreamOverlayServiceTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/dreams/DreamOverlayServiceTest.java
@@ -23,7 +23,6 @@
 import static org.mockito.Mockito.doAnswer;
 import static org.mockito.Mockito.doThrow;
 import static org.mockito.Mockito.inOrder;
-import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.never;
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
@@ -498,18 +497,14 @@
                 true /*shouldShowComplication*/);
         mMainExecutor.runAllReady();
 
-        final Runnable callback = mock(Runnable.class);
-        mService.onWakeUp(callback);
-        mMainExecutor.runAllReady();
-        verify(mDreamOverlayContainerViewController).wakeUp(callback, mMainExecutor);
+        mService.onWakeUp();
+        verify(mDreamOverlayContainerViewController).wakeUp();
         verify(mDreamOverlayCallbackController).onWakeUp();
     }
 
     @Test
     public void testWakeUpBeforeStartDoesNothing() {
-        final Runnable callback = mock(Runnable.class);
-        mService.onWakeUp(callback);
-        mMainExecutor.runAllReady();
-        verify(mDreamOverlayContainerViewController, never()).wakeUp(callback, mMainExecutor);
+        mService.onWakeUp();
+        verify(mDreamOverlayContainerViewController, never()).wakeUp();
     }
 }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/KeyguardViewMediatorTest.java b/packages/SystemUI/tests/src/com/android/systemui/keyguard/KeyguardViewMediatorTest.java
index f31ac00..8a422c8 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/KeyguardViewMediatorTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/KeyguardViewMediatorTest.java
@@ -21,6 +21,7 @@
 
 import static com.android.internal.widget.LockPatternUtils.StrongAuthTracker.STRONG_AUTH_REQUIRED_AFTER_DPM_LOCK_NOW;
 import static com.android.internal.widget.LockPatternUtils.StrongAuthTracker.STRONG_AUTH_REQUIRED_AFTER_NON_STRONG_BIOMETRICS_TIMEOUT;
+import static com.android.internal.widget.LockPatternUtils.StrongAuthTracker.STRONG_AUTH_REQUIRED_AFTER_USER_LOCKDOWN;
 
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
@@ -71,6 +72,7 @@
 import com.android.systemui.dump.DumpManager;
 import com.android.systemui.flags.FakeFeatureFlags;
 import com.android.systemui.flags.Flags;
+import com.android.systemui.keyguard.ui.viewmodel.DreamingToLockscreenTransitionViewModel;
 import com.android.systemui.log.SessionTracker;
 import com.android.systemui.navigationbar.NavigationModeController;
 import com.android.systemui.settings.UserTracker;
@@ -105,6 +107,9 @@
 import org.mockito.Mock;
 import org.mockito.MockitoAnnotations;
 
+import kotlinx.coroutines.CoroutineDispatcher;
+import kotlinx.coroutines.flow.Flow;
+
 @RunWith(AndroidTestingRunner.class)
 @TestableLooper.RunWithLooper
 @SmallTest
@@ -156,6 +161,8 @@
     private @Mock CentralSurfaces mCentralSurfaces;
     private @Mock UiEventLogger mUiEventLogger;
     private @Mock SessionTracker mSessionTracker;
+    private @Mock CoroutineDispatcher mDispatcher;
+    private @Mock DreamingToLockscreenTransitionViewModel mDreamingToLockscreenTransitionViewModel;
 
     private FakeFeatureFlags mFeatureFlags;
 
@@ -171,6 +178,8 @@
         final ViewRootImpl testViewRoot = mock(ViewRootImpl.class);
         when(testViewRoot.getView()).thenReturn(mock(View.class));
         when(mStatusBarKeyguardViewManager.getViewRootImpl()).thenReturn(testViewRoot);
+        when(mDreamingToLockscreenTransitionViewModel.getDreamOverlayAlpha())
+                .thenReturn(mock(Flow.class));
         mNotificationShadeWindowController = new NotificationShadeWindowControllerImpl(mContext,
                 mWindowManager, mActivityManager, mDozeParameters, mStatusBarStateController,
                 mConfigurationController, mViewMediator, mKeyguardBypassController,
@@ -186,6 +195,7 @@
     }
 
     @Test
+    @TestableLooper.RunWithLooper(setAsMainLooper = true)
     public void onLockdown_showKeyguard_evenIfKeyguardIsNotEnabledExternally() {
         // GIVEN keyguard is not enabled and isn't showing
         mViewMediator.onSystemReady();
@@ -347,6 +357,42 @@
     }
 
     @Test
+    public void testBouncerPrompt_afterUserLockDown() {
+        // GIVEN biometrics enrolled
+        when(mUpdateMonitor.isUnlockingWithBiometricsPossible(anyInt())).thenReturn(true);
+
+        // WHEN user has locked down the device
+        KeyguardUpdateMonitor.StrongAuthTracker strongAuthTracker =
+                mock(KeyguardUpdateMonitor.StrongAuthTracker.class);
+        when(mUpdateMonitor.getStrongAuthTracker()).thenReturn(strongAuthTracker);
+        when(strongAuthTracker.hasUserAuthenticatedSinceBoot()).thenReturn(true);
+        when(strongAuthTracker.getStrongAuthForUser(anyInt()))
+                .thenReturn(STRONG_AUTH_REQUIRED_AFTER_USER_LOCKDOWN);
+
+        // THEN the bouncer prompt reason should return PROMPT_REASON_USER_REQUEST
+        assertEquals(KeyguardSecurityView.PROMPT_REASON_USER_REQUEST,
+                mViewMediator.mViewMediatorCallback.getBouncerPromptReason());
+    }
+
+    @Test
+    public void testBouncerPrompt_afterUserLockDown_noBiometricsEnrolled() {
+        // GIVEN biometrics not enrolled
+        when(mUpdateMonitor.isUnlockingWithBiometricsPossible(anyInt())).thenReturn(false);
+
+        // WHEN user has locked down the device
+        KeyguardUpdateMonitor.StrongAuthTracker strongAuthTracker =
+                mock(KeyguardUpdateMonitor.StrongAuthTracker.class);
+        when(mUpdateMonitor.getStrongAuthTracker()).thenReturn(strongAuthTracker);
+        when(strongAuthTracker.hasUserAuthenticatedSinceBoot()).thenReturn(true);
+        when(strongAuthTracker.getStrongAuthForUser(anyInt()))
+                .thenReturn(STRONG_AUTH_REQUIRED_AFTER_USER_LOCKDOWN);
+
+        // THEN the bouncer prompt reason should return the default prompt
+        assertEquals(KeyguardSecurityView.PROMPT_REASON_NONE,
+                mViewMediator.mViewMediatorCallback.getBouncerPromptReason());
+    }
+
+    @Test
     public void testBouncerPrompt_nonStrongIdleTimeout() {
         // GIVEN trust agents enabled and biometrics are enrolled
         when(mUpdateMonitor.isTrustUsuallyManaged(anyInt())).thenReturn(true);
@@ -629,7 +675,9 @@
                 () -> mNotificationShadeWindowController,
                 () -> mActivityLaunchAnimator,
                 () -> mScrimController,
-                mFeatureFlags);
+                mFeatureFlags,
+                mDispatcher,
+                () -> mDreamingToLockscreenTransitionViewModel);
         mViewMediator.start();
 
         mViewMediator.registerCentralSurfaces(mCentralSurfaces, null, null, null, null, null);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/ResourceTrimmerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/ResourceTrimmerTest.kt
index 78a65a8..6447368 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/ResourceTrimmerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/ResourceTrimmerTest.kt
@@ -70,7 +70,10 @@
         resourceTrimmer =
             ResourceTrimmer(
                 keyguardInteractor,
-                KeyguardTransitionInteractor(keyguardTransitionRepository),
+                KeyguardTransitionInteractor(
+                    keyguardTransitionRepository,
+                    testScope.backgroundScope
+                ),
                 globalWindowManager,
                 testScope.backgroundScope,
                 testDispatcher,
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/repository/DeviceEntryFaceAuthRepositoryTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/repository/DeviceEntryFaceAuthRepositoryTest.kt
index e61620b..1090c15 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/repository/DeviceEntryFaceAuthRepositoryTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/repository/DeviceEntryFaceAuthRepositoryTest.kt
@@ -215,7 +215,7 @@
             )
         keyguardTransitionRepository = FakeKeyguardTransitionRepository()
         val keyguardTransitionInteractor =
-            KeyguardTransitionInteractor(keyguardTransitionRepository)
+            KeyguardTransitionInteractor(keyguardTransitionRepository, testScope.backgroundScope)
         return DeviceEntryFaceAuthRepositoryImpl(
             mContext,
             fmOverride,
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardFaceAuthInteractorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardFaceAuthInteractorTest.kt
index 6af1220..71e73cbd 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardFaceAuthInteractorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardFaceAuthInteractorTest.kt
@@ -82,7 +82,8 @@
         bouncerRepository = FakeKeyguardBouncerRepository()
         faceAuthRepository = FakeDeviceEntryFaceAuthRepository()
         keyguardTransitionRepository = FakeKeyguardTransitionRepository()
-        keyguardTransitionInteractor = KeyguardTransitionInteractor(keyguardTransitionRepository)
+        keyguardTransitionInteractor =
+            KeyguardTransitionInteractor(keyguardTransitionRepository, testScope.backgroundScope)
 
         underTest =
             SystemUIKeyguardFaceAuthInteractor(
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardLongPressInteractorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardLongPressInteractorTest.kt
index 5de24e4..f63be61 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardLongPressInteractorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardLongPressInteractorTest.kt
@@ -292,7 +292,8 @@
                 scope = testScope.backgroundScope,
                 transitionInteractor =
                     KeyguardTransitionInteractor(
-                        repository = keyguardTransitionRepository,
+                        keyguardTransitionRepository,
+                        testScope.backgroundScope
                     ),
                 repository = keyguardRepository,
                 logger = logger,
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionInteractorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionInteractorTest.kt
index d66e420..fa4941c 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionInteractorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionInteractorTest.kt
@@ -27,11 +27,14 @@
 import com.android.systemui.keyguard.shared.model.KeyguardState.DOZING
 import com.android.systemui.keyguard.shared.model.KeyguardState.GONE
 import com.android.systemui.keyguard.shared.model.KeyguardState.LOCKSCREEN
+import com.android.systemui.keyguard.shared.model.KeyguardState.OFF
+import com.android.systemui.keyguard.shared.model.KeyguardState.PRIMARY_BOUNCER
 import com.android.systemui.keyguard.shared.model.TransitionState.FINISHED
 import com.android.systemui.keyguard.shared.model.TransitionState.RUNNING
 import com.android.systemui.keyguard.shared.model.TransitionState.STARTED
 import com.android.systemui.keyguard.shared.model.TransitionStep
 import com.google.common.truth.Truth.assertThat
+import kotlinx.coroutines.test.TestScope
 import kotlinx.coroutines.test.runCurrent
 import kotlinx.coroutines.test.runTest
 import org.junit.Before
@@ -46,11 +49,12 @@
 
     private lateinit var underTest: KeyguardTransitionInteractor
     private lateinit var repository: FakeKeyguardTransitionRepository
+    private val testScope = TestScope()
 
     @Before
     fun setUp() {
         repository = FakeKeyguardTransitionRepository()
-        underTest = KeyguardTransitionInteractor(repository)
+        underTest = KeyguardTransitionInteractor(repository, testScope.backgroundScope)
     }
 
     @Test
@@ -108,17 +112,17 @@
     }
 
     @Test
-    fun keyguardStateTests() = runTest {
+    fun finishedKeyguardStateTests() = testScope.runTest {
         val finishedSteps by collectValues(underTest.finishedKeyguardState)
-
+        runCurrent()
         val steps = mutableListOf<TransitionStep>()
 
-        steps.add(TransitionStep(AOD, LOCKSCREEN, 0f, STARTED))
-        steps.add(TransitionStep(AOD, LOCKSCREEN, 0.5f, RUNNING))
-        steps.add(TransitionStep(AOD, LOCKSCREEN, 1f, FINISHED))
-        steps.add(TransitionStep(LOCKSCREEN, AOD, 0f, STARTED))
-        steps.add(TransitionStep(LOCKSCREEN, AOD, 0.9f, RUNNING))
-        steps.add(TransitionStep(LOCKSCREEN, AOD, 1f, FINISHED))
+        steps.add(TransitionStep(AOD, PRIMARY_BOUNCER, 0f, STARTED))
+        steps.add(TransitionStep(AOD, PRIMARY_BOUNCER, 0.5f, RUNNING))
+        steps.add(TransitionStep(AOD, PRIMARY_BOUNCER, 1f, FINISHED))
+        steps.add(TransitionStep(PRIMARY_BOUNCER, AOD, 0f, STARTED))
+        steps.add(TransitionStep(PRIMARY_BOUNCER, AOD, 0.9f, RUNNING))
+        steps.add(TransitionStep(PRIMARY_BOUNCER, AOD, 1f, FINISHED))
         steps.add(TransitionStep(AOD, GONE, 1f, STARTED))
 
         steps.forEach {
@@ -126,7 +130,29 @@
             runCurrent()
         }
 
-        assertThat(finishedSteps).isEqualTo(listOf(LOCKSCREEN, AOD))
+        assertThat(finishedSteps).isEqualTo(listOf(LOCKSCREEN, PRIMARY_BOUNCER, AOD))
+    }
+
+    @Test
+    fun startedKeyguardStateTests() = testScope.runTest {
+        val finishedSteps by collectValues(underTest.startedKeyguardState)
+        runCurrent()
+        val steps = mutableListOf<TransitionStep>()
+
+        steps.add(TransitionStep(AOD, PRIMARY_BOUNCER, 0f, STARTED))
+        steps.add(TransitionStep(AOD, PRIMARY_BOUNCER, 0.5f, RUNNING))
+        steps.add(TransitionStep(AOD, PRIMARY_BOUNCER, 1f, FINISHED))
+        steps.add(TransitionStep(PRIMARY_BOUNCER, AOD, 0f, STARTED))
+        steps.add(TransitionStep(PRIMARY_BOUNCER, AOD, 0.9f, RUNNING))
+        steps.add(TransitionStep(PRIMARY_BOUNCER, AOD, 1f, FINISHED))
+        steps.add(TransitionStep(AOD, GONE, 1f, STARTED))
+
+        steps.forEach {
+            repository.sendTransitionStep(it)
+            runCurrent()
+        }
+
+        assertThat(finishedSteps).isEqualTo(listOf(OFF, PRIMARY_BOUNCER, AOD, GONE))
     }
 
     @Test
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionScenariosTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionScenariosTest.kt
index 603f199..30dba23 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionScenariosTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionScenariosTest.kt
@@ -110,7 +110,8 @@
                 keyguardInteractor = createKeyguardInteractor(featureFlags),
                 shadeRepository = shadeRepository,
                 keyguardTransitionRepository = mockTransitionRepository,
-                keyguardTransitionInteractor = KeyguardTransitionInteractor(transitionRepository),
+                keyguardTransitionInteractor =
+                    KeyguardTransitionInteractor(transitionRepository, testScope.backgroundScope),
             )
         fromLockscreenTransitionInteractor.start()
 
@@ -119,7 +120,8 @@
                 scope = testScope,
                 keyguardInteractor = createKeyguardInteractor(featureFlags),
                 keyguardTransitionRepository = mockTransitionRepository,
-                keyguardTransitionInteractor = KeyguardTransitionInteractor(transitionRepository),
+                keyguardTransitionInteractor =
+                    KeyguardTransitionInteractor(transitionRepository, testScope.backgroundScope),
             )
         fromDreamingTransitionInteractor.start()
 
@@ -128,7 +130,8 @@
                 scope = testScope,
                 keyguardInteractor = createKeyguardInteractor(featureFlags),
                 keyguardTransitionRepository = mockTransitionRepository,
-                keyguardTransitionInteractor = KeyguardTransitionInteractor(transitionRepository),
+                keyguardTransitionInteractor =
+                    KeyguardTransitionInteractor(transitionRepository, testScope.backgroundScope),
             )
         fromAodTransitionInteractor.start()
 
@@ -137,7 +140,8 @@
                 scope = testScope,
                 keyguardInteractor = createKeyguardInteractor(featureFlags),
                 keyguardTransitionRepository = mockTransitionRepository,
-                keyguardTransitionInteractor = KeyguardTransitionInteractor(transitionRepository),
+                keyguardTransitionInteractor =
+                    KeyguardTransitionInteractor(transitionRepository, testScope.backgroundScope),
             )
         fromGoneTransitionInteractor.start()
 
@@ -146,7 +150,8 @@
                 scope = testScope,
                 keyguardInteractor = createKeyguardInteractor(featureFlags),
                 keyguardTransitionRepository = mockTransitionRepository,
-                keyguardTransitionInteractor = KeyguardTransitionInteractor(transitionRepository),
+                keyguardTransitionInteractor =
+                    KeyguardTransitionInteractor(transitionRepository, testScope.backgroundScope),
             )
         fromDozingTransitionInteractor.start()
 
@@ -155,7 +160,8 @@
                 scope = testScope,
                 keyguardInteractor = createKeyguardInteractor(featureFlags),
                 keyguardTransitionRepository = mockTransitionRepository,
-                keyguardTransitionInteractor = KeyguardTransitionInteractor(transitionRepository),
+                keyguardTransitionInteractor =
+                    KeyguardTransitionInteractor(transitionRepository, testScope.backgroundScope),
             )
         fromOccludedTransitionInteractor.start()
 
@@ -164,7 +170,8 @@
                 scope = testScope,
                 keyguardInteractor = createKeyguardInteractor(featureFlags),
                 keyguardTransitionRepository = mockTransitionRepository,
-                keyguardTransitionInteractor = KeyguardTransitionInteractor(transitionRepository),
+                keyguardTransitionInteractor =
+                    KeyguardTransitionInteractor(transitionRepository, testScope.backgroundScope),
             )
         fromAlternateBouncerTransitionInteractor.start()
 
@@ -173,48 +180,14 @@
                 scope = testScope,
                 keyguardInteractor = createKeyguardInteractor(featureFlags),
                 keyguardTransitionRepository = mockTransitionRepository,
-                keyguardTransitionInteractor = KeyguardTransitionInteractor(transitionRepository),
+                keyguardTransitionInteractor =
+                    KeyguardTransitionInteractor(transitionRepository, testScope.backgroundScope),
                 keyguardSecurityModel = keyguardSecurityModel,
             )
         fromPrimaryBouncerTransitionInteractor.start()
     }
 
     @Test
-    fun dreamingToLockscreen() =
-        testScope.runTest {
-            // GIVEN a device is dreaming
-            keyguardRepository.setDreamingWithOverlay(true)
-            keyguardRepository.setWakefulnessModel(startingToWake())
-            runCurrent()
-
-            // GIVEN a prior transition has run to DREAMING
-            runTransition(KeyguardState.LOCKSCREEN, KeyguardState.DREAMING)
-
-            // WHEN doze is complete
-            keyguardRepository.setDozeTransitionModel(
-                DozeTransitionModel(from = DozeStateModel.DOZE, to = DozeStateModel.FINISH)
-            )
-            // AND dreaming has stopped
-            keyguardRepository.setDreamingWithOverlay(false)
-            advanceUntilIdle()
-            // AND then occluded has stopped
-            keyguardRepository.setKeyguardOccluded(false)
-            advanceUntilIdle()
-
-            val info =
-                withArgCaptor<TransitionInfo> {
-                    verify(mockTransitionRepository).startTransition(capture(), anyBoolean())
-                }
-            // THEN a transition to BOUNCER should occur
-            assertThat(info.ownerName).isEqualTo("FromDreamingTransitionInteractor")
-            assertThat(info.from).isEqualTo(KeyguardState.DREAMING)
-            assertThat(info.to).isEqualTo(KeyguardState.LOCKSCREEN)
-            assertThat(info.animator).isNotNull()
-
-            coroutineContext.cancelChildren()
-        }
-
-    @Test
     fun lockscreenToPrimaryBouncerViaBouncerShowingCall() =
         testScope.runTest {
             // GIVEN a device that has at least woken up
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/LightRevealScrimInteractorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/LightRevealScrimInteractorTest.kt
index 4440946..08e99dc 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/LightRevealScrimInteractorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/LightRevealScrimInteractorTest.kt
@@ -29,6 +29,7 @@
 import com.android.systemui.statusbar.LightRevealScrim
 import kotlinx.coroutines.flow.launchIn
 import kotlinx.coroutines.flow.onEach
+import kotlinx.coroutines.test.TestScope
 import kotlinx.coroutines.test.UnconfinedTestDispatcher
 import kotlinx.coroutines.test.runTest
 import org.junit.Assert.assertEquals
@@ -45,7 +46,7 @@
     private val fakeLightRevealScrimRepository = FakeLightRevealScrimRepository()
 
     private val keyguardTransitionInteractor =
-        KeyguardTransitionInteractor(fakeKeyguardTransitionRepository)
+        KeyguardTransitionInteractor(fakeKeyguardTransitionRepository, TestScope().backgroundScope)
 
     private lateinit var underTest: LightRevealScrimInteractor
 
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/DreamingToLockscreenTransitionViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/DreamingToLockscreenTransitionViewModelTest.kt
index cdd06ac..a341346 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/DreamingToLockscreenTransitionViewModelTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/DreamingToLockscreenTransitionViewModelTest.kt
@@ -25,11 +25,12 @@
 import com.android.systemui.keyguard.shared.model.KeyguardState
 import com.android.systemui.keyguard.shared.model.TransitionState
 import com.android.systemui.keyguard.shared.model.TransitionStep
-import com.android.systemui.keyguard.ui.KeyguardTransitionAnimationFlow
+import com.android.systemui.util.mockito.mock
 import com.google.common.collect.Range
 import com.google.common.truth.Truth.assertThat
 import kotlinx.coroutines.flow.launchIn
 import kotlinx.coroutines.flow.onEach
+import kotlinx.coroutines.test.TestScope
 import kotlinx.coroutines.test.UnconfinedTestDispatcher
 import kotlinx.coroutines.test.runTest
 import org.junit.Before
@@ -42,13 +43,12 @@
 class DreamingToLockscreenTransitionViewModelTest : SysuiTestCase() {
     private lateinit var underTest: DreamingToLockscreenTransitionViewModel
     private lateinit var repository: FakeKeyguardTransitionRepository
-    private lateinit var transitionAnimation: KeyguardTransitionAnimationFlow
 
     @Before
     fun setUp() {
         repository = FakeKeyguardTransitionRepository()
-        val interactor = KeyguardTransitionInteractor(repository)
-        underTest = DreamingToLockscreenTransitionViewModel(interactor)
+        val interactor = KeyguardTransitionInteractor(repository, TestScope().backgroundScope)
+        underTest = DreamingToLockscreenTransitionViewModel(interactor, mock())
     }
 
     @Test
@@ -60,17 +60,15 @@
             val job =
                 underTest.dreamOverlayTranslationY(pixels).onEach { values.add(it) }.launchIn(this)
 
-            // Should start running here...
             repository.sendTransitionStep(step(0f, TransitionState.STARTED))
             repository.sendTransitionStep(step(0f))
             repository.sendTransitionStep(step(0.3f))
             repository.sendTransitionStep(step(0.5f))
             repository.sendTransitionStep(step(0.6f))
-            // ...up to here
             repository.sendTransitionStep(step(0.8f))
             repository.sendTransitionStep(step(1f))
 
-            assertThat(values.size).isEqualTo(5)
+            assertThat(values.size).isEqualTo(7)
             values.forEach { assertThat(it).isIn(Range.closed(0f, 100f)) }
 
             job.cancel()
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/GoneToDreamingTransitionViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/GoneToDreamingTransitionViewModelTest.kt
index 40511a0..694539b 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/GoneToDreamingTransitionViewModelTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/GoneToDreamingTransitionViewModelTest.kt
@@ -29,6 +29,7 @@
 import com.google.common.truth.Truth.assertThat
 import kotlinx.coroutines.flow.launchIn
 import kotlinx.coroutines.flow.onEach
+import kotlinx.coroutines.test.TestScope
 import kotlinx.coroutines.test.UnconfinedTestDispatcher
 import kotlinx.coroutines.test.runTest
 import org.junit.Before
@@ -45,7 +46,7 @@
     @Before
     fun setUp() {
         repository = FakeKeyguardTransitionRepository()
-        val interactor = KeyguardTransitionInteractor(repository)
+        val interactor = KeyguardTransitionInteractor(repository, TestScope().backgroundScope)
         underTest = GoneToDreamingTransitionViewModel(interactor)
     }
 
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardBottomAreaViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardBottomAreaViewModelTest.kt
index 73fe380..b6368cf 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardBottomAreaViewModelTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardBottomAreaViewModelTest.kt
@@ -219,6 +219,7 @@
                 transitionInteractor =
                     KeyguardTransitionInteractor(
                         repository = FakeKeyguardTransitionRepository(),
+                        scope = testScope.backgroundScope
                     ),
                 repository = repository,
                 logger = UiEventLoggerFake(),
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenToDreamingTransitionViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenToDreamingTransitionViewModelTest.kt
index c98058d..ea17751 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenToDreamingTransitionViewModelTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenToDreamingTransitionViewModelTest.kt
@@ -29,6 +29,7 @@
 import com.google.common.truth.Truth.assertThat
 import kotlinx.coroutines.flow.launchIn
 import kotlinx.coroutines.flow.onEach
+import kotlinx.coroutines.test.TestScope
 import kotlinx.coroutines.test.UnconfinedTestDispatcher
 import kotlinx.coroutines.test.runTest
 import org.junit.Before
@@ -45,7 +46,7 @@
     @Before
     fun setUp() {
         repository = FakeKeyguardTransitionRepository()
-        val interactor = KeyguardTransitionInteractor(repository)
+        val interactor = KeyguardTransitionInteractor(repository, TestScope().backgroundScope)
         underTest = LockscreenToDreamingTransitionViewModel(interactor)
     }
 
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenToOccludedTransitionViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenToOccludedTransitionViewModelTest.kt
index 031b7fb..bf56a98 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenToOccludedTransitionViewModelTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenToOccludedTransitionViewModelTest.kt
@@ -29,6 +29,7 @@
 import com.google.common.truth.Truth.assertThat
 import kotlinx.coroutines.flow.launchIn
 import kotlinx.coroutines.flow.onEach
+import kotlinx.coroutines.test.TestScope
 import kotlinx.coroutines.test.UnconfinedTestDispatcher
 import kotlinx.coroutines.test.runTest
 import org.junit.Before
@@ -45,7 +46,7 @@
     @Before
     fun setUp() {
         repository = FakeKeyguardTransitionRepository()
-        val interactor = KeyguardTransitionInteractor(repository)
+        val interactor = KeyguardTransitionInteractor(repository, TestScope().backgroundScope)
         underTest = LockscreenToOccludedTransitionViewModel(interactor)
     }
 
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/OccludedToLockscreenTransitionViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/OccludedToLockscreenTransitionViewModelTest.kt
index c7ff882..34da26e 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/OccludedToLockscreenTransitionViewModelTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/OccludedToLockscreenTransitionViewModelTest.kt
@@ -29,6 +29,7 @@
 import com.google.common.truth.Truth.assertThat
 import kotlinx.coroutines.flow.launchIn
 import kotlinx.coroutines.flow.onEach
+import kotlinx.coroutines.test.TestScope
 import kotlinx.coroutines.test.UnconfinedTestDispatcher
 import kotlinx.coroutines.test.runTest
 import org.junit.Before
@@ -45,7 +46,7 @@
     @Before
     fun setUp() {
         repository = FakeKeyguardTransitionRepository()
-        val interactor = KeyguardTransitionInteractor(repository)
+        val interactor = KeyguardTransitionInteractor(repository, TestScope().backgroundScope)
         underTest = OccludedToLockscreenTransitionViewModel(interactor)
     }
 
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/PrimaryBouncerToGoneTransitionViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/PrimaryBouncerToGoneTransitionViewModelTest.kt
index db251a0..65b2ef7 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/PrimaryBouncerToGoneTransitionViewModelTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/PrimaryBouncerToGoneTransitionViewModelTest.kt
@@ -33,6 +33,7 @@
 import com.google.common.truth.Truth.assertThat
 import kotlinx.coroutines.flow.launchIn
 import kotlinx.coroutines.flow.onEach
+import kotlinx.coroutines.test.TestScope
 import kotlinx.coroutines.test.UnconfinedTestDispatcher
 import kotlinx.coroutines.test.runTest
 import org.junit.Before
@@ -54,7 +55,7 @@
     fun setUp() {
         MockitoAnnotations.initMocks(this)
         repository = FakeKeyguardTransitionRepository()
-        val interactor = KeyguardTransitionInteractor(repository)
+        val interactor = KeyguardTransitionInteractor(repository, TestScope().backgroundScope)
         underTest =
             PrimaryBouncerToGoneTransitionViewModel(
                 interactor,
diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/controls/ui/MediaCarouselControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/media/controls/ui/MediaCarouselControllerTest.kt
index 07f7c15..2aff90c 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/media/controls/ui/MediaCarouselControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/media/controls/ui/MediaCarouselControllerTest.kt
@@ -63,6 +63,7 @@
 import junit.framework.Assert.assertFalse
 import junit.framework.Assert.assertTrue
 import kotlinx.coroutines.ExperimentalCoroutinesApi
+import kotlinx.coroutines.test.TestScope
 import kotlinx.coroutines.test.UnconfinedTestDispatcher
 import kotlinx.coroutines.test.runTest
 import org.junit.Before
@@ -146,7 +147,7 @@
                 debugLogger,
                 mediaFlags,
                 keyguardUpdateMonitor,
-                KeyguardTransitionInteractor(repository = transitionRepository),
+                KeyguardTransitionInteractor(transitionRepository, TestScope().backgroundScope),
             )
         verify(configurationController).addCallback(capture(configListener))
         verify(mediaDataManager).addListener(capture(listener))
diff --git a/packages/SystemUI/tests/src/com/android/systemui/multishade/domain/interactor/MultiShadeMotionEventInteractorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/multishade/domain/interactor/MultiShadeMotionEventInteractorTest.kt
index 19f9960..9e54224 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/multishade/domain/interactor/MultiShadeMotionEventInteractorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/multishade/domain/interactor/MultiShadeMotionEventInteractorTest.kt
@@ -99,6 +99,7 @@
                 keyguardTransitionInteractor =
                     KeyguardTransitionInteractor(
                         repository = keyguardTransitionRepository,
+                        scope = testScope.backgroundScope
                     ),
                 falsingManager = falsingManager,
                 shadeController = shadeController,
diff --git a/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationShadeWindowViewControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationShadeWindowViewControllerTest.kt
index 16277de..3995e71 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationShadeWindowViewControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationShadeWindowViewControllerTest.kt
@@ -103,8 +103,8 @@
     @Mock lateinit var keyguardBouncerComponentFactory: KeyguardBouncerComponent.Factory
     @Mock lateinit var keyguardBouncerComponent: KeyguardBouncerComponent
     @Mock lateinit var keyguardSecurityContainerController: KeyguardSecurityContainerController
-    @Mock
-    private lateinit var unfoldTransitionProgressProvider: Optional<UnfoldTransitionProgressProvider>
+    @Mock private lateinit var unfoldTransitionProgressProvider:
+            Optional<UnfoldTransitionProgressProvider>
     @Mock lateinit var keyguardTransitionInteractor: KeyguardTransitionInteractor
     @Mock
     lateinit var primaryBouncerToGoneTransitionViewModel: PrimaryBouncerToGoneTransitionViewModel
@@ -184,6 +184,7 @@
                         keyguardTransitionInteractor =
                             KeyguardTransitionInteractor(
                                 repository = FakeKeyguardTransitionRepository(),
+                                scope = testScope.backgroundScope
                             ),
                         falsingManager = FalsingManagerFake(),
                         shadeController = shadeController,
diff --git a/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationShadeWindowViewTest.kt b/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationShadeWindowViewTest.kt
index 16af208..fe95742 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationShadeWindowViewTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationShadeWindowViewTest.kt
@@ -59,6 +59,7 @@
 import com.android.systemui.util.mockito.whenever
 import com.android.systemui.util.time.FakeSystemClock
 import com.google.common.truth.Truth.assertThat
+import java.util.Optional
 import kotlinx.coroutines.ExperimentalCoroutinesApi
 import kotlinx.coroutines.flow.emptyFlow
 import kotlinx.coroutines.test.TestScope
@@ -72,7 +73,6 @@
 import org.mockito.Mockito.spy
 import org.mockito.Mockito.verify
 import org.mockito.MockitoAnnotations
-import java.util.Optional
 
 @OptIn(ExperimentalCoroutinesApi::class)
 @RunWith(AndroidTestingRunner::class)
@@ -106,7 +106,8 @@
     @Mock
     private lateinit var keyguardSecurityContainerController: KeyguardSecurityContainerController
     @Mock
-    private lateinit var unfoldTransitionProgressProvider: Optional<UnfoldTransitionProgressProvider>
+    private lateinit var unfoldTransitionProgressProvider:
+        Optional<UnfoldTransitionProgressProvider>
     @Mock private lateinit var notificationInsetsController: NotificationInsetsController
     @Mock private lateinit var keyguardTransitionInteractor: KeyguardTransitionInteractor
     @Mock
@@ -195,6 +196,7 @@
                         keyguardTransitionInteractor =
                             KeyguardTransitionInteractor(
                                 repository = FakeKeyguardTransitionRepository(),
+                                scope = testScope.backgroundScope
                             ),
                         falsingManager = FalsingManagerFake(),
                         shadeController = shadeController,
diff --git a/packages/SystemUI/tests/src/com/android/systemui/shade/QsBatteryModeControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/shade/QsBatteryModeControllerTest.kt
index d421aca..b028f1f 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/shade/QsBatteryModeControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/shade/QsBatteryModeControllerTest.kt
@@ -63,36 +63,40 @@
 
     @Test
     fun returnsMODE_ESTIMATEforQsWithCenterCutout() {
+        // TODO (b/282044659): revert this test to previous behavior
         assertThat(controller.getBatteryMode(CENTER_TOP_CUTOUT, QS_END_FRAME.nextFrameToFraction()))
-            .isEqualTo(BatteryMeterView.MODE_ESTIMATE)
+            .isEqualTo(BatteryMeterView.MODE_ON)
     }
 
     @Test
     fun returnsMODE_ONforQqsWithCornerCutout() {
         whenever(insetsProvider.currentRotationHasCornerCutout()).thenReturn(true)
 
+        // TODO (b/282044659): revert this test to previous behavior
         assertThat(
                 controller.getBatteryMode(CENTER_TOP_CUTOUT, QQS_START_FRAME.prevFrameToFraction())
             )
-            .isEqualTo(BatteryMeterView.MODE_ESTIMATE)
+            .isEqualTo(BatteryMeterView.MODE_ON)
     }
 
     @Test
     fun returnsMODE_ESTIMATEforQsWithCornerCutout() {
         whenever(insetsProvider.currentRotationHasCornerCutout()).thenReturn(true)
 
+        // TODO (b/282044659): revert this test to previous behavior
         assertThat(controller.getBatteryMode(CENTER_TOP_CUTOUT, QS_END_FRAME.nextFrameToFraction()))
-            .isEqualTo(BatteryMeterView.MODE_ESTIMATE)
+            .isEqualTo(BatteryMeterView.MODE_ON)
     }
 
     @Test
     fun returnsNullInBetween() {
+        // TODO (b/282044659): revert this test to previous behavior
         assertThat(
                 controller.getBatteryMode(CENTER_TOP_CUTOUT, QQS_START_FRAME.nextFrameToFraction())
             )
-            .isNull()
+            .isEqualTo(BatteryMeterView.MODE_ON)
         assertThat(controller.getBatteryMode(CENTER_TOP_CUTOUT, QS_END_FRAME.prevFrameToFraction()))
-            .isNull()
+            .isEqualTo(BatteryMeterView.MODE_ON)
     }
 
     private fun Int.prevFrameToFraction(): Float = (this - 1) / MOTION_LAYOUT_MAX_FRAME.toFloat()
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/CentralSurfacesImplTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/CentralSurfacesImplTest.java
index 8062272..7702630 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/CentralSurfacesImplTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/CentralSurfacesImplTest.java
@@ -350,7 +350,9 @@
         // For the Shade to animate during the Back gesture, we must enable the animation flag.
         mFeatureFlags.set(Flags.WM_SHADE_ANIMATE_BACK_GESTURE, true);
         mFeatureFlags.set(Flags.LIGHT_REVEAL_MIGRATION, true);
+        // Turn AOD on and toggle feature flag for jank fixes
         mFeatureFlags.set(Flags.ZJ_285570694_LOCKSCREEN_TRANSITION_FROM_AOD, true);
+        when(mDozeParameters.getAlwaysOn()).thenReturn(true);
 
         IThermalService thermalService = mock(IThermalService.class);
         mPowerManager = new PowerManager(mContext, mPowerManagerService, thermalService,
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/shared/ui/viewmodel/CollapsedStatusBarViewModelImplTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/shared/ui/viewmodel/CollapsedStatusBarViewModelImplTest.kt
index c8c24a7..6301fa0 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/shared/ui/viewmodel/CollapsedStatusBarViewModelImplTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/shared/ui/viewmodel/CollapsedStatusBarViewModelImplTest.kt
@@ -47,7 +47,8 @@
         testScope = TestScope(UnconfinedTestDispatcher())
 
         keyguardTransitionRepository = FakeKeyguardTransitionRepository()
-        val interactor = KeyguardTransitionInteractor(keyguardTransitionRepository)
+        val interactor =
+            KeyguardTransitionInteractor(keyguardTransitionRepository, testScope.backgroundScope)
         underTest = CollapsedStatusBarViewModelImpl(interactor, testScope.backgroundScope)
     }
 
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/BaseUserSwitcherAdapterTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/BaseUserSwitcherAdapterTest.kt
index 67727ae..d1c38f6 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/BaseUserSwitcherAdapterTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/BaseUserSwitcherAdapterTest.kt
@@ -77,6 +77,7 @@
             )
 
         whenever(controller.users).thenAnswer { users }
+        whenever(controller.isUserSwitcherEnabled).thenReturn(true)
 
         underTest =
             object : BaseUserSwitcherAdapter(controller) {
@@ -162,6 +163,19 @@
     }
 
     @Test
+    fun count_onlyShowsCurrentUserWhenMultiUserDisabled() {
+        whenever(controller.isUserSwitcherEnabled).thenReturn(false)
+        assertThat(underTest.count).isEqualTo(1)
+        assertThat(underTest.getItem(0).isCurrent).isTrue()
+    }
+
+    @Test
+    fun count_doesNotIgnoreAllOtherUsersWhenMultiUserEnabled() {
+        whenever(controller.isUserSwitcherEnabled).thenReturn(true)
+        assertThat(underTest.count).isEqualTo(users.size)
+    }
+
+    @Test
     fun getItem() {
         assertThat((0 until underTest.count).map { position -> underTest.getItem(position) })
             .isEqualTo(users)
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/KeyguardUserSwitcherAdapterTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/KeyguardUserSwitcherAdapterTest.kt
index 8290dab..1ab62d0 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/KeyguardUserSwitcherAdapterTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/KeyguardUserSwitcherAdapterTest.kt
@@ -29,6 +29,7 @@
 import com.android.systemui.SysuiTestCase
 import com.android.systemui.qs.tiles.UserDetailItemView
 import com.android.systemui.user.data.source.UserRecord
+import com.android.systemui.util.mockito.whenever
 import org.junit.Assert.assertFalse
 import org.junit.Assert.assertNotNull
 import org.junit.Assert.assertTrue
@@ -68,6 +69,8 @@
     fun setUp() {
         MockitoAnnotations.initMocks(this)
 
+        whenever(userSwitcherController.isUserSwitcherEnabled).thenReturn(true)
+
         mContext.addMockSystemService(Context.LAYOUT_INFLATER_SERVICE, layoutInflater)
         `when`(layoutInflater.inflate(anyInt(), any(ViewGroup::class.java), anyBoolean()))
                 .thenReturn(inflatedUserDetailItemView)
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/user/data/repository/FakeUserRepository.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/user/data/repository/FakeUserRepository.kt
index fbc2381..61e5b5f 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/user/data/repository/FakeUserRepository.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/user/data/repository/FakeUserRepository.kt
@@ -79,6 +79,10 @@
         return _userSwitcherSettings.value.isSimpleUserSwitcher
     }
 
+    override fun isUserSwitcherEnabled(): Boolean {
+        return _userSwitcherSettings.value.isUserSwitcherEnabled
+    }
+
     fun setUserInfos(infos: List<UserInfo>) {
         _userInfos.value = infos
     }
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index 0916960..a7db663 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -14449,6 +14449,8 @@
                     && !Intent.ACTION_SHUTDOWN.equals(intent.getAction())) {
                 Slog.w(TAG, "Skipping broadcast of " + intent
                         + ": user " + userId + " and its parent (if any) are stopped");
+                scheduleCanceledResultTo(resultToApp, resultTo, intent, userId,
+                        brOptions, callingUid, callerPackage);
                 return ActivityManager.BROADCAST_FAILED_USER_STOPPED;
             }
         }
@@ -14520,6 +14522,8 @@
             isProtectedBroadcast = AppGlobals.getPackageManager().isProtectedBroadcast(action);
         } catch (RemoteException e) {
             Slog.w(TAG, "Remote exception", e);
+            scheduleCanceledResultTo(resultToApp, resultTo, intent,
+                    userId, brOptions, callingUid, callerPackage);
             return ActivityManager.BROADCAST_SUCCESS;
         }
 
@@ -14753,6 +14757,8 @@
                         if (aInfo == null) {
                             Slog.w(TAG, "Dropping ACTION_PACKAGE_REPLACED for non-existent pkg:"
                                     + " ssp=" + ssp + " data=" + data);
+                            scheduleCanceledResultTo(resultToApp, resultTo, intent,
+                                    userId, brOptions, callingUid, callerPackage);
                             return ActivityManager.BROADCAST_SUCCESS;
                         }
                         updateAssociationForApp(aInfo);
@@ -14838,6 +14844,8 @@
                     // Apps should now be using ShortcutManager.pinRequestShortcut().
                     Log.w(TAG, "Broadcast " + action
                             + " no longer supported. It will not be delivered.");
+                    scheduleCanceledResultTo(resultToApp, resultTo, intent,
+                            userId, brOptions, callingUid, callerPackage);
                     return ActivityManager.BROADCAST_SUCCESS;
                 case Intent.ACTION_PRE_BOOT_COMPLETED:
                     timeoutExempt = true;
@@ -14845,6 +14853,8 @@
                 case Intent.ACTION_CLOSE_SYSTEM_DIALOGS:
                     if (!mAtmInternal.checkCanCloseSystemDialogs(callingPid, callingUid,
                             callerPackage)) {
+                        scheduleCanceledResultTo(resultToApp, resultTo, intent,
+                                userId, brOptions, callingUid, callerPackage);
                         // Returning success seems to be the pattern here
                         return ActivityManager.BROADCAST_SUCCESS;
                     }
@@ -14879,6 +14889,8 @@
             if (requiredPermissions != null && requiredPermissions.length > 0) {
                 Slog.w(TAG, "Can't broadcast sticky intent " + intent
                         + " and enforce permissions " + Arrays.toString(requiredPermissions));
+                scheduleCanceledResultTo(resultToApp, resultTo, intent,
+                        userId, brOptions, callingUid, callerPackage);
                 return ActivityManager.BROADCAST_STICKY_CANT_HAVE_PERMISSION;
             }
             if (intent.getComponent() != null) {
@@ -15130,6 +15142,33 @@
     }
 
     @GuardedBy("this")
+    private void scheduleCanceledResultTo(ProcessRecord resultToApp, IIntentReceiver resultTo,
+            Intent intent, int userId, BroadcastOptions options, int callingUid,
+            String callingPackage) {
+        if (resultTo == null) {
+            return;
+        }
+        final ProcessRecord app = resultToApp;
+        final IApplicationThread thread  = (app != null) ? app.getOnewayThread() : null;
+        if (thread != null) {
+            try {
+                final boolean shareIdentity = (options != null && options.isShareIdentityEnabled());
+                thread.scheduleRegisteredReceiver(
+                        resultTo, intent, Activity.RESULT_CANCELED, null, null,
+                        false, false, true, userId, app.mState.getReportedProcState(),
+                        shareIdentity ? callingUid : Process.INVALID_UID,
+                        shareIdentity ? callingPackage : null);
+            } catch (RemoteException e) {
+                final String msg = "Failed to schedule result of " + intent + " via "
+                        + app + ": " + e;
+                app.killLocked("Can't schedule resultTo", ApplicationExitInfo.REASON_OTHER,
+                        ApplicationExitInfo.SUBREASON_UNDELIVERED_BROADCAST, true);
+                Slog.d(TAG, msg);
+            }
+        }
+    }
+
+    @GuardedBy("this")
     private int getRealProcessStateLocked(ProcessRecord app, int pid) {
         if (app == null) {
             synchronized (mPidsSelfLocked) {
diff --git a/services/core/java/com/android/server/am/ActivityManagerShellCommand.java b/services/core/java/com/android/server/am/ActivityManagerShellCommand.java
index ba8a1b9..569f55f 100644
--- a/services/core/java/com/android/server/am/ActivityManagerShellCommand.java
+++ b/services/core/java/com/android/server/am/ActivityManagerShellCommand.java
@@ -928,8 +928,8 @@
         final int result = mInterface.broadcastIntentWithFeature(null, null, intent, null,
                 receiver, 0, null, null, requiredPermissions, null, null,
                 android.app.AppOpsManager.OP_NONE, bundle, true, false, mUserId);
-        Slogf.i(TAG, "Broadcasted %s: " + result, intent);
-        if (!mAsync) {
+        Slogf.i(TAG, "Enqueued broadcast %s: " + result, intent);
+        if (result == ActivityManager.BROADCAST_SUCCESS && !mAsync) {
             receiver.waitForFinish();
         }
         return 0;
diff --git a/services/core/java/com/android/server/am/BroadcastQueueModernImpl.java b/services/core/java/com/android/server/am/BroadcastQueueModernImpl.java
index 33e21f1..03d1fbb 100644
--- a/services/core/java/com/android/server/am/BroadcastQueueModernImpl.java
+++ b/services/core/java/com/android/server/am/BroadcastQueueModernImpl.java
@@ -1608,11 +1608,15 @@
                     refreshProcessQueuesLocked(uid);
                 }
             }
+        }, ActivityManager.UID_OBSERVER_PROCSTATE,
+                ActivityManager.PROCESS_STATE_TOP, "android");
 
+        mService.registerUidObserver(new UidObserver() {
             @Override
-            public void onUidCachedChanged(int uid, boolean cached) {
+            public void onUidStateChanged(int uid, int procState, long procStateSeq,
+                    int capability) {
                 synchronized (mService) {
-                    if (cached) {
+                    if (procState > ActivityManager.PROCESS_STATE_LAST_ACTIVITY) {
                         mUidCached.put(uid, true);
                     } else {
                         mUidCached.delete(uid);
@@ -1620,8 +1624,8 @@
                     refreshProcessQueuesLocked(uid);
                 }
             }
-        }, ActivityManager.UID_OBSERVER_PROCSTATE | ActivityManager.UID_OBSERVER_CACHED,
-                ActivityManager.PROCESS_STATE_TOP, "android");
+        }, ActivityManager.UID_OBSERVER_PROCSTATE,
+                ActivityManager.PROCESS_STATE_LAST_ACTIVITY, "android");
 
         // Kick off periodic health checks
         mLocalHandler.sendEmptyMessage(MSG_CHECK_HEALTH);
diff --git a/services/core/java/com/android/server/am/CachedAppOptimizer.java b/services/core/java/com/android/server/am/CachedAppOptimizer.java
index 7773190..eccff2a 100644
--- a/services/core/java/com/android/server/am/CachedAppOptimizer.java
+++ b/services/core/java/com/android/server/am/CachedAppOptimizer.java
@@ -123,7 +123,14 @@
             "freeze_debounce_timeout";
     @VisibleForTesting static final String KEY_FREEZER_EXEMPT_INST_PKG =
             "freeze_exempt_inst_pkg";
-
+    @VisibleForTesting static final String KEY_FREEZER_BINDER_ENABLED =
+            "freeze_binder_enabled";
+    @VisibleForTesting static final String KEY_FREEZER_BINDER_DIVISOR =
+            "freeze_binder_divisor";
+    @VisibleForTesting static final String KEY_FREEZER_BINDER_OFFSET =
+            "freeze_binder_offset";
+    @VisibleForTesting static final String KEY_FREEZER_BINDER_THRESHOLD =
+            "freeze_binder_threshold";
 
     static final int UNFREEZE_REASON_NONE =
             FrameworkStatsLog.APP_FREEZE_CHANGED__UNFREEZE_REASON_V2__UFR_NONE;
@@ -237,8 +244,8 @@
     @VisibleForTesting static final boolean ENABLE_FILE_COMPACT = false;
 
     // Defaults for phenotype flags.
-    @VisibleForTesting static final Boolean DEFAULT_USE_COMPACTION = true;
-    @VisibleForTesting static final Boolean DEFAULT_USE_FREEZER = true;
+    @VisibleForTesting static final boolean DEFAULT_USE_COMPACTION = true;
+    @VisibleForTesting static final boolean DEFAULT_USE_FREEZER = true;
     @VisibleForTesting static final long DEFAULT_COMPACT_THROTTLE_1 = 5_000;
     @VisibleForTesting static final long DEFAULT_COMPACT_THROTTLE_2 = 10_000;
     @VisibleForTesting static final long DEFAULT_COMPACT_THROTTLE_3 = 500;
@@ -257,7 +264,11 @@
     @VisibleForTesting static final String DEFAULT_COMPACT_PROC_STATE_THROTTLE =
             String.valueOf(ActivityManager.PROCESS_STATE_RECEIVER);
     @VisibleForTesting static final long DEFAULT_FREEZER_DEBOUNCE_TIMEOUT = 10_000L;
-    @VisibleForTesting static final Boolean DEFAULT_FREEZER_EXEMPT_INST_PKG = true;
+    @VisibleForTesting static final boolean DEFAULT_FREEZER_EXEMPT_INST_PKG = true;
+    @VisibleForTesting static final boolean DEFAULT_FREEZER_BINDER_ENABLED = true;
+    @VisibleForTesting static final long DEFAULT_FREEZER_BINDER_DIVISOR = 4;
+    @VisibleForTesting static final int DEFAULT_FREEZER_BINDER_OFFSET = 500;
+    @VisibleForTesting static final long DEFAULT_FREEZER_BINDER_THRESHOLD = 1_000;
 
     @VisibleForTesting static final Uri CACHED_APP_FREEZER_ENABLED_URI = Settings.Global.getUriFor(
                 Settings.Global.CACHED_APPS_FREEZER_ENABLED);
@@ -393,6 +404,11 @@
                                 updateFreezerDebounceTimeout();
                             } else if (KEY_FREEZER_EXEMPT_INST_PKG.equals(name)) {
                                 updateFreezerExemptInstPkg();
+                            } else if (KEY_FREEZER_BINDER_ENABLED.equals(name)
+                                    || KEY_FREEZER_BINDER_DIVISOR.equals(name)
+                                    || KEY_FREEZER_BINDER_THRESHOLD.equals(name)
+                                    || KEY_FREEZER_BINDER_OFFSET.equals(name)) {
+                                updateFreezerBinderState();
                             }
                         }
                     }
@@ -455,6 +471,16 @@
     @GuardedBy("mPhenotypeFlagLock")
     @VisibleForTesting final Set<Integer> mProcStateThrottle;
 
+    @GuardedBy("mPhenotypeFlagLock")
+    @VisibleForTesting volatile boolean mFreezerBinderEnabled = DEFAULT_FREEZER_BINDER_ENABLED;
+    @GuardedBy("mPhenotypeFlagLock")
+    @VisibleForTesting volatile long mFreezerBinderDivisor = DEFAULT_FREEZER_BINDER_DIVISOR;
+    @GuardedBy("mPhenotypeFlagLock")
+    @VisibleForTesting volatile int mFreezerBinderOffset = DEFAULT_FREEZER_BINDER_OFFSET;
+    @GuardedBy("mPhenotypeFlagLock")
+    @VisibleForTesting volatile long mFreezerBinderThreshold = DEFAULT_FREEZER_BINDER_THRESHOLD;
+
+
     // Handler on which compaction runs.
     @VisibleForTesting
     Handler mCompactionHandler;
@@ -759,6 +785,10 @@
             pw.println("  " + KEY_FREEZER_STATSD_SAMPLE_RATE + "=" + mFreezerStatsdSampleRate);
             pw.println("  " + KEY_FREEZER_DEBOUNCE_TIMEOUT + "=" + mFreezerDebounceTimeout);
             pw.println("  " + KEY_FREEZER_EXEMPT_INST_PKG + "=" + mFreezerExemptInstPkg);
+            pw.println("  " + KEY_FREEZER_BINDER_ENABLED + "=" + mFreezerBinderEnabled);
+            pw.println("  " + KEY_FREEZER_BINDER_THRESHOLD + "=" + mFreezerBinderThreshold);
+            pw.println("  " + KEY_FREEZER_BINDER_DIVISOR + "=" + mFreezerBinderDivisor);
+            pw.println("  " + KEY_FREEZER_BINDER_OFFSET + "=" + mFreezerBinderOffset);
             synchronized (mProcLock) {
                 int size = mFrozenProcesses.size();
                 pw.println("  Apps frozen: " + size);
@@ -1264,6 +1294,26 @@
         Slog.d(TAG_AM, "Freezer exemption set to " + mFreezerExemptInstPkg);
     }
 
+    @GuardedBy("mPhenotypeFlagLock")
+    private void updateFreezerBinderState() {
+        mFreezerBinderEnabled = DeviceConfig.getBoolean(
+                DeviceConfig.NAMESPACE_ACTIVITY_MANAGER_NATIVE_BOOT,
+                KEY_FREEZER_BINDER_ENABLED, DEFAULT_FREEZER_BINDER_ENABLED);
+        mFreezerBinderDivisor = DeviceConfig.getLong(
+                DeviceConfig.NAMESPACE_ACTIVITY_MANAGER_NATIVE_BOOT,
+                KEY_FREEZER_BINDER_DIVISOR, DEFAULT_FREEZER_BINDER_DIVISOR);
+        mFreezerBinderOffset = DeviceConfig.getInt(
+                DeviceConfig.NAMESPACE_ACTIVITY_MANAGER_NATIVE_BOOT,
+                KEY_FREEZER_BINDER_OFFSET, DEFAULT_FREEZER_BINDER_OFFSET);
+        mFreezerBinderThreshold = DeviceConfig.getLong(
+                DeviceConfig.NAMESPACE_ACTIVITY_MANAGER_NATIVE_BOOT,
+                KEY_FREEZER_BINDER_THRESHOLD, DEFAULT_FREEZER_BINDER_THRESHOLD);
+        Slog.d(TAG_AM, "Freezer binder state set to enabled=" + mFreezerBinderEnabled
+                + ", divisor=" + mFreezerBinderDivisor
+                + ", offset=" + mFreezerBinderOffset
+                + ", threshold=" + mFreezerBinderThreshold);
+    }
+
     private boolean parseProcStateThrottle(String procStateThrottleString) {
         String[] procStates = TextUtils.split(procStateThrottleString, ",");
         mProcStateThrottle.clear();
@@ -1352,6 +1402,7 @@
                 }
             }
         }
+        app.mOptRecord.setLastUsedTimeout(delayMillis);
         mFreezeHandler.sendMessageDelayed(
                 mFreezeHandler.obtainMessage(SET_FROZEN_PROCESS_MSG, DO_FREEZE, 0, app),
                 delayMillis);
@@ -1525,10 +1576,14 @@
                 opt.setPendingFreeze(false);
             }
 
-            UidRecord uidRec = app.getUidRecord();
-            if (uidRec != null && uidRec.isFrozen()) {
-                uidRec.setFrozen(false);
-                postUidFrozenMessage(uidRec.getUid(), false);
+            final UidRecord uidRec = app.getUidRecord();
+            if (uidRec != null) {
+                final boolean isFrozen = uidRec.getNumOfProcs() > 1
+                        && uidRec.areAllProcessesFrozen(app);
+                if (isFrozen != uidRec.isFrozen()) {
+                    uidRec.setFrozen(isFrozen);
+                    postUidFrozenMessage(uidRec.getUid(), isFrozen);
+                }
             }
 
             mFrozenProcesses.delete(app.getPid());
@@ -2117,12 +2172,54 @@
         }
 
         @GuardedBy({"mAm", "mProcLock"})
-        private void rescheduleFreeze(final ProcessRecord proc, final String reason,
-                @UnfreezeReason int reasonCode) {
+        private void handleBinderFreezerFailure(final ProcessRecord proc, final String reason) {
+            if (!mFreezerBinderEnabled) {
+                // Just reschedule indefinitely.
+                unfreezeAppLSP(proc, UNFREEZE_REASON_BINDER_TXNS);
+                freezeAppAsyncLSP(proc);
+                return;
+            }
+            /*
+             * This handles the case where a process couldn't be frozen due to pending binder
+             * transactions. In order to prevent apps from avoiding the freezer by spamming binder
+             * transactions, there is an exponential decrease in freezer retry times plus a random
+             * offset per attempt to avoid phase issues. Once the last-attempted timeout is below a
+             * threshold, we assume that the app is spamming binder calls and can never be frozen,
+             * and we will then crash the app.
+             */
+            if (proc.mOptRecord.getLastUsedTimeout() <= mFreezerBinderThreshold) {
+                // We've given the app plenty of chances, assume broken. Time to die.
+                Slog.d(TAG_AM, "Kill app due to repeated failure to freeze binder: "
+                        + proc.getPid() + " " + proc.processName);
+                mAm.mHandler.post(() -> {
+                    synchronized (mAm) {
+                        // Crash regardless of procstate in case the app has found another way
+                        // to abuse oom_adj
+                        if (proc.getThread() == null) {
+                            return;
+                        }
+                        proc.killLocked("excessive binder traffic during cached",
+                                ApplicationExitInfo.REASON_EXCESSIVE_RESOURCE_USAGE,
+                                ApplicationExitInfo.SUBREASON_EXCESSIVE_CPU,
+                                true);
+                    }
+                });
+                return;
+            }
+
+            long timeout = proc.mOptRecord.getLastUsedTimeout() / mFreezerBinderDivisor;
+            // range is [-mFreezerBinderOffset, +mFreezerBinderOffset]
+            int offset = mRandom.nextInt(mFreezerBinderOffset * 2) - mFreezerBinderOffset;
+            timeout = Math.max(timeout + offset, mFreezerBinderThreshold);
+
             Slog.d(TAG_AM, "Reschedule freeze for process " + proc.getPid()
-                    + " " + proc.processName + " (" + reason + ")");
-            unfreezeAppLSP(proc, reasonCode);
-            freezeAppAsyncLSP(proc);
+                    + " " + proc.processName + " (" + reason  + "), timeout=" + timeout);
+            Trace.instantForTrack(Trace.TRACE_TAG_ACTIVITY_MANAGER, ATRACE_FREEZER_TRACK,
+                    "Reschedule freeze " + proc.processName + ":" + proc.getPid()
+                    + " timeout=" + timeout + ", reason=" + reason);
+
+            unfreezeAppLSP(proc, UNFREEZE_REASON_BINDER_TXNS);
+            freezeAppAsyncLSP(proc, timeout);
         }
 
         /**
@@ -2169,7 +2266,7 @@
                 // transactions that might be pending.
                 try {
                     if (freezeBinder(pid, true, FREEZE_BINDER_TIMEOUT_MS) != 0) {
-                        rescheduleFreeze(proc, "outstanding txns", UNFREEZE_REASON_BINDER_TXNS);
+                        handleBinderFreezerFailure(proc, "outstanding txns");
                         return;
                     }
                 } catch (RuntimeException e) {
@@ -2230,7 +2327,7 @@
 
                 if ((freezeInfo & TXNS_PENDING_WHILE_FROZEN) != 0) {
                     synchronized (mProcLock) {
-                        rescheduleFreeze(proc, "new pending txns", UNFREEZE_REASON_BINDER_TXNS);
+                        handleBinderFreezerFailure(proc, "new pending txns");
                     }
                     return;
                 }
diff --git a/services/core/java/com/android/server/am/ProcessCachedOptimizerRecord.java b/services/core/java/com/android/server/am/ProcessCachedOptimizerRecord.java
index ffe5a6e..f5c5ea8 100644
--- a/services/core/java/com/android/server/am/ProcessCachedOptimizerRecord.java
+++ b/services/core/java/com/android/server/am/ProcessCachedOptimizerRecord.java
@@ -127,6 +127,12 @@
     @GuardedBy("mProcLock")
     private @UptimeMillisLong long mEarliestFreezableTimeMillis;
 
+    /**
+     * This is the most recently used timeout for freezing the app in millis
+     */
+    @GuardedBy("mProcLock")
+    private long mLastUsedTimeout;
+
     @GuardedBy("mProcLock")
     long getLastCompactTime() {
         return mLastCompactTime;
@@ -282,6 +288,16 @@
     }
 
     @GuardedBy("mProcLock")
+    long getLastUsedTimeout() {
+        return mLastUsedTimeout;
+    }
+
+    @GuardedBy("mProcLock")
+    void setLastUsedTimeout(long lastUsedTimeout) {
+        mLastUsedTimeout = lastUsedTimeout;
+    }
+
+    @GuardedBy("mProcLock")
     boolean isFreezeExempt() {
         return mFreezeExempt;
     }
diff --git a/services/core/java/com/android/server/am/StackTracesDumpHelper.java b/services/core/java/com/android/server/am/StackTracesDumpHelper.java
index af99684..cf69b53 100644
--- a/services/core/java/com/android/server/am/StackTracesDumpHelper.java
+++ b/services/core/java/com/android/server/am/StackTracesDumpHelper.java
@@ -229,7 +229,7 @@
                 firstPidEnd = new File(tracesFile).length();
             }
             // Append the Durations/latency comma separated array after the first PID.
-            if (latencyTracker != null) {
+            if (firstPidTempDumpCopied && latencyTracker != null) {
                 appendtoANRFile(tracesFile,
                         latencyTracker.dumpAsCommaSeparatedArrayWithHeader());
             }
diff --git a/services/core/java/com/android/server/am/UidRecord.java b/services/core/java/com/android/server/am/UidRecord.java
index 993088e..4329afc 100644
--- a/services/core/java/com/android/server/am/UidRecord.java
+++ b/services/core/java/com/android/server/am/UidRecord.java
@@ -345,21 +345,32 @@
     }
 
     /**
+     * Check whether all processes in the Uid are frozen.
+     *
+     * @param excluding Skip this process record during the check.
      * @return true if all processes in the Uid are frozen, false otherwise.
      */
     @GuardedBy(anyOf = {"mService", "mProcLock"})
-    public boolean areAllProcessesFrozen() {
+    public boolean areAllProcessesFrozen(ProcessRecord excluding) {
         for (int i = mProcRecords.size() - 1; i >= 0; i--) {
             final ProcessRecord app = mProcRecords.valueAt(i);
             final ProcessCachedOptimizerRecord opt = app.mOptRecord;
 
-            if (!opt.isFrozen()) {
+            if (excluding != app && !opt.isFrozen()) {
                 return false;
             }
         }
         return true;
     }
 
+    /**
+     * @return true if all processes in the Uid are frozen, false otherwise.
+     */
+    @GuardedBy(anyOf = {"mService", "mProcLock"})
+    public boolean areAllProcessesFrozen() {
+        return areAllProcessesFrozen(null);
+    }
+
     @GuardedBy(anyOf = {"mService", "mProcLock"})
     public void setFrozen(boolean frozen) {
         mUidIsFrozen = frozen;
diff --git a/services/core/java/com/android/server/am/UserSwitchingDialog.java b/services/core/java/com/android/server/am/UserSwitchingDialog.java
index 4e7865c..2d74564 100644
--- a/services/core/java/com/android/server/am/UserSwitchingDialog.java
+++ b/services/core/java/com/android/server/am/UserSwitchingDialog.java
@@ -88,8 +88,6 @@
     UserSwitchingDialog(Context context, UserInfo oldUser, UserInfo newUser,
             String switchingFromSystemUserMessage, String switchingToSystemUserMessage,
             WindowManagerService windowManager) {
-        // TODO(b/278857848): Make full screen user switcher cover top part of the screen as well.
-        //                    This problem is seen only on phones, it works fine on tablets.
         super(context, R.style.Theme_Material_NoActionBar_Fullscreen);
 
         mContext = context;
@@ -112,9 +110,12 @@
         final WindowManager.LayoutParams attrs = window.getAttributes();
         attrs.privateFlags = WindowManager.LayoutParams.PRIVATE_FLAG_SYSTEM_ERROR |
                 WindowManager.LayoutParams.SYSTEM_FLAG_SHOW_FOR_ALL_USERS;
+        attrs.layoutInDisplayCutoutMode =
+                WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS;
         window.setAttributes(attrs);
         window.setBackgroundDrawableResource(android.R.color.transparent);
         window.setType(WindowManager.LayoutParams.TYPE_SYSTEM_ERROR);
+        window.setDecorFitsSystemWindows(false);
     }
 
     void inflateContent() {
diff --git a/services/core/java/com/android/server/audio/PlaybackActivityMonitor.java b/services/core/java/com/android/server/audio/PlaybackActivityMonitor.java
index 9fc0038..50ffbcb9 100644
--- a/services/core/java/com/android/server/audio/PlaybackActivityMonitor.java
+++ b/services/core/java/com/android/server/audio/PlaybackActivityMonitor.java
@@ -812,8 +812,7 @@
             return false;
         }
         final int reqUsage = requester.getAudioAttributes().getUsage();
-        if ((reqUsage == AudioAttributes.USAGE_ASSISTANT)
-                || (reqUsage == AudioAttributes.USAGE_ASSISTANCE_NAVIGATION_GUIDANCE)) {
+        if (reqUsage == AudioAttributes.USAGE_ASSISTANT) {
             return true;
         }
         return false;
diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java
index d29d9c8..488745c 100644
--- a/services/core/java/com/android/server/notification/NotificationManagerService.java
+++ b/services/core/java/com/android/server/notification/NotificationManagerService.java
@@ -8718,13 +8718,7 @@
 
         ToastRecord lastToast = mToastQueue.remove(index);
 
-        mWindowManagerInternal.removeWindowToken(lastToast.windowToken, false /* removeWindows */,
-                lastToast.displayId);
-        // We passed 'false' for 'removeWindows' so that the client has time to stop
-        // rendering (as hide above is a one-way message), otherwise we could crash
-        // a client which was actively using a surface made from the token. However
-        // we need to schedule a timeout to make sure the token is eventually killed
-        // one way or another.
+        // We need to schedule a timeout to make sure the token is eventually killed
         scheduleKillTokenTimeout(lastToast);
 
         keepProcessAliveForToastIfNeededLocked(record.pid);
diff --git a/services/core/java/com/android/server/pm/ComputerEngine.java b/services/core/java/com/android/server/pm/ComputerEngine.java
index abfc1d7..78f1fa6 100644
--- a/services/core/java/com/android/server/pm/ComputerEngine.java
+++ b/services/core/java/com/android/server/pm/ComputerEngine.java
@@ -4311,7 +4311,12 @@
         if (Process.isIsolatedUid(uid)
                 && mPermissionManager.getHotwordDetectionServiceProvider() != null
                 && uid == mPermissionManager.getHotwordDetectionServiceProvider().getUid()) {
-            uid = getIsolatedOwner(uid);
+            try {
+                uid = getIsolatedOwner(uid);
+            } catch (IllegalStateException e) {
+                // If the owner uid doesn't exist, just use the current uid
+                Slog.wtf(TAG, "Expected isolated uid " + uid + " to have an owner", e);
+            }
         }
         final int callingUserId = UserHandle.getUserId(callingUid);
         final int appId = UserHandle.getAppId(uid);
@@ -4352,7 +4357,12 @@
             if (Process.isIsolatedUid(uid)
                     && mPermissionManager.getHotwordDetectionServiceProvider() != null
                     && uid == mPermissionManager.getHotwordDetectionServiceProvider().getUid()) {
-                uid = getIsolatedOwner(uid);
+                try {
+                    uid = getIsolatedOwner(uid);
+                } catch (IllegalStateException e) {
+                    // If the owner uid doesn't exist, just use the current uid
+                    Slog.wtf(TAG, "Expected isolated uid " + uid + " to have an owner", e);
+                }
             }
             final int appId = UserHandle.getAppId(uid);
             final Object obj = mSettings.getSettingBase(appId);
diff --git a/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java b/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java
index 9e9b344..e31b53c 100644
--- a/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java
+++ b/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java
@@ -3293,7 +3293,7 @@
         WallpaperData wallpaper;
 
         synchronized (mLock) {
-            Slog.v(TAG, "setWallpaperComponent name=" + name);
+            Slog.v(TAG, "setWallpaperComponent name=" + name + ", which=" + which);
             wallpaper = mWallpaperMap.get(userId);
             if (wallpaper == null) {
                 throw new IllegalStateException("Wallpaper not yet initialized for user " + userId);
@@ -3324,7 +3324,11 @@
                 wallpaper.mWhich = which;
                 wallpaper.fromForegroundApp = isFromForegroundApp(callingPackage);
                 boolean same = changingToSame(name, wallpaper);
-                if (bindWallpaperComponentLocked(name, false, true, wallpaper, null)) {
+
+                // force rebind when reapplying a system-only wallpaper to system+lock
+                boolean forceRebind = same && mLockWallpaperMap.get(userId) != null
+                        && which == (FLAG_SYSTEM | FLAG_LOCK);
+                if (bindWallpaperComponentLocked(name, forceRebind, true, wallpaper, null)) {
                     if (!same) {
                         wallpaper.primaryColors = null;
                     } else {
diff --git a/services/core/java/com/android/server/wm/Dimmer.java b/services/core/java/com/android/server/wm/Dimmer.java
index 8660bec..89f044b 100644
--- a/services/core/java/com/android/server/wm/Dimmer.java
+++ b/services/core/java/com/android/server/wm/Dimmer.java
@@ -178,6 +178,10 @@
         mSurfaceAnimatorStarter = surfaceAnimatorStarter;
     }
 
+    WindowContainer<?> getHost() {
+        return mHost;
+    }
+
     private SurfaceControl makeDimLayer() {
         return mHost.makeChildSurface(null)
                 .setParent(mHost.getSurfaceControl())
diff --git a/services/core/java/com/android/server/wm/DisplayArea.java b/services/core/java/com/android/server/wm/DisplayArea.java
index 9f59f5a..f81e5d4 100644
--- a/services/core/java/com/android/server/wm/DisplayArea.java
+++ b/services/core/java/com/android/server/wm/DisplayArea.java
@@ -790,7 +790,8 @@
 
             // If SystemUI is dragging for recents, we want to reset the dim state so any dim layer
             // on the display level fades out.
-            if (forAllTasks(task -> !task.canAffectSystemUiFlags())) {
+            if (!mTransitionController.isShellTransitionsEnabled()
+                    && forAllTasks(task -> !task.canAffectSystemUiFlags())) {
                 mDimmer.resetDimStates();
             }
 
diff --git a/services/core/java/com/android/server/wm/DisplayPolicy.java b/services/core/java/com/android/server/wm/DisplayPolicy.java
index 65771d1..95c953a 100644
--- a/services/core/java/com/android/server/wm/DisplayPolicy.java
+++ b/services/core/java/com/android/server/wm/DisplayPolicy.java
@@ -2368,7 +2368,8 @@
         // We need to force the consumption of the system bars if they are force shown or if they
         // are controlled by a remote insets controller.
         mForceConsumeSystemBars = mForceShowSystemBars
-                || mDisplayContent.getInsetsPolicy().remoteInsetsControllerControlsSystemBars(win);
+                || getInsetsPolicy().remoteInsetsControllerControlsSystemBars(win)
+                || getInsetsPolicy().forcesShowingNavigationBars(win);
         mDisplayContent.getInsetsPolicy().updateBarControlTarget(win);
 
         final boolean topAppHidesStatusBar = topAppHidesSystemBar(Type.statusBars());
diff --git a/services/core/java/com/android/server/wm/InsetsPolicy.java b/services/core/java/com/android/server/wm/InsetsPolicy.java
index ddf96c5..daa823c 100644
--- a/services/core/java/com/android/server/wm/InsetsPolicy.java
+++ b/services/core/java/com/android/server/wm/InsetsPolicy.java
@@ -567,8 +567,7 @@
                 return focusedWin;
             }
         }
-        if (mPolicy.isForceShowNavigationBarEnabled() && focusedWin != null
-                && focusedWin.getActivityType() == ACTIVITY_TYPE_STANDARD) {
+        if (forcesShowingNavigationBars(focusedWin)) {
             // When "force show navigation bar" is enabled, it means both force visible is true, and
             // we are in 3-button navigation. In this mode, the navigation bar is forcibly shown
             // when activity type is ACTIVITY_TYPE_STANDARD which means Launcher or Recent could
@@ -604,6 +603,11 @@
         return focusedWin;
     }
 
+    boolean forcesShowingNavigationBars(WindowState win) {
+        return mPolicy.isForceShowNavigationBarEnabled() && win != null
+                && win.getActivityType() == ACTIVITY_TYPE_STANDARD;
+    }
+
     /**
      * Determines whether the remote insets controller should take control of system bars for all
      * windows.
diff --git a/services/core/java/com/android/server/wm/Transition.java b/services/core/java/com/android/server/wm/Transition.java
index aad1225..3d9edca 100644
--- a/services/core/java/com/android/server/wm/Transition.java
+++ b/services/core/java/com/android/server/wm/Transition.java
@@ -397,6 +397,28 @@
         return false;
     }
 
+    boolean canApplyDim(@NonNull Task task) {
+        if (mTransientLaunches == null) return true;
+        final Dimmer dimmer = task.getDimmer();
+        final WindowContainer<?> dimmerHost = dimmer != null ? dimmer.getHost() : null;
+        if (dimmerHost == null) return false;
+        if (isInTransientHide(dimmerHost)) {
+            // The layer of dimmer is inside transient-hide task, then allow to dim.
+            return true;
+        }
+        // The dimmer host of a translucent task can be a display, then it is not in transient-hide.
+        for (int i = mTransientLaunches.size() - 1; i >= 0; --i) {
+            // The transient task is usually the task of recents/home activity.
+            final Task transientTask = mTransientLaunches.keyAt(i).getTask();
+            if (transientTask != null && transientTask.canAffectSystemUiFlags()) {
+                // It usually means that the recents animation has moved the transient-hide task
+                // an noticeable distance, then the display level dimmer should not show.
+                return false;
+            }
+        }
+        return true;
+    }
+
     boolean hasTransientLaunch() {
         return mTransientLaunches != null && !mTransientLaunches.isEmpty();
     }
@@ -1224,6 +1246,16 @@
                     mController.mAtm.mRootWindowContainer.getDisplayContent(mRecentsDisplayId);
             dc.getInputMonitor().setActiveRecents(null /* activity */, null /* layer */);
         }
+        if (mTransientLaunches != null) {
+            for (int i = mTransientLaunches.size() - 1; i >= 0; --i) {
+                // Reset the ability of controlling SystemUi which might be changed by
+                // setTransientLaunch or setRecentsAppBehindSystemBars.
+                final Task task = mTransientLaunches.keyAt(i).getTask();
+                if (task != null) {
+                    task.setCanAffectSystemUiFlags(true);
+                }
+            }
+        }
 
         for (int i = 0; i < mTargetDisplays.size(); ++i) {
             final DisplayContent dc = mTargetDisplays.get(i);
diff --git a/services/core/java/com/android/server/wm/TransitionController.java b/services/core/java/com/android/server/wm/TransitionController.java
index 359b353..a539a48 100644
--- a/services/core/java/com/android/server/wm/TransitionController.java
+++ b/services/core/java/com/android/server/wm/TransitionController.java
@@ -58,6 +58,7 @@
 import com.android.server.FgThread;
 
 import java.util.ArrayList;
+import java.util.function.Consumer;
 import java.util.function.LongConsumer;
 
 /**
@@ -476,6 +477,19 @@
         return false;
     }
 
+    boolean canApplyDim(@Nullable Task task) {
+        if (task == null) {
+            // Always allow non-activity window.
+            return true;
+        }
+        for (int i = mPlayingTransitions.size() - 1; i >= 0; --i) {
+            if (!mPlayingTransitions.get(i).canApplyDim(task)) {
+                return false;
+            }
+        }
+        return true;
+    }
+
     /**
      * During transient-launch, the "behind" app should retain focus during the transition unless
      * something takes focus from it explicitly (eg. by calling ATMS.setFocusedTask or by another
@@ -1314,18 +1328,18 @@
         return transit;
     }
 
-    /** Returns {@code true} if it started collecting, {@code false} if it was queued. */
-    boolean startLegacySyncOrQueue(BLASTSyncEngine.SyncGroup syncGroup, Runnable applySync) {
+    /** Starts the sync set if there is no pending or active syncs, otherwise enqueue the sync. */
+    void startLegacySyncOrQueue(BLASTSyncEngine.SyncGroup syncGroup, Consumer<Boolean> applySync) {
         if (!mQueuedTransitions.isEmpty() || mSyncEngine.hasActiveSync()) {
             // Just add to queue since we already have a queue.
-            mQueuedTransitions.add(new QueuedTransition(syncGroup, (d) -> applySync.run()));
+            mQueuedTransitions.add(new QueuedTransition(syncGroup,
+                    (deferred) -> applySync.accept(true /* deferred */)));
             ProtoLog.v(ProtoLogGroup.WM_DEBUG_WINDOW_TRANSITIONS_MIN,
                     "Queueing legacy sync-set: %s", syncGroup.mSyncId);
-            return false;
+            return;
         }
         mSyncEngine.startSyncSet(syncGroup);
-        applySync.run();
-        return true;
+        applySync.accept(false /* deferred */);
     }
 
     interface OnStartCollect {
diff --git a/services/core/java/com/android/server/wm/WallpaperController.java b/services/core/java/com/android/server/wm/WallpaperController.java
index 7f41ff1..eb7b8c2 100644
--- a/services/core/java/com/android/server/wm/WallpaperController.java
+++ b/services/core/java/com/android/server/wm/WallpaperController.java
@@ -21,7 +21,6 @@
 import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM;
 import static android.view.Display.DEFAULT_DISPLAY;
 import static android.view.ViewGroup.LayoutParams.MATCH_PARENT;
-import static android.view.WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED;
 import static android.view.WindowManager.LayoutParams.TYPE_BASE_APPLICATION;
 import static android.view.WindowManager.LayoutParams.TYPE_WALLPAPER;
 import static android.view.WindowManager.TRANSIT_FLAG_KEYGUARD_GOING_AWAY_WITH_WALLPAPER;
@@ -137,7 +136,8 @@
     };
 
     private final ToBooleanFunction<WindowState> mFindWallpaperTargetFunction = w -> {
-        if (!w.mTransitionController.isShellTransitionsEnabled()) {
+        final boolean useShellTransition = w.mTransitionController.isShellTransitionsEnabled();
+        if (!useShellTransition) {
             if (w.mActivityRecord != null && !w.mActivityRecord.isVisible()
                     && !w.mActivityRecord.isAnimating(TRANSITION | PARENTS)) {
                 // If this window's app token is hidden and not animating, it is of no interest.
@@ -159,30 +159,23 @@
 
         final WindowContainer animatingContainer = w.mActivityRecord != null
                 ? w.mActivityRecord.getAnimatingContainer() : null;
-        final boolean keyguardGoingAwayWithWallpaper = (animatingContainer != null
+        if (!useShellTransition && animatingContainer != null
                 && animatingContainer.isAnimating(TRANSITION | PARENTS)
                 && AppTransition.isKeyguardGoingAwayTransitOld(animatingContainer.mTransit)
                 && (animatingContainer.mTransitFlags
-                & TRANSIT_FLAG_KEYGUARD_GOING_AWAY_WITH_WALLPAPER) != 0);
-
-        boolean needsShowWhenLockedWallpaper = false;
-        if ((w.mAttrs.flags & FLAG_SHOW_WHEN_LOCKED) != 0 && mService.mPolicy.isKeyguardLocked()) {
-            final TransitionController tc = w.mTransitionController;
-            final boolean isInTransition = tc.isShellTransitionsEnabled()
-                    && tc.inTransition(w);
-            if (mService.mPolicy.isKeyguardOccluded() || mService.mPolicy.isKeyguardUnoccluding()
-                    || isInTransition) {
-                // The lowest show when locked window decides whether we need to put the wallpaper
-                // behind.
-                needsShowWhenLockedWallpaper = !isFullscreen(w.mAttrs)
-                        || (w.mActivityRecord != null && !w.mActivityRecord.fillsParent());
-            }
+                & TRANSIT_FLAG_KEYGUARD_GOING_AWAY_WITH_WALLPAPER) != 0) {
+            // Keep the wallpaper visible when Keyguard is going away.
+            mFindResults.setUseTopWallpaperAsTarget(true);
         }
 
-        if (keyguardGoingAwayWithWallpaper || needsShowWhenLockedWallpaper) {
-            // Keep the wallpaper during Keyguard exit but also when it's needed for a
-            // non-fullscreen show when locked activity.
-            mFindResults.setUseTopWallpaperAsTarget(true);
+        if (mService.mPolicy.isKeyguardLocked() && w.canShowWhenLocked()) {
+            if (mService.mPolicy.isKeyguardOccluded() || (useShellTransition
+                    ? w.inTransition() : mService.mPolicy.isKeyguardUnoccluding())) {
+                // The lowest show when locked window decides whether we need to put the wallpaper
+                // behind.
+                mFindResults.mNeedsShowWhenLockedWallpaper = !isFullscreen(w.mAttrs)
+                        || (w.mActivityRecord != null && !w.mActivityRecord.fillsParent());
+            }
         }
 
         final boolean animationWallpaper = animatingContainer != null
@@ -691,7 +684,8 @@
 
     private void findWallpaperTarget() {
         mFindResults.reset();
-        if (mDisplayContent.getDefaultTaskDisplayArea()
+        if (mService.mAtmService.mSupportsFreeformWindowManagement
+                && mDisplayContent.getDefaultTaskDisplayArea()
                 .isRootTaskVisible(WINDOWING_MODE_FREEFORM)) {
             // In freeform mode we set the wallpaper as its own target, so we don't need an
             // additional window to make it visible.
@@ -700,6 +694,10 @@
 
         mDisplayContent.forAllWindows(mFindWallpapers, true /* traverseTopToBottom */);
         mDisplayContent.forAllWindows(mFindWallpaperTargetFunction, true /* traverseTopToBottom */);
+        if (mFindResults.mNeedsShowWhenLockedWallpaper) {
+            // Keep wallpaper visible if the show-when-locked activities doesn't fill screen.
+            mFindResults.setUseTopWallpaperAsTarget(true);
+        }
 
         if (mFindResults.wallpaperTarget == null && mFindResults.useTopWallpaperAsTarget) {
             mFindResults.setWallpaperTarget(
@@ -1084,6 +1082,7 @@
         }
 
         TopWallpaper mTopWallpaper = new TopWallpaper();
+        boolean mNeedsShowWhenLockedWallpaper;
         boolean useTopWallpaperAsTarget = false;
         WindowState wallpaperTarget = null;
         boolean isWallpaperTargetForLetterbox = false;
@@ -1132,6 +1131,7 @@
 
         void reset() {
             mTopWallpaper.reset();
+            mNeedsShowWhenLockedWallpaper = false;
             wallpaperTarget = null;
             useTopWallpaperAsTarget = false;
             isWallpaperTargetForLetterbox = false;
diff --git a/services/core/java/com/android/server/wm/WindowOrganizerController.java b/services/core/java/com/android/server/wm/WindowOrganizerController.java
index 8e85e5b..a2f7ba4 100644
--- a/services/core/java/com/android/server/wm/WindowOrganizerController.java
+++ b/services/core/java/com/android/server/wm/WindowOrganizerController.java
@@ -232,8 +232,8 @@
                 final BLASTSyncEngine.SyncGroup syncGroup = prepareSyncWithOrganizer(callback);
                 final int syncId = syncGroup.mSyncId;
                 if (mTransitionController.isShellTransitionsEnabled()) {
-                    mTransitionController.startLegacySyncOrQueue(syncGroup, () -> {
-                        applyTransaction(t, syncId, null /*transition*/, caller);
+                    mTransitionController.startLegacySyncOrQueue(syncGroup, (deferred) -> {
+                        applyTransaction(t, syncId, null /* transition */, caller, deferred);
                         setSyncReady(syncId);
                     });
                 } else {
@@ -304,7 +304,8 @@
                             (deferred) -> {
                                 nextTransition.start();
                                 nextTransition.mLogger.mStartWCT = wct;
-                                applyTransaction(wct, -1 /*syncId*/, nextTransition, caller);
+                                applyTransaction(wct, -1 /* syncId */, nextTransition, caller,
+                                        deferred);
                                 if (needsSetReady) {
                                     nextTransition.setAllReady();
                                 }
@@ -456,7 +457,7 @@
                     transition.abort();
                     return;
                 }
-                if (applyTransaction(wct, -1 /* syncId */, transition, caller)
+                if (applyTransaction(wct, -1 /* syncId */, transition, caller, deferred)
                         == TRANSACT_EFFECTS_NONE && transition.mParticipants.isEmpty()) {
                     transition.abort();
                     return;
@@ -476,6 +477,23 @@
         return applyTransaction(t, syncId, transition, caller, null /* finishTransition */);
     }
 
+    private int applyTransaction(@NonNull WindowContainerTransaction t, int syncId,
+            @Nullable Transition transition, @NonNull CallerInfo caller, boolean deferred) {
+        if (deferred) {
+            try {
+                return applyTransaction(t, syncId, transition, caller);
+            } catch (RuntimeException e) {
+                // If the transaction is deferred, the caller could be from TransitionController
+                // #tryStartCollectFromQueue that executes on system's worker thread rather than
+                // binder thread. And the operation in the WCT may be outdated that violates the
+                // current state. So catch the exception to avoid crashing the system.
+                Slog.e(TAG, "Failed to execute deferred applyTransaction", e);
+            }
+            return TRANSACT_EFFECTS_NONE;
+        }
+        return applyTransaction(t, syncId, transition, caller);
+    }
+
     /**
      * @param syncId If non-null, this will be a sync-transaction.
      * @param transition A transition to collect changes into.
@@ -838,13 +856,21 @@
         switch (type) {
             case HIERARCHY_OP_TYPE_REMOVE_TASK: {
                 final WindowContainer wc = WindowContainer.fromBinder(hop.getContainer());
-                final Task task = wc != null ? wc.asTask() : null;
+                if (wc == null || wc.asTask() == null || !wc.isAttached()) {
+                    Slog.e(TAG, "Attempt to remove invalid task: " + wc);
+                    break;
+                }
+                final Task task = wc.asTask();
                 task.remove(true, "Applying remove task Hierarchy Op");
                 break;
             }
             case HIERARCHY_OP_TYPE_SET_LAUNCH_ROOT: {
                 final WindowContainer wc = WindowContainer.fromBinder(hop.getContainer());
-                final Task task = wc != null ? wc.asTask() : null;
+                if (wc == null || !wc.isAttached()) {
+                    Slog.e(TAG, "Attempt to set launch root to a detached container: " + wc);
+                    break;
+                }
+                final Task task = wc.asTask();
                 if (task == null) {
                     throw new IllegalArgumentException("Cannot set non-task as launch root: " + wc);
                 } else if (task.getTaskDisplayArea() == null) {
@@ -858,7 +884,11 @@
             }
             case HIERARCHY_OP_TYPE_SET_LAUNCH_ADJACENT_FLAG_ROOT: {
                 final WindowContainer wc = WindowContainer.fromBinder(hop.getContainer());
-                final Task task = wc != null ? wc.asTask() : null;
+                if (wc == null || !wc.isAttached()) {
+                    Slog.e(TAG, "Attempt to set launch adjacent to a detached container: " + wc);
+                    break;
+                }
+                final Task task = wc.asTask();
                 final boolean clearRoot = hop.getToTop();
                 if (task == null) {
                     throw new IllegalArgumentException("Cannot set non-task as launch root: " + wc);
diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java
index b899b4f..cc9ac76 100644
--- a/services/core/java/com/android/server/wm/WindowState.java
+++ b/services/core/java/com/android/server/wm/WindowState.java
@@ -2983,10 +2983,11 @@
 
     @Override
     public boolean canShowWhenLocked() {
-        final boolean showBecauseOfActivity =
-                mActivityRecord != null && mActivityRecord.canShowWhenLocked();
-        final boolean showBecauseOfWindow = (getAttrs().flags & FLAG_SHOW_WHEN_LOCKED) != 0;
-        return showBecauseOfActivity || showBecauseOfWindow;
+        if (mActivityRecord != null) {
+            // It will also check if its windows contain FLAG_SHOW_WHEN_LOCKED.
+            return mActivityRecord.canShowWhenLocked();
+        }
+        return (mAttrs.flags & FLAG_SHOW_WHEN_LOCKED) != 0;
     }
 
     /**
@@ -5119,12 +5120,13 @@
 
     private void applyDims() {
         if (((mAttrs.flags & FLAG_DIM_BEHIND) != 0 || shouldDrawBlurBehind())
-                   && isVisibleNow() && !mHidden) {
+                   && isVisibleNow() && !mHidden && mTransitionController.canApplyDim(getTask())) {
             // Only show the Dimmer when the following is satisfied:
             // 1. The window has the flag FLAG_DIM_BEHIND or blur behind is requested
             // 2. The WindowToken is not hidden so dims aren't shown when the window is exiting.
             // 3. The WS is considered visible according to the isVisible() method
             // 4. The WS is not hidden.
+            // 5. The window is not in a transition or is in a transition that allows to dim.
             mIsDimming = true;
             final float dimAmount = (mAttrs.flags & FLAG_DIM_BEHIND) != 0 ? mAttrs.dimAmount : 0;
             final int blurRadius = shouldDrawBlurBehind() ? mAttrs.getBlurBehindRadius() : 0;
diff --git a/services/credentials/java/com/android/server/credentials/CredentialManagerService.java b/services/credentials/java/com/android/server/credentials/CredentialManagerService.java
index cadee6f..a1199d9 100644
--- a/services/credentials/java/com/android/server/credentials/CredentialManagerService.java
+++ b/services/credentials/java/com/android/server/credentials/CredentialManagerService.java
@@ -21,6 +21,7 @@
 import static android.content.Context.CREDENTIAL_SERVICE;
 import static android.content.pm.PackageManager.PERMISSION_GRANTED;
 
+import android.Manifest;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.annotation.UserIdInt;
@@ -55,6 +56,7 @@
 import android.provider.Settings;
 import android.service.credentials.CallingAppInfo;
 import android.service.credentials.CredentialProviderInfoFactory;
+import android.service.credentials.PermissionUtils;
 import android.text.TextUtils;
 import android.util.Pair;
 import android.util.Slog;
@@ -546,11 +548,16 @@
 
             if (providerSessions.isEmpty()) {
                 try {
-                    // TODO: fix
                     prepareGetCredentialCallback.onResponse(
-                            new PrepareGetCredentialResponseInternal(
-                                    false, null,
-                                    false, false, null));
+                            new PrepareGetCredentialResponseInternal(PermissionUtils.hasPermission(
+                                    mContext,
+                                    callingPackage,
+                                    Manifest.permission
+                                            .CREDENTIAL_MANAGER_QUERY_CANDIDATE_CREDENTIALS),
+                                    /*credentialResultTypes=*/null,
+                                    /*hasAuthenticationResults=*/false,
+                                    /*hasRemoteResults=*/false,
+                                    /*pendingIntent=*/null));
                 } catch (RemoteException e) {
                     Slog.e(
                             TAG,
diff --git a/services/tests/mockingservicestests/src/com/android/server/am/BroadcastQueueTest.java b/services/tests/mockingservicestests/src/com/android/server/am/BroadcastQueueTest.java
index e7a94c0..7a88069 100644
--- a/services/tests/mockingservicestests/src/com/android/server/am/BroadcastQueueTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/am/BroadcastQueueTest.java
@@ -172,6 +172,7 @@
     BroadcastConstants mConstants;
     private BroadcastSkipPolicy mSkipPolicy;
     private UidObserver mUidObserver;
+    private UidObserver mUidCachedStateObserver;
 
     /**
      * Desired behavior of the next
@@ -317,7 +318,13 @@
         doAnswer((invocation) -> {
             mUidObserver = invocation.getArgument(0);
             return null;
-        }).when(mAms).registerUidObserver(any(), anyInt(), anyInt(), any());
+        }).when(mAms).registerUidObserver(any(), anyInt(),
+                eq(ActivityManager.PROCESS_STATE_TOP), any());
+        doAnswer((invocation) -> {
+            mUidCachedStateObserver = invocation.getArgument(0);
+            return null;
+        }).when(mAms).registerUidObserver(any(), anyInt(),
+                eq(ActivityManager.PROCESS_STATE_LAST_ACTIVITY), any());
 
         mConstants = new BroadcastConstants(Settings.Global.BROADCAST_FG_CONSTANTS);
         mConstants.TIMEOUT = 100;
@@ -1762,8 +1769,12 @@
         final ProcessRecord receiverYellowApp = makeActiveProcessRecord(PACKAGE_YELLOW);
         final ProcessRecord receiverOrangeApp = makeActiveProcessRecord(PACKAGE_ORANGE);
 
-        mUidObserver.onUidCachedChanged(getUidForPackage(PACKAGE_GREEN), true);
-        mUidObserver.onUidCachedChanged(getUidForPackage(PACKAGE_BLUE), true);
+        mUidCachedStateObserver.onUidStateChanged(getUidForPackage(PACKAGE_GREEN),
+                ActivityManager.PROCESS_STATE_CACHED_ACTIVITY, 0,
+                ActivityManager.PROCESS_CAPABILITY_NONE);
+        mUidCachedStateObserver.onUidStateChanged(getUidForPackage(PACKAGE_BLUE),
+                ActivityManager.PROCESS_STATE_CACHED_EMPTY, 0,
+                ActivityManager.PROCESS_CAPABILITY_NONE);
 
         final Intent timeTick = new Intent(Intent.ACTION_TIME_TICK);
         final BroadcastOptions opts = BroadcastOptions.makeBasic()
@@ -1807,12 +1818,16 @@
                 eq(UserHandle.USER_SYSTEM), anyInt(), anyInt(), any());
 
         // Shift blue to be active and confirm that deferred broadcast is delivered
-        mUidObserver.onUidCachedChanged(getUidForPackage(PACKAGE_BLUE), false);
+        mUidCachedStateObserver.onUidStateChanged(getUidForPackage(PACKAGE_BLUE),
+                ActivityManager.PROCESS_STATE_TOP, 0,
+                ActivityManager.PROCESS_CAPABILITY_NONE);
         waitForIdle();
         verifyScheduleRegisteredReceiver(times(1), receiverBlueApp, timeTick);
 
         // Shift green to be active and confirm that deferred broadcast is delivered
-        mUidObserver.onUidCachedChanged(getUidForPackage(PACKAGE_GREEN), false);
+        mUidCachedStateObserver.onUidStateChanged(getUidForPackage(PACKAGE_GREEN),
+                ActivityManager.PROCESS_STATE_SERVICE, 0,
+                ActivityManager.PROCESS_CAPABILITY_NONE);
         waitForIdle();
         verifyScheduleRegisteredReceiver(times(1), receiverGreenApp, timeTick);
     }
@@ -2237,9 +2252,15 @@
         final ProcessRecord receiverBlueApp = makeActiveProcessRecord(PACKAGE_BLUE);
         final ProcessRecord receiverYellowApp = makeActiveProcessRecord(PACKAGE_YELLOW);
 
-        mUidObserver.onUidCachedChanged(getUidForPackage(PACKAGE_GREEN), true);
-        mUidObserver.onUidCachedChanged(getUidForPackage(PACKAGE_BLUE), true);
-        mUidObserver.onUidCachedChanged(getUidForPackage(PACKAGE_YELLOW), false);
+        mUidCachedStateObserver.onUidStateChanged(getUidForPackage(PACKAGE_GREEN),
+                ActivityManager.PROCESS_STATE_CACHED_ACTIVITY, 0,
+                ActivityManager.PROCESS_CAPABILITY_NONE);
+        mUidCachedStateObserver.onUidStateChanged(getUidForPackage(PACKAGE_BLUE),
+                ActivityManager.PROCESS_STATE_CACHED_EMPTY, 0,
+                ActivityManager.PROCESS_CAPABILITY_NONE);
+        mUidCachedStateObserver.onUidStateChanged(getUidForPackage(PACKAGE_YELLOW),
+                ActivityManager.PROCESS_STATE_SERVICE, 0,
+                ActivityManager.PROCESS_CAPABILITY_NONE);
 
         final Intent airplane = new Intent(Intent.ACTION_AIRPLANE_MODE_CHANGED);
         final BroadcastOptions opts = BroadcastOptions.makeBasic()
@@ -2262,7 +2283,9 @@
         verifyScheduleRegisteredReceiver(times(1), receiverYellowApp, airplane);
 
         // Shift green to be active and confirm that deferred broadcast is delivered
-        mUidObserver.onUidCachedChanged(getUidForPackage(PACKAGE_GREEN), false);
+        mUidCachedStateObserver.onUidStateChanged(getUidForPackage(PACKAGE_GREEN),
+                ActivityManager.PROCESS_STATE_TOP_SLEEPING, 0,
+                ActivityManager.PROCESS_CAPABILITY_NONE);
         waitForIdle();
         verifyScheduleRegisteredReceiver(times(1), receiverGreenApp, airplane);
     }
diff --git a/services/tests/servicestests/src/com/android/server/dreams/DreamOverlayServiceTest.java b/services/tests/servicestests/src/com/android/server/dreams/DreamOverlayServiceTest.java
index 851d8f9..f05fa65 100644
--- a/services/tests/servicestests/src/com/android/server/dreams/DreamOverlayServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/dreams/DreamOverlayServiceTest.java
@@ -101,12 +101,6 @@
             mMonitor.onEndDream();
             super.onEndDream();
         }
-
-        @Override
-        public void onWakeUp(@NonNull Runnable onCompleteCallback) {
-            mMonitor.onWakeUp();
-            super.onWakeUp(onCompleteCallback);
-        }
     }
 
     /**
diff --git a/services/tests/servicestests/src/com/android/server/systemconfig/SystemConfigTest.java b/services/tests/servicestests/src/com/android/server/systemconfig/SystemConfigTest.java
index aad373f..aca96ad 100644
--- a/services/tests/servicestests/src/com/android/server/systemconfig/SystemConfigTest.java
+++ b/services/tests/servicestests/src/com/android/server/systemconfig/SystemConfigTest.java
@@ -445,14 +445,14 @@
                         + "    <library \n"
                         + "        name=\"foo\"\n"
                         + "        file=\"" + mFooJar + "\"\n"
-                        + "        on-bootclasspath-before=\"A\"\n"
+                        + "        on-bootclasspath-before=\"Q\"\n"
                         + "        on-bootclasspath-since=\"W\"\n"
                         + "     />\n\n"
                         + " </permissions>";
         parseSharedLibraries(contents);
         assertFooIsOnlySharedLibrary();
         SystemConfig.SharedLibraryEntry entry = mSysConfig.getSharedLibraries().get("foo");
-        assertThat(entry.onBootclasspathBefore).isEqualTo("A");
+        assertThat(entry.onBootclasspathBefore).isEqualTo("Q");
         assertThat(entry.onBootclasspathSince).isEqualTo("W");
     }
 
diff --git a/services/tests/wmtests/src/com/android/server/wm/TransitionTests.java b/services/tests/wmtests/src/com/android/server/wm/TransitionTests.java
index 1126726..ed0c8ef 100644
--- a/services/tests/wmtests/src/com/android/server/wm/TransitionTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/TransitionTests.java
@@ -1452,6 +1452,11 @@
             }
         });
         assertTrue(activity1.isVisible());
+        doReturn(false).when(task1).isTranslucent(null);
+        assertTrue(controller.canApplyDim(task1));
+        doReturn(true).when(task1).isTranslucent(null);
+        assertFalse(controller.canApplyDim(task1));
+
         controller.finishTransition(closeTransition);
         assertTrue(wasInFinishingTransition[0]);
         assertNull(controller.mFinishingTransition);
@@ -2191,8 +2196,11 @@
 
         BLASTSyncEngine.SyncGroup legacySync = mSyncEngine.prepareSyncSet(
                 mock(BLASTSyncEngine.TransactionReadyListener.class), "test");
-        final boolean[] applyLegacy = new boolean[]{false};
-        controller.startLegacySyncOrQueue(legacySync, () -> applyLegacy[0] = true);
+        final boolean[] applyLegacy = new boolean[2];
+        controller.startLegacySyncOrQueue(legacySync, (deferred) -> {
+            applyLegacy[0] = true;
+            applyLegacy[1] = deferred;
+        });
         assertFalse(applyLegacy[0]);
         waitUntilHandlersIdle();
 
@@ -2208,6 +2216,7 @@
         assertTrue(transitA.isPlaying());
         // legacy sync should start now
         assertTrue(applyLegacy[0]);
+        assertTrue(applyLegacy[1]);
         // transitB must wait
         assertTrue(transitB.isPending());
 
diff --git a/services/tests/wmtests/src/com/android/server/wm/WallpaperControllerTests.java b/services/tests/wmtests/src/com/android/server/wm/WallpaperControllerTests.java
index f3d8114..4afcd05 100644
--- a/services/tests/wmtests/src/com/android/server/wm/WallpaperControllerTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/WallpaperControllerTests.java
@@ -288,6 +288,32 @@
         assertEquals(homeWin, dc.mWallpaperController.getWallpaperTarget());
     }
 
+    @Test
+    public void testShowWhenLockedWallpaperTarget() {
+        final WindowState wallpaperWindow = createWallpaperWindow(mDisplayContent);
+        wallpaperWindow.mToken.asWallpaperToken().setShowWhenLocked(true);
+        final WindowState behind = createWindow(null, TYPE_BASE_APPLICATION, "behind");
+        final WindowState topTranslucent = createWindow(null, TYPE_BASE_APPLICATION,
+                "topTranslucent");
+        behind.mAttrs.width = behind.mAttrs.height = topTranslucent.mAttrs.width =
+                topTranslucent.mAttrs.height = WindowManager.LayoutParams.MATCH_PARENT;
+        topTranslucent.mAttrs.flags |= WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED;
+        doReturn(true).when(behind.mActivityRecord).fillsParent();
+        doReturn(false).when(topTranslucent.mActivityRecord).fillsParent();
+
+        spyOn(mWm.mPolicy);
+        doReturn(true).when(mWm.mPolicy).isKeyguardLocked();
+        doReturn(true).when(mWm.mPolicy).isKeyguardOccluded();
+        mDisplayContent.mWallpaperController.adjustWallpaperWindows();
+        // Wallpaper is visible because the show-when-locked activity is translucent.
+        assertTrue(mDisplayContent.mWallpaperController.isWallpaperTarget(wallpaperWindow));
+
+        behind.mActivityRecord.setShowWhenLocked(true);
+        mDisplayContent.mWallpaperController.adjustWallpaperWindows();
+        // Wallpaper is invisible because the lowest show-when-locked activity is opaque.
+        assertTrue(mDisplayContent.mWallpaperController.isWallpaperTarget(null));
+    }
+
     /**
      * Tests that the windowing mode of the wallpaper window must always be fullscreen.
      */