Merge Android 13 QPR2

Bug: 273316506
Merged-In: I980e75363b4bd089152515d208df4e65130a722b
Change-Id: Ib25740221b9d6d7d2403c0729c2ce89dbd378690
diff --git a/res/values-night/colors.xml b/res/values-night/colors.xml
index af5b7ab..7d752c7 100644
--- a/res/values-night/colors.xml
+++ b/res/values-night/colors.xml
@@ -16,7 +16,6 @@
   -->
 <resources xmlns:android="http://schemas.android.com/apk/res/android">
     <color name="car_accent">#356FE5</color>
-    <color name="status_bar_background_color">#ff000000</color>
     <color name="system_bar_background_opaque">#ff0c1013</color>
 
     <!-- The background color of the notification shade -->
diff --git a/res/values/colors.xml b/res/values/colors.xml
index af70691..125fd00 100644
--- a/res/values/colors.xml
+++ b/res/values/colors.xml
@@ -43,8 +43,7 @@
     <color name="system_bar_text_color">#FFFFFF</color>
     <color name="system_bar_text_selected_color">#000000</color>
     <color name="system_bar_text_unavailable_color">#B0B0B0</color>
-    <color name="status_bar_background_color">#33000000</color>
-    <drawable name="system_bar_background">@color/status_bar_background_color</drawable>
+    <drawable name="system_bar_background">#000000</drawable>
 
     <!-- colors for quick controls entry points icon   -->
     <color name="car_quick_controls_icon_drawable_color">#FFFFFF</color>
diff --git a/res/values/config.xml b/res/values/config.xml
index 10a3ae0..eb5a9a4 100644
--- a/res/values/config.xml
+++ b/res/values/config.xml
@@ -186,5 +186,6 @@
     <!-- Determines whether the shell task organizer be registered automatiacly or not.
          It needs to be disabled for CarSystemUI as CarLauncher already registers one. With 2
          organizers there can be recovery problems if either of the process crashes. -->
-    <bool name="config_registerShellTaskOrganizerOnInit">false</bool>
+    <!-- TODO(b/228598071): Enabled this to fix b/250675259. -->
+    <bool name="config_registerShellTaskOrganizerOnInit">true</bool>
 </resources>
diff --git a/res/values/overlayable.xml b/res/values/overlayable.xml
index dcd8b00..196d1f6 100644
--- a/res/values/overlayable.xml
+++ b/res/values/overlayable.xml
@@ -150,7 +150,6 @@
       <item type="color" name="privacy_chip_indicator_color"/>
       <item type="color" name="privacy_chip_indicator_outside_stroke_color"/>
       <item type="color" name="privacy_chip_light_icon_color"/>
-      <item type="color" name="status_bar_background_color"/>
       <item type="color" name="status_icon_highlighted_color"/>
       <item type="color" name="status_icon_not_highlighted_color"/>
       <item type="color" name="status_icon_panel_bg_color"/>
diff --git a/src/com/android/systemui/CarSystemUIModule.java b/src/com/android/systemui/CarSystemUIModule.java
index dfb5a19..31a2d62 100644
--- a/src/com/android/systemui/CarSystemUIModule.java
+++ b/src/com/android/systemui/CarSystemUIModule.java
@@ -22,12 +22,10 @@
 import android.content.Context;
 import android.hardware.SensorPrivacyManager;
 import android.os.Handler;
-import android.os.PowerManager;
 import android.window.DisplayAreaOrganizer;
 
 import com.android.internal.logging.UiEventLogger;
 import com.android.keyguard.KeyguardViewController;
-import com.android.systemui.broadcast.BroadcastDispatcher;
 import com.android.systemui.car.CarDeviceProvisionedController;
 import com.android.systemui.car.CarDeviceProvisionedControllerImpl;
 import com.android.systemui.car.keyguard.CarKeyguardViewController;
@@ -36,17 +34,13 @@
 import com.android.systemui.car.volume.CarVolumeModule;
 import com.android.systemui.dagger.GlobalRootComponent;
 import com.android.systemui.dagger.SysUISingleton;
-import com.android.systemui.dagger.qualifiers.Background;
 import com.android.systemui.dagger.qualifiers.Main;
-import com.android.systemui.demomode.DemoModeController;
 import com.android.systemui.dock.DockManager;
 import com.android.systemui.dock.DockManagerImpl;
 import com.android.systemui.doze.DozeHost;
-import com.android.systemui.dump.DumpManager;
 import com.android.systemui.navigationbar.gestural.GestureModule;
 import com.android.systemui.plugins.qs.QSFactory;
 import com.android.systemui.plugins.statusbar.StatusBarStateController;
-import com.android.systemui.power.EnhancedEstimates;
 import com.android.systemui.power.dagger.PowerModule;
 import com.android.systemui.qs.dagger.QSModule;
 import com.android.systemui.qs.tileimpl.QSFactoryImpl;
