Merge "bootanimation: correct logo position and size after resolution changed" into tm-dev
diff --git a/core/api/current.txt b/core/api/current.txt
index e260ad0..c8a43db 100644
--- a/core/api/current.txt
+++ b/core/api/current.txt
@@ -44254,6 +44254,9 @@
     method @RequiresPermission(android.Manifest.permission.READ_PRECISE_PHONE_STATE) public void unregisterImsRegistrationCallback(@NonNull android.telephony.ims.RegistrationManager.RegistrationCallback);
     method public void unregisterImsStateCallback(@NonNull android.telephony.ims.ImsStateCallback);
     field public static final String ACTION_SHOW_CAPABILITY_DISCOVERY_OPT_IN = "android.telephony.ims.action.SHOW_CAPABILITY_DISCOVERY_OPT_IN";
+    field public static final int CAPABILITY_TYPE_NONE = 0; // 0x0
+    field public static final int CAPABILITY_TYPE_OPTIONS_UCE = 1; // 0x1
+    field public static final int CAPABILITY_TYPE_PRESENCE_UCE = 2; // 0x2
   }
 
   public final class ImsReasonInfo implements android.os.Parcelable {
@@ -44475,10 +44478,10 @@
     method public void unregisterFeatureProvisioningChangedCallback(@NonNull android.telephony.ims.ProvisioningManager.FeatureProvisioningCallback);
   }
 
-  public static class ProvisioningManager.FeatureProvisioningCallback {
+  public abstract static class ProvisioningManager.FeatureProvisioningCallback {
     ctor public ProvisioningManager.FeatureProvisioningCallback();
-    method public void onFeatureProvisioningChanged(int, int, boolean);
-    method public void onRcsFeatureProvisioningChanged(int, int, boolean);
+    method public abstract void onFeatureProvisioningChanged(int, int, boolean);
+    method public abstract void onRcsFeatureProvisioningChanged(int, int, boolean);
   }
 
   public class RcsUceAdapter {
@@ -44521,15 +44524,6 @@
     field public static final int CAPABILITY_TYPE_VOICE = 1; // 0x1
   }
 
-  public class RcsFeature {
-  }
-
-  public static class RcsFeature.RcsImsCapabilities {
-    field public static final int CAPABILITY_TYPE_NONE = 0; // 0x0
-    field public static final int CAPABILITY_TYPE_OPTIONS_UCE = 1; // 0x1
-    field public static final int CAPABILITY_TYPE_PRESENCE_UCE = 2; // 0x2
-  }
-
 }
 
 package android.telephony.ims.stub {
diff --git a/core/api/system-current.txt b/core/api/system-current.txt
index b25d1e3..ec4ad8b 100644
--- a/core/api/system-current.txt
+++ b/core/api/system-current.txt
@@ -15024,7 +15024,7 @@
     method @RequiresPermission(allOf={android.Manifest.permission.ACCESS_RCS_USER_CAPABILITY_EXCHANGE, android.Manifest.permission.READ_CONTACTS}) public void requestAvailability(@NonNull android.net.Uri, @NonNull java.util.concurrent.Executor, @NonNull android.telephony.ims.RcsUceAdapter.CapabilitiesCallback) throws android.telephony.ims.ImsException;
     method @RequiresPermission(allOf={android.Manifest.permission.ACCESS_RCS_USER_CAPABILITY_EXCHANGE, android.Manifest.permission.READ_CONTACTS}) public void requestCapabilities(@NonNull java.util.Collection<android.net.Uri>, @NonNull java.util.concurrent.Executor, @NonNull android.telephony.ims.RcsUceAdapter.CapabilitiesCallback) throws android.telephony.ims.ImsException;
     method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void setUceSettingEnabled(boolean) throws android.telephony.ims.ImsException;
-    field public static final int CAPABILITY_TYPE_PRESENCE_UCE = 2; // 0x2
+    field @Deprecated public static final int CAPABILITY_TYPE_PRESENCE_UCE = 2; // 0x2
     field public static final int CAPABILITY_UPDATE_TRIGGER_ETAG_EXPIRED = 1; // 0x1
     field public static final int CAPABILITY_UPDATE_TRIGGER_MOVE_TO_2G = 7; // 0x7
     field public static final int CAPABILITY_UPDATE_TRIGGER_MOVE_TO_3G = 6; // 0x6
@@ -15307,6 +15307,9 @@
     method public void addCapabilities(int);
     method public boolean isCapable(int);
     method public void removeCapabilities(int);
+    field public static final int CAPABILITY_TYPE_NONE = 0; // 0x0
+    field public static final int CAPABILITY_TYPE_OPTIONS_UCE = 1; // 0x1
+    field public static final int CAPABILITY_TYPE_PRESENCE_UCE = 2; // 0x2
   }
 
 }
diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java
index 7d68eb9..b4cabad 100644
--- a/core/java/android/app/ActivityThread.java
+++ b/core/java/android/app/ActivityThread.java
@@ -7030,7 +7030,13 @@
                 // local, we'll need to wait for the publishing of the provider.
                 if (holder != null && holder.provider == null && !holder.mLocal) {
                     synchronized (key.mLock) {
-                        key.mLock.wait(ContentResolver.CONTENT_PROVIDER_READY_TIMEOUT_MILLIS);
+                        if (key.mHolder != null) {
+                            if (DEBUG_PROVIDER) {
+                                Slog.i(TAG, "already received provider: " + auth);
+                            }
+                        } else {
+                            key.mLock.wait(ContentResolver.CONTENT_PROVIDER_READY_TIMEOUT_MILLIS);
+                        }
                         holder = key.mHolder;
                     }
                     if (holder != null && holder.provider == null) {
diff --git a/core/java/android/net/NetworkPolicy.java b/core/java/android/net/NetworkPolicy.java
index 714227d..570211e 100644
--- a/core/java/android/net/NetworkPolicy.java
+++ b/core/java/android/net/NetworkPolicy.java
@@ -396,7 +396,8 @@
                 return true;
             case MATCH_CARRIER:
             case MATCH_MOBILE:
-                return !template.getSubscriberIds().isEmpty();
+                return !template.getSubscriberIds().isEmpty()
+                        && template.getMeteredness() == METERED_YES;
             case MATCH_WIFI:
                 if (template.getWifiNetworkKeys().isEmpty()
                         && template.getSubscriberIds().isEmpty()) {
diff --git a/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/SplitController.java b/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/SplitController.java
index e20cef2..ca420c6 100644
--- a/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/SplitController.java
+++ b/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/SplitController.java
@@ -40,6 +40,7 @@
 import android.os.IBinder;
 import android.os.Looper;
 import android.util.ArraySet;
+import android.util.Log;
 import android.util.SparseArray;
 import android.window.TaskFragmentInfo;
 import android.window.WindowContainerTransaction;
@@ -59,6 +60,7 @@
  */
 public class SplitController implements JetpackTaskFragmentOrganizer.TaskFragmentCallback,
         ActivityEmbeddingComponent {
+    private static final String TAG = "SplitController";
 
     @VisibleForTesting
     final SplitPresenter mPresenter;
@@ -229,8 +231,8 @@
             }
             if (taskContainer.isEmpty()) {
                 // Cleanup the TaskContainer if it becomes empty.
-                mPresenter.stopOverrideSplitAnimation(taskContainer.mTaskId);
-                mTaskContainers.remove(taskContainer.mTaskId);
+                mPresenter.stopOverrideSplitAnimation(taskContainer.getTaskId());
+                mTaskContainers.remove(taskContainer.getTaskId());
             }
             return;
         }
@@ -241,13 +243,13 @@
         if (taskContainer == null) {
             return;
         }
-        final boolean wasInPip = isInPictureInPicture(taskContainer.mConfiguration);
+        final boolean wasInPip = isInPictureInPicture(taskContainer.getConfiguration());
         final boolean isInPIp = isInPictureInPicture(config);
-        taskContainer.mConfiguration = config;
+        taskContainer.setConfiguration(config);
 
         // We need to check the animation override when enter/exit PIP or has bounds changed.
         boolean shouldUpdateAnimationOverride = wasInPip != isInPIp;
-        if (onTaskBoundsMayChange(taskContainer, config.windowConfiguration.getBounds())
+        if (taskContainer.setTaskBounds(config.windowConfiguration.getBounds())
                 && !isInPIp) {
             // We don't care the bounds change when it has already entered PIP.
             shouldUpdateAnimationOverride = true;
@@ -257,16 +259,6 @@
         }
     }
 
-    /** Returns {@code true} if the bounds is changed. */
-    private boolean onTaskBoundsMayChange(@NonNull TaskContainer taskContainer,
-            @NonNull Rect taskBounds) {
-        if (!taskBounds.isEmpty() && !taskContainer.mTaskBounds.equals(taskBounds)) {
-            taskContainer.mTaskBounds.set(taskBounds);
-            return true;
-        }
-        return false;
-    }
-
     /**
      * Updates if we should override transition animation. We only want to override if the Task
      * bounds is large enough for at least one split rule.
@@ -279,15 +271,15 @@
 
         // We only want to override if it supports split.
         if (supportSplit(taskContainer)) {
-            mPresenter.startOverrideSplitAnimation(taskContainer.mTaskId);
+            mPresenter.startOverrideSplitAnimation(taskContainer.getTaskId());
         } else {
-            mPresenter.stopOverrideSplitAnimation(taskContainer.mTaskId);
+            mPresenter.stopOverrideSplitAnimation(taskContainer.getTaskId());
         }
     }
 
     private boolean supportSplit(@NonNull TaskContainer taskContainer) {
         // No split inside PIP.
-        if (isInPictureInPicture(taskContainer.mConfiguration)) {
+        if (isInPictureInPicture(taskContainer.getConfiguration())) {
             return false;
         }
         // Check if the parent container bounds can support any split rule.
@@ -295,7 +287,7 @@
             if (!(rule instanceof SplitRule)) {
                 continue;
             }
-            if (mPresenter.shouldShowSideBySide(taskContainer.mTaskBounds, (SplitRule) rule)) {
+            if (mPresenter.shouldShowSideBySide(taskContainer.getTaskBounds(), (SplitRule) rule)) {
                 return true;
             }
         }
@@ -425,21 +417,36 @@
         return null;
     }
 
+    TaskFragmentContainer newContainer(@NonNull Activity activity, int taskId) {
+        return newContainer(activity, activity, taskId);
+    }
+
     /**
      * Creates and registers a new organized container with an optional activity that will be
      * re-parented to it in a WCT.
+     *
+     * @param activity          the activity that will be reparented to the TaskFragment.
+     * @param activityInTask    activity in the same Task so that we can get the Task bounds if
+     *                          needed.
+     * @param taskId            parent Task of the new TaskFragment.
      */
-    TaskFragmentContainer newContainer(@Nullable Activity activity, int taskId) {
+    TaskFragmentContainer newContainer(@Nullable Activity activity,
+            @NonNull Activity activityInTask, int taskId) {
+        if (activityInTask == null) {
+            throw new IllegalArgumentException("activityInTask must not be null,");
+        }
         final TaskFragmentContainer container = new TaskFragmentContainer(activity, taskId);
         if (!mTaskContainers.contains(taskId)) {
             mTaskContainers.put(taskId, new TaskContainer(taskId));
         }
         final TaskContainer taskContainer = mTaskContainers.get(taskId);
         taskContainer.mContainers.add(container);
-        if (activity != null && !taskContainer.isTaskBoundsInitialized()
-                && onTaskBoundsMayChange(taskContainer,
-                SplitPresenter.getTaskBoundsFromActivity(activity))) {
-            // Initial check before any TaskFragment has appeared.
+        if (!taskContainer.isTaskBoundsInitialized()) {
+            // Get the initial bounds before the TaskFragment has appeared.
+            final Rect taskBounds = SplitPresenter.getTaskBoundsFromActivity(activityInTask);
+            if (!taskContainer.setTaskBounds(taskBounds)) {
+                Log.w(TAG, "Can't find bounds from activity=" + activityInTask);
+            }
             updateAnimationOverride(taskContainer);
         }
         return container;
@@ -887,6 +894,11 @@
         return null;
     }
 
+    @Nullable
+    TaskContainer getTaskContainer(int taskId) {
+        return mTaskContainers.get(taskId);
+    }
+
     /**
      * Returns {@code true} if an Activity with the provided component name should always be
      * expanded to occupy full task bounds. Such activity must not be put in a split.
@@ -1211,37 +1223,4 @@
         return configuration != null
                 && configuration.windowConfiguration.getWindowingMode() == WINDOWING_MODE_PINNED;
     }
-
-    /** Represents TaskFragments and split pairs below a Task. */
-    @VisibleForTesting
-    static class TaskContainer {
-        /** The unique task id. */
-        final int mTaskId;
-        /** Active TaskFragments in this Task. */
-        final List<TaskFragmentContainer> mContainers = new ArrayList<>();
-        /** Active split pairs in this Task. */
-        final List<SplitContainer> mSplitContainers = new ArrayList<>();
-        /**
-         * TaskFragments that the organizer has requested to be closed. They should be removed when
-         * the organizer receives {@link #onTaskFragmentVanished(TaskFragmentInfo)} event for them.
-         */
-        final Set<IBinder> mFinishedContainer = new ArraySet<>();
-        /** Available window bounds of this Task. */
-        final Rect mTaskBounds = new Rect();
-        /** Configuration of the Task. */
-        @Nullable
-        Configuration mConfiguration;
-
-        TaskContainer(int taskId) {
-            mTaskId = taskId;
-        }
-
-        boolean isEmpty() {
-            return mContainers.isEmpty() && mFinishedContainer.isEmpty();
-        }
-
-        boolean isTaskBoundsInitialized() {
-            return !mTaskBounds.isEmpty();
-        }
-    }
 }
diff --git a/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/SplitPresenter.java b/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/SplitPresenter.java
index 1b49585..716a087 100644
--- a/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/SplitPresenter.java
+++ b/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/SplitPresenter.java
@@ -19,9 +19,9 @@
 import static android.app.WindowConfiguration.WINDOWING_MODE_MULTI_WINDOW;
 
 import android.app.Activity;
+import android.app.WindowConfiguration;
 import android.content.Context;
 import android.content.Intent;
-import android.content.res.Configuration;
 import android.graphics.Rect;
 import android.os.Bundle;
 import android.os.IBinder;
@@ -111,8 +111,8 @@
                 primaryActivity, primaryRectBounds, null);
 
         // Create new empty task fragment
-        final TaskFragmentContainer secondaryContainer = mController.newContainer(null,
-                primaryContainer.getTaskId());
+        final TaskFragmentContainer secondaryContainer = mController.newContainer(
+                null /* activity */, primaryActivity, primaryContainer.getTaskId());
         final Rect secondaryRectBounds = getBoundsForPosition(POSITION_END, parentBounds,
                 rule, isLtr(primaryActivity, rule));
         createTaskFragment(wct, secondaryContainer.getTaskFragmentToken(),
@@ -168,8 +168,8 @@
      * Creates a new expanded container.
      */
     TaskFragmentContainer createNewExpandedContainer(@NonNull Activity launchingActivity) {
-        final TaskFragmentContainer newContainer = mController.newContainer(null,
-                launchingActivity.getTaskId());
+        final TaskFragmentContainer newContainer = mController.newContainer(null /* activity */,
+                launchingActivity, launchingActivity.getTaskId());
 
         final WindowContainerTransaction wct = new WindowContainerTransaction();
         createTaskFragment(wct, newContainer.getTaskFragmentToken(),
@@ -236,8 +236,8 @@
                     launchingActivity.getTaskId());
         }
 
-        TaskFragmentContainer secondaryContainer = mController.newContainer(null,
-                primaryContainer.getTaskId());
+        TaskFragmentContainer secondaryContainer = mController.newContainer(null /* activity */,
+                launchingActivity, primaryContainer.getTaskId());
         final WindowContainerTransaction wct = new WindowContainerTransaction();
         mController.registerSplit(wct, primaryContainer, launchingActivity, secondaryContainer,
                 rule);
@@ -398,20 +398,12 @@
 
     @NonNull
     Rect getParentContainerBounds(@NonNull TaskFragmentContainer container) {
-        final Configuration parentConfig = mFragmentParentConfigs.get(
-                container.getTaskFragmentToken());
-        if (parentConfig != null) {
-            return parentConfig.windowConfiguration.getBounds();
+        final int taskId = container.getTaskId();
+        final TaskContainer taskContainer = mController.getTaskContainer(taskId);
+        if (taskContainer == null) {
+            throw new IllegalStateException("Can't find TaskContainer taskId=" + taskId);
         }
-
-        // If there is no parent yet - then assuming that activities are running in full task bounds
-        final Activity topActivity = container.getTopNonFinishingActivity();
-        final Rect bounds = topActivity != null ? getParentContainerBounds(topActivity) : null;
-
-        if (bounds == null) {
-            throw new IllegalStateException("Unknown parent bounds");
-        }
-        return bounds;
+        return taskContainer.getTaskBounds();
     }
 
     @NonNull
@@ -419,22 +411,19 @@
         final TaskFragmentContainer container = mController.getContainerWithActivity(
                 activity.getActivityToken());
         if (container != null) {
-            final Configuration parentConfig = mFragmentParentConfigs.get(
-                    container.getTaskFragmentToken());
-            if (parentConfig != null) {
-                return parentConfig.windowConfiguration.getBounds();
-            }
+            return getParentContainerBounds(container);
         }
-
         return getTaskBoundsFromActivity(activity);
     }
 
     @NonNull
     static Rect getTaskBoundsFromActivity(@NonNull Activity activity) {
+        final WindowConfiguration windowConfiguration =
+                activity.getResources().getConfiguration().windowConfiguration;
         if (!activity.isInMultiWindowMode()) {
             // In fullscreen mode the max bounds should correspond to the task bounds.
-            return activity.getResources().getConfiguration().windowConfiguration.getMaxBounds();
+            return windowConfiguration.getMaxBounds();
         }
-        return activity.getResources().getConfiguration().windowConfiguration.getBounds();
+        return windowConfiguration.getBounds();
     }
 }
diff --git a/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/TaskContainer.java b/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/TaskContainer.java
new file mode 100644
index 0000000..be79301
--- /dev/null
+++ b/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/TaskContainer.java
@@ -0,0 +1,97 @@
+/*
+ * 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 androidx.window.extensions.embedding;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.content.res.Configuration;
+import android.graphics.Rect;
+import android.os.IBinder;
+import android.util.ArraySet;
+import android.window.TaskFragmentInfo;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Set;
+
+/** Represents TaskFragments and split pairs below a Task. */
+class TaskContainer {
+
+    /** The unique task id. */
+    private final int mTaskId;
+
+    /** Available window bounds of this Task. */
+    private final Rect mTaskBounds = new Rect();
+
+    /** Configuration of the Task. */
+    @Nullable
+    private Configuration mConfiguration;
+
+    /** Active TaskFragments in this Task. */
+    final List<TaskFragmentContainer> mContainers = new ArrayList<>();
+
+    /** Active split pairs in this Task. */
+    final List<SplitContainer> mSplitContainers = new ArrayList<>();
+
+    /**
+     * TaskFragments that the organizer has requested to be closed. They should be removed when
+     * the organizer receives {@link SplitController#onTaskFragmentVanished(TaskFragmentInfo)} event
+     * for them.
+     */
+    final Set<IBinder> mFinishedContainer = new ArraySet<>();
+
+    TaskContainer(int taskId) {
+        mTaskId = taskId;
+    }
+
+    int getTaskId() {
+        return mTaskId;
+    }
+
+    @NonNull
+    Rect getTaskBounds() {
+        return mTaskBounds;
+    }
+
+    /** Returns {@code true} if the bounds is changed. */
+    boolean setTaskBounds(@NonNull Rect taskBounds) {
+        if (!taskBounds.isEmpty() && !mTaskBounds.equals(taskBounds)) {
+            mTaskBounds.set(taskBounds);
+            return true;
+        }
+        return false;
+    }
+
+    /** Whether the Task bounds has been initialized. */
+    boolean isTaskBoundsInitialized() {
+        return !mTaskBounds.isEmpty();
+    }
+
+    @Nullable
+    Configuration getConfiguration() {
+        return mConfiguration;
+    }
+
+    void setConfiguration(@Nullable Configuration configuration) {
+        mConfiguration = configuration;
+    }
+
+    /** Whether there is any {@link TaskFragmentContainer} below this Task. */
+    boolean isEmpty() {
+        return mContainers.isEmpty() && mFinishedContainer.isEmpty();
+    }
+}
diff --git a/libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/embedding/SplitControllerTest.java b/libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/embedding/SplitControllerTest.java
index 72519dc..e0fda58 100644
--- a/libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/embedding/SplitControllerTest.java
+++ b/libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/embedding/SplitControllerTest.java
@@ -21,6 +21,9 @@
 
 import static com.google.common.truth.Truth.assertWithMessage;
 
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertThrows;
 import static org.mockito.ArgumentMatchers.any;
 import static org.mockito.Mockito.doReturn;
 import static org.mockito.Mockito.mock;
@@ -29,12 +32,12 @@
 import android.app.Activity;
 import android.content.res.Configuration;
 import android.content.res.Resources;
+import android.graphics.Rect;
 import android.platform.test.annotations.Presubmit;
 import android.window.TaskFragmentInfo;
 
 import androidx.test.ext.junit.runners.AndroidJUnit4;
 import androidx.test.filters.SmallTest;
-import androidx.window.extensions.embedding.SplitController.TaskContainer;
 
 import org.junit.Before;
 import org.junit.Test;
@@ -53,6 +56,7 @@
 @RunWith(AndroidJUnit4.class)
 public class SplitControllerTest {
     private static final int TASK_ID = 10;
+    private static final Rect TASK_BOUNDS = new Rect(0, 0, 600, 1200);
 
     @Mock
     private Activity mActivity;
@@ -70,8 +74,11 @@
         mSplitPresenter = mSplitController.mPresenter;
         spyOn(mSplitController);
         spyOn(mSplitPresenter);
+        final Configuration activityConfig = new Configuration();
+        activityConfig.windowConfiguration.setBounds(TASK_BOUNDS);
+        activityConfig.windowConfiguration.setMaxBounds(TASK_BOUNDS);
         doReturn(mActivityResources).when(mActivity).getResources();
-        doReturn(new Configuration()).when(mActivityResources).getConfiguration();
+        doReturn(activityConfig).when(mActivityResources).getConfiguration();
     }
 
     @Test
@@ -117,4 +124,20 @@
         verify(mSplitController).removeContainer(tf);
         verify(mActivity, never()).finish();
     }
+
+    @Test
+    public void testNewContainer() {
+        // Must pass in a valid activity.
+        assertThrows(IllegalArgumentException.class, () ->
+                mSplitController.newContainer(null /* activity */, TASK_ID));
+        assertThrows(IllegalArgumentException.class, () ->
+                mSplitController.newContainer(mActivity, null /* launchingActivity */, TASK_ID));
+
+        final TaskFragmentContainer tf = mSplitController.newContainer(null, mActivity, TASK_ID);
+        final TaskContainer taskContainer = mSplitController.getTaskContainer(TASK_ID);
+
+        assertNotNull(tf);
+        assertNotNull(taskContainer);
+        assertEquals(TASK_BOUNDS, taskContainer.getTaskBounds());
+    }
 }