@@ -55,6 +49,7 @@
 import com.android.systemui.screenshot.ReferenceScreenshotModule;
 import com.android.systemui.shade.ShadeController;
 import com.android.systemui.shade.ShadeControllerImpl;
+import com.android.systemui.shade.ShadeExpansionStateManager;
 import com.android.systemui.statusbar.CommandQueue;
 import com.android.systemui.statusbar.NotificationLockscreenUserManager;
 import com.android.systemui.statusbar.NotificationLockscreenUserManagerImpl;
@@ -64,8 +59,7 @@
 import com.android.systemui.statusbar.phone.HeadsUpManagerPhone;
 import com.android.systemui.statusbar.phone.KeyguardBypassController;
 import com.android.systemui.statusbar.policy.AccessibilityManagerWrapper;
-import com.android.systemui.statusbar.policy.BatteryController;
-import com.android.systemui.statusbar.policy.BatteryControllerImpl;
+import com.android.systemui.statusbar.policy.AospPolicyModule;
 import com.android.systemui.statusbar.policy.ConfigurationController;
 import com.android.systemui.statusbar.policy.DeviceProvisionedController;
 import com.android.systemui.statusbar.policy.HeadsUpManager;
@@ -85,12 +79,14 @@
 
 @Module(
         includes = {
+                AospPolicyModule.class,
                 CarVolumeModule.class,
                 GestureModule.class,
                 PowerModule.class,
                 QSModule.class,
                 ReferenceScreenshotModule.class
-        })
+        }
+        )
 abstract class CarSystemUIModule {
 
     @SysUISingleton
@@ -112,18 +108,20 @@
             ConfigurationController configurationController,
             @Main Handler handler,
             AccessibilityManagerWrapper accessibilityManagerWrapper,
-            UiEventLogger uiEventLogger) {
+            UiEventLogger uiEventLogger,
+            ShadeExpansionStateManager shadeExpansionStateManager) {
         return new HeadsUpManagerPhone(
-            context,
-            headsUpManagerLogger,
-            statusBarStateController,
-            bypassController,
-            groupManager,
-            visualStabilityProvider,
-            configurationController,
-            handler,
-            accessibilityManagerWrapper,
-            uiEventLogger
+                context,
+                headsUpManagerLogger,
+                statusBarStateController,
+                bypassController,
+                groupManager,
+                visualStabilityProvider,
+                configurationController,
+                handler,
+                accessibilityManagerWrapper,
+                uiEventLogger,
+                shadeExpansionStateManager
         );
     }
 
@@ -156,20 +154,6 @@
 
     @Provides
     @SysUISingleton
-    static BatteryController provideBatteryController(Context context,
-            EnhancedEstimates enhancedEstimates, PowerManager powerManager,
-            BroadcastDispatcher broadcastDispatcher, DemoModeController demoModeController,
-            DumpManager dumpManager,
-            @Main Handler mainHandler,
-            @Background Handler bgHandler) {
-        BatteryController bC = new BatteryControllerImpl(context, enhancedEstimates, powerManager,
-                broadcastDispatcher, demoModeController, dumpManager, mainHandler, bgHandler);
-        bC.init();
-        return bC;
-    }
-
-    @Provides
-    @SysUISingleton
     static SensorPrivacyController provideSensorPrivacyController(
             SensorPrivacyManager sensorPrivacyManager) {
         SensorPrivacyController spC = new SensorPrivacyControllerImpl(sensorPrivacyManager);
@@ -214,7 +198,7 @@
             CarDeviceProvisionedControllerImpl deviceProvisionedController) {
         deviceProvisionedController.init();
         return deviceProvisionedController;
-    };
+    }
 
     @Binds
     abstract CarDeviceProvisionedController bindCarDeviceProvisionedController(
diff --git a/src/com/android/systemui/car/cluster/ClusterDisplayController.java b/src/com/android/systemui/car/cluster/ClusterDisplayController.java
index 1ad284b..f06036a 100644
--- a/src/com/android/systemui/car/cluster/ClusterDisplayController.java
+++ b/src/com/android/systemui/car/cluster/ClusterDisplayController.java
@@ -22,7 +22,6 @@
 import android.car.Car;
 import android.car.cluster.ClusterHomeManager;
 import android.car.cluster.ClusterState;
-import android.content.Context;
 import android.graphics.Rect;
 import android.util.Slog;
 import android.view.Display;
@@ -46,7 +45,7 @@
  * Controls the RootTDA of cluster display per CLUSTER_DISPLAY_STATE message.
  */
 @SysUISingleton
-public class ClusterDisplayController extends CoreStartable {
+public class ClusterDisplayController implements CoreStartable {
     private static final String TAG = ClusterDisplayController.class.getSimpleName();
     private static final boolean DBG = false;
 
@@ -59,10 +58,9 @@
     private ClusterState mClusterState;
 
     @Inject
-    public ClusterDisplayController(Context context,
+    public ClusterDisplayController(
             Optional<RootTaskDisplayAreaOrganizer> rootTDAOrganizer,
             CarServiceProvider carServiceProvider, @Main Executor mainExecutor) {
-        super(context);
         mRootTDAOrganizer = rootTDAOrganizer.orElse(null);
         mCarServiceProvider = carServiceProvider;
         mMainExecutor = mainExecutor;
diff --git a/src/com/android/systemui/car/keyguard/CarKeyguardViewController.java b/src/com/android/systemui/car/keyguard/CarKeyguardViewController.java
index 1cf6359..9307e30 100644
--- a/src/com/android/systemui/car/keyguard/CarKeyguardViewController.java
+++ b/src/com/android/systemui/car/keyguard/CarKeyguardViewController.java
@@ -45,12 +45,12 @@
 import com.android.systemui.dagger.SysUISingleton;
 import com.android.systemui.dagger.qualifiers.Main;
 import com.android.systemui.shade.NotificationPanelViewController;
+import com.android.systemui.shade.ShadeExpansionStateManager;
 import com.android.systemui.statusbar.phone.BiometricUnlockController;
 import com.android.systemui.statusbar.phone.CentralSurfaces;
 import com.android.systemui.statusbar.phone.KeyguardBouncer;
 import com.android.systemui.statusbar.phone.KeyguardBouncer.Factory;
 import com.android.systemui.statusbar.phone.KeyguardBypassController;
-import com.android.systemui.statusbar.phone.panelstate.PanelExpansionStateManager;
 import com.android.systemui.statusbar.policy.KeyguardStateController;
 import com.android.systemui.toast.SystemUIToast;
 import com.android.systemui.toast.ToastFactory;
@@ -84,8 +84,8 @@
     private final CarSystemBarController mCarSystemBarController;
     private final Factory mKeyguardBouncerFactory;
     // Needed to instantiate mBouncer.
-    private final KeyguardBouncer.BouncerExpansionCallback mExpansionCallback =
-            new KeyguardBouncer.BouncerExpansionCallback() {
+    private final KeyguardBouncer.PrimaryBouncerExpansionCallback mExpansionCallback =
+            new KeyguardBouncer.PrimaryBouncerExpansionCallback() {
                 @Override
                 public void onFullyShown() {
                     LockPatternView patternView = getLayout().findViewById(R.id.lockPatternView);
@@ -182,7 +182,7 @@
 
     @Override
     @MainThread
-    public void showBouncer(boolean scrimmed) {
+    public void showPrimaryBouncer(boolean scrimmed) {
         if (mShowing && !mBouncer.isShowing()) {
             mBouncer.show(/* resetSecuritySelection= */ false);
         }
@@ -241,7 +241,7 @@
     }
 
     @Override
-    public void resetAlternateAuth(boolean forceUpdateScrim) {
+    public void hideAlternateBouncer(boolean forceUpdateScrim) {
         // no-op
     }
 
@@ -281,11 +281,6 @@
     }
 
     @Override
-    public boolean isShowing() {
-        return mShowing;
-    }
-
-    @Override
     @MainThread
     public void dismissAndCollapse() {
         // If dismissing and collapsing Keyguard is requested (e.g. by a Keyguard-dismissing
@@ -352,7 +347,7 @@
 
     @Override
     @MainThread
-    public boolean bouncerIsOrWillBeShowing() {
+    public boolean primaryBouncerIsOrWillBeShowing() {
         return mBouncer != null && (mBouncer.isShowing() || mBouncer.inTransit());
     }
 
@@ -397,7 +392,7 @@
     public void registerCentralSurfaces(
             CentralSurfaces centralSurfaces,
             NotificationPanelViewController notificationPanelViewController,
-            PanelExpansionStateManager panelExpansionStateManager,
+            ShadeExpansionStateManager shadeExpansionStateManager,
             BiometricUnlockController biometricUnlockController,
             View notificationContainer,
             KeyguardBypassController bypassController) {
@@ -446,10 +441,9 @@
     }
 
     private void notifyKeyguardUpdateMonitor() {
-        mKeyguardUpdateMonitor.onKeyguardVisibilityChanged(mShowing);
         if (mBouncer != null) {
-            mKeyguardUpdateMonitor.sendKeyguardBouncerChanged(
-                    bouncerIsOrWillBeShowing(), isBouncerShowing());
+            mKeyguardUpdateMonitor.sendPrimaryBouncerChanged(
+                    primaryBouncerIsOrWillBeShowing(), isBouncerShowing());
         }
     }
 
diff --git a/src/com/android/systemui/car/qc/ProfileSwitcher.java b/src/com/android/systemui/car/qc/ProfileSwitcher.java
index 900cad6..3b19e51 100644
--- a/src/com/android/systemui/car/qc/ProfileSwitcher.java
+++ b/src/com/android/systemui/car/qc/ProfileSwitcher.java
@@ -148,6 +148,7 @@
         return mUserManager.getAliveUsers()
                 .stream()
                 .filter(userInfo -> userInfo.supportsSwitchToByUser() && !userInfo.isGuest())
+                .sorted((u1, u2) -> Long.signum(u1.creationTime - u2.creationTime))
                 .collect(Collectors.toList());
     }
 
diff --git a/src/com/android/systemui/car/sideloaded/SideLoadedAppController.java b/src/com/android/systemui/car/sideloaded/SideLoadedAppController.java
index df996ec..fd52515 100644
--- a/src/com/android/systemui/car/sideloaded/SideLoadedAppController.java
+++ b/src/com/android/systemui/car/sideloaded/SideLoadedAppController.java
@@ -17,7 +17,6 @@
 package com.android.systemui.car.sideloaded;
 
 import android.app.IActivityTaskManager;
-import android.content.Context;
 import android.os.RemoteException;
 import android.util.Log;
 
@@ -30,7 +29,7 @@
  * Controller responsible for detecting unsafe apps.
  */
 @SysUISingleton
-public class SideLoadedAppController extends CoreStartable {
+public class SideLoadedAppController implements CoreStartable {
     private static final String TAG = SideLoadedAppController.class.getSimpleName();
 
     private IActivityTaskManager mActivityTaskManager;
@@ -39,13 +38,11 @@
     private SideLoadedAppStateController mSideLoadedAppStateController;
 
     @Inject
-    public SideLoadedAppController(Context context,
+    public SideLoadedAppController(
             IActivityTaskManager activityTaskManager,
             SideLoadedAppDetector sideLoadedAppDetector,
             SideLoadedAppListener sideLoadedAppListener,
             SideLoadedAppStateController sideLoadedAppStateController) {
-        super(context);
-
         mSideLoadedAppDetector = sideLoadedAppDetector;
         mActivityTaskManager = activityTaskManager;
         mSideLoadedAppListener = sideLoadedAppListener;
@@ -57,7 +54,7 @@
     }
 
     @Override
-    protected void onBootCompleted() {
+    public void onBootCompleted() {
         Log.i(TAG, "OnBootCompleted");
 
         try {
diff --git a/src/com/android/systemui/car/statusbar/DozeServiceHost.java b/src/com/android/systemui/car/statusbar/DozeServiceHost.java
index 10774b3..d477fe5 100644
--- a/src/com/android/systemui/car/statusbar/DozeServiceHost.java
+++ b/src/com/android/systemui/car/statusbar/DozeServiceHost.java
@@ -73,6 +73,17 @@
         return false;
     }
 
+
+    @Override
+    public boolean isPulsePending() {
+        return false;
+    }
+
+    @Override
+    public void setPulsePending(boolean isPulsePending) {
+        // No op.
+    }
+
     @Override
     public void extendPulse(int reason) {
         // No op.
diff --git a/src/com/android/systemui/car/systembar/CarSystemBar.java b/src/com/android/systemui/car/systembar/CarSystemBar.java
index 3c98d52..9c6ee64 100644
--- a/src/com/android/systemui/car/systembar/CarSystemBar.java
+++ b/src/com/android/systemui/car/systembar/CarSystemBar.java
@@ -77,8 +77,9 @@
 import dagger.Lazy;
 
 /** Navigation bars customized for the automotive use case. */
-public class CarSystemBar extends CoreStartable implements CommandQueue.Callbacks,
+public class CarSystemBar implements CoreStartable, CommandQueue.Callbacks,
         ConfigurationController.ConfigurationListener {
+    private final Context mContext;
     private final CarSystemBarController mCarSystemBarController;
     private final SysuiDarkIconDispatcher mStatusBarIconController;
     private final WindowManager mWindowManager;
@@ -154,7 +155,7 @@
             SystemBarConfigs systemBarConfigs,
             ConfigurationController configurationController
     ) {
-        super(context);
+        mContext = context;
         mCarSystemBarController = carSystemBarController;
         mStatusBarIconController = (SysuiDarkIconDispatcher) darkIconDispatcher;
         mWindowManager = windowManager;
diff --git a/src/com/android/systemui/car/systembar/CarSystemBarButton.java b/src/com/android/systemui/car/systembar/CarSystemBarButton.java
index 79f1011..8f828a6 100644
--- a/src/com/android/systemui/car/systembar/CarSystemBarButton.java
+++ b/src/com/android/systemui/car/systembar/CarSystemBarButton.java
@@ -56,6 +56,8 @@
     private static final String BUTTON_FILTER_DELIMITER = ";";
     private static final String EXTRA_BUTTON_CATEGORIES = "categories";
     private static final String EXTRA_BUTTON_PACKAGES = "packages";
+    private static final String EXTRA_DIALOG_CLOSE_REASON = "reason";
+    private static final String DIALOG_CLOSE_REASON_CAR_SYSTEMBAR_BUTTON = "carsystembarbutton";
     private static final float DEFAULT_SELECTED_ALPHA = 1f;
     private static final float DEFAULT_UNSELECTED_ALPHA = 0.75f;
     private static final float DISABLED_ALPHA = 0.25f;
@@ -315,8 +317,9 @@
                 return;
             }
             boolean startState = mSelected;
-            mContext.sendBroadcastAsUser(new Intent(Intent.ACTION_CLOSE_SYSTEM_DIALOGS),
-                    UserHandle.CURRENT);
+            Intent intent = new Intent(Intent.ACTION_CLOSE_SYSTEM_DIALOGS);
+            intent.putExtra(EXTRA_DIALOG_CLOSE_REASON, DIALOG_CLOSE_REASON_CAR_SYSTEMBAR_BUTTON);
+            mContext.sendBroadcastAsUser(intent, UserHandle.CURRENT);
 
             boolean intentLaunched = false;
             try {
@@ -357,8 +360,9 @@
     /** Defines the behavior of a long click. */
     protected OnLongClickListener getButtonLongClickListener(Intent toSend) {
         return v -> {
-            mContext.sendBroadcastAsUser(new Intent(Intent.ACTION_CLOSE_SYSTEM_DIALOGS),
-                    UserHandle.CURRENT);
+            Intent intent = new Intent(Intent.ACTION_CLOSE_SYSTEM_DIALOGS);
+            intent.putExtra(EXTRA_DIALOG_CLOSE_REASON, DIALOG_CLOSE_REASON_CAR_SYSTEMBAR_BUTTON);
+            mContext.sendBroadcastAsUser(intent, UserHandle.CURRENT);
             try {
                 ActivityOptions options = ActivityOptions.makeBasic();
                 options.setLaunchDisplayId(mContext.getDisplayId());
diff --git a/src/com/android/systemui/car/userswitcher/UserGridRecyclerView.java b/src/com/android/systemui/car/userswitcher/UserGridRecyclerView.java
index 0b94386..1bd67a0 100644
--- a/src/com/android/systemui/car/userswitcher/UserGridRecyclerView.java
+++ b/src/com/android/systemui/car/userswitcher/UserGridRecyclerView.java
@@ -136,6 +136,7 @@
         return mUserManager.getAliveUsers()
                 .stream()
                 .filter(UserInfo::supportsSwitchToByUser)
+                .sorted((u1, u2) -> Long.signum(u1.creationTime - u2.creationTime))
                 .collect(Collectors.toList());
     }
 
diff --git a/src/com/android/systemui/car/voicerecognition/ConnectedDeviceVoiceRecognitionNotifier.java b/src/com/android/systemui/car/voicerecognition/ConnectedDeviceVoiceRecognitionNotifier.java
index 2657c4f..6dff1bd 100644
--- a/src/com/android/systemui/car/voicerecognition/ConnectedDeviceVoiceRecognitionNotifier.java
+++ b/src/com/android/systemui/car/voicerecognition/ConnectedDeviceVoiceRecognitionNotifier.java
@@ -37,7 +37,7 @@
  * Controller responsible for showing toast message when voice recognition over bluetooth device
  * getting activated.
  */
-public class ConnectedDeviceVoiceRecognitionNotifier extends CoreStartable {
+public class ConnectedDeviceVoiceRecognitionNotifier implements CoreStartable {
 
     private static final String TAG = "CarVoiceRecognition";
     @VisibleForTesting
@@ -52,6 +52,7 @@
     private static final String HEADSET_CLIENT_EXTRA_VOICE_RECOGNITION =
             "android.bluetooth.headsetclient.extra.VOICE_RECOGNITION";
 
+    private final Context mContext;
     private final DelayableExecutor mExecutor;
 
     private final BroadcastReceiver mVoiceRecognitionReceiver = new BroadcastReceiver() {
@@ -86,7 +87,7 @@
             Context context,
             @Main DelayableExecutor mainExecutor
     ) {
-        super(context);
+        mContext = context;
         mExecutor = mainExecutor;
     }
 
@@ -95,7 +96,7 @@
     }
 
     @Override
-    protected void onBootCompleted() {
+    public void onBootCompleted() {
         IntentFilter filter = new IntentFilter();
         filter.addAction(HEADSET_CLIENT_ACTION_AG_EVENT);
         mContext.registerReceiverAsUser(mVoiceRecognitionReceiver, UserHandle.ALL, filter,
diff --git a/src/com/android/systemui/car/volume/CarVolumeDialogImpl.java b/src/com/android/systemui/car/volume/CarVolumeDialogImpl.java
index 6c064ee..f306824 100644
--- a/src/com/android/systemui/car/volume/CarVolumeDialogImpl.java
+++ b/src/com/android/systemui/car/volume/CarVolumeDialogImpl.java
@@ -22,6 +22,8 @@
 import android.animation.Animator;
 import android.animation.AnimatorInflater;
 import android.animation.AnimatorSet;
+import android.animation.ObjectAnimator;
+import android.animation.PropertyValuesHolder;
 import android.annotation.DrawableRes;
 import android.annotation.Nullable;
 import android.app.Dialog;
@@ -65,6 +67,7 @@
 import com.android.systemui.R;
 import com.android.systemui.car.CarServiceProvider;
 import com.android.systemui.plugins.VolumeDialog;
+import com.android.systemui.statusbar.policy.ConfigurationController;
 import com.android.systemui.volume.Events;
 import com.android.systemui.volume.SystemUIInterpolators;
 import com.android.systemui.volume.VolumeDialogImpl;
@@ -80,7 +83,8 @@
  *
  * Methods ending in "H" must be called on the (ui) handler.
  */
-public class CarVolumeDialogImpl implements VolumeDialog {
+public class CarVolumeDialogImpl
+        implements VolumeDialog, ConfigurationController.ConfigurationListener {
 
     private static final String TAG = "CarVolumeDialog";
     private static final boolean DEBUG = Build.IS_USERDEBUG || Build.IS_ENG;
@@ -105,6 +109,7 @@
     private final int mExpNormalTimeout;
     private final int mExpHoveringTimeout;
     private final CarServiceProvider mCarServiceProvider;
+    private final ConfigurationController mConfigurationController;
 
     private Window mWindow;
     private CustomDialog mDialog;
@@ -194,7 +199,10 @@
         }
     };
 
-    public CarVolumeDialogImpl(Context context, CarServiceProvider carServiceProvider) {
+    public CarVolumeDialogImpl(
+            Context context,
+            CarServiceProvider carServiceProvider,
+            ConfigurationController configurationController) {
         mContext = context;
         mCarServiceProvider = carServiceProvider;
         mKeyguard = (KeyguardManager) mContext.getSystemService(Context.KEYGUARD_SERVICE);
@@ -206,6 +214,7 @@
                 R.integer.car_volume_dialog_display_expanded_normal_timeout);
         mExpHoveringTimeout = mContext.getResources().getInteger(
                 R.integer.car_volume_dialog_display_expanded_hovering_timeout);
+        mConfigurationController = configurationController;
     }
 
     private static int getSeekbarValue(CarAudioManager carAudioManager, int volumeGroupId) {
@@ -235,6 +244,7 @@
         mContext.registerReceiverAsUser(mHomeButtonPressedBroadcastReceiver, UserHandle.CURRENT,
                 new IntentFilter(Intent.ACTION_CLOSE_SYSTEM_DIALOGS), /* broadcastPermission= */
                 null, /* scheduler= */ null, Context.RECEIVER_EXPORTED);
+        mConfigurationController.addCallback(this);
     }
 
     @Override
@@ -244,6 +254,15 @@
         mContext.unregisterReceiver(mHomeButtonPressedBroadcastReceiver);
 
         cleanupAudioManager();
+        mConfigurationController.removeCallback(this);
+    }
+
+    @Override
+    public void onLayoutDirectionChanged(boolean isLayoutRtl) {
+        if (mListView != null) {
+            mListView.setLayoutDirection(
+                    isLayoutRtl ? View.LAYOUT_DIRECTION_RTL : View.LAYOUT_DIRECTION_LTR);
+        }
     }
 
     /**
@@ -295,12 +314,13 @@
         mDialog.setOnShowListener(dialog -> {
             mListView.setTranslationY(-mListView.getHeight());
             mListView.setAlpha(0);
-            mListView.animate()
-                    .alpha(1)
-                    .translationY(0)
-                    .setDuration(LISTVIEW_ANIMATION_DURATION_IN_MILLIS)
-                    .setInterpolator(new SystemUIInterpolators.LogDecelerateInterpolator())
-                    .start();
+            PropertyValuesHolder pvhAlpha = PropertyValuesHolder.ofFloat(View.ALPHA, 1f);
+            PropertyValuesHolder pvhY = PropertyValuesHolder.ofFloat(View.TRANSLATION_Y, 0f);
+            ObjectAnimator showAnimator = ObjectAnimator.ofPropertyValuesHolder(mListView, pvhAlpha,
+                    pvhY);
+            showAnimator.setDuration(LISTVIEW_ANIMATION_DURATION_IN_MILLIS);
+            showAnimator.setInterpolator(new SystemUIInterpolators.LogDecelerateInterpolator());
+            showAnimator.start();
         });
         mListView = mWindow.findViewById(R.id.volume_list);
         mListView.setOnHoverListener((v, event) -> {
@@ -383,26 +403,15 @@
             return;
         }
 
-        mDismissing = true;
-        mListView.animate()
-                .alpha(0)
-                .translationY(-mListView.getHeight())
-                .setDuration(LISTVIEW_ANIMATION_DURATION_IN_MILLIS)
-                .setInterpolator(new SystemUIInterpolators.LogAccelerateInterpolator())
-                .withEndAction(() -> mHandler.postDelayed(() -> {
-                    if (DEBUG) {
-                        Log.d(TAG, "mDialog.dismiss()");
-                    }
-                    mDialog.dismiss();
-                    mDismissing = false;
-                    // if mExpandIcon is null that means user never clicked on the expanded arrow
-                    // which implies that the dialog is still not expanded. In that case we do
-                    // not want to reset the state
-                    if (mExpandIcon != null && mExpanded) {
-                        toggleDialogExpansion(/* isClicked = */ false);
-                    }
-                }, DISMISS_DELAY_IN_MILLIS))
-                .start();
+        PropertyValuesHolder pvhAlpha = PropertyValuesHolder.ofFloat(View.ALPHA, 0f);
+        PropertyValuesHolder pvhY = PropertyValuesHolder.ofFloat(View.TRANSLATION_Y,
+                (float) -mListView.getHeight());
+        ObjectAnimator dismissAnimator = ObjectAnimator.ofPropertyValuesHolder(mListView, pvhAlpha,
+                pvhY);
+        dismissAnimator.setDuration(LISTVIEW_ANIMATION_DURATION_IN_MILLIS);
+        dismissAnimator.setInterpolator(new SystemUIInterpolators.LogAccelerateInterpolator());
+        dismissAnimator.addListener(new DismissAnimationListener());
+        dismissAnimator.start();
 
         Events.writeEvent(Events.EVENT_DISMISS_DIALOG, reason);
     }
@@ -605,6 +614,44 @@
         }
     }
 
+    private final class DismissAnimationListener implements Animator.AnimatorListener {
+        @Override
+        public void onAnimationStart(Animator animation) {
+            mDismissing = true;
+        }
+
+        @Override
+        public void onAnimationEnd(Animator animation) {
+            mHandler.postDelayed(() -> {
+                if (DEBUG) {
+                    Log.d(TAG, "mDialog.dismiss()");
+                }
+                mDialog.dismiss();
+                mDismissing = false;
+                // if mExpandIcon is null that means user never clicked on the expanded arrow
+                // which implies that the dialog is still not expanded. In that case we do
+                // not want to reset the state
+                if (mExpandIcon != null && mExpanded) {
+                    toggleDialogExpansion(/* isClicked = */ false);
+                }
+            }, DISMISS_DELAY_IN_MILLIS);
+        }
+
+        @Override
+        public void onAnimationCancel(Animator animation) {
+            // A canceled animation will also call onAnimationEnd so any necessary cleanup will
+            // already happen there
+            if (DEBUG) {
+                Log.d(TAG, "dismiss animation canceled");
+            }
+        }
+
+        @Override
+        public void onAnimationRepeat(Animator animation) {
+            // no-op
+        }
+    }
+
     private final class ExpandIconListener implements View.OnClickListener {
         @Override
         public void onClick(final View v) {
diff --git a/src/com/android/systemui/car/volume/CarVolumeModule.java b/src/com/android/systemui/car/volume/CarVolumeModule.java
index c51dff1..ee35b16 100644
--- a/src/com/android/systemui/car/volume/CarVolumeModule.java
+++ b/src/com/android/systemui/car/volume/CarVolumeModule.java
@@ -22,6 +22,7 @@
 
 import com.android.systemui.car.CarServiceProvider;
 import com.android.systemui.plugins.VolumeDialog;
+import com.android.systemui.statusbar.policy.ConfigurationController;
 import com.android.systemui.volume.VolumeComponent;
 import com.android.systemui.volume.VolumeDialogComponent;
 
@@ -40,7 +41,8 @@
     /** */
     @Provides
     static VolumeDialog provideVolumeDialog(Context context,
-            CarServiceProvider carServiceProvider) {
-        return new CarVolumeDialogImpl(context, carServiceProvider);
+            CarServiceProvider carServiceProvider,
+            ConfigurationController configurationController) {
+        return new CarVolumeDialogImpl(context, carServiceProvider, configurationController);
     }
 }
diff --git a/src/com/android/systemui/car/volume/VolumeUI.java b/src/com/android/systemui/car/volume/VolumeUI.java
index 46341da..05dd065 100644
--- a/src/com/android/systemui/car/volume/VolumeUI.java
+++ b/src/com/android/systemui/car/volume/VolumeUI.java
@@ -18,7 +18,6 @@
 
 import android.car.Car;
 import android.car.media.CarAudioManager;
-import android.content.Context;
 import android.content.res.Configuration;
 import android.content.res.Resources;
 import android.os.Handler;
@@ -39,7 +38,7 @@
 
 /** The entry point for controlling the volume ui in cars. */
 @SysUISingleton
-public class VolumeUI extends CoreStartable {
+public class VolumeUI implements CoreStartable {
 
     private static final String TAG = "VolumeUI";
     private final Resources mResources;
@@ -76,13 +75,11 @@
 
     @Inject
     public VolumeUI(
-            Context context,
             @Main Resources resources,
             @Main Handler mainHandler,
             CarServiceProvider carServiceProvider,
             Lazy<VolumeDialogComponent> volumeDialogComponentLazy
     ) {
-        super(context);
         mResources = resources;
         mMainHandler = mainHandler;
         mCarServiceProvider = carServiceProvider;
@@ -109,8 +106,7 @@
     }
 
     @Override
-    protected void onConfigurationChanged(Configuration newConfig) {
-        super.onConfigurationChanged(newConfig);
+    public void onConfigurationChanged(Configuration newConfig) {
         if (!mEnabled) return;
         if (mVolumeDialogComponent != null) {
             mVolumeDialogComponent.onConfigurationChanged(newConfig);
diff --git a/src/com/android/systemui/car/window/SystemUIOverlayWindowManager.java b/src/com/android/systemui/car/window/SystemUIOverlayWindowManager.java
index 2f06f76..40fd28b 100644
--- a/src/com/android/systemui/car/window/SystemUIOverlayWindowManager.java
+++ b/src/com/android/systemui/car/window/SystemUIOverlayWindowManager.java
@@ -35,8 +35,9 @@
  * OverlayViewController}(s) to allow for the correct visibility of system bars.
  */
 @SysUISingleton
-public class SystemUIOverlayWindowManager extends CoreStartable {
+public class SystemUIOverlayWindowManager implements CoreStartable {
     private static final String TAG = "SystemUIOverlayWM";
+    private final Context mContext;
     private final Map<Class<?>, Provider<OverlayViewMediator>>
             mContentMediatorCreators;
     private final OverlayViewGlobalStateController mOverlayViewGlobalStateController;
@@ -46,7 +47,7 @@
             Context context,
             Map<Class<?>, Provider<OverlayViewMediator>> contentMediatorCreators,
             OverlayViewGlobalStateController overlayViewGlobalStateController) {
-        super(context);
+        mContext = context;
         mContentMediatorCreators = contentMediatorCreators;
         mOverlayViewGlobalStateController = overlayViewGlobalStateController;
     }
diff --git a/tests/src/com/android/systemui/car/keyguard/CarKeyguardViewControllerTest.java b/tests/src/com/android/systemui/car/keyguard/CarKeyguardViewControllerTest.java
index 0479882..3d49259 100644
--- a/tests/src/com/android/systemui/car/keyguard/CarKeyguardViewControllerTest.java
+++ b/tests/src/com/android/systemui/car/keyguard/CarKeyguardViewControllerTest.java
@@ -85,7 +85,7 @@
 
         when(mKeyguardBouncerFactory.create(
                 any(ViewGroup.class),
-                any(KeyguardBouncer.BouncerExpansionCallback.class)))
+                any(KeyguardBouncer.PrimaryBouncerExpansionCallback.class)))
                 .thenReturn(mBouncer);
         when(mSystemUIOverlayWindowController.getBaseLayout()).thenReturn(mockBaseLayout);
         mExecutor = new FakeExecutor(new FakeSystemClock());
diff --git a/tests/src/com/android/systemui/car/qc/ProfileSwitcherTest.java b/tests/src/com/android/systemui/car/qc/ProfileSwitcherTest.java
index 145ad58..8d754cd 100644
--- a/tests/src/com/android/systemui/car/qc/ProfileSwitcherTest.java
+++ b/tests/src/com/android/systemui/car/qc/ProfileSwitcherTest.java
@@ -37,8 +37,8 @@
 import android.car.util.concurrent.AsyncFuture;
 import android.content.Intent;
 import android.content.pm.UserInfo;
-import android.os.UserManager;
 import android.os.UserHandle;
+import android.os.UserManager;
 import android.testing.AndroidTestingRunner;
 import android.testing.TestableLooper;
 
@@ -177,6 +177,25 @@
     }
 
     @Test
+    public void switchAllowed_orderUsersByCreationTime() {
+        UserInfo user1 = generateUser(1001, "User2", /* supportsSwitch= */ true,
+                /* isGuest= */ false);
+        UserInfo user2 = generateUser(1000, "User1", /* supportsSwitch= */ true,
+                /* isGuest= */ false);
+        mAliveUsers.add(user1);
+        mAliveUsers.add(user2);
+        List<QCRow> rows = getProfileRows();
+        // Expect four rows - one for each user, one for the guest user, and one for add user
+        assertThat(rows).hasSize(4);
+        assertThat(rows.get(0).getTitle()).isEqualTo("User2");
+        assertThat(rows.get(1).getTitle()).isEqualTo("User1");
+        assertThat(rows.get(2).getTitle()).isEqualTo(
+                mContext.getString(com.android.internal.R.string.guest_name));
+        assertThat(rows.get(3).getTitle()).isEqualTo(
+                mContext.getString(R.string.car_add_user));
+    }
+
+    @Test
     public void switchAllowed_userNotSwitchable_returnsValidRows() {
         UserInfo user1 = generateUser(1000, "User1", /* supportsSwitch= */ true,
                 /* isGuest= */ false);
@@ -304,6 +323,7 @@
         UserInfo info = mock(UserInfo.class);
         info.id = id;
         info.name = name;
+        info.creationTime = System.currentTimeMillis();
         when(info.supportsSwitchToByUser()).thenReturn(supportsSwitch);
         when(info.isGuest()).thenReturn(isGuest);
         return info;