diff --git a/libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/embedding/TaskContainerTest.java b/libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/embedding/TaskContainerTest.java
new file mode 100644
index 0000000..9fb08df
--- /dev/null
+++ b/libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/embedding/TaskContainerTest.java
@@ -0,0 +1,82 @@
+/*
+ * 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 androidx.window.extensions.embedding;
+
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+import android.graphics.Rect;
+import android.platform.test.annotations.Presubmit;
+
+import androidx.test.ext.junit.runners.AndroidJUnit4;
+import androidx.test.filters.SmallTest;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+/**
+ * Test class for {@link TaskContainer}.
+ *
+ * Build/Install/Run:
+ *  atest WMJetpackUnitTests:TaskContainerTest
+ */
+@Presubmit
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class TaskContainerTest {
+    private static final int TASK_ID = 10;
+    private static final Rect TASK_BOUNDS = new Rect(0, 0, 600, 1200);
+
+    @Test
+    public void testIsTaskBoundsInitialized() {
+        final TaskContainer taskContainer = new TaskContainer(TASK_ID);
+
+        assertFalse(taskContainer.isTaskBoundsInitialized());
+
+        taskContainer.setTaskBounds(TASK_BOUNDS);
+
+        assertTrue(taskContainer.isTaskBoundsInitialized());
+    }
+
+    @Test
+    public void testSetTaskBounds() {
+        final TaskContainer taskContainer = new TaskContainer(TASK_ID);
+
+        assertFalse(taskContainer.setTaskBounds(new Rect()));
+
+        assertTrue(taskContainer.setTaskBounds(TASK_BOUNDS));
+
+        assertFalse(taskContainer.setTaskBounds(TASK_BOUNDS));
+    }
+
+    @Test
+    public void testIsEmpty() {
+        final TaskContainer taskContainer = new TaskContainer(TASK_ID);
+
+        assertTrue(taskContainer.isEmpty());
+
+        final TaskFragmentContainer tf = new TaskFragmentContainer(null, TASK_ID);
+        taskContainer.mContainers.add(tf);
+
+        assertFalse(taskContainer.isEmpty());
+
+        taskContainer.mFinishedContainer.add(tf.getTaskFragmentToken());
+        taskContainer.mContainers.clear();
+
+        assertFalse(taskContainer.isEmpty());
+    }
+}
diff --git a/libs/WindowManager/Shell/res/layout/split_decor.xml b/libs/WindowManager/Shell/res/layout/split_decor.xml
index 9ffa5e8..dfb90af 100644
--- a/libs/WindowManager/Shell/res/layout/split_decor.xml
+++ b/libs/WindowManager/Shell/res/layout/split_decor.xml
@@ -20,9 +20,10 @@
     android:layout_width="match_parent">
 
     <ImageView android:id="@+id/split_resizing_icon"
-               android:layout_height="wrap_content"
-               android:layout_width="wrap_content"
+               android:layout_height="@*android:dimen/starting_surface_icon_size"
+               android:layout_width="@*android:dimen/starting_surface_icon_size"
                android:layout_gravity="center"
+               android:scaleType="fitCenter"
                android:padding="0dp"
                android:visibility="gone"
                android:background="@null"/>
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DropZoneView.java b/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DropZoneView.java
index 38870bc..0cea36e 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DropZoneView.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DropZoneView.java
@@ -28,6 +28,7 @@
 import android.graphics.drawable.Drawable;
 import android.util.AttributeSet;
 import android.util.FloatProperty;
+import android.view.Gravity;
 import android.view.View;
 import android.view.ViewGroup;
 import android.widget.FrameLayout;
@@ -110,10 +111,12 @@
         mColorDrawable = new ColorDrawable();
         setBackgroundDrawable(mColorDrawable);
 
+        final int iconSize = context.getResources().getDimensionPixelSize(
+                com.android.internal.R.dimen.starting_surface_icon_size);
         mSplashScreenView = new ImageView(context);
-        mSplashScreenView.setScaleType(ImageView.ScaleType.CENTER);
-        addView(mSplashScreenView, new FrameLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT,
-                ViewGroup.LayoutParams.MATCH_PARENT));
+        mSplashScreenView.setScaleType(ImageView.ScaleType.FIT_CENTER);
+        addView(mSplashScreenView,
+                new FrameLayout.LayoutParams(iconSize, iconSize, Gravity.CENTER));
         mSplashScreenView.setAlpha(0f);
 
         mMarginView = new MarginView(context);
diff --git a/media/Android.bp b/media/Android.bp
index 3516d25..b45d694 100644
--- a/media/Android.bp
+++ b/media/Android.bp
@@ -120,6 +120,13 @@
             ],
         },
     },
+    versions_with_info: [
+        {
+            version: "1",
+            imports: [],
+        },
+    ],
+
 }
 
 aidl_interface {
diff --git a/native/android/performance_hint.cpp b/native/android/performance_hint.cpp
index 65428de..d627984 100644
--- a/native/android/performance_hint.cpp
+++ b/native/android/performance_hint.cpp
@@ -184,13 +184,13 @@
     mTimestampsNanos.push_back(now);
 
     /**
-     * Use current sample to determine the rate limit. We can pick a shorter rate limit
-     * if any sample underperformed, however, it could be the lower level system is slow
-     * to react. So here we explicitly choose the rate limit with the latest sample.
+     * Cache the hint if the hint is not overtime and the mLastUpdateTimestamp is
+     * still in the mPreferredRateNanos duration.
      */
-    int64_t rateLimit = actualDurationNanos > mTargetDurationNanos ? mPreferredRateNanos
-                                                                   : 10 * mPreferredRateNanos;
-    if (now - mLastUpdateTimestamp <= rateLimit) return 0;
+    if (actualDurationNanos < mTargetDurationNanos &&
+        now - mLastUpdateTimestamp <= mPreferredRateNanos) {
+        return 0;
+    }
 
     binder::Status ret =
             mHintSession->reportActualWorkDuration(mActualDurationsNanos, mTimestampsNanos);
diff --git a/omapi/aidl/Android.bp b/omapi/aidl/Android.bp
index d80317b..58bcd1d 100644
--- a/omapi/aidl/Android.bp
+++ b/omapi/aidl/Android.bp
@@ -29,4 +29,11 @@
             enabled: true,
         },
     },
+    versions_with_info: [
+        {
+            version: "1",
+            imports: [],
+        },
+    ],
+
 }
diff --git a/omapi/aidl/aidl_api/android.se.omapi/1/.hash b/omapi/aidl/aidl_api/android.se.omapi/1/.hash
new file mode 100644
index 0000000..f77182a
--- /dev/null
+++ b/omapi/aidl/aidl_api/android.se.omapi/1/.hash
@@ -0,0 +1 @@
+894069bcfe4f35ceb2088278ddf87c83adee8014
diff --git a/omapi/aidl/aidl_api/android.se.omapi/1/android/se/omapi/ISecureElementChannel.aidl b/omapi/aidl/aidl_api/android.se.omapi/1/android/se/omapi/ISecureElementChannel.aidl
new file mode 100644
index 0000000..87fdac0
--- /dev/null
+++ b/omapi/aidl/aidl_api/android.se.omapi/1/android/se/omapi/ISecureElementChannel.aidl
@@ -0,0 +1,46 @@
+/*
+ * Copyright (C) 2017, 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.
+ *//*
+ * Contributed by: Giesecke & Devrient GmbH.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+//     the interface (from the latest frozen version), the build system will
+//     prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.se.omapi;
+/* @hide */
+@VintfStability
+interface ISecureElementChannel {
+  void close();
+  boolean isClosed();
+  boolean isBasicChannel();
+  byte[] getSelectResponse();
+  byte[] transmit(in byte[] command);
+  boolean selectNext();
+}
diff --git a/omapi/aidl/aidl_api/android.se.omapi/1/android/se/omapi/ISecureElementListener.aidl b/omapi/aidl/aidl_api/android.se.omapi/1/android/se/omapi/ISecureElementListener.aidl
new file mode 100644
index 0000000..77e1c53f
--- /dev/null
+++ b/omapi/aidl/aidl_api/android.se.omapi/1/android/se/omapi/ISecureElementListener.aidl
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2017, 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.
+ *//*
+ * Contributed by: Giesecke & Devrient GmbH.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+//     the interface (from the latest frozen version), the build system will
+//     prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.se.omapi;
+/* @hide */
+@VintfStability
+interface ISecureElementListener {
+}
diff --git a/omapi/aidl/aidl_api/android.se.omapi/1/android/se/omapi/ISecureElementReader.aidl b/omapi/aidl/aidl_api/android.se.omapi/1/android/se/omapi/ISecureElementReader.aidl
new file mode 100644
index 0000000..2b10c47
--- /dev/null
+++ b/omapi/aidl/aidl_api/android.se.omapi/1/android/se/omapi/ISecureElementReader.aidl
@@ -0,0 +1,44 @@
+/*
+ * Copyright (C) 2017, 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.
+ *//*
+ * Contributed by: Giesecke & Devrient GmbH.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+//     the interface (from the latest frozen version), the build system will
+//     prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.se.omapi;
+/* @hide */
+@VintfStability
+interface ISecureElementReader {
+  boolean isSecureElementPresent();
+  android.se.omapi.ISecureElementSession openSession();
+  void closeSessions();
+  boolean reset();
+}
diff --git a/omapi/aidl/aidl_api/android.se.omapi/1/android/se/omapi/ISecureElementService.aidl b/omapi/aidl/aidl_api/android.se.omapi/1/android/se/omapi/ISecureElementService.aidl
new file mode 100644
index 0000000..0c8e431
--- /dev/null
+++ b/omapi/aidl/aidl_api/android.se.omapi/1/android/se/omapi/ISecureElementService.aidl
@@ -0,0 +1,45 @@
+/*
+ * Copyright (C) 2017, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *//*
+ * Copyright (c) 2015-2017, The Linux Foundation.
+ *//*
+ * Contributed by: Giesecke & Devrient GmbH.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+//     the interface (from the latest frozen version), the build system will
+//     prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.se.omapi;
+/* @hide */
+@VintfStability
+interface ISecureElementService {
+  String[] getReaders();
+  android.se.omapi.ISecureElementReader getReader(in String reader);
+  boolean[] isNfcEventAllowed(in String reader, in byte[] aid, in String[] packageNames, in int userId);
+}
diff --git a/omapi/aidl/aidl_api/android.se.omapi/1/android/se/omapi/ISecureElementSession.aidl b/omapi/aidl/aidl_api/android.se.omapi/1/android/se/omapi/ISecureElementSession.aidl
new file mode 100644
index 0000000..06287c5
--- /dev/null
+++ b/omapi/aidl/aidl_api/android.se.omapi/1/android/se/omapi/ISecureElementSession.aidl
@@ -0,0 +1,48 @@
+/*
+ * Copyright (C) 2017, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *//*
+ * Copyright (c) 2015-2017, The Linux Foundation.
+ *//*
+ * Contributed by: Giesecke & Devrient GmbH.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+//     the interface (from the latest frozen version), the build system will
+//     prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.se.omapi;
+/* @hide */
+@VintfStability
+interface ISecureElementSession {
+  byte[] getAtr();
+  void close();
+  void closeChannels();
+  boolean isClosed();
+  android.se.omapi.ISecureElementChannel openBasicChannel(in byte[] aid, in byte p2, in android.se.omapi.ISecureElementListener listener);
+  android.se.omapi.ISecureElementChannel openLogicalChannel(in byte[] aid, in byte p2, in android.se.omapi.ISecureElementListener listener);
+}
diff --git a/packages/SettingsLib/src/com/android/settingslib/wifi/WifiStateWorker.java b/packages/SettingsLib/src/com/android/settingslib/wifi/WifiStateWorker.java
new file mode 100644
index 0000000..a0c2698
--- /dev/null
+++ b/packages/SettingsLib/src/com/android/settingslib/wifi/WifiStateWorker.java
@@ -0,0 +1,165 @@
+/*
+ * 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.settingslib.wifi;
+
+import static android.net.wifi.WifiManager.EXTRA_WIFI_STATE;
+import static android.net.wifi.WifiManager.WIFI_STATE_CHANGED_ACTION;
+import static android.net.wifi.WifiManager.WIFI_STATE_DISABLED;
+import static android.net.wifi.WifiManager.WIFI_STATE_ENABLED;
+
+import android.annotation.AnyThread;
+import android.annotation.NonNull;
+import android.annotation.TestApi;
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.net.wifi.WifiManager;
+import android.os.HandlerThread;
+import android.os.Process;
+import android.util.Log;
+
+import androidx.annotation.GuardedBy;
+import androidx.annotation.VisibleForTesting;
+import androidx.annotation.WorkerThread;
+
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+
+/**
+ * This is a singleton class for Wi-Fi state worker.
+ */
+public class WifiStateWorker {
+
+    private static final String TAG = "WifiStateWorker";
+    private static final Object sLock = new Object();
+
+    /**
+     * A singleton {@link WifiStateWorker} object is used to share with all sub-settings.
+     */
+    @GuardedBy("sLock")
+    private static WifiStateWorker sInstance;
+    @TestApi
+    @GuardedBy("sLock")
+    private static Map<Context, WifiStateWorker> sTestInstances;
+
+    @VisibleForTesting
+    static WifiManager sWifiManager;
+    private static int sWifiState;
+    private static HandlerThread sWorkerThread;
+
+    /**
+     * Static method to create a singleton class for WifiStateWorker.
+     *
+     * @param context The Context this is associated with.
+     * @return an instance of {@link WifiStateWorker} object.
+     */
+    @NonNull
+    @AnyThread
+    public static WifiStateWorker getInstance(@NonNull Context context) {
+        synchronized (sLock) {
+            if (sTestInstances != null && sTestInstances.containsKey(context)) {
+                WifiStateWorker testInstance = sTestInstances.get(context);
+                Log.w(TAG, "The context owner try to use a test instance:" + testInstance);
+                return testInstance;
+            }
+
+            if (sInstance != null) return sInstance;
+
+            sInstance = new WifiStateWorker();
+            sWorkerThread = new HandlerThread(
+                    TAG + ":{" + context.getApplicationInfo().className + "}",
+                    Process.THREAD_PRIORITY_DISPLAY);
+            sWorkerThread.start();
+            sWorkerThread.getThreadHandler().post(() -> init(context));
+            return sInstance;
+        }
+    }
+
+    /**
+     * A convenience method to set pre-prepared instance or mock(WifiStateWorker.class) for testing.
+     *
+     * @param context  The Context this is associated with.
+     * @param instance of {@link WifiStateWorker} object.
+     * @hide
+     */
+    @TestApi
+    @VisibleForTesting
+    public static void setTestInstance(@NonNull Context context, WifiStateWorker instance) {
+        synchronized (sLock) {
+            if (sTestInstances == null) sTestInstances = new ConcurrentHashMap<>();
+
+            Log.w(TAG, "Try to set a test instance by context:" + context);
+            sTestInstances.put(context, instance);
+        }
+    }
+
+    @WorkerThread
+    private static void init(@NonNull Context context) {
+        final Context appContext = context.getApplicationContext();
+        final IntentReceiver receiver = new IntentReceiver();
+        appContext.registerReceiver(receiver, new IntentFilter(WIFI_STATE_CHANGED_ACTION), null,
+                sWorkerThread.getThreadHandler());
+        sWifiManager = appContext.getSystemService(WifiManager.class);
+        refresh();
+    }
+
+    /**
+     * Refresh Wi-Fi state with WifiManager#getWifiState()
+     */
+    @AnyThread
+    public static void refresh() {
+        if (sWifiManager == null) return;
+        Log.d(TAG, "Start calling WifiManager#getWifiState.");
+        sWifiState = sWifiManager.getWifiState();
+        Log.d(TAG, "WifiManager#getWifiState return state:" + sWifiState);
+    }
+
+    /**
+     * Gets the Wi-Fi enabled state.
+     *
+     * @return One of {@link WifiManager#WIFI_STATE_DISABLED},
+     * {@link WifiManager#WIFI_STATE_DISABLING}, {@link WifiManager#WIFI_STATE_ENABLED},
+     * {@link WifiManager#WIFI_STATE_ENABLING}, {@link WifiManager#WIFI_STATE_UNKNOWN}
+     * @see #isWifiEnabled()
+     */
+    @AnyThread
+    public int getWifiState() {
+        return sWifiState;
+    }
+
+    /**
+     * Return whether Wi-Fi is enabled or disabled.
+     *
+     * @return {@code true} if Wi-Fi is enabled
+     * @see #getWifiState()
+     */
+    @AnyThread
+    public boolean isWifiEnabled() {
+        return sWifiState == WIFI_STATE_ENABLED;
+    }
+
+    @WorkerThread
+    private static class IntentReceiver extends BroadcastReceiver {
+        @Override
+        public void onReceive(Context context, Intent intent) {
+            if (WIFI_STATE_CHANGED_ACTION.equals(intent.getAction())) {
+                sWifiState = intent.getIntExtra(EXTRA_WIFI_STATE, WIFI_STATE_DISABLED);
+            }
+        }
+    }
+}
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/wifi/WifiStateWorkerTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/wifi/WifiStateWorkerTest.java
new file mode 100644
index 0000000..2589a90
--- /dev/null
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/wifi/WifiStateWorkerTest.java
@@ -0,0 +1,136 @@
+/*
+ * 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.settingslib.wifi;
+
+import static android.net.wifi.WifiManager.WIFI_STATE_DISABLED;
+import static android.net.wifi.WifiManager.WIFI_STATE_DISABLING;
+import static android.net.wifi.WifiManager.WIFI_STATE_ENABLED;
+import static android.net.wifi.WifiManager.WIFI_STATE_ENABLING;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.mockito.Mockito.when;
+
+import android.content.Context;
+import android.net.wifi.WifiManager;
+import android.os.UserHandle;
+
+import androidx.test.core.app.ApplicationProvider;
+
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.Spy;
+import org.mockito.junit.MockitoJUnit;
+import org.mockito.junit.MockitoRule;
+import org.robolectric.RobolectricTestRunner;
+
+@RunWith(RobolectricTestRunner.class)
+public class WifiStateWorkerTest {
+
+    @Rule
+    public final MockitoRule mMockitoRule = MockitoJUnit.rule();
+    @Spy
+    Context mContext = ApplicationProvider.getApplicationContext();
+    @Mock
+    WifiManager mWifiManager;
+
+    WifiStateWorker mWifiStateWorker;
+
+    @Before
+    public void setUp() {
+        when(mWifiManager.getWifiState()).thenReturn(WIFI_STATE_ENABLED);
+        WifiStateWorker.sWifiManager = mWifiManager;
+
+        mWifiStateWorker = WifiStateWorker.getInstance(mContext);
+    }
+
+    @Test
+    public void getInstance_diffContext_getSameInstance() {
+        Context context = mContext.createContextAsUser(UserHandle.ALL, 0 /* flags */);
+        WifiStateWorker instance = WifiStateWorker.getInstance(context);
+
+        assertThat(mContext).isNotEqualTo(context);
+        assertThat(mWifiStateWorker).isEqualTo(instance);
+    }
+
+    @Test
+    public void getWifiState_wifiStateDisabling_returnWifiStateDisabling() {
+        when(mWifiManager.getWifiState()).thenReturn(WIFI_STATE_DISABLING);
+        WifiStateWorker.refresh();
+
+        assertThat(mWifiStateWorker.getWifiState()).isEqualTo(WIFI_STATE_DISABLING);
+    }
+
+    @Test
+    public void getWifiState_wifiStateDisabled_returnWifiStateDisabled() {
+        when(mWifiManager.getWifiState()).thenReturn(WIFI_STATE_DISABLED);
+        WifiStateWorker.refresh();
+
+        assertThat(mWifiStateWorker.getWifiState()).isEqualTo(WIFI_STATE_DISABLED);
+    }
+
+    @Test
+    public void getWifiState_wifiStateEnabling_returnWifiStateEnabling() {
+        when(mWifiManager.getWifiState()).thenReturn(WIFI_STATE_ENABLING);
+        WifiStateWorker.refresh();
+
+        assertThat(mWifiStateWorker.getWifiState()).isEqualTo(WIFI_STATE_ENABLING);
+    }
+
+    @Test
+    public void getWifiState_wifiStateEnabled_returnWifiStateEnabled() {
+        when(mWifiManager.getWifiState()).thenReturn(WIFI_STATE_ENABLED);
+        WifiStateWorker.refresh();
+
+        assertThat(mWifiStateWorker.getWifiState()).isEqualTo(WIFI_STATE_ENABLED);
+    }
+
+    @Test
+    public void isWifiEnabled_wifiStateDisabling_returnFalse() {
+        when(mWifiManager.getWifiState()).thenReturn(WIFI_STATE_DISABLING);
+        WifiStateWorker.refresh();
+
+        assertThat(mWifiStateWorker.isWifiEnabled()).isFalse();
+    }
+
+    @Test
+    public void isWifiEnabled_wifiStateDisabled_returnFalse() {
+        when(mWifiManager.getWifiState()).thenReturn(WIFI_STATE_DISABLED);
+        WifiStateWorker.refresh();
+
+        assertThat(mWifiStateWorker.isWifiEnabled()).isFalse();
+    }
+
+    @Test
+    public void isWifiEnabled_wifiStateEnabling_returnFalse() {
+        when(mWifiManager.getWifiState()).thenReturn(WIFI_STATE_ENABLING);
+        WifiStateWorker.refresh();
+
+        assertThat(mWifiStateWorker.isWifiEnabled()).isFalse();
+    }
+
+    @Test
+    public void isWifiEnabled_wifiStateEnabled_returnTrue() {
+        when(mWifiManager.getWifiState()).thenReturn(WIFI_STATE_ENABLED);
+        WifiStateWorker.refresh();
+
+        assertThat(mWifiStateWorker.isWifiEnabled()).isTrue();
+    }
+}
diff --git a/packages/SystemUI/res/layout/auth_biometric_contents.xml b/packages/SystemUI/res/layout/auth_biometric_contents.xml
index 58adb91..e1b294f 100644
--- a/packages/SystemUI/res/layout/auth_biometric_contents.xml
+++ b/packages/SystemUI/res/layout/auth_biometric_contents.xml
@@ -21,6 +21,9 @@
         android:layout_width="match_parent"
         android:layout_height="wrap_content"
         android:gravity="@integer/biometric_dialog_text_gravity"
+        android:singleLine="true"
+        android:marqueeRepeatLimit="1"
+        android:ellipsize="marquee"
         style="@style/TextAppearance.AuthCredential.Title"/>
 
     <TextView
@@ -28,13 +31,16 @@
         android:layout_width="match_parent"
         android:layout_height="wrap_content"
         android:gravity="@integer/biometric_dialog_text_gravity"
+        android:singleLine="true"
+        android:marqueeRepeatLimit="1"
+        android:ellipsize="marquee"
         style="@style/TextAppearance.AuthCredential.Subtitle"/>
 
     <TextView
         android:id="@+id/description"
         android:layout_width="match_parent"
         android:layout_height="wrap_content"
-        android:gravity="@integer/biometric_dialog_text_gravity"
+        android:scrollbars ="vertical"
         style="@style/TextAppearance.AuthCredential.Description"/>
 
     <Space android:id="@+id/space_above_icon"
diff --git a/packages/SystemUI/res/layout/media_carousel.xml b/packages/SystemUI/res/layout/media_carousel.xml
index 52132e8..50d3cc4 100644
--- a/packages/SystemUI/res/layout/media_carousel.xml
+++ b/packages/SystemUI/res/layout/media_carousel.xml
@@ -48,7 +48,7 @@
         android:layout_width="wrap_content"
         android:layout_height="48dp"
         android:layout_marginBottom="4dp"
-        android:tint="?android:attr/textColor"
+        android:tint="@color/media_paging_indicator"
         android:forceHasOverlappingRendering="false"
     />
 </FrameLayout>
diff --git a/packages/SystemUI/res/values/colors.xml b/packages/SystemUI/res/values/colors.xml
index 24118d2..02ba271 100644
--- a/packages/SystemUI/res/values/colors.xml
+++ b/packages/SystemUI/res/values/colors.xml
@@ -176,6 +176,7 @@
 
     <!-- media -->
     <color name="media_seamless_border">?android:attr/colorAccent</color>
+    <color name="media_paging_indicator">@color/material_dynamic_neutral_variant80</color>
 
     <!-- media output dialog-->
     <color name="media_dialog_background" android:lstar="98">@color/material_dynamic_neutral90</color>
diff --git a/packages/SystemUI/src/com/android/systemui/accessibility/floatingmenu/AccessibilityFloatingMenu.java b/packages/SystemUI/src/com/android/systemui/accessibility/floatingmenu/AccessibilityFloatingMenu.java
index f182e77..9af8300 100644
--- a/packages/SystemUI/src/com/android/systemui/accessibility/floatingmenu/AccessibilityFloatingMenu.java
+++ b/packages/SystemUI/src/com/android/systemui/accessibility/floatingmenu/AccessibilityFloatingMenu.java
@@ -39,10 +39,13 @@
 
 import androidx.annotation.NonNull;
 
+import com.android.internal.accessibility.dialog.AccessibilityTarget;
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.systemui.Prefs;
 import com.android.systemui.shared.system.SysUiStatsLog;
 
+import java.util.List;
+
 /**
  * Contains logic for an accessibility floating menu view.
  */
@@ -120,9 +123,13 @@
         if (isShowing()) {
             return;
         }
+        final List<AccessibilityTarget> targetList = getTargets(mContext, ACCESSIBILITY_BUTTON);
+        if (targetList.isEmpty()) {
+            return;
+        }
 
         mMenuView.show();
-        mMenuView.onTargetsChanged(getTargets(mContext, ACCESSIBILITY_BUTTON));
+        mMenuView.onTargetsChanged(targetList);
         mMenuView.updateOpacityWith(isFadeEffectEnabled(mContext),
                 getOpacityValue(mContext));
         mMenuView.setSizeType(getSizeType(mContext));
diff --git a/packages/SystemUI/src/com/android/systemui/accessibility/floatingmenu/AccessibilityFloatingMenuController.java b/packages/SystemUI/src/com/android/systemui/accessibility/floatingmenu/AccessibilityFloatingMenuController.java
index cc5a792..11353f6 100644
--- a/packages/SystemUI/src/com/android/systemui/accessibility/floatingmenu/AccessibilityFloatingMenuController.java
+++ b/packages/SystemUI/src/com/android/systemui/accessibility/floatingmenu/AccessibilityFloatingMenuController.java
@@ -51,26 +51,19 @@
     private int mBtnMode;
     private String mBtnTargets;
     private boolean mIsKeyguardVisible;
-    private boolean mIsAccessibilityManagerServiceReady;
 
     @VisibleForTesting
     final KeyguardUpdateMonitorCallback mKeyguardCallback = new KeyguardUpdateMonitorCallback() {
-        // Accessibility floating menu needs to retrieve information from
-        // AccessibilityManagerService, and it would be ready before onUserUnlocked().
+
         @Override
         public void onUserUnlocked() {
-            mIsAccessibilityManagerServiceReady = true;
             handleFloatingMenuVisibility(mIsKeyguardVisible, mBtnMode, mBtnTargets);
         }
 
-        // Keyguard state would be changed before AccessibilityManagerService is ready to retrieve,
-        // need to wait until receive onUserUnlocked().
         @Override
         public void onKeyguardVisibilityChanged(boolean showing) {
             mIsKeyguardVisible = showing;
-            if (mIsAccessibilityManagerServiceReady) {
-                handleFloatingMenuVisibility(mIsKeyguardVisible, mBtnMode, mBtnTargets);
-            }
+            handleFloatingMenuVisibility(mIsKeyguardVisible, mBtnMode, mBtnTargets);
         }
 
         @Override
@@ -99,7 +92,6 @@
         mKeyguardUpdateMonitor = keyguardUpdateMonitor;
 
         mIsKeyguardVisible = false;
-        mIsAccessibilityManagerServiceReady = false;
     }
 
     /**
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/AuthBiometricView.java b/packages/SystemUI/src/com/android/systemui/biometrics/AuthBiometricView.java
index 55da8da..1413f4a 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/AuthBiometricView.java
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/AuthBiometricView.java
@@ -34,6 +34,7 @@
 import android.os.Handler;
 import android.os.Looper;
 import android.text.TextUtils;
+import android.text.method.ScrollingMovementMethod;
 import android.util.AttributeSet;
 import android.util.Log;
 import android.view.View;
@@ -706,6 +707,12 @@
 
         mTitleView.setText(mPromptInfo.getTitle());
 
+        //setSelected could make marguee work
+        mTitleView.setSelected(true);
+        mSubtitleView.setSelected(true);
+        //make description view become scrollable
+        mDescriptionView.setMovementMethod(new ScrollingMovementMethod());
+
         if (isDeviceCredentialAllowed()) {
             final CharSequence credentialButtonText;
             @Utils.CredentialType final int credentialType =
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsDialogMeasureAdapter.java b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsDialogMeasureAdapter.java
index 6afe420..dbfce2e 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsDialogMeasureAdapter.java
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsDialogMeasureAdapter.java
@@ -139,6 +139,9 @@
                 child.measure(
                         MeasureSpec.makeMeasureSpec(width, MeasureSpec.EXACTLY),
                         MeasureSpec.makeMeasureSpec(clampedSpacerHeight, MeasureSpec.EXACTLY));
+            } else if (child.getId() == R.id.description) {
+                //skip description view and compute later
+                continue;
             } else {
                 child.measure(
                         MeasureSpec.makeMeasureSpec(width, MeasureSpec.EXACTLY),
@@ -150,9 +153,27 @@
             }
         }
 
+        //re-calculate the height of description
+        View description = mView.findViewById(R.id.description);
+        totalHeight += measureDescription(description, displayHeight, width, totalHeight);
+
         return new AuthDialog.LayoutParams(width, totalHeight);
     }
 
+    private int measureDescription(View description, int displayHeight, int currWidth,
+                                   int currHeight) {
+        //description view should be measured in AuthBiometricFingerprintView#onMeasureInternal
+        //so we could getMeasuredHeight in onMeasureInternalPortrait directly.
+        int newHeight = description.getMeasuredHeight() + currHeight;
+        int limit = (int) (displayHeight * 0.75);
+        if (newHeight > limit) {
+            description.measure(
+                    MeasureSpec.makeMeasureSpec(currWidth, MeasureSpec.EXACTLY),
+                    MeasureSpec.makeMeasureSpec(limit - currHeight, MeasureSpec.EXACTLY));
+        }
+        return description.getMeasuredHeight();
+    }
+
     @NonNull
     private AuthDialog.LayoutParams onMeasureInternalLandscape(int width, int height) {
         final WindowMetrics windowMetrics = mWindowManager.getMaximumWindowMetrics();
diff --git a/packages/SystemUI/src/com/android/systemui/log/dagger/LogModule.java b/packages/SystemUI/src/com/android/systemui/log/dagger/LogModule.java
index 79ac9e8..39f00f4 100644
--- a/packages/SystemUI/src/com/android/systemui/log/dagger/LogModule.java
+++ b/packages/SystemUI/src/com/android/systemui/log/dagger/LogModule.java
@@ -176,7 +176,6 @@
         return factory.create("MediaTttReceiver", 20);
     }
 
-
     /**
      * Provides a logging buffer for logs related to the media mute-await connections. See
      * {@link com.android.systemui.media.muteawait.MediaMuteAwaitConnectionManager}.
@@ -199,6 +198,16 @@
         return factory.create("NearbyMediaDevicesLog", 20);
     }
 
+    /**
+     * Provides a buffer for logs related to media view events
+     */
+    @Provides
+    @SysUISingleton
+    @MediaViewLog
+    public static LogBuffer provideMediaViewLogBuffer(LogBufferFactory factory) {
+        return factory.create("MediaView", 100);
+    }
+
     /** Allows logging buffers to be tweaked via adb on debug builds but not on prod builds. */
     @Provides
     @SysUISingleton
diff --git a/packages/SystemUI/src/com/android/systemui/log/dagger/MediaViewLog.java b/packages/SystemUI/src/com/android/systemui/log/dagger/MediaViewLog.java
new file mode 100644
index 0000000..75a34fc
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/log/dagger/MediaViewLog.java
@@ -0,0 +1,35 @@
+/*
+ * 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.systemui.log.dagger;
+
+import static java.lang.annotation.RetentionPolicy.RUNTIME;
+
+import com.android.systemui.log.LogBuffer;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.Retention;
+
+import javax.inject.Qualifier;
+
+/**
+ * A {@link LogBuffer} for {@link com.android.systemui.media.MediaViewLogger}
+ */
+@Qualifier
+@Documented
+@Retention(RUNTIME)
+public @interface MediaViewLog {
+}
diff --git a/packages/SystemUI/src/com/android/systemui/media/MediaCarouselController.kt b/packages/SystemUI/src/com/android/systemui/media/MediaCarouselController.kt
index ca25a18..7b72ab7 100644
--- a/packages/SystemUI/src/com/android/systemui/media/MediaCarouselController.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/MediaCarouselController.kt
@@ -533,7 +533,9 @@
     }
 
     private fun recreatePlayers() {
-        pageIndicator.tintList = ColorStateList.valueOf(R.color.material_dynamic_neutral_variant80)
+        pageIndicator.tintList = ColorStateList.valueOf(
+            context.getColor(R.color.media_paging_indicator)
+        )
 
         MediaPlayerData.mediaData().forEach { (key, data, isSsMediaRec) ->
             if (isSsMediaRec) {
diff --git a/packages/SystemUI/src/com/android/systemui/media/MediaControlPanel.java b/packages/SystemUI/src/com/android/systemui/media/MediaControlPanel.java
index 48a63ed..12369e5 100644
--- a/packages/SystemUI/src/com/android/systemui/media/MediaControlPanel.java
+++ b/packages/SystemUI/src/com/android/systemui/media/MediaControlPanel.java
@@ -176,9 +176,12 @@
     private String mPackageName;
 
     private boolean mIsScrubbing = false;
+    private boolean mIsSeekBarEnabled = false;
 
     private final SeekBarViewModel.ScrubbingChangeListener mScrubbingChangeListener =
             this::setIsScrubbing;
+    private final SeekBarViewModel.EnabledChangeListener mEnabledChangeListener =
+            this::setIsSeekBarEnabled;
 
     /**
      * Initialize a new control panel
@@ -235,8 +238,9 @@
     public void onDestroy() {
         if (mSeekBarObserver != null) {
             mSeekBarViewModel.getProgress().removeObserver(mSeekBarObserver);
-            mSeekBarViewModel.removeScrubbingChangeListener(mScrubbingChangeListener);
         }
+        mSeekBarViewModel.removeScrubbingChangeListener(mScrubbingChangeListener);
+        mSeekBarViewModel.removeEnabledChangeListener(mEnabledChangeListener);
         mSeekBarViewModel.onDestroy();
         mMediaViewController.onDestroy();
     }
@@ -283,7 +287,7 @@
     }
 
     /** Sets whether the user is touching the seek bar to change the track position. */
-    public void setIsScrubbing(boolean isScrubbing) {
+    private void setIsScrubbing(boolean isScrubbing) {
         if (mMediaData == null || mMediaData.getSemanticActions() == null) {
             return;
         }
@@ -295,6 +299,14 @@
                 updateDisplayForScrubbingChange(mMediaData.getSemanticActions()));
     }
 
+    private void setIsSeekBarEnabled(boolean isSeekBarEnabled) {
+        if (isSeekBarEnabled == this.mIsSeekBarEnabled) {
+            return;
+        }
+        this.mIsSeekBarEnabled = isSeekBarEnabled;
+        updateSeekBarVisibility();
+    }
+
     /**
      * Get the context
      *
@@ -313,6 +325,7 @@
         mSeekBarViewModel.getProgress().observeForever(mSeekBarObserver);
         mSeekBarViewModel.attachTouchHandlers(vh.getSeekBar());
         mSeekBarViewModel.setScrubbingChangeListener(mScrubbingChangeListener);
+        mSeekBarViewModel.setEnabledChangeListener(mEnabledChangeListener);
         mMediaViewController.attach(player, MediaViewController.TYPE.PLAYER);
 
         vh.getPlayer().setOnLongClickListener(v -> {
@@ -450,8 +463,8 @@
 
         bindOutputSwitcherChip(data);
         bindLongPressMenu(data);
-        bindActionButtons(data);
         bindScrubbingTime(data);
+        bindActionButtons(data);
 
         boolean isSongUpdated = bindSongMetadata(data);
         bindArtworkAndColors(data, isSongUpdated);
@@ -735,13 +748,18 @@
                         /* showInCompact= */ false);
             }
         }
+
+        updateSeekBarVisibility();
+    }
+
+    private void updateSeekBarVisibility() {
+        ConstraintSet expandedSet = mMediaViewController.getExpandedLayout();
         expandedSet.setVisibility(R.id.media_progress_bar, getSeekBarVisibility());
-        expandedSet.setAlpha(R.id.media_progress_bar, mSeekBarViewModel.getEnabled() ? 1.0f : 0.0f);
+        expandedSet.setAlpha(R.id.media_progress_bar, mIsSeekBarEnabled ? 1.0f : 0.0f);
     }
 
     private int getSeekBarVisibility() {
-        boolean seekbarEnabled = mSeekBarViewModel.getEnabled();
-        if (seekbarEnabled) {
+        if (mIsSeekBarEnabled) {
             return ConstraintSet.VISIBLE;
         }
         // If disabled and "neighbours" are visible, set progress bar to INVISIBLE instead of GONE
@@ -751,8 +769,7 @@
 
     private boolean areAnyExpandedBottomActionsVisible() {
         ConstraintSet expandedSet = mMediaViewController.getExpandedLayout();
-        int[] referencedIds = mMediaViewHolder.getActionsTopBarrier().getReferencedIds();
-        for (int id : referencedIds) {
+        for (int id : MediaViewHolder.Companion.getExpandedBottomActionIds()) {
             if (expandedSet.getVisibility(id) == ConstraintSet.VISIBLE) {
                 return true;
             }
@@ -872,7 +889,6 @@
     }
 
     /** Updates all the views that might change due to a scrubbing state change. */
-    // TODO(b/209656742): Handle scenarios where actionPrev and/or actionNext aren't active.
     private void updateDisplayForScrubbingChange(@NonNull MediaButton semanticActions) {
         // Update visibilities of the scrubbing time views and the scrubbing-dependent buttons.
         bindScrubbingTime(mMediaData);
diff --git a/packages/SystemUI/src/com/android/systemui/media/MediaViewController.kt b/packages/SystemUI/src/com/android/systemui/media/MediaViewController.kt
index 5210499..327268b 100644
--- a/packages/SystemUI/src/com/android/systemui/media/MediaViewController.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/MediaViewController.kt
@@ -35,7 +35,8 @@
 class MediaViewController @Inject constructor(
     private val context: Context,
     private val configurationController: ConfigurationController,
-    private val mediaHostStatesManager: MediaHostStatesManager
+    private val mediaHostStatesManager: MediaHostStatesManager,
+    private val logger: MediaViewLogger
 ) {
 
     /**
@@ -330,6 +331,7 @@
             // is cheap
             setGutsViewState(result)
             viewStates[cacheKey] = result
+            logger.logMediaSize("measured new viewState", result.width, result.height)
         } else {
             // This is an interpolated state
             val startState = state.copy().also { it.expansion = 0.0f }
@@ -344,6 +346,7 @@
                     startViewState,
                     endViewState,
                     state.expansion)
+            logger.logMediaSize("interpolated viewState", result.width, result.height)
         }
         if (state.squishFraction < 1f) {
             return squishViewState(result, state.squishFraction)
@@ -371,6 +374,7 @@
      */
     fun attach(transitionLayout: TransitionLayout, type: TYPE) {
         updateMediaViewControllerType(type)
+        logger.logMediaLocation("attach", currentStartLocation, currentEndLocation)
         this.transitionLayout = transitionLayout
         layoutController.attach(transitionLayout)
         if (currentEndLocation == -1) {
@@ -409,6 +413,7 @@
         currentEndLocation = endLocation
         currentStartLocation = startLocation
         currentTransitionProgress = transitionProgress
+        logger.logMediaLocation("setCurrentState", startLocation, endLocation)
 
         val shouldAnimate = animateNextStateChange && !applyImmediately
 
@@ -461,6 +466,7 @@
             result = layoutController.getInterpolatedState(startViewState, endViewState,
                     transitionProgress, tmpState)
         }
+        logger.logMediaSize("setCurrentState", result.width, result.height)
         layoutController.setState(result, applyImmediately, shouldAnimate, animationDuration,
                 animationDelay)
     }
@@ -478,6 +484,7 @@
             result.height = Math.max(it.measuredHeight, result.height)
             result.width = Math.max(it.measuredWidth, result.width)
         }
+        logger.logMediaSize("update to carousel", result.width, result.height)
         return result
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/media/MediaViewHolder.kt b/packages/SystemUI/src/com/android/systemui/media/MediaViewHolder.kt
index 8964d71..b8b7318 100644
--- a/packages/SystemUI/src/com/android/systemui/media/MediaViewHolder.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/MediaViewHolder.kt
@@ -187,5 +187,17 @@
             R.id.action3,
             R.id.action4
         )
+
+        val expandedBottomActionIds = setOf(
+            R.id.actionPrev,
+            R.id.actionNext,
+            R.id.action0,
+            R.id.action1,
+            R.id.action2,
+            R.id.action3,
+            R.id.action4,
+            R.id.media_scrubbing_elapsed_time,
+            R.id.media_scrubbing_total_time
+        )
     }
-}
\ No newline at end of file
+}
diff --git a/packages/SystemUI/src/com/android/systemui/media/MediaViewLogger.kt b/packages/SystemUI/src/com/android/systemui/media/MediaViewLogger.kt
new file mode 100644
index 0000000..73868189
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/media/MediaViewLogger.kt
@@ -0,0 +1,63 @@
+/*
+ * 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.systemui.media
+
+import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.log.LogBuffer
+import com.android.systemui.log.LogLevel
+import com.android.systemui.log.dagger.MediaViewLog
+import javax.inject.Inject
+
+private const val TAG = "MediaView"
+
+/**
+ * A buffered log for media view events that are too noisy for regular logging
+ */
+@SysUISingleton
+class MediaViewLogger @Inject constructor(
+    @MediaViewLog private val buffer: LogBuffer
+) {
+    fun logMediaSize(reason: String, width: Int, height: Int) {
+        buffer.log(
+                TAG,
+                LogLevel.DEBUG,
+                {
+                    str1 = reason
+                    int1 = width
+                    int2 = height
+                },
+                {
+                    "size ($str1): $int1 x $int2"
+                }
+        )
+    }
+
+    fun logMediaLocation(reason: String, startLocation: Int, endLocation: Int) {
+        buffer.log(
+                TAG,
+                LogLevel.DEBUG,
+                {
+                    str1 = reason
+                    int1 = startLocation
+                    int2 = endLocation
+                },
+                {
+                    "location ($str1): $int1 -> $int2"
+                }
+        )
+    }
+}
\ No newline at end of file
diff --git a/packages/SystemUI/src/com/android/systemui/media/SeekBarViewModel.kt b/packages/SystemUI/src/com/android/systemui/media/SeekBarViewModel.kt
index 5218492..193166b 100644
--- a/packages/SystemUI/src/com/android/systemui/media/SeekBarViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/SeekBarViewModel.kt
@@ -76,7 +76,11 @@
 ) {
     private var _data = Progress(false, false, false, false, null, 0)
         set(value) {
+            val enabledChanged = value.enabled != field.enabled
             field = value
+            if (enabledChanged) {
+                enabledChangeListener?.onEnabledChanged(value.enabled)
+            }
             _progress.postValue(value)
         }
     private val _progress = MutableLiveData<Progress>().apply {
@@ -122,6 +126,7 @@
         }
 
     private var scrubbingChangeListener: ScrubbingChangeListener? = null
+    private var enabledChangeListener: EnabledChangeListener? = null
 
     /** Set to true when the user is touching the seek bar to change the position. */
     private var scrubbing = false
@@ -136,8 +141,6 @@
 
     lateinit var logSeek: () -> Unit
 
-    fun getEnabled() = _data.enabled
-
     /**
      * Event indicating that the user has started interacting with the seek bar.
      */
@@ -189,6 +192,9 @@
 
     /**
      * Updates media information.
+     *
+     * This function makes a binder call, so it must happen on a worker thread.
+     *
      * @param mediaController controller for media session
      */
     @WorkerThread
@@ -232,6 +238,7 @@
         cancel?.run()
         cancel = null
         scrubbingChangeListener = null
+        enabledChangeListener = null
     }
 
     @WorkerThread
@@ -279,11 +286,26 @@
         }
     }
 
+    fun setEnabledChangeListener(listener: EnabledChangeListener) {
+        enabledChangeListener = listener
+    }
+
+    fun removeEnabledChangeListener(listener: EnabledChangeListener) {
+        if (listener == enabledChangeListener) {
+            enabledChangeListener = null
+        }
+    }
+
     /** Listener interface to be notified when the user starts or stops scrubbing. */
     interface ScrubbingChangeListener {
         fun onScrubbingChanged(scrubbing: Boolean)
     }
 
+    /** Listener interface to be notified when the seekbar's enabled status changes. */
+    interface EnabledChangeListener {
+        fun onEnabledChanged(enabled: Boolean)
+    }
+
     private class SeekBarChangeListener(
         val viewModel: SeekBarViewModel
     ) : SeekBar.OnSeekBarChangeListener {
diff --git a/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBar.java b/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBar.java
index 740ecff..72488f3 100644
--- a/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBar.java
+++ b/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBar.java
@@ -197,7 +197,6 @@
     private final Optional<Pip> mPipOptional;
     private final Optional<Recents> mRecentsOptional;
     private final DeviceConfigProxy mDeviceConfigProxy;
-    private final NavigationBarTransitions mNavigationBarTransitions;
     private final Optional<BackAnimation> mBackAnimation;
     private final Handler mHandler;
     private final NavigationBarOverlayController mNavbarOverlayController;
@@ -514,7 +513,6 @@
             InputMethodManager inputMethodManager,
             DeadZone deadZone,
             DeviceConfigProxy deviceConfigProxy,
-            NavigationBarTransitions navigationBarTransitions,
             Optional<BackAnimation> backAnimation) {
         super(navigationBarView);
         mFrame = navigationBarFrame;
@@ -539,7 +537,6 @@
         mRecentsOptional = recentsOptional;
         mDeadZone = deadZone;
         mDeviceConfigProxy = deviceConfigProxy;
-        mNavigationBarTransitions = navigationBarTransitions;
         mBackAnimation = backAnimation;
         mHandler = mainHandler;
         mNavbarOverlayController = navbarOverlayController;
@@ -564,7 +561,6 @@
     public void onInit() {
         // TODO: A great deal of this code should probably live in onViewAttached.
         // It should also has corresponding cleanup in onViewDetached.
-        mView.setBarTransitions(mNavigationBarTransitions);
         mView.setTouchHandler(mTouchHandler);
         mView.setNavBarMode(mNavBarMode);
         mView.updateRotationButton();
@@ -636,7 +632,7 @@
         mView.setOnVerticalChangedListener(this::onVerticalChanged);
         mView.setOnTouchListener(this::onNavigationTouch);
         if (mSavedState != null) {
-            getBarTransitions().getLightTransitionsController().restoreState(mSavedState);
+            mView.getLightTransitionsController().restoreState(mSavedState);
         }
         setNavigationIconHints(mNavigationIconHints);
         mView.setWindowVisible(isNavBarWindowVisible());
@@ -709,7 +705,8 @@
                 mView.getRotationButtonController();
         rotationButtonController.setRotationCallback(null);
         mView.setUpdateActiveTouchRegionsCallback(null);
-        getBarTransitions().destroy();
+        mView.getBarTransitions().destroy();
+        mView.getLightTransitionsController().destroy(mContext);
         mOverviewProxyService.removeCallback(mOverviewProxyListener);
         mBroadcastDispatcher.unregisterReceiver(mBroadcastReceiver);
         if (mOrientationHandle != null) {
@@ -735,7 +732,7 @@
         outState.putInt(EXTRA_APPEARANCE, mAppearance);
         outState.putInt(EXTRA_BEHAVIOR, mBehavior);
         outState.putBoolean(EXTRA_TRANSIENT_STATE, mTransientShown);
-        getBarTransitions().getLightTransitionsController().saveState(outState);
+        mView.getLightTransitionsController().saveState(outState);
     }
 
     /**
@@ -896,7 +893,7 @@
         pw.println("  mTransientShown=" + mTransientShown);
         pw.println("  mTransientShownFromGestureOnSystemBar="
                 + mTransientShownFromGestureOnSystemBar);
-        dumpBarTransitions(pw, "mNavigationBarView", getBarTransitions());
+        dumpBarTransitions(pw, "mNavigationBarView", mView.getBarTransitions());
         mView.dump(pw);
     }
 
@@ -1433,7 +1430,7 @@
         mLightBarController = lightBarController;
         if (mLightBarController != null) {
             mLightBarController.setNavigationBar(
-                    getBarTransitions().getLightTransitionsController());
+                    mView.getLightTransitionsController());
         }
     }
 
@@ -1475,7 +1472,7 @@
                 mCentralSurfacesOptionalLazy.get().map(CentralSurfaces::isDeviceInteractive)
                         .orElse(false)
                 && mNavigationBarWindowState != WINDOW_STATE_HIDDEN;
-        getBarTransitions().transitionTo(mTransitionMode, anim);
+        mView.getBarTransitions().transitionTo(mTransitionMode, anim);
     }
 
     public void disableAnimationsDuringHide(long delay) {
@@ -1495,11 +1492,11 @@
     }
 
     public NavigationBarTransitions getBarTransitions() {
-        return mNavigationBarTransitions;
+        return mView.getBarTransitions();
     }
 
     public void finishBarAnimations() {
-        getBarTransitions().finishAnimations();
+        mView.getBarTransitions().finishAnimations();
     }
 
     private WindowManager.LayoutParams getBarLayoutParams(int rotation) {
diff --git a/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarTransitions.java b/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarTransitions.java
index e625501..58e07db 100644
--- a/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarTransitions.java
+++ b/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarTransitions.java
@@ -31,19 +31,17 @@
 
 import com.android.systemui.Dependency;
 import com.android.systemui.R;
-import com.android.systemui.navigationbar.NavigationBarComponent.NavigationBarScope;
 import com.android.systemui.navigationbar.buttons.ButtonDispatcher;
+import com.android.systemui.plugins.statusbar.StatusBarStateController;
+import com.android.systemui.statusbar.CommandQueue;
 import com.android.systemui.statusbar.phone.BarTransitions;
 import com.android.systemui.statusbar.phone.LightBarTransitionsController;
+import com.android.systemui.statusbar.policy.KeyguardStateController;
 
 import java.io.PrintWriter;
 import java.util.ArrayList;
 import java.util.List;
 
-import javax.inject.Inject;
-
-/** */
-@NavigationBarScope
 public final class NavigationBarTransitions extends BarTransitions implements
         LightBarTransitionsController.DarkIntensityApplier {
 
@@ -83,13 +81,15 @@
         }
     };
 
-    @Inject
-    public NavigationBarTransitions(
-            NavigationBarView view,
-            LightBarTransitionsController.Factory lightBarTransitionsControllerFactory) {
+    public NavigationBarTransitions(NavigationBarView view, CommandQueue commandQueue) {
         super(view, R.drawable.nav_background);
         mView = view;
-        mLightTransitionsController = lightBarTransitionsControllerFactory.create(this);
+        mLightTransitionsController = new LightBarTransitionsController(
+                view.getContext(),
+                this,
+                commandQueue,
+                Dependency.get(KeyguardStateController.class),
+                Dependency.get(StatusBarStateController.class));
         mAllowAutoDimWallpaperNotVisible = view.getContext().getResources()
                 .getBoolean(R.bool.config_navigation_bar_enable_auto_dim_no_visible_wallpaper);
         mDarkIntensityListeners = new ArrayList();
@@ -127,7 +127,6 @@
                     Display.DEFAULT_DISPLAY);
         } catch (RemoteException e) {
         }
-        mLightTransitionsController.destroy();
     }
 
     @Override
diff --git a/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarView.java b/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarView.java
index 8878c2d..abff914 100644
--- a/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarView.java
+++ b/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarView.java
@@ -85,6 +85,7 @@
 import com.android.systemui.shared.system.ActivityManagerWrapper;
 import com.android.systemui.shared.system.QuickStepContract;
 import com.android.systemui.shared.system.WindowManagerWrapper;
+import com.android.systemui.statusbar.CommandQueue;
 import com.android.systemui.statusbar.phone.AutoHideController;
 import com.android.systemui.statusbar.phone.CentralSurfaces;
 import com.android.systemui.statusbar.phone.LightBarTransitionsController;
@@ -139,7 +140,7 @@
     private EdgeBackGestureHandler mEdgeBackGestureHandler;
     private final DeadZone mDeadZone;
     private boolean mDeadZoneConsuming = false;
-    private NavigationBarTransitions mBarTransitions;
+    private final NavigationBarTransitions mBarTransitions;
     @Nullable
     private AutoHideController mAutoHideController;
 
@@ -369,6 +370,7 @@
         mConfiguration.updateFrom(context.getResources().getConfiguration());
 
         mScreenPinningNotify = new ScreenPinningNotify(mContext);
+        mBarTransitions = new NavigationBarTransitions(this, Dependency.get(CommandQueue.class));
 
         mButtonDispatchers.put(R.id.back, new ButtonDispatcher(R.id.back));
         mButtonDispatchers.put(R.id.home, new ButtonDispatcher(R.id.home));
@@ -416,14 +418,14 @@
         }
     }
 
-    void setBarTransitions(NavigationBarTransitions navigationBarTransitions) {
-        mBarTransitions = navigationBarTransitions;
-    }
-
     public void setAutoHideController(AutoHideController autoHideController) {
         mAutoHideController = autoHideController;
     }
 
+    public NavigationBarTransitions getBarTransitions() {
+        return mBarTransitions;
+    }
+
     public LightBarTransitionsController getLightTransitionsController() {
         return mBarTransitions.getLightTransitionsController();
     }
diff --git a/packages/SystemUI/src/com/android/systemui/navigationbar/TaskbarDelegate.java b/packages/SystemUI/src/com/android/systemui/navigationbar/TaskbarDelegate.java
index 363baaa..cdc6b3b 100644
--- a/packages/SystemUI/src/com/android/systemui/navigationbar/TaskbarDelegate.java
+++ b/packages/SystemUI/src/com/android/systemui/navigationbar/TaskbarDelegate.java
@@ -264,7 +264,7 @@
             mWindowContext = null;
         }
         mAutoHideController.setNavigationBar(null);
-        mLightBarTransitionsController.destroy();
+        mLightBarTransitionsController.destroy(mContext);
         mLightBarController.setNavigationBar(null);
         mPipOptional.ifPresent(this::removePipExclusionBoundsChangeListener);
         mInitialized = false;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardStatusBarView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardStatusBarView.java
index 673c1a6..18877f9 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardStatusBarView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardStatusBarView.java
@@ -233,9 +233,6 @@
         LinearLayout.LayoutParams lp =
                 (LinearLayout.LayoutParams) mSystemIconsContainer.getLayoutParams();
 
-        int marginStart = getResources().getDimensionPixelSize(
-                R.dimen.system_icons_super_container_margin_start);
-
         // Use status_bar_padding_end to replace original
         // system_icons_super_container_avatarless_margin_end to prevent different end alignment
         // between PhoneStatusBarView and KeyguardStatusBarView
@@ -248,8 +245,7 @@
         // 1. status bar layout: mPadding(consider round_corner + privacy dot)
         // 2. icon container: R.dimen.status_bar_padding_end
 
-        if (marginEnd != lp.getMarginEnd() || marginStart != lp.getMarginStart()) {
-            lp.setMarginStart(marginStart);
+        if (marginEnd != lp.getMarginEnd()) {
             lp.setMarginEnd(marginEnd);
             mSystemIconsContainer.setLayoutParams(lp);
         }
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 16fddb42..b6ad9f7 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/LightBarTransitionsController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/LightBarTransitionsController.java
@@ -93,8 +93,7 @@
         mDisplayId = mContext.getDisplayId();
     }
 
-    /** Call to cleanup the LightBarTransitionsController when done with it. */
-    public void destroy() {
+    public void destroy(Context context) {
         mCommandQueue.removeCallback(this);
         mStatusBarStateController.removeCallback(this);
     }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/accessibility/floatingmenu/AccessibilityFloatingMenuTest.java b/packages/SystemUI/tests/src/com/android/systemui/accessibility/floatingmenu/AccessibilityFloatingMenuTest.java
index e027a2b7..558261b 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/accessibility/floatingmenu/AccessibilityFloatingMenuTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/accessibility/floatingmenu/AccessibilityFloatingMenuTest.java
@@ -87,6 +87,17 @@
         assertThat(mMenuView.isShowing()).isFalse();
     }
 
+    @Test
+    public void showMenuView_emptyTarget_notShow() {
+        final List<String> emptyTargets = new ArrayList<>();
+        doReturn(emptyTargets).when(mAccessibilityManager).getAccessibilityShortcutTargets(
+                anyInt());
+
+        mMenu.show();
+
+        assertThat(mMenuView.isShowing()).isFalse();
+    }
+
     @After
     public void tearDown() {
         mMenu.hide();
diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/MediaControlPanelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/media/MediaControlPanelTest.kt
index 33db993..4e130d1 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/media/MediaControlPanelTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/media/MediaControlPanelTest.kt
@@ -291,7 +291,7 @@
         seamlessButton = View(context)
         seamlessIcon = ImageView(context)
         seamlessText = TextView(context)
-        seekBar = SeekBar(context)
+        seekBar = SeekBar(context).also { it.id = R.id.media_progress_bar }
         settings = ImageButton(context)
         cancel = View(context)
         cancelText = TextView(context)
@@ -539,8 +539,8 @@
     }
 
     @Test
-    fun bind_seekBarDisabled_seekBarVisibilityIsSetToInvisible() {
-        whenever(seekBarViewModel.getEnabled()).thenReturn(false)
+    fun bind_seekBarDisabled_hasActions_seekBarVisibilityIsSetToInvisible() {
+        useRealConstraintSets()
 
         val icon = context.getDrawable(android.R.drawable.ic_media_play)
         val semanticActions = MediaButton(
@@ -550,21 +550,84 @@
         val state = mediaData.copy(semanticActions = semanticActions)
 
         player.attachPlayer(viewHolder)
+        getEnabledChangeListener().onEnabledChanged(enabled = false)
+
         player.bindPlayer(state, PACKAGE)
 
-        verify(expandedSet).setVisibility(R.id.media_progress_bar, ConstraintSet.INVISIBLE)
+        assertThat(expandedSet.getVisibility(seekBar.id)).isEqualTo(ConstraintSet.INVISIBLE)
     }
 
     @Test
     fun bind_seekBarDisabled_noActions_seekBarVisibilityIsSetToGone() {
-        whenever(seekBarViewModel.getEnabled()).thenReturn(false)
+        useRealConstraintSets()
+
+        val state = mediaData.copy(semanticActions = MediaButton())
+        player.attachPlayer(viewHolder)
+        getEnabledChangeListener().onEnabledChanged(enabled = false)
+
+        player.bindPlayer(state, PACKAGE)
+
+        assertThat(expandedSet.getVisibility(seekBar.id)).isEqualTo(ConstraintSet.GONE)
+    }
+
+    @Test
+    fun bind_seekBarEnabled_seekBarVisible() {
+        useRealConstraintSets()
+
+        val state = mediaData.copy(semanticActions = MediaButton())
+        player.attachPlayer(viewHolder)
+        getEnabledChangeListener().onEnabledChanged(enabled = true)
+
+        player.bindPlayer(state, PACKAGE)
+
+        assertThat(expandedSet.getVisibility(seekBar.id)).isEqualTo(ConstraintSet.VISIBLE)
+    }
+
+    @Test
+    fun seekBarChangesToEnabledAfterBind_seekBarChangesToVisible() {
+        useRealConstraintSets()
+
+        val state = mediaData.copy(semanticActions = MediaButton())
+        player.attachPlayer(viewHolder)
+        player.bindPlayer(state, PACKAGE)
+
+        getEnabledChangeListener().onEnabledChanged(enabled = true)
+
+        assertThat(expandedSet.getVisibility(seekBar.id)).isEqualTo(ConstraintSet.VISIBLE)
+    }
+
+    @Test
+    fun seekBarChangesToDisabledAfterBind_noActions_seekBarChangesToGone() {
+        useRealConstraintSets()
 
         val state = mediaData.copy(semanticActions = MediaButton())
 
         player.attachPlayer(viewHolder)
+        getEnabledChangeListener().onEnabledChanged(enabled = true)
         player.bindPlayer(state, PACKAGE)
 
-        verify(expandedSet).setVisibility(R.id.media_progress_bar, ConstraintSet.INVISIBLE)
+        getEnabledChangeListener().onEnabledChanged(enabled = false)
+
+        assertThat(expandedSet.getVisibility(seekBar.id)).isEqualTo(ConstraintSet.GONE)
+    }
+
+    @Test
+    fun seekBarChangesToDisabledAfterBind_hasActions_seekBarChangesToInvisible() {
+        useRealConstraintSets()
+
+        val icon = context.getDrawable(android.R.drawable.ic_media_play)
+        val semanticActions = MediaButton(
+            nextOrCustom = MediaAction(icon, Runnable {}, "next", null)
+        )
+        val state = mediaData.copy(semanticActions = semanticActions)
+
+        player.attachPlayer(viewHolder)
+        getEnabledChangeListener().onEnabledChanged(enabled = true)
+        player.bindPlayer(state, PACKAGE)
+
+        getEnabledChangeListener().onEnabledChanged(enabled = false)
+
+        assertThat(expandedSet.getVisibility(seekBar.id)).isEqualTo(ConstraintSet.INVISIBLE)
     }
 
     @Test
@@ -1317,4 +1380,24 @@
 
     private fun getScrubbingChangeListener(): SeekBarViewModel.ScrubbingChangeListener =
         withArgCaptor { verify(seekBarViewModel).setScrubbingChangeListener(capture()) }
+
+    private fun getEnabledChangeListener(): SeekBarViewModel.EnabledChangeListener =
+        withArgCaptor { verify(seekBarViewModel).setEnabledChangeListener(capture()) }
+
+    /**
+     *  Update our test to use real ConstraintSets instead of mocks.
+     *
+     *  Some item visibilities, such as the seekbar visibility, are dependent on other action's
+     *  visibilities. If we use mocks for the ConstraintSets, then action visibility changes are
+     *  just thrown away instead of being saved for reference later. This method sets us up to use
+     *  ConstraintSets so that we do save visibility changes.
+     *
+     *  TODO(b/229740380): Can/should we use real expanded and collapsed sets for all tests?
+     */
+    private fun useRealConstraintSets() {
+        expandedSet = ConstraintSet()
+        collapsedSet = ConstraintSet()
+        whenever(mediaViewController.expandedLayout).thenReturn(expandedSet)
+        whenever(mediaViewController.collapsedLayout).thenReturn(collapsedSet)
+    }
 }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/MediaViewControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/media/MediaViewControllerTest.kt
index b7d5ba1..604e1f3 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/media/MediaViewControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/media/MediaViewControllerTest.kt
@@ -12,6 +12,8 @@
 import org.junit.Before
 import org.junit.Test
 import org.junit.runner.RunWith
+import org.mockito.Mock
+import org.mockito.MockitoAnnotations
 
 /**
  * Tests for {@link MediaViewController}.
@@ -20,16 +22,25 @@
 @RunWith(AndroidTestingRunner::class)
 @TestableLooper.RunWithLooper
 class MediaViewControllerTest : SysuiTestCase() {
+    @Mock
+    private lateinit var logger: MediaViewLogger
+
     private val configurationController =
             com.android.systemui.statusbar.phone.ConfigurationControllerImpl(context)
     private val mediaHostStatesManager = MediaHostStatesManager()
-    private val mediaViewController =
-            MediaViewController(context, configurationController, mediaHostStatesManager)
+    private lateinit var mediaViewController: MediaViewController
     private val mediaHostStateHolder = MediaHost.MediaHostStateHolder()
     private var transitionLayout = TransitionLayout(context, /* attrs */ null, /* defStyleAttr */ 0)
 
     @Before
     fun setUp() {
+        MockitoAnnotations.initMocks(this)
+        mediaViewController = MediaViewController(
+                context,
+                configurationController,
+                mediaHostStatesManager,
+                logger
+        )
         mediaViewController.attach(transitionLayout, MediaViewController.TYPE.PLAYER)
     }
 
diff --git a/packages/SystemUI/tests/src/com/android/systemui/navigationbar/NavigationBarTest.java b/packages/SystemUI/tests/src/com/android/systemui/navigationbar/NavigationBarTest.java
index 4a740f6..f5b006d 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/navigationbar/NavigationBarTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/navigationbar/NavigationBarTest.java
@@ -205,9 +205,10 @@
         when(mNavigationBarView.getAccessibilityButton()).thenReturn(mAccessibilityButton);
         when(mNavigationBarView.getImeSwitchButton()).thenReturn(mImeSwitchButton);
         when(mNavigationBarView.getBackButton()).thenReturn(mBackButton);
+        when(mNavigationBarView.getBarTransitions()).thenReturn(mNavigationBarTransitions);
         when(mNavigationBarView.getRotationButtonController())
                 .thenReturn(mRotationButtonController);
-        when(mNavigationBarTransitions.getLightTransitionsController())
+        when(mNavigationBarView.getLightTransitionsController())
                 .thenReturn(mLightBarTransitionsController);
         when(mStatusBarKeyguardViewManager.isNavBarVisible()).thenReturn(true);
         setupSysuiDependency();
@@ -458,7 +459,6 @@
                 mInputMethodManager,
                 mDeadZone,
                 mDeviceConfigProxyFake,
-                mNavigationBarTransitions,
                 Optional.of(mock(BackAnimation.class))));
     }
 
diff --git a/packages/SystemUI/tests/src/com/android/systemui/navigationbar/NavigationBarTransitionsTest.java b/packages/SystemUI/tests/src/com/android/systemui/navigationbar/NavigationBarTransitionsTest.java
index 084eca8..6a2a78b 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/navigationbar/NavigationBarTransitionsTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/navigationbar/NavigationBarTransitionsTest.java
@@ -21,6 +21,7 @@
 import static org.mockito.ArgumentMatchers.any;
 import static org.mockito.ArgumentMatchers.anyInt;
 import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.spy;
 import static org.mockito.Mockito.when;
 
@@ -36,8 +37,8 @@
 import com.android.systemui.navigationbar.gestural.EdgeBackGestureHandler;
 import com.android.systemui.plugins.statusbar.StatusBarStateController;
 import com.android.systemui.recents.OverviewProxyService;
+import com.android.systemui.statusbar.CommandQueue;
 import com.android.systemui.statusbar.phone.BarTransitions;
-import com.android.systemui.statusbar.phone.LightBarTransitionsController;
 import com.android.systemui.statusbar.policy.KeyguardStateController;
 
 import org.junit.Before;
@@ -52,10 +53,6 @@
 public class NavigationBarTransitionsTest extends SysuiTestCase {
 
     @Mock
-    LightBarTransitionsController.Factory mLightBarTransitionsFactory;
-    @Mock
-    LightBarTransitionsController mLightBarTransitions;
-    @Mock
     EdgeBackGestureHandler.Factory mEdgeBackGestureHandlerFactory;
     @Mock
     EdgeBackGestureHandler mEdgeBackGestureHandler;
@@ -79,11 +76,10 @@
                 .when(mDependency.injectMockDependency(NavigationModeController.class))
                 .getCurrentUserContext();
 
-        when(mLightBarTransitionsFactory.create(any())).thenReturn(mLightBarTransitions);
         NavigationBarView navBar = spy(new NavigationBarView(mContext, null));
         when(navBar.getCurrentView()).thenReturn(navBar);
         when(navBar.findViewById(anyInt())).thenReturn(navBar);
-        mTransitions = new NavigationBarTransitions(navBar, mLightBarTransitionsFactory);
+        mTransitions = new NavigationBarTransitions(navBar, mock(CommandQueue.class));
     }
 
     @Test
diff --git a/services/core/java/com/android/server/am/AppErrors.java b/services/core/java/com/android/server/am/AppErrors.java
index 97dd323..36c40a1 100644
--- a/services/core/java/com/android/server/am/AppErrors.java
+++ b/services/core/java/com/android/server/am/AppErrors.java
@@ -577,12 +577,14 @@
             mPackageWatchdog.onPackageFailure(r.getPackageListWithVersionCode(),
                     PackageWatchdog.FAILURE_REASON_APP_CRASH);
 
-            mService.mProcessList.noteAppKill(r, (crashInfo != null
-                      && "Native crash".equals(crashInfo.exceptionClassName))
-                      ? ApplicationExitInfo.REASON_CRASH_NATIVE
-                      : ApplicationExitInfo.REASON_CRASH,
-                      ApplicationExitInfo.SUBREASON_UNKNOWN,
-                    "crash");
+            synchronized (mService) {
+                mService.mProcessList.noteAppKill(r, (crashInfo != null
+                          && "Native crash".equals(crashInfo.exceptionClassName))
+                          ? ApplicationExitInfo.REASON_CRASH_NATIVE
+                          : ApplicationExitInfo.REASON_CRASH,
+                          ApplicationExitInfo.SUBREASON_UNKNOWN,
+                        "crash");
+            }
         }
 
         final int relaunchReason = r != null
diff --git a/services/core/java/com/android/server/display/AutomaticBrightnessController.java b/services/core/java/com/android/server/display/AutomaticBrightnessController.java
index 54e83ec..4bba686 100644
--- a/services/core/java/com/android/server/display/AutomaticBrightnessController.java
+++ b/services/core/java/com/android/server/display/AutomaticBrightnessController.java
@@ -46,6 +46,7 @@
 import com.android.internal.display.BrightnessSynchronizer;
 import com.android.internal.os.BackgroundThread;
 import com.android.server.EventLogTags;
+import com.android.server.display.DisplayPowerController.BrightnessEvent;
 
 import java.io.PrintWriter;
 
@@ -147,6 +148,9 @@
     // The currently accepted nominal ambient light level.
     private float mAmbientLux;
 
+    // The last ambient lux value prior to passing the darkening or brightening threshold.
+    private float mPreThresholdLux;
+
     // True if mAmbientLux holds a valid value.
     private boolean mAmbientLuxValid;
 
@@ -154,6 +158,9 @@
     private float mAmbientBrighteningThreshold;
     private float mAmbientDarkeningThreshold;
 
+    // The last brightness value prior to passing the darkening or brightening threshold.
+    private float mPreThresholdBrightness;
+
     // The screen brightness threshold at which to brighten or darken the screen.
     private float mScreenBrighteningThreshold;
     private float mScreenDarkeningThreshold;
@@ -325,6 +332,21 @@
     }
 
     public float getAutomaticScreenBrightness() {
+        return getAutomaticScreenBrightness(null);
+    }
+
+    float getAutomaticScreenBrightness(BrightnessEvent brightnessEvent) {
+        if (brightnessEvent != null) {
+            brightnessEvent.lux =
+                    mAmbientLuxValid ? mAmbientLux : PowerManager.BRIGHTNESS_INVALID_FLOAT;
+            brightnessEvent.preThresholdLux = mPreThresholdLux;
+            brightnessEvent.preThresholdBrightness = mPreThresholdBrightness;
+            brightnessEvent.recommendedBrightness = mScreenAutoBrightness;
+            brightnessEvent.flags |= (!mAmbientLuxValid ? BrightnessEvent.FLAG_INVALID_LUX : 0)
+                    | (mDisplayPolicy == DisplayPowerRequest.POLICY_DOZE
+                        ? BrightnessEvent.FLAG_DOZE_SCALE : 0);
+        }
+
         if (!mAmbientLuxValid) {
             return PowerManager.BRIGHTNESS_INVALID_FLOAT;
         }
@@ -506,6 +528,8 @@
         pw.println("  mCurrentLightSensorRate=" + mCurrentLightSensorRate);
         pw.println("  mAmbientLux=" + mAmbientLux);
         pw.println("  mAmbientLuxValid=" + mAmbientLuxValid);
+        pw.println("  mPreThesholdLux=" + mPreThresholdLux);
+        pw.println("  mPreThesholdBrightness=" + mPreThresholdBrightness);
         pw.println("  mAmbientBrighteningThreshold=" + mAmbientBrighteningThreshold);
         pw.println("  mAmbientDarkeningThreshold=" + mAmbientDarkeningThreshold);
         pw.println("  mScreenBrighteningThreshold=" + mScreenBrighteningThreshold);
@@ -574,7 +598,11 @@
         } else if (mLightSensorEnabled) {
             mLightSensorEnabled = false;
             mAmbientLuxValid = !mResetAmbientLuxAfterWarmUpConfig;
+            if (!mAmbientLuxValid) {
+                mPreThresholdLux = PowerManager.BRIGHTNESS_INVALID_FLOAT;
+            }
             mScreenAutoBrightness = PowerManager.BRIGHTNESS_INVALID_FLOAT;
+            mPreThresholdBrightness = PowerManager.BRIGHTNESS_INVALID_FLOAT;
             mRecentLightSamples = 0;
             mAmbientLightRingBuffer.clear();
             mCurrentLightSensorRate = -1;
@@ -790,6 +818,7 @@
                 || (slowAmbientLux <= mAmbientDarkeningThreshold
                         && fastAmbientLux <= mAmbientDarkeningThreshold
                         && nextDarkenTransition <= time)) {
+            mPreThresholdLux = mAmbientLux;
             setAmbientLux(fastAmbientLux);
             if (mLoggingEnabled) {
                 Slog.d(TAG, "updateAmbientLux: "
@@ -834,11 +863,11 @@
         // If screenAutoBrightness is set, we should have screen{Brightening,Darkening}Threshold,
         // in which case we ignore the new screen brightness if it doesn't differ enough from the
         // previous one.
-        if (!Float.isNaN(mScreenAutoBrightness)
-                && !isManuallySet
+        boolean withinThreshold = !Float.isNaN(mScreenAutoBrightness)
                 && newScreenAutoBrightness > mScreenDarkeningThreshold
-                && newScreenAutoBrightness < mScreenBrighteningThreshold
-                && currentBrightnessWithinAllowedRange) {
+                && newScreenAutoBrightness < mScreenBrighteningThreshold;
+
+        if (withinThreshold && !isManuallySet && currentBrightnessWithinAllowedRange) {
             if (mLoggingEnabled) {
                 Slog.d(TAG, "ignoring newScreenAutoBrightness: "
                         + mScreenDarkeningThreshold + " < " + newScreenAutoBrightness
@@ -853,6 +882,9 @@
                         + "mScreenAutoBrightness=" + mScreenAutoBrightness + ", "
                         + "newScreenAutoBrightness=" + newScreenAutoBrightness);
             }
+            if (!withinThreshold) {
+                mPreThresholdBrightness = mScreenAutoBrightness;
+            }
             mScreenAutoBrightness = newScreenAutoBrightness;
             mScreenBrighteningThreshold = clampScreenBrightness(
                     mScreenBrightnessThresholds.getBrighteningThreshold(newScreenAutoBrightness));
diff --git a/services/core/java/com/android/server/display/DisplayPowerController.java b/services/core/java/com/android/server/display/DisplayPowerController.java
index 67268e2..698f41f 100644
--- a/services/core/java/com/android/server/display/DisplayPowerController.java
+++ b/services/core/java/com/android/server/display/DisplayPowerController.java
@@ -216,9 +216,6 @@
 
     private final float mScreenBrightnessDefault;
 
-    // Previously logged screen brightness. Used for autobrightness event dumpsys.
-    private float mPreviousScreenBrightness = Float.NaN;
-
     // The minimum allowed brightness while in VR.
     private final float mScreenBrightnessForVrRangeMinimum;
 
@@ -394,8 +391,11 @@
 
     private final Runnable mOnBrightnessChangeRunnable;
 
-    // Used for keeping record in dumpsys for when and to which brightness auto adaptions were made.
-    private RingBuffer<AutobrightnessEvent> mAutobrightnessEventRingBuffer;
+    private final BrightnessEvent mLastBrightnessEvent;
+    private final BrightnessEvent mTempBrightnessEvent;
+
+    // Keeps a record of brightness changes for dumpsys.
+    private RingBuffer<BrightnessEvent> mBrightnessEventRingBuffer;
 
     // A record of state for skipping brightness ramps.
     private int mSkipRampState = RAMP_STATE_SKIP_NONE;
@@ -455,6 +455,8 @@
     // PowerManager.BRIGHTNESS_INVALID_FLOAT when there's no temporary adjustment set.
     private float mTemporaryAutoBrightnessAdjustment;
 
+    private boolean mIsRbcActive;
+
     // Animators.
     private ObjectAnimator mColorFadeOnAnimator;
     private ObjectAnimator mColorFadeOffAnimator;
@@ -481,6 +483,8 @@
         mUniqueDisplayId = logicalDisplay.getPrimaryDisplayDeviceLocked().getUniqueId();
         mDisplayStatsId = mUniqueDisplayId.hashCode();
         mHandler = new DisplayControllerHandler(handler.getLooper());
+        mLastBrightnessEvent = new BrightnessEvent(mDisplayId);
+        mTempBrightnessEvent = new BrightnessEvent(mDisplayId);
 
         if (mDisplayId == Display.DEFAULT_DISPLAY) {
             mBatteryStats = BatteryStatsService.getService();
@@ -634,8 +638,8 @@
         for (int i = 0; i < mNitsRange.length; i++) {
             adjustedNits[i] = mCdsi.getReduceBrightColorsAdjustedBrightnessNits(mNitsRange[i]);
         }
-        mAutomaticBrightnessController.recalculateSplines(mCdsi.isReduceBrightColorsActivated(),
-                adjustedNits);
+        mIsRbcActive = mCdsi.isReduceBrightColorsActivated();
+        mAutomaticBrightnessController.recalculateSplines(mIsRbcActive, adjustedNits);
 
 
         // If rbc is turned on, off or there is a change in strength, we want to reset the short
@@ -991,8 +995,8 @@
                     mDisplayDeviceConfig.getAmbientHorizonShort(),
                     mDisplayDeviceConfig.getAmbientHorizonLong());
 
-            mAutobrightnessEventRingBuffer =
-                    new RingBuffer<>(AutobrightnessEvent.class, RINGBUFFER_MAX);
+            mBrightnessEventRingBuffer =
+                    new RingBuffer<>(BrightnessEvent.class, RINGBUFFER_MAX);
         } else {
             mUseSoftwareAutoBrightnessConfig = false;
         }
@@ -1088,6 +1092,7 @@
         boolean mustInitialize = false;
         int brightnessAdjustmentFlags = 0;
         mBrightnessReasonTemp.set(null);
+        mTempBrightnessEvent.reset();
         synchronized (mLock) {
             if (mStopped) {
                 return;
@@ -1314,7 +1319,8 @@
         if (Float.isNaN(brightnessState)) {
             float newAutoBrightnessAdjustment = autoBrightnessAdjustment;
             if (autoBrightnessEnabled) {
-                brightnessState = mAutomaticBrightnessController.getAutomaticScreenBrightness();
+                brightnessState = mAutomaticBrightnessController.getAutomaticScreenBrightness(
+                        mTempBrightnessEvent);
                 newAutoBrightnessAdjustment =
                         mAutomaticBrightnessController.getAutomaticScreenBrightnessAdjustment();
             }
@@ -1376,6 +1382,7 @@
         // we broadcast this change through setting.
         final float unthrottledBrightnessState = brightnessState;
         if (mBrightnessThrottler.isThrottled()) {
+            mTempBrightnessEvent.thermalMax = mBrightnessThrottler.getBrightnessCap();
             brightnessState = Math.min(brightnessState, mBrightnessThrottler.getBrightnessCap());
             mBrightnessReasonTemp.addModifier(BrightnessReason.MODIFIER_THROTTLED);
             if (!mAppliedThrottling) {
@@ -1567,13 +1574,35 @@
             Slog.v(TAG, "Brightness [" + brightnessState + "] manual adjustment.");
         }
 
-        // Add any automatic changes to autobrightness ringbuffer for dumpsys.
-        if (mBrightnessReason.reason == BrightnessReason.REASON_AUTOMATIC
-                && !BrightnessSynchronizer.floatEquals(
-                        mPreviousScreenBrightness, brightnessState)) {
-            mPreviousScreenBrightness = brightnessState;
-            mAutobrightnessEventRingBuffer.append(new AutobrightnessEvent(
-                    System.currentTimeMillis(), brightnessState));
+
+        // Log brightness events when a detail of significance has changed. Generally this is the
+        // brightness itself changing, but also includes data like HBM cap, thermal throttling
+        // brightness cap, RBC state, etc.
+        mTempBrightnessEvent.time = System.currentTimeMillis();
+        mTempBrightnessEvent.brightness = brightnessState;
+        mTempBrightnessEvent.reason.set(mBrightnessReason);
+        mTempBrightnessEvent.hbmMax = mHbmController.getCurrentBrightnessMax();
+        mTempBrightnessEvent.hbmMode = mHbmController.getHighBrightnessMode();
+        mTempBrightnessEvent.flags |= (mIsRbcActive ? BrightnessEvent.FLAG_RBC : 0);
+        // Temporary is what we use during slider interactions. We avoid logging those so that
+        // we don't spam logcat when the slider is being used.
+        boolean tempToTempTransition =
+                mTempBrightnessEvent.reason.reason == BrightnessReason.REASON_TEMPORARY
+                && mLastBrightnessEvent.reason.reason == BrightnessReason.REASON_TEMPORARY;
+        if ((!mTempBrightnessEvent.equalsMainData(mLastBrightnessEvent) && !tempToTempTransition)
+                || brightnessAdjustmentFlags != 0) {
+            mLastBrightnessEvent.copyFrom(mTempBrightnessEvent);
+            BrightnessEvent newEvent = new BrightnessEvent(mTempBrightnessEvent);
+
+            // Adjustment flags (and user-set flag) only get added after the equality checks since
+            // they are transient.
+            newEvent.adjustmentFlags = brightnessAdjustmentFlags;
+            newEvent.flags |= (userSetBrightnessChanged ? BrightnessEvent.FLAG_USER_SET : 0);
+            Slog.i(TAG, newEvent.toString(/* includeTime= */ false));
+
+            if (mBrightnessEventRingBuffer != null) {
+                mBrightnessEventRingBuffer.append(newEvent);
+            }
         }
 
         // Update display white-balance.
@@ -2482,6 +2511,7 @@
         pw.println("  mPendingScreenOff=" + mPendingScreenOff);
         pw.println("  mReportedToPolicy="
                 + reportedToPolicyToString(mReportedScreenStateToPolicy));
+        pw.println("  mIsRbcActive=" + mIsRbcActive);
 
         if (mScreenBrightnessRampAnimator != null) {
             pw.println("  mScreenBrightnessRampAnimator.isAnimating()="
@@ -2503,7 +2533,7 @@
 
         if (mAutomaticBrightnessController != null) {
             mAutomaticBrightnessController.dump(pw);
-            dumpAutobrightnessEvents(pw);
+            dumpBrightnessEvents(pw);
         }
 
         if (mHbmController != null) {
@@ -2560,16 +2590,16 @@
         }
     }
 
-    private void dumpAutobrightnessEvents(PrintWriter pw) {
-        int size = mAutobrightnessEventRingBuffer.size();
+    private void dumpBrightnessEvents(PrintWriter pw) {
+        int size = mBrightnessEventRingBuffer.size();
         if (size < 1) {
             pw.println("No Automatic Brightness Adjustments");
             return;
         }
 
         pw.println("Automatic Brightness Adjustments Last " + size + " Events: ");
-        AutobrightnessEvent[] eventArray = mAutobrightnessEventRingBuffer.toArray();
-        for (int i = 0; i < mAutobrightnessEventRingBuffer.size(); i++) {
+        BrightnessEvent[] eventArray = mBrightnessEventRingBuffer.toArray();
+        for (int i = 0; i < mBrightnessEventRingBuffer.size(); i++) {
             pw.println("  " + eventArray[i].toString());
         }
     }
@@ -2646,18 +2676,115 @@
         }
     }
 
-    private static class AutobrightnessEvent {
-        final long mTime;
-        final float mBrightness;
+    class BrightnessEvent {
+        static final int FLAG_RBC = 0x1;
+        static final int FLAG_INVALID_LUX = 0x2;
+        static final int FLAG_DOZE_SCALE = 0x3;
+        static final int FLAG_USER_SET = 0x4;
 
-        AutobrightnessEvent(long time, float brightness) {
-            mTime = time;
-            mBrightness = brightness;
+        public final BrightnessReason reason = new BrightnessReason();
+
+        public int displayId;
+        public float lux;
+        public float preThresholdLux;
+        public long time;
+        public float brightness;
+        public float recommendedBrightness;
+        public float preThresholdBrightness;
+        public float hbmMax;
+        public float thermalMax;
+        public int hbmMode;
+        public int flags;
+        public int adjustmentFlags;
+
+        BrightnessEvent(BrightnessEvent that) {
+            copyFrom(that);
+        }
+
+        BrightnessEvent(int displayId) {
+            this.displayId = displayId;
+            reset();
+        }
+
+        void copyFrom(BrightnessEvent that) {
+            displayId = that.displayId;
+            time = that.time;
+            lux = that.lux;
+            preThresholdLux = that.preThresholdLux;
+            brightness = that.brightness;
+            recommendedBrightness = that.recommendedBrightness;
+            preThresholdBrightness = that.preThresholdBrightness;
+            hbmMax = that.hbmMax;
+            thermalMax = that.thermalMax;
+            flags = that.flags;
+            hbmMode = that.hbmMode;
+            reason.set(that.reason);
+            adjustmentFlags = that.adjustmentFlags;
+        }
+
+        void reset() {
+            time = SystemClock.uptimeMillis();
+            brightness = PowerManager.BRIGHTNESS_INVALID_FLOAT;
+            recommendedBrightness = PowerManager.BRIGHTNESS_INVALID_FLOAT;
+            lux = 0;
+            preThresholdLux = 0;
+            preThresholdBrightness = PowerManager.BRIGHTNESS_INVALID_FLOAT;
+            hbmMax = PowerManager.BRIGHTNESS_MAX;
+            thermalMax = PowerManager.BRIGHTNESS_MAX;
+            flags = 0;
+            hbmMode = BrightnessInfo.HIGH_BRIGHTNESS_MODE_OFF;
+            reason.set(null);
+            adjustmentFlags = 0;
+        }
+
+        boolean equalsMainData(BrightnessEvent that) {
+            // This equals comparison purposefully ignores time since it is regularly changing and
+            // we don't want to log a brightness event just because the time changed.
+            return displayId == that.displayId
+                    && Float.floatToRawIntBits(brightness)
+                        == Float.floatToRawIntBits(that.brightness)
+                    && Float.floatToRawIntBits(recommendedBrightness)
+                        == Float.floatToRawIntBits(that.recommendedBrightness)
+                    && Float.floatToRawIntBits(preThresholdBrightness)
+                        == Float.floatToRawIntBits(that.preThresholdBrightness)
+                    && Float.floatToRawIntBits(lux) == Float.floatToRawIntBits(that.lux)
+                    && Float.floatToRawIntBits(preThresholdLux)
+                        == Float.floatToRawIntBits(that.preThresholdLux)
+                    && Float.floatToRawIntBits(hbmMax) == Float.floatToRawIntBits(that.hbmMax)
+                    && hbmMode == that.hbmMode
+                    && Float.floatToRawIntBits(thermalMax)
+                        == Float.floatToRawIntBits(that.thermalMax)
+                    && flags == that.flags
+                    && adjustmentFlags == that.adjustmentFlags
+                    && reason.equals(that.reason);
+        }
+
+        public String toString(boolean includeTime) {
+            return (includeTime ? TimeUtils.formatForLogging(time) + " - " : "")
+                    + "BrightnessEvent: "
+                    + "disp=" + displayId
+                    + ", brt=" + brightness + ((flags & FLAG_USER_SET) != 0 ? "(user_set)" : "")
+                    + ", rcmdBrt=" + recommendedBrightness
+                    + ", preBrt=" + preThresholdBrightness
+                    + ", lux=" + lux
+                    + ", preLux=" + preThresholdLux
+                    + ", hbmMax=" + hbmMax
+                    + ", hbmMode=" + BrightnessInfo.hbmToString(hbmMode)
+                    + ", thrmMax=" + thermalMax
+                    + ", flags=" + flagsToString()
+                    + ", reason=" + reason.toString(adjustmentFlags);
         }
 
         @Override
         public String toString() {
-            return TimeUtils.formatForLogging(mTime) + " - Brightness: " + mBrightness;
+            return toString(/* includeTime */ true);
+        }
+
+        private String flagsToString() {
+            return ((flags & FLAG_USER_SET) != 0 ? "user_set " : "")
+                    + ((flags & FLAG_RBC) != 0 ? "rbc " : "")
+                    + ((flags & FLAG_INVALID_LUX) != 0 ? "invalid_lux " : "")
+                    + ((flags & FLAG_DOZE_SCALE) != 0 ? "doze_scale " : "");
         }
     }
 
diff --git a/services/core/java/com/android/server/inputmethod/InputMethodBindingController.java b/services/core/java/com/android/server/inputmethod/InputMethodBindingController.java
index 0de523c..c4ff4ac 100644
--- a/services/core/java/com/android/server/inputmethod/InputMethodBindingController.java
+++ b/services/core/java/com/android/server/inputmethod/InputMethodBindingController.java
@@ -313,6 +313,7 @@
                             mSupportsStylusHw);
                     mService.scheduleNotifyImeUidToAudioService(mCurMethodUid);
                     mService.reRequestCurrentClientSessionLocked();
+                    mService.performOnCreateInlineSuggestionsRequestLocked();
                 }
 
                 // reset Handwriting event receiver.
diff --git a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
index 3c31405..bcebcb4 100644
--- a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
+++ b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
@@ -286,6 +286,30 @@
     @NonNull
     private final Set<String> mNonPreemptibleInputMethods;
 
+    private static final class CreateInlineSuggestionsRequest {
+        @NonNull final InlineSuggestionsRequestInfo mRequestInfo;
+        @NonNull final IInlineSuggestionsRequestCallback mCallback;
+        @NonNull final String mPackageName;
+
+        CreateInlineSuggestionsRequest(
+                @NonNull InlineSuggestionsRequestInfo requestInfo,
+                @NonNull IInlineSuggestionsRequestCallback callback,
+                @NonNull String packageName) {
+            mRequestInfo = requestInfo;
+            mCallback = callback;
+            mPackageName = packageName;
+        }
+    }
+
+    /**
+     * If a request to create inline autofill suggestions comes in while the IME is unbound
+     * due to {@link #mPreventImeStartupUnlessTextEditor}, this is where it is stored, so
+     * that it may be fulfilled once the IME rebinds.
+     */
+    @GuardedBy("ImfLock.class")
+    @Nullable
+    private CreateInlineSuggestionsRequest mPendingInlineSuggestionsRequest;
+
     @UserIdInt
     private int mLastSwitchUserId;
 
@@ -2137,16 +2161,24 @@
     private void onCreateInlineSuggestionsRequestLocked(@UserIdInt int userId,
             InlineSuggestionsRequestInfo requestInfo, IInlineSuggestionsRequestCallback callback,
             boolean touchExplorationEnabled) {
+        clearPendingInlineSuggestionsRequestLocked();
         final InputMethodInfo imi = mMethodMap.get(getSelectedMethodIdLocked());
         try {
-            IInputMethodInvoker curMethod = getCurMethodLocked();
-            if (userId == mSettings.getCurrentUserId() && curMethod != null
+            if (userId == mSettings.getCurrentUserId()
                     && imi != null && isInlineSuggestionsEnabled(imi, touchExplorationEnabled)) {
-                final IInlineSuggestionsRequestCallback callbackImpl =
-                        new InlineSuggestionsRequestCallbackDecorator(callback,
-                                imi.getPackageName(), mCurTokenDisplayId, getCurTokenLocked(),
-                                this);
-                curMethod.onCreateInlineSuggestionsRequest(requestInfo, callbackImpl);
+                mPendingInlineSuggestionsRequest = new CreateInlineSuggestionsRequest(
+                        requestInfo, callback, imi.getPackageName());
+                if (getCurMethodLocked() != null) {
+                    // In the normal case when the IME is connected, we can make the request here.
+                    performOnCreateInlineSuggestionsRequestLocked();
+                } else {
+                    // Otherwise, the next time the IME connection is established,
+                    // InputMethodBindingController.mMainConnection#onServiceConnected() will call
+                    // into #performOnCreateInlineSuggestionsRequestLocked() to make the request.
+                    if (DEBUG) {
+                        Slog.d(TAG, "IME not connected. Delaying inline suggestions request.");
+                    }
+                }
             } else {
                 callback.onInlineSuggestionsUnsupported();
             }
@@ -2155,6 +2187,34 @@
         }
     }
 
+    @GuardedBy("ImfLock.class")
+    void performOnCreateInlineSuggestionsRequestLocked() {
+        if (mPendingInlineSuggestionsRequest == null) {
+            return;
+        }
+        IInputMethodInvoker curMethod = getCurMethodLocked();
+        if (DEBUG) {
+            Slog.d(TAG, "Performing onCreateInlineSuggestionsRequest. mCurMethod = " + curMethod);
+        }
+        if (curMethod != null) {
+            final IInlineSuggestionsRequestCallback callback =
+                    new InlineSuggestionsRequestCallbackDecorator(
+                            mPendingInlineSuggestionsRequest.mCallback,
+                            mPendingInlineSuggestionsRequest.mPackageName,
+                            mCurTokenDisplayId, getCurTokenLocked(), this);
+            curMethod.onCreateInlineSuggestionsRequest(
+                    mPendingInlineSuggestionsRequest.mRequestInfo, callback);
+        } else {
+            Slog.w(TAG, "No IME connected! Abandoning inline suggestions creation request.");
+        }
+        clearPendingInlineSuggestionsRequestLocked();
+    }
+
+    @GuardedBy("ImfLock.class")
+    private void clearPendingInlineSuggestionsRequestLocked() {
+        mPendingInlineSuggestionsRequest = null;
+    }
+
     private static boolean isInlineSuggestionsEnabled(InputMethodInfo imi,
             boolean touchExplorationEnabled) {
         return imi.isInlineSuggestionsEnabled()
diff --git a/services/core/java/com/android/server/location/contexthub/ContextHubService.java b/services/core/java/com/android/server/location/contexthub/ContextHubService.java
index de8e06a..111621d 100644
--- a/services/core/java/com/android/server/location/contexthub/ContextHubService.java
+++ b/services/core/java/com/android/server/location/contexthub/ContextHubService.java
@@ -1058,31 +1058,35 @@
         }
 
         int msgVersion = 0;
-        int callbacksCount = mCallbacksList.beginBroadcast();
-        if (DEBUG_LOG_ENABLED) {
-            Log.v(TAG, "Sending message " + msgType + " version " + msgVersion + " from hubHandle "
-                    + contextHubHandle + ", appInstance " + appInstance + ", callBackCount "
-                    + callbacksCount);
-        }
-
-        if (callbacksCount < 1) {
+        // Synchronize access to mCallbacksList to prevent more than one outstanding broadcast as
+        // that will cause a crash.
+        synchronized (mCallbacksList) {
+            int callbacksCount = mCallbacksList.beginBroadcast();
             if (DEBUG_LOG_ENABLED) {
-                Log.v(TAG, "No message callbacks registered.");
+                Log.v(TAG, "Sending message " + msgType + " version " + msgVersion
+                        + " from hubHandle " + contextHubHandle + ", appInstance " + appInstance
+                        + ", callBackCount " + callbacksCount);
             }
-            return 0;
-        }
 
-        ContextHubMessage msg = new ContextHubMessage(msgType, msgVersion, data);
-        for (int i = 0; i < callbacksCount; ++i) {
-            IContextHubCallback callback = mCallbacksList.getBroadcastItem(i);
-            try {
-                callback.onMessageReceipt(contextHubHandle, appInstance, msg);
-            } catch (RemoteException e) {
-                Log.i(TAG, "Exception (" + e + ") calling remote callback (" + callback + ").");
-                continue;
+            if (callbacksCount < 1) {
+                if (DEBUG_LOG_ENABLED) {
+                    Log.v(TAG, "No message callbacks registered.");
+                }
+                return 0;
             }
+
+            ContextHubMessage msg = new ContextHubMessage(msgType, msgVersion, data);
+            for (int i = 0; i < callbacksCount; ++i) {
+                IContextHubCallback callback = mCallbacksList.getBroadcastItem(i);
+                try {
+                    callback.onMessageReceipt(contextHubHandle, appInstance, msg);
+                } catch (RemoteException e) {
+                    Log.i(TAG, "Exception (" + e + ") calling remote callback (" + callback + ").");
+                    continue;
+                }
+            }
+            mCallbacksList.finishBroadcast();
         }
-        mCallbacksList.finishBroadcast();
         return 0;
     }
 
diff --git a/telephony/java/android/telephony/CarrierConfigManager.java b/telephony/java/android/telephony/CarrierConfigManager.java
index daa7f29..09d3a0d 100644
--- a/telephony/java/android/telephony/CarrierConfigManager.java
+++ b/telephony/java/android/telephony/CarrierConfigManager.java
@@ -176,7 +176,7 @@
      * This flag specifies whether VoLTE availability is based on provisioning. By default this is
      * false.
      * Used for UCE to determine if EAB provisioning checks should be based on provisioning.
-     * @deprecated Use {@link Ims#KEY_MMTEL_REQUIRES_PROVISIONING_BUNDLE} instead.
+     * @deprecated Use {@link Ims#KEY_CARRIER_RCS_PROVISIONING_REQUIRED_BOOL} instead.
      */
     @Deprecated
     public static final String
diff --git a/telephony/java/android/telephony/ims/ImsRcsManager.java b/telephony/java/android/telephony/ims/ImsRcsManager.java
index 3415868..e00ea0e 100644
--- a/telephony/java/android/telephony/ims/ImsRcsManager.java
+++ b/telephony/java/android/telephony/ims/ImsRcsManager.java
@@ -18,6 +18,7 @@
 
 import android.Manifest;
 import android.annotation.CallbackExecutor;
+import android.annotation.IntDef;
 import android.annotation.NonNull;
 import android.annotation.RequiresFeature;
 import android.annotation.RequiresPermission;
@@ -43,6 +44,8 @@
 import com.android.internal.telephony.IIntegerConsumer;
 import com.android.internal.telephony.ITelephony;
 
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
 import java.util.HashMap;
 import java.util.Map;
 import java.util.Objects;
@@ -87,6 +90,46 @@
             "android.telephony.ims.action.SHOW_CAPABILITY_DISCOVERY_OPT_IN";
 
     /**
+     * This carrier supports User Capability Exchange as, defined by the framework using a
+     * presence server. If set, the RcsFeature should support capability exchange. If not set, this
+     * RcsFeature should not publish capabilities or service capability requests.
+     * @hide
+     */
+    @Retention(RetentionPolicy.SOURCE)
+    @IntDef(prefix = "CAPABILITY_TYPE_", flag = true, value = {
+            CAPABILITY_TYPE_NONE,
+            CAPABILITY_TYPE_OPTIONS_UCE,
+            CAPABILITY_TYPE_PRESENCE_UCE
+    })
+    public @interface RcsImsCapabilityFlag {}
+
+    /**
+     * Undefined capability type for initialization
+     */
+    public static final int CAPABILITY_TYPE_NONE = 0;
+
+    /**
+     * This carrier supports User Capability Exchange using SIP OPTIONS as defined by the
+     * framework. If set, the RcsFeature should support capability exchange using SIP OPTIONS.
+     * If not set, this RcsFeature should not service capability requests.
+     */
+    public static final int CAPABILITY_TYPE_OPTIONS_UCE = 1 << 0;
+
+    /**
+     * This carrier supports User Capability Exchange using a presence server as defined by the
+     * framework. If set, the RcsFeature should support capability exchange using a presence
+     * server. If not set, this RcsFeature should not publish capabilities or service capability
+     * requests using presence.
+     */
+    public static final int CAPABILITY_TYPE_PRESENCE_UCE = 1 << 1;
+
+    /**
+     * This is used to check the upper range of RCS capability
+     * @hide
+     */
+    public static final int CAPABILITY_TYPE_MAX = CAPABILITY_TYPE_PRESENCE_UCE + 1;
+
+    /**
      * An application can use {@link #addOnAvailabilityChangedListener} to register a
      * {@link OnAvailabilityChangedListener}, which will notify the user when the RCS feature
      * availability status updates from the ImsService.
@@ -104,7 +147,7 @@
          *
          * @param capabilities The new availability of the capabilities.
          */
-        void onAvailabilityChanged(@RcsUceAdapter.RcsImsCapabilityFlag int capabilities);
+        void onAvailabilityChanged(@RcsImsCapabilityFlag int capabilities);
     }
 
     /**
@@ -486,7 +529,7 @@
      */
     @SystemApi
     @RequiresPermission(Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
-    public boolean isCapable(@RcsUceAdapter.RcsImsCapabilityFlag int capability,
+    public boolean isCapable(@RcsImsCapabilityFlag int capability,
             @ImsRegistrationImplBase.ImsRegistrationTech int radioTech) throws ImsException {
         IImsRcsController imsRcsController = getIImsRcsController();
         if (imsRcsController == null) {
@@ -522,7 +565,7 @@
      */
     @SystemApi
     @RequiresPermission(Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
-    public boolean isAvailable(@RcsUceAdapter.RcsImsCapabilityFlag int capability,
+    public boolean isAvailable(@RcsImsCapabilityFlag int capability,
             @ImsRegistrationImplBase.ImsRegistrationTech int radioTech)
             throws ImsException {
         IImsRcsController imsRcsController = getIImsRcsController();
diff --git a/telephony/java/android/telephony/ims/ProvisioningManager.java b/telephony/java/android/telephony/ims/ProvisioningManager.java
index 677c1a9..2833489 100644
--- a/telephony/java/android/telephony/ims/ProvisioningManager.java
+++ b/telephony/java/android/telephony/ims/ProvisioningManager.java
@@ -38,7 +38,6 @@
 import android.telephony.ims.aidl.IImsConfigCallback;
 import android.telephony.ims.aidl.IRcsConfigCallback;
 import android.telephony.ims.feature.MmTelFeature;
-import android.telephony.ims.feature.RcsFeature;
 import android.telephony.ims.stub.ImsConfigImplBase;
 import android.telephony.ims.stub.ImsRegistrationImplBase;
 
@@ -970,7 +969,7 @@
     /**
      * Callback for IMS provisioning feature changes.
      */
-    public static class FeatureProvisioningCallback {
+    public abstract static class FeatureProvisioningCallback {
 
         private static class CallbackBinder extends IFeatureProvisioningCallback.Stub {
 
@@ -1024,12 +1023,10 @@
          * specified, or {@code false} if the capability is not provisioned for the technology
          * specified.
          */
-        public void onFeatureProvisioningChanged(
+        public abstract void onFeatureProvisioningChanged(
                 @MmTelFeature.MmTelCapabilities.MmTelCapability int capability,
                 @ImsRegistrationImplBase.ImsRegistrationTech int tech,
-                boolean isProvisioned) {
-            // Base Implementation
-        }
+                boolean isProvisioned);
 
         /**
          * The IMS RCS provisioning has changed for a specific capability and IMS
@@ -1041,12 +1038,10 @@
          * specified, or {@code false} if the capability is not provisioned for the technology
          * specified.
          */
-        public void onRcsFeatureProvisioningChanged(
-                @RcsFeature.RcsImsCapabilities.RcsImsCapabilityFlag int capability,
+        public abstract void onRcsFeatureProvisioningChanged(
+                @ImsRcsManager.RcsImsCapabilityFlag int capability,
                 @ImsRegistrationImplBase.ImsRegistrationTech int tech,
-                boolean isProvisioned) {
-            // Base Implementation
-        }
+                boolean isProvisioned);
 
         /**@hide*/
         public final IFeatureProvisioningCallback getBinder() {
@@ -1505,7 +1500,7 @@
      * Get the provisioning status for the IMS RCS capability specified.
      *
      * If provisioning is not required for the queried
-     * {@link RcsFeature.RcsImsCapabilities.RcsImsCapabilityFlag} this method will always return
+     * {@link ImsRcsManager.RcsImsCapabilityFlag} this method will always return
      * {@code true}.
      *
      * @see CarrierConfigManager.Ims#KEY_CARRIER_RCS_PROVISIONING_REQUIRED_BOOL
@@ -1522,7 +1517,7 @@
     @WorkerThread
     @RequiresPermission(Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
     public boolean getRcsProvisioningStatusForCapability(
-            @RcsFeature.RcsImsCapabilities.RcsImsCapabilityFlag int capability) {
+            @ImsRcsManager.RcsImsCapabilityFlag int capability) {
         try {
             return getITelephony().getRcsProvisioningStatusForCapability(mSubId, capability,
             ImsRegistrationImplBase.REGISTRATION_TECH_LTE);
@@ -1535,7 +1530,7 @@
      * Get the provisioning status for the IMS RCS capability specified.
      *
      * If provisioning is not required for the queried
-     * {@link RcsFeature.RcsImsCapabilities.RcsImsCapabilityFlag} this method
+     * {@link ImsRcsManager.RcsImsCapabilityFlag} this method
      * will always return {@code true}.
      *
      * <p> Requires Permission:
@@ -1553,7 +1548,7 @@
     @WorkerThread
     @RequiresPermission(Manifest.permission.READ_PRECISE_PHONE_STATE)
     public boolean getRcsProvisioningStatusForCapability(
-            @RcsFeature.RcsImsCapabilities.RcsImsCapabilityFlag int capability,
+            @ImsRcsManager.RcsImsCapabilityFlag int capability,
             @ImsRegistrationImplBase.ImsRegistrationTech int tech) {
         try {
             return getITelephony().getRcsProvisioningStatusForCapability(mSubId, capability, tech);
@@ -1590,7 +1585,7 @@
     @WorkerThread
     @RequiresPermission(Manifest.permission.MODIFY_PHONE_STATE)
     public void setRcsProvisioningStatusForCapability(
-            @RcsFeature.RcsImsCapabilities.RcsImsCapabilityFlag int capability,
+            @ImsRcsManager.RcsImsCapabilityFlag int capability,
             boolean isProvisioned) {
         try {
             getITelephony().setRcsProvisioningStatusForCapability(mSubId, capability,
@@ -1622,7 +1617,7 @@
     @WorkerThread
     @RequiresPermission(Manifest.permission.MODIFY_PHONE_STATE)
     public void setRcsProvisioningStatusForCapability(
-            @RcsFeature.RcsImsCapabilities.RcsImsCapabilityFlag int capability,
+            @ImsRcsManager.RcsImsCapabilityFlag int capability,
             @ImsRegistrationImplBase.ImsRegistrationTech int tech, boolean isProvisioned) {
         try {
             getITelephony().setRcsProvisioningStatusForCapability(mSubId, capability,
@@ -1676,7 +1671,7 @@
      */
     @RequiresPermission(Manifest.permission.READ_PRECISE_PHONE_STATE)
     public boolean isRcsProvisioningRequiredForCapability(
-            @RcsFeature.RcsImsCapabilities.RcsImsCapabilityFlag int capability,
+            @ImsRcsManager.RcsImsCapabilityFlag int capability,
             @ImsRegistrationImplBase.ImsRegistrationTech int tech) {
         try {
             return getITelephony().isRcsProvisioningRequiredForCapability(mSubId, capability, tech);
diff --git a/telephony/java/android/telephony/ims/RcsUceAdapter.java b/telephony/java/android/telephony/ims/RcsUceAdapter.java
index 154bb11..91dc38f 100644
--- a/telephony/java/android/telephony/ims/RcsUceAdapter.java
+++ b/telephony/java/android/telephony/ims/RcsUceAdapter.java
@@ -55,20 +55,28 @@
      * This carrier supports User Capability Exchange as, defined by the framework using
      * SIP OPTIONS. If set, the RcsFeature should support capability exchange. If not set, this
      * RcsFeature should not publish capabilities or service capability requests.
+     * @deprecated Use {@link ImsRcsManager#CAPABILITY_TYPE_OPTIONS_UCE} instead.
      * @hide
      */
+    @Deprecated
     public static final int CAPABILITY_TYPE_OPTIONS_UCE = 1 << 0;
 
     /**
      * This carrier supports User Capability Exchange as, defined by the framework using a
      * presence server. If set, the RcsFeature should support capability exchange. If not set, this
      * RcsFeature should not publish capabilities or service capability requests.
+     * @deprecated Use {@link ImsRcsManager#CAPABILITY_TYPE_PRESENCE_UCE} instead.
      * @hide
      */
+    @Deprecated
     @SystemApi
     public static final int CAPABILITY_TYPE_PRESENCE_UCE = 1 << 1;
 
-    /**@hide*/
+    /**
+     * @deprecated Use {@link ImsRcsManager.RcsImsCapabilityFlag} instead.
+     * @hide
+     */
+    @Deprecated
     @Retention(RetentionPolicy.SOURCE)
     @IntDef(prefix = "CAPABILITY_TYPE_", value = {
             CAPABILITY_TYPE_OPTIONS_UCE,
diff --git a/telephony/java/android/telephony/ims/feature/MmTelFeature.java b/telephony/java/android/telephony/ims/feature/MmTelFeature.java
index ad2e9e1..fb0e659 100644
--- a/telephony/java/android/telephony/ims/feature/MmTelFeature.java
+++ b/telephony/java/android/telephony/ims/feature/MmTelFeature.java
@@ -396,7 +396,7 @@
         /**
          * Undefined capability type for initialization
          * This is used to check the upper range of MmTel capability
-         * {@hide}
+         * @hide
          */
         public static final int CAPABILITY_TYPE_NONE = 0;
 
@@ -427,7 +427,7 @@
 
         /**
          * This is used to check the upper range of MmTel capability
-         * {@hide}
+         * @hide
          */
         public static final int CAPABILITY_TYPE_MAX = CAPABILITY_TYPE_CALL_COMPOSER + 1;
 
@@ -738,7 +738,7 @@
      * Enabling/Disabling a capability here indicates that the capability should be registered or
      * deregistered (depending on the capability change) and become available or unavailable to
      * the framework.
-     * * @hide
+     * @hide
      */
     @Override
     @SystemApi
diff --git a/telephony/java/android/telephony/ims/feature/RcsFeature.java b/telephony/java/android/telephony/ims/feature/RcsFeature.java
index 70e4ef1..843827b 100644
--- a/telephony/java/android/telephony/ims/feature/RcsFeature.java
+++ b/telephony/java/android/telephony/ims/feature/RcsFeature.java
@@ -24,7 +24,7 @@
 import android.content.Context;
 import android.net.Uri;
 import android.os.RemoteException;
-import android.telephony.ims.RcsUceAdapter;
+import android.telephony.ims.ImsRcsManager;
 import android.telephony.ims.aidl.CapabilityExchangeAidlWrapper;
 import android.telephony.ims.aidl.ICapabilityExchangeEventListener;
 import android.telephony.ims.aidl.IImsCapabilityCallback;
@@ -59,7 +59,9 @@
 /**
  * Base implementation of the RcsFeature APIs. Any ImsService wishing to support RCS should extend
  * this class and provide implementations of the RcsFeature methods that they support.
+ * @hide
  */
+@SystemApi
 public class RcsFeature extends ImsFeature {
 
     private static final String LOG_TAG = "RcsFeature";
@@ -184,18 +186,22 @@
      * Contains the capabilities defined and supported by a {@link RcsFeature} in the
      * form of a bitmask. The capabilities that are used in the RcsFeature are
      * defined as:
-     * {RcsUceAdapter.RcsImsCapabilityFlag#CAPABILITY_TYPE_OPTIONS_UCE}
-     * {RcsUceAdapter.RcsImsCapabilityFlag#CAPABILITY_TYPE_PRESENCE_UCE}
+     * {@link ImsRcsManager.RcsImsCapabilityFlag#CAPABILITY_TYPE_OPTIONS_UCE}
+     * {@link ImsRcsManager.RcsImsCapabilityFlag#CAPABILITY_TYPE_PRESENCE_UCE}
      *
      * The enabled capabilities of this RcsFeature will be set by the framework
-     * using {#changeEnabledCapabilities(CapabilityChangeRequest, CapabilityCallbackProxy)}.
+     * using {@link #changeEnabledCapabilities(CapabilityChangeRequest, CapabilityCallbackProxy)}.
      * After the capabilities have been set, the RcsFeature may then perform the necessary bring up
      * of the capability and notify the capability status as true using
-     * {#notifyCapabilitiesStatusChanged(RcsImsCapabilities)}. This will signal to the
+     * {@link #notifyCapabilitiesStatusChanged(RcsImsCapabilities)}. This will signal to the
      * framework that the capability is available for usage.
      */
     public static class RcsImsCapabilities extends Capabilities {
-        /** @hide*/
+
+        /**
+         * Use {@link ImsRcsManager.RcsImsCapabilityFlag} instead in case used for public API
+         * @hide
+         */
         @Retention(RetentionPolicy.SOURCE)
         @IntDef(prefix = "CAPABILITY_TYPE_", flag = true, value = {
                 CAPABILITY_TYPE_NONE,
@@ -226,7 +232,7 @@
 
         /**
          * This is used to check the upper range of RCS capability
-         * {@hide}
+         * @hide
          */
         public static final int CAPABILITY_TYPE_MAX = CAPABILITY_TYPE_PRESENCE_UCE + 1;
 
@@ -234,10 +240,8 @@
          * Create a new {@link RcsImsCapabilities} instance with the provided capabilities.
          * @param capabilities The capabilities that are supported for RCS in the form of a
          * bitfield.
-         * @hide
          */
-        @SystemApi
-        public RcsImsCapabilities(@RcsUceAdapter.RcsImsCapabilityFlag int capabilities) {
+        public RcsImsCapabilities(@ImsRcsManager.RcsImsCapabilityFlag int capabilities) {
             super(capabilities);
         }
 
@@ -249,30 +253,18 @@
             super(capabilities.getMask());
         }
 
-        /**
-         * @hide
-         */
         @Override
-        @SystemApi
-        public void addCapabilities(@RcsUceAdapter.RcsImsCapabilityFlag int capabilities) {
+        public void addCapabilities(@ImsRcsManager.RcsImsCapabilityFlag int capabilities) {
             super.addCapabilities(capabilities);
         }
 
-        /**
-         * @hide
-         */
         @Override
-        @SystemApi
-        public void removeCapabilities(@RcsUceAdapter.RcsImsCapabilityFlag int capabilities) {
+        public void removeCapabilities(@ImsRcsManager.RcsImsCapabilityFlag int capabilities) {
             super.removeCapabilities(capabilities);
         }
 
-        /**
-         * @hide
-         */
         @Override
-        @SystemApi
-        public boolean isCapable(@RcsUceAdapter.RcsImsCapabilityFlag int capabilities) {
+        public boolean isCapable(@ImsRcsManager.RcsImsCapabilityFlag int capabilities) {
             return super.isCapable(capabilities);
         }
     }
@@ -288,9 +280,7 @@
      * Method stubs called from the framework will be called asynchronously. To specify the
      * {@link Executor} that the methods stubs will be called, use
      * {@link RcsFeature#RcsFeature(Executor)} instead.
-     * @hide
      */
-    @SystemApi
     public RcsFeature() {
         super();
         // Run on the Binder threads that call them.
@@ -302,9 +292,7 @@
      * framework.
      * @param executor The executor for the framework to use when executing the methods overridden
      * by the implementation of RcsFeature.
-     * @hide
      */
-    @SystemApi
     public RcsFeature(@NonNull Executor executor) {
         super();
         if (executor == null) {
@@ -335,10 +323,8 @@
      * requests. To change the status of the capabilities
      * {@link #notifyCapabilitiesStatusChanged(RcsImsCapabilities)} should be called.
      * @return A copy of the current RcsFeature capability status.
-     * @hide
      */
     @Override
-    @SystemApi
     public @NonNull final RcsImsCapabilities queryCapabilityStatus() {
         return new RcsImsCapabilities(super.queryCapabilityStatus());
     }
@@ -348,9 +334,7 @@
      * this signals to the framework that the capability has been initialized and is ready.
      * Call {@link #queryCapabilityStatus()} to return the current capability status.
      * @param capabilities The current capability status of the RcsFeature.
-     * @hide
      */
-    @SystemApi
     public final void notifyCapabilitiesStatusChanged(@NonNull RcsImsCapabilities capabilities) {
         if (capabilities == null) {
             throw new IllegalArgumentException("RcsImsCapabilities must be non-null!");
@@ -367,11 +351,9 @@
      * @param capability The capability that we are querying the configuration for.
      * @param radioTech The radio technology type that we are querying.
      * @return true if the capability is enabled, false otherwise.
-     * @hide
      */
-    @SystemApi
     public boolean queryCapabilityConfiguration(
-            @RcsUceAdapter.RcsImsCapabilityFlag int capability,
+            @ImsRcsManager.RcsImsCapabilityFlag int capability,
             @ImsRegistrationImplBase.ImsRegistrationTech int radioTech) {
         // Base Implementation - Override to provide functionality
         return false;
@@ -392,10 +374,8 @@
      * be called for each capability change that resulted in an error.
      * @param request The request to change the capability.
      * @param callback To notify the framework that the result of the capability changes.
-     * @hide
      */
     @Override
-    @SystemApi
     public void changeEnabledCapabilities(@NonNull CapabilityChangeRequest request,
             @NonNull CapabilityCallbackProxy callback) {
         // Base Implementation - Override to provide functionality
@@ -415,9 +395,7 @@
      * event to the framework.
      * @return An instance of {@link RcsCapabilityExchangeImplBase} that implements capability
      * exchange if it is supported by the device.
-     * @hide
      */
-    @SystemApi
     public @NonNull RcsCapabilityExchangeImplBase createCapabilityExchangeImpl(
             @NonNull CapabilityExchangeEventListener listener) {
         // Base Implementation, override to implement functionality
@@ -427,28 +405,20 @@
     /**
      * Remove the given CapabilityExchangeImplBase instance.
      * @param capExchangeImpl The {@link RcsCapabilityExchangeImplBase} instance to be destroyed.
-     * @hide
      */
-    @SystemApi
     public void destroyCapabilityExchangeImpl(
             @NonNull RcsCapabilityExchangeImplBase capExchangeImpl) {
         // Override to implement the process of destroying RcsCapabilityExchangeImplBase instance.
     }
 
-    /**{@inheritDoc}
-     * @hide
-     */
+    /**{@inheritDoc}*/
     @Override
-    @SystemApi
     public void onFeatureRemoved() {
 
     }
 
-    /**{@inheritDoc}
-     * @hide
-     */
+    /**{@inheritDoc}*/
     @Override
-    @SystemApi
     public void onFeatureReady() {
 
     }
diff --git a/telephony/java/android/telephony/ims/stub/ImsRegistrationImplBase.java b/telephony/java/android/telephony/ims/stub/ImsRegistrationImplBase.java
index ac5565b..593f080 100644
--- a/telephony/java/android/telephony/ims/stub/ImsRegistrationImplBase.java
+++ b/telephony/java/android/telephony/ims/stub/ImsRegistrationImplBase.java
@@ -93,7 +93,7 @@
 
     /**
      * This is used to check the upper range of registration tech
-     * {@hide}
+     * @hide
      */
     public static final int REGISTRATION_TECH_MAX = REGISTRATION_TECH_NR + 1;
 
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/CommonAssertions.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/CommonAssertions.kt
index 75f1337..7f309e1 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/CommonAssertions.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/CommonAssertions.kt
@@ -102,28 +102,59 @@
     }
 }
 
-fun FlickerTestParameter.navBarLayerRotatesAndScales() {
+/**
+ * Asserts that the [FlickerComponentName.NAV_BAR] layer is at the correct position at the start
+ * of the SF trace
+ */
+fun FlickerTestParameter.navBarLayerPositionStart() {
     assertLayersStart {
         val display = this.entry.displays.minByOrNull { it.id }
-            ?: throw RuntimeException("There is no display!")
-        this.visibleRegion(FlickerComponentName.NAV_BAR)
-                .coversExactly(WindowUtils.getNavigationBarPosition(display))
-    }
-    assertLayersEnd {
-        val display = this.entry.displays.minByOrNull { it.id }
-            ?: throw RuntimeException("There is no display!")
+                ?: throw RuntimeException("There is no display!")
         this.visibleRegion(FlickerComponentName.NAV_BAR)
                 .coversExactly(WindowUtils.getNavigationBarPosition(display))
     }
 }
 
-fun FlickerTestParameter.statusBarLayerRotatesScales() {
+/**
+ * Asserts that the [FlickerComponentName.NAV_BAR] layer is at the correct position at the end
+ * of the SF trace
+ */
+fun FlickerTestParameter.navBarLayerPositionEnd() {
+    assertLayersEnd {
+        val display = this.entry.displays.minByOrNull { it.id }
+                ?: throw RuntimeException("There is no display!")
+        this.visibleRegion(FlickerComponentName.NAV_BAR)
+                .coversExactly(WindowUtils.getNavigationBarPosition(display))
+    }
+}
+
+/**
+ * Asserts that the [FlickerComponentName.NAV_BAR] layer is at the correct position at the start
+ * and end of the SF trace
+ */
+fun FlickerTestParameter.navBarLayerRotatesAndScales() {
+    navBarLayerPositionStart()
+    navBarLayerPositionEnd()
+}
+
+/**
+ * Asserts that the [FlickerComponentName.STATUS_BAR] layer is at the correct position at the start
+ * of the SF trace
+ */
+fun FlickerTestParameter.statusBarLayerPositionStart() {
     assertLayersStart {
         val display = this.entry.displays.minByOrNull { it.id }
             ?: throw RuntimeException("There is no display!")
         this.visibleRegion(FlickerComponentName.STATUS_BAR)
             .coversExactly(WindowUtils.getStatusBarPosition(display))
     }
+}
+
+/**
+ * Asserts that the [FlickerComponentName.STATUS_BAR] layer is at the correct position at the end
+ * of the SF trace
+ */
+fun FlickerTestParameter.statusBarLayerPositionEnd() {
     assertLayersEnd {
         val display = this.entry.displays.minByOrNull { it.id }
             ?: throw RuntimeException("There is no display!")
@@ -133,6 +164,15 @@
 }
 
 /**
+ * Asserts that the [FlickerComponentName.STATUS_BAR] layer is at the correct position at the start
+ * and end of the SF trace
+ */
+fun FlickerTestParameter.statusBarLayerRotatesScales() {
+    statusBarLayerPositionStart()
+    statusBarLayerPositionEnd()
+}
+
+/**
  * Asserts that:
  *     [originalLayer] is visible at the start of the trace
  *     [originalLayer] becomes invisible during the trace and (in the same entry) [newLayer]
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/close/CloseAppBackButtonTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/close/CloseAppBackButtonTest.kt
index d1319ac..20a2e22 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/close/CloseAppBackButtonTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/close/CloseAppBackButtonTest.kt
@@ -98,6 +98,12 @@
         super.statusBarLayerRotatesScales()
     }
 
+    /** {@inheritDoc} */
+    @FlakyTest(bugId = 229762973)
+    @Test
+    override fun visibleLayersShownMoreThanOneConsecutiveEntry() =
+        super.visibleLayersShownMoreThanOneConsecutiveEntry()
+
     companion object {
         /**
          * Creates the test configurations.
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/close/CloseAppHomeButtonTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/close/CloseAppHomeButtonTest.kt
index f5fb106..d00fd7d 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/close/CloseAppHomeButtonTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/close/CloseAppHomeButtonTest.kt
@@ -101,11 +101,10 @@
     }
 
     /** {@inheritDoc} */
-    @Presubmit
+    @FlakyTest(bugId = 229762973)
     @Test
-    override fun visibleLayersShownMoreThanOneConsecutiveEntry() {
+    override fun visibleLayersShownMoreThanOneConsecutiveEntry() =
         super.visibleLayersShownMoreThanOneConsecutiveEntry()
-    }
 
     companion object {
         /**
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/ImeAppAutoFocusHelper.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/ImeAppAutoFocusHelper.kt
index 535612a..93b987e 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/ImeAppAutoFocusHelper.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/ImeAppAutoFocusHelper.kt
@@ -41,6 +41,16 @@
         waitIMEShown(device, wmHelper)
     }
 
+    override fun launchViaIntent(
+        wmHelper: WindowManagerStateHelper,
+        expectedWindowName: String,
+        action: String?,
+        stringExtras: Map<String, String>
+    ) {
+        super.launchViaIntent(wmHelper, expectedWindowName, action, stringExtras)
+        waitIMEShown(uiDevice, wmHelper)
+    }
+
     override fun open() {
         val expectedPackage = if (rotation.isRotated()) {
             imePackageName
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromLockNotificationCold.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromLockNotificationCold.kt
index 8daf4ca..774b85b 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromLockNotificationCold.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromLockNotificationCold.kt
@@ -18,12 +18,14 @@
 
 import android.platform.test.annotations.Postsubmit
 import android.platform.test.annotations.RequiresDevice
+import androidx.test.filters.FlakyTest
 import com.android.server.wm.flicker.FlickerParametersRunnerFactory
 import com.android.server.wm.flicker.FlickerTestParameter
 import com.android.server.wm.flicker.FlickerTestParameterFactory
 import com.android.server.wm.flicker.annotation.Group1
 import com.android.server.wm.flicker.dsl.FlickerBuilder
 import org.junit.FixMethodOrder
+import org.junit.Test
 import org.junit.runner.RunWith
 import org.junit.runners.MethodSorters
 import org.junit.runners.Parameterized
@@ -31,6 +33,8 @@
 /**
  * Test cold launching an app from a notification from the lock screen.
  *
+ * This test assumes the device doesn't have AOD enabled
+ *
  * To run this test: `atest FlickerTests:OpenAppFromLockNotificationCold`
  */
 @RequiresDevice
@@ -65,6 +69,11 @@
             }
         }
 
+    /** {@inheritDoc} */
+    @FlakyTest(bugId = 229735718)
+    @Test
+    override fun entireScreenCovered() = super.entireScreenCovered()
+
     companion object {
         /**
          * Creates the test configurations.
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromLockNotificationWarm.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromLockNotificationWarm.kt
index 8eb182a..53ee57b 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromLockNotificationWarm.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromLockNotificationWarm.kt
@@ -18,6 +18,7 @@
 
 import android.platform.test.annotations.Postsubmit
 import android.platform.test.annotations.RequiresDevice
+import androidx.test.filters.FlakyTest
 import com.android.server.wm.flicker.FlickerParametersRunnerFactory
 import com.android.server.wm.flicker.FlickerTestParameter
 import com.android.server.wm.flicker.FlickerTestParameterFactory
@@ -33,6 +34,8 @@
 /**
  * Test warm launching an app from a notification from the lock screen.
  *
+ * This test assumes the device doesn't have AOD enabled
+ *
  * To run this test: `atest FlickerTests:OpenAppFromLockNotificationWarm`
  */
 @RequiresDevice
@@ -97,6 +100,11 @@
         }
     }
 
+    /** {@inheritDoc} */
+    @FlakyTest(bugId = 229735718)
+    @Test
+    override fun entireScreenCovered() = super.entireScreenCovered()
+
     companion object {
         /**
          * Creates the test configurations.
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromLockNotificationWithLockOverlayApp.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromLockNotificationWithLockOverlayApp.kt
index 28a914b..bc637f8 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromLockNotificationWithLockOverlayApp.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromLockNotificationWithLockOverlayApp.kt
@@ -18,6 +18,7 @@
 
 import android.platform.test.annotations.Postsubmit
 import android.platform.test.annotations.RequiresDevice
+import androidx.test.filters.FlakyTest
 import com.android.server.wm.flicker.FlickerParametersRunnerFactory
 import com.android.server.wm.flicker.FlickerTestParameter
 import com.android.server.wm.flicker.FlickerTestParameterFactory
@@ -103,6 +104,11 @@
         }
     }
 
+    /** {@inheritDoc} */
+    @FlakyTest(bugId = 229735718)
+    @Test
+    override fun entireScreenCovered() = super.entireScreenCovered()
+
     companion object {
         /**
          * Creates the test configurations.
@@ -113,7 +119,7 @@
         @Parameterized.Parameters(name = "{0}")
         @JvmStatic
         fun getParams(): Collection<FlickerTestParameter> {
-            return com.android.server.wm.flicker.FlickerTestParameterFactory.getInstance()
+            return FlickerTestParameterFactory.getInstance()
                     .getConfigNonRotationTests(repetitions = 3)
         }
     }
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromLockTransition.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromLockTransition.kt
index f47e272..fe80162 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromLockTransition.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromLockTransition.kt
@@ -20,6 +20,7 @@
 import androidx.test.filters.FlakyTest
 import com.android.server.wm.flicker.FlickerTestParameter
 import com.android.server.wm.flicker.dsl.FlickerBuilder
+import com.android.server.wm.flicker.navBarLayerPositionEnd
 import com.android.server.wm.traces.common.FlickerComponentName
 import org.junit.Test
 
@@ -99,4 +100,27 @@
     @FlakyTest(bugId = 203538234)
     @Test
     override fun appWindowBecomesVisible() = super.appWindowBecomesVisible()
+
+    /**
+     * Checks the position of the navigation bar at the start and end of the transition
+     *
+     * Differently from the normal usage of this assertion, check only the final state of the
+     * transition because the display is off at the start and the NavBar is never visible
+     */
+    @Presubmit
+    @Test
+    override fun navBarLayerRotatesAndScales() = testSpec.navBarLayerPositionEnd()
+
+    /**
+     * Checks that the status bar layer is visible at the end of the trace
+     *
+     * It is not possible to check at the start because the screen is off
+     */
+    @Presubmit
+    @Test
+    override fun statusBarLayerIsVisible() {
+        testSpec.assertLayersEnd {
+            this.isVisible(FlickerComponentName.STATUS_BAR)
+        }
+    }
 }
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromNotificationCold.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromNotificationCold.kt
index ee018ec..5022dd8 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromNotificationCold.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromNotificationCold.kt
@@ -32,6 +32,8 @@
 /**
  * Test cold launching an app from a notification.
  *
+ * This test assumes the device doesn't have AOD enabled
+ *
  * To run this test: `atest FlickerTests:OpenAppFromNotificationCold`
  */
 @RequiresDevice
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromNotificationWarm.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromNotificationWarm.kt
index 74f1fd7..af9eaa5 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromNotificationWarm.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromNotificationWarm.kt
@@ -40,6 +40,8 @@
 /**
  * Test cold launching an app from a notification.
  *
+ * This test assumes the device doesn't have AOD enabled
+ *
  * To run this test: `atest FlickerTests:OpenAppFromNotificationWarm`
  */
 @RequiresDevice
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromOverviewTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromOverviewTest.kt
index 6e33f66..18f077f 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromOverviewTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromOverviewTest.kt
@@ -26,9 +26,11 @@
 import com.android.server.wm.flicker.LAUNCHER_COMPONENT
 import com.android.server.wm.flicker.annotation.Group1
 import com.android.server.wm.flicker.dsl.FlickerBuilder
+import com.android.server.wm.flicker.helpers.isShellTransitionsEnabled
 import com.android.server.wm.flicker.helpers.reopenAppFromOverview
 import com.android.server.wm.flicker.helpers.setRotation
 import com.android.server.wm.traces.common.WindowManagerConditionsFactory
+import org.junit.Assume
 import org.junit.FixMethodOrder
 import org.junit.Test
 import org.junit.runner.RunWith
@@ -132,6 +134,26 @@
     @Test
     override fun appWindowBecomesVisible() = super.appWindowBecomesVisible_warmStart()
 
+    /** {@inheritDoc} */
+    @FlakyTest(bugId = 229735718)
+    @Test
+    override fun entireScreenCovered() = super.entireScreenCovered()
+
+    /** {@inheritDoc} */
+    @Presubmit
+    @Test
+    override fun appWindowReplacesLauncherAsTopWindow() {
+        Assume.assumeFalse(isShellTransitionsEnabled)
+        super.appWindowReplacesLauncherAsTopWindow()
+    }
+
+    @FlakyTest(bugId = 229738092)
+    @Test
+    fun appWindowReplacesLauncherAsTopWindow_ShellTransit() {
+        Assume.assumeTrue(isShellTransitionsEnabled)
+        super.appWindowReplacesLauncherAsTopWindow()
+    }
+
     companion object {
         /**
          * Creates the test configurations.
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppNonResizeableTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppNonResizeableTest.kt
index f357177..55eb3c3 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppNonResizeableTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppNonResizeableTest.kt
@@ -16,6 +16,7 @@
 
 package com.android.server.wm.flicker.launch
 
+import android.platform.test.annotations.Postsubmit
 import androidx.test.filters.FlakyTest
 import android.platform.test.annotations.Presubmit
 import android.platform.test.annotations.RequiresDevice
@@ -27,6 +28,7 @@
 import com.android.server.wm.flicker.annotation.Group1
 import com.android.server.wm.flicker.helpers.NonResizeableAppHelper
 import com.android.server.wm.flicker.helpers.WindowUtils
+import com.android.server.wm.flicker.navBarLayerPositionEnd
 import com.android.server.wm.traces.common.FlickerComponentName
 import org.junit.FixMethodOrder
 import org.junit.Test
@@ -37,6 +39,8 @@
 /**
  * Test launching an app while the device is locked
  *
+ * This test assumes the device doesn't have AOD enabled
+ *
  * To run this test: `atest FlickerTests:OpenAppNonResizeableTest`
  *
  * Actions:
@@ -103,8 +107,7 @@
     /**
      * Checks that the status bar layer is visible at the end of the trace
      *
-     * It is not possible to check at the start because the animation is working differently
-     * in devices with and without blur (b/202936526)
+     * It is not possible to check at the start because the screen is off
      */
     @Presubmit
     @Test
@@ -115,7 +118,7 @@
     }
 
     /** {@inheritDoc} */
-    @FlakyTest(bugId = 202936526)
+    @FlakyTest(bugId = 206753786)
     @Test
     override fun statusBarLayerRotatesScales() = super.statusBarLayerRotatesScales()
 
@@ -131,10 +134,15 @@
         }
     }
 
-    /** {@inheritDoc} */
-    @FlakyTest
+    /**
+     * Checks the position of the navigation bar at the start and end of the transition
+     *
+     * Differently from the normal usage of this assertion, check only the final state of the
+     * transition because the display is off at the start and the NavBar is never visible
+     */
+    @Postsubmit
     @Test
-    override fun navBarLayerRotatesAndScales() = super.navBarLayerRotatesAndScales()
+    override fun navBarLayerRotatesAndScales() = testSpec.navBarLayerPositionEnd()
 
     /** {@inheritDoc} */
     @FlakyTest
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppWarmTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppWarmTest.kt
index 48f6aeb..97528c0 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppWarmTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppWarmTest.kt
@@ -130,6 +130,10 @@
     @Test
     override fun appWindowBecomesVisible() = super.appWindowBecomesVisible_warmStart()
 
+    @FlakyTest(bugId = 229735718)
+    @Test
+    override fun entireScreenCovered() = super.entireScreenCovered()
+
     companion object {
         /**
          * Creates the test configurations.