summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--core/res/res/layout/car_user_switching_dialog.xml37
-rw-r--r--core/res/res/values/dimens_car.xml7
-rw-r--r--core/res/res/values/symbols.xml7
-rw-r--r--packages/CarSystemUI/AndroidManifest.xml2
-rw-r--r--packages/CarSystemUI/res/layout/car_user_switching_dialog.xml43
-rw-r--r--packages/CarSystemUI/res/layout/sysui_overlay_window.xml5
-rw-r--r--packages/CarSystemUI/res/values/colors.xml3
-rw-r--r--packages/CarSystemUI/res/values/config.xml4
-rw-r--r--packages/CarSystemUI/res/values/dimens.xml32
-rw-r--r--packages/CarSystemUI/res/values/strings.xml6
-rw-r--r--packages/CarSystemUI/src/com/android/systemui/car/userswitcher/FullscreenUserSwitcherViewMediator.java10
-rw-r--r--packages/CarSystemUI/src/com/android/systemui/car/userswitcher/UserSwitchTransitionViewController.java126
-rw-r--r--packages/CarSystemUI/src/com/android/systemui/car/userswitcher/UserSwitchTransitionViewMediator.java85
-rw-r--r--packages/CarSystemUI/src/com/android/systemui/car/window/OverlayViewMediator.java3
-rw-r--r--packages/CarSystemUI/src/com/android/systemui/car/window/OverlayWindowModule.java8
-rw-r--r--packages/CarSystemUI/tests/src/com/android/systemui/car/userswitcher/UserSwitchTransitionViewControllerTest.java145
-rw-r--r--packages/CarSystemUI/tests/src/com/android/systemui/car/userswitcher/UserSwitchTransitionViewMediatorTest.java76
-rw-r--r--services/core/java/com/android/server/am/CarUserSwitchingDialog.java193
-rw-r--r--services/core/java/com/android/server/am/UserController.java14
19 files changed, 549 insertions, 257 deletions
diff --git a/core/res/res/layout/car_user_switching_dialog.xml b/core/res/res/layout/car_user_switching_dialog.xml
deleted file mode 100644
index d7274348bd16..000000000000
--- a/core/res/res/layout/car_user_switching_dialog.xml
+++ /dev/null
@@ -1,37 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
- Copyright (C) 2018 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.
--->
-<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
- android:fitsSystemWindows="true"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content">
-
- <ImageView
- android:id="@+id/user_loading_avatar"
- android:layout_width="@dimen/car_fullscreen_user_pod_image_avatar_width"
- android:layout_height="@dimen/car_fullscreen_user_pod_image_avatar_height"
- android:layout_centerHorizontal="true"/>
-
- <TextView android:id="@+id/user_loading"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:layout_marginTop="@dimen/car_padding_4"
- android:textSize="@dimen/car_body1_size"
- android:textColor="@color/car_body1"
- android:layout_below="@id/user_loading_avatar"
- android:gravity="center"/>
-
-</RelativeLayout> \ No newline at end of file
diff --git a/core/res/res/values/dimens_car.xml b/core/res/res/values/dimens_car.xml
index bd4c48427e0e..2c4f4c89ab81 100644
--- a/core/res/res/values/dimens_car.xml
+++ b/core/res/res/values/dimens_car.xml
@@ -16,14 +16,7 @@
*/
-->
<resources>
- <dimen name="car_fullscreen_user_pod_icon_text_size">64sp</dimen>
- <dimen name="car_fullscreen_user_pod_width">243dp</dimen>
- <dimen name="car_fullscreen_user_pod_height">356dp</dimen>
- <dimen name="car_fullscreen_user_pod_image_avatar_width">96dp</dimen>
- <dimen name="car_fullscreen_user_pod_image_avatar_height">96dp</dimen>
<dimen name="car_large_avatar_size">96dp</dimen>
-
-
<!-- Application Bar -->
<dimen name="car_app_bar_height">80dp</dimen>
<!-- Margin -->
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index 369a3e51df26..19cdbbf83ebf 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -3638,13 +3638,6 @@
<java-symbol type="color" name="car_card_dark" />
<java-symbol type="dimen" name="car_body1_size" />
<java-symbol type="dimen" name="car_padding_4" />
- <java-symbol type="dimen" name="car_fullscreen_user_pod_icon_text_size" />
- <java-symbol type="dimen" name="car_fullscreen_user_pod_image_avatar_height" />
- <java-symbol type="dimen" name="car_fullscreen_user_pod_image_avatar_width" />
- <java-symbol type="dimen" name="car_large_avatar_size" />
- <java-symbol type="layout" name="car_user_switching_dialog" />
- <java-symbol type="id" name="user_loading_avatar" />
- <java-symbol type="id" name="user_loading" />
<java-symbol type="style" name="Theme.DeviceDefault.Light.Dialog.Alert.UserSwitchingDialog" />
<java-symbol type="string" name="battery_saver_description_with_learn_more" />
diff --git a/packages/CarSystemUI/AndroidManifest.xml b/packages/CarSystemUI/AndroidManifest.xml
index 261b9f508ccd..1dd02919a093 100644
--- a/packages/CarSystemUI/AndroidManifest.xml
+++ b/packages/CarSystemUI/AndroidManifest.xml
@@ -25,4 +25,6 @@
<uses-permission android:name="android.car.permission.CAR_ENROLL_TRUST"/>
<!-- This permission is required to get bluetooth broadcast. -->
<uses-permission android:name="android.permission.BLUETOOTH" />
+ <!-- This permission is required to check the foreground user id. -->
+ <uses-permission android:name="android.permission.INTERACT_ACROSS_USERS_FULL" />
</manifest>
diff --git a/packages/CarSystemUI/res/layout/car_user_switching_dialog.xml b/packages/CarSystemUI/res/layout/car_user_switching_dialog.xml
new file mode 100644
index 000000000000..0a294246dfaa
--- /dev/null
+++ b/packages/CarSystemUI/res/layout/car_user_switching_dialog.xml
@@ -0,0 +1,43 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2020 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:fitsSystemWindows="true"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:gravity="center"
+ android:background="@color/car_user_switching_dialog_background_color">
+ <LinearLayout
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:orientation="vertical"
+ android:layout_gravity="center"
+ android:gravity="center_horizontal">
+ <ImageView
+ android:id="@+id/user_loading_avatar"
+ android:layout_width="@dimen/car_fullscreen_user_pod_image_avatar_width"
+ android:layout_height="@dimen/car_fullscreen_user_pod_image_avatar_height"/>
+
+ <TextView
+ android:id="@+id/user_loading"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginTop="@dimen/car_user_switching_dialog_loading_text_margin_top"
+ android:textSize="@dimen/car_user_switching_dialog_loading_text_font_size"
+ android:textColor="@color/car_user_switching_dialog_loading_text_color"
+ android:layout_below="@id/user_loading_avatar"/>
+ </LinearLayout>
+</FrameLayout>
diff --git a/packages/CarSystemUI/res/layout/sysui_overlay_window.xml b/packages/CarSystemUI/res/layout/sysui_overlay_window.xml
index 35423231bb97..2dc499c160c6 100644
--- a/packages/CarSystemUI/res/layout/sysui_overlay_window.xml
+++ b/packages/CarSystemUI/res/layout/sysui_overlay_window.xml
@@ -39,4 +39,9 @@
android:layout_height="match_parent"
android:layout="@layout/car_fullscreen_user_switcher"/>
+ <ViewStub android:id="@+id/user_switching_dialog_stub"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:layout="@layout/car_user_switching_dialog"/>
+
</FrameLayout> \ No newline at end of file
diff --git a/packages/CarSystemUI/res/values/colors.xml b/packages/CarSystemUI/res/values/colors.xml
index 3e44721848a1..0e84d517759a 100644
--- a/packages/CarSystemUI/res/values/colors.xml
+++ b/packages/CarSystemUI/res/values/colors.xml
@@ -55,4 +55,7 @@
<color name="list_divider_color">@*android:color/car_list_divider_light</color>
<color name="car_volume_item_divider_color">@*android:color/car_list_divider</color>
<color name="car_volume_item_background_color">@*android:color/car_card_dark</color>
+
+ <color name="car_user_switching_dialog_background_color">@android:color/black</color>
+ <color name="car_user_switching_dialog_loading_text_color">@*android:color/car_body1</color>
</resources>
diff --git a/packages/CarSystemUI/res/values/config.xml b/packages/CarSystemUI/res/values/config.xml
index 67066d7c426f..4bf0fca445d1 100644
--- a/packages/CarSystemUI/res/values/config.xml
+++ b/packages/CarSystemUI/res/values/config.xml
@@ -70,11 +70,13 @@
to a constant alpha percent value using the initial alpha. -->
<integer name="config_finalNotificationBackgroundAlpha">100</integer>
- <!-- Car System UI's OverlayViewsMediator-->
+ <!-- Car System UI's OverlayViewsMediator.
+ Whenever a new class is added, make sure to also add that class to OverlayWindowModule. -->
<string-array name="config_carSystemUIOverlayViewsMediators" translatable="false">
<item>@string/config_notificationPanelViewMediator</item>
<item>com.android.systemui.car.keyguard.CarKeyguardViewMediator</item>
<item>com.android.systemui.car.userswitcher.FullscreenUserSwitcherViewMediator</item>
+ <item>com.android.systemui.car.userswitcher.UserSwitchTransitionViewMediator</item>
</string-array>
<!--
diff --git a/packages/CarSystemUI/res/values/dimens.xml b/packages/CarSystemUI/res/values/dimens.xml
index 9014eb15d6cf..ed0b4853994d 100644
--- a/packages/CarSystemUI/res/values/dimens.xml
+++ b/packages/CarSystemUI/res/values/dimens.xml
@@ -15,6 +15,32 @@
~ limitations under the License
-->
<resources>
+ <!-- Text size for car -->
+ <dimen name="car_title_size">32sp</dimen>
+ <dimen name="car_title2_size">32sp</dimen>
+ <dimen name="car_headline1_size">45sp</dimen>
+ <dimen name="car_headline2_size">32sp</dimen>
+ <dimen name="car_headline3_size">24sp</dimen>
+ <dimen name="car_headline4_size">20sp</dimen>
+ <dimen name="car_body1_size">32sp</dimen>
+ <dimen name="car_body2_size">28sp</dimen>
+ <dimen name="car_body3_size">26sp</dimen>
+ <dimen name="car_body4_size">24sp</dimen>
+ <!-- car_body5_size is deprecated -->
+ <dimen name="car_body5_size">18sp</dimen>
+ <dimen name="car_label1_size">26sp</dimen>
+ <dimen name="car_label2_size">64sp</dimen>
+ <dimen name="car_action1_size">26sp</dimen>
+ <dimen name="car_action2_size">26sp</dimen>
+ <!-- Paddings -->
+ <dimen name="car_padding_0">4dp</dimen>
+ <dimen name="car_padding_1">8dp</dimen>
+ <dimen name="car_padding_2">16dp</dimen>
+ <dimen name="car_padding_3">24dp</dimen>
+ <dimen name="car_padding_4">32dp</dimen>
+ <dimen name="car_padding_5">64dp</dimen>
+ <dimen name="car_padding_6">96dp</dimen>
+
<!--
Note: status bar height and navigation bar heights are defined
in frameworks/base/core package and thus will have no effect if
@@ -156,4 +182,10 @@
<dimen name="car_user_switcher_container_height">420dp</dimen>
<!-- This must be the negative of car_user_switcher_container_height for the animation. -->
<dimen name="car_user_switcher_container_anim_height">-420dp</dimen>
+
+ <!-- dimensions for car user switching dialog -->
+ <dimen name="car_fullscreen_user_pod_image_avatar_width">96dp</dimen>
+ <dimen name="car_fullscreen_user_pod_image_avatar_height">96dp</dimen>
+ <dimen name="car_user_switching_dialog_loading_text_margin_top">@*android:dimen/car_padding_4</dimen>
+ <dimen name="car_user_switching_dialog_loading_text_font_size">@*android:dimen/car_body1_size</dimen>
</resources>
diff --git a/packages/CarSystemUI/res/values/strings.xml b/packages/CarSystemUI/res/values/strings.xml
index 9fae4b3e2b46..67fd5bb68521 100644
--- a/packages/CarSystemUI/res/values/strings.xml
+++ b/packages/CarSystemUI/res/values/strings.xml
@@ -15,7 +15,7 @@
~ limitations under the License.
-->
-<resources>
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<!-- String to represent lowest setting of an HVAC system [CHAR LIMIT=10]-->
<string name="hvac_min_text">Min</string>
<!-- String to represent largest setting of an HVAC system [CHAR LIMIT=10]-->
@@ -34,4 +34,8 @@
<string name="user_add_user_message_setup">When you add a new user, that person needs to set up their space.</string>
<!-- Message to inform user that the newly created user will have permissions to update apps for all other users. [CHAR LIMIT=100] -->
<string name="user_add_user_message_update">Any user can update apps for all other users.</string>
+ <!-- Message to inform user that the new user profile is loading. [CHAR LIMIT=20] -->
+ <string name="car_loading_profile">Loading</string>
+ <!-- Message to inform user that the new user profile is loading with additional information on the previous and the next user. [CHAR LIMIT=100] -->
+ <string name="car_loading_profile_developer_message">Loading user (from <xliff:g id="from_user" example="10">%1$d</xliff:g> to <xliff:g id="to_user" example="12">%2$d</xliff:g>)</string>
</resources>
diff --git a/packages/CarSystemUI/src/com/android/systemui/car/userswitcher/FullscreenUserSwitcherViewMediator.java b/packages/CarSystemUI/src/com/android/systemui/car/userswitcher/FullscreenUserSwitcherViewMediator.java
index 346c38ced766..8b399f888eb3 100644
--- a/packages/CarSystemUI/src/com/android/systemui/car/userswitcher/FullscreenUserSwitcherViewMediator.java
+++ b/packages/CarSystemUI/src/com/android/systemui/car/userswitcher/FullscreenUserSwitcherViewMediator.java
@@ -34,16 +34,19 @@ public class FullscreenUserSwitcherViewMediator implements OverlayViewMediator {
private final StatusBarStateController mStatusBarStateController;
private final FullScreenUserSwitcherViewController mFullScreenUserSwitcherViewController;
private final CarKeyguardViewController mCarKeyguardViewController;
+ private final UserSwitchTransitionViewController mUserSwitchTransitionViewController;
@Inject
public FullscreenUserSwitcherViewMediator(
StatusBarStateController statusBarStateController,
CarKeyguardViewController carKeyguardViewController,
+ UserSwitchTransitionViewController userSwitchTransitionViewController,
FullScreenUserSwitcherViewController fullScreenUserSwitcherViewController) {
mStatusBarStateController = statusBarStateController;
- mFullScreenUserSwitcherViewController = fullScreenUserSwitcherViewController;
mCarKeyguardViewController = carKeyguardViewController;
+ mUserSwitchTransitionViewController = userSwitchTransitionViewController;
+ mFullScreenUserSwitcherViewController = fullScreenUserSwitcherViewController;
}
@Override
@@ -74,6 +77,11 @@ public class FullscreenUserSwitcherViewMediator implements OverlayViewMediator {
private void onUserSelected(UserGridRecyclerView.UserRecord record) {
if (record.mType != UserGridRecyclerView.UserRecord.FOREGROUND_USER) {
mCarKeyguardViewController.hideKeyguardToPrepareBouncer();
+ // If guest user, we cannot use record.mInfo.id and should listen to the User lifecycle
+ // event instead.
+ if (record.mType != UserGridRecyclerView.UserRecord.START_GUEST) {
+ mUserSwitchTransitionViewController.handleShow(record.mInfo.id);
+ }
}
hide();
diff --git a/packages/CarSystemUI/src/com/android/systemui/car/userswitcher/UserSwitchTransitionViewController.java b/packages/CarSystemUI/src/com/android/systemui/car/userswitcher/UserSwitchTransitionViewController.java
new file mode 100644
index 000000000000..775ef8152ca2
--- /dev/null
+++ b/packages/CarSystemUI/src/com/android/systemui/car/userswitcher/UserSwitchTransitionViewController.java
@@ -0,0 +1,126 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.car.userswitcher;
+
+import static android.car.settings.CarSettings.Global.ENABLE_USER_SWITCH_DEVELOPER_MESSAGE;
+
+import android.annotation.UserIdInt;
+import android.content.Context;
+import android.content.res.Resources;
+import android.graphics.Bitmap;
+import android.os.Handler;
+import android.os.UserHandle;
+import android.os.UserManager;
+import android.provider.Settings;
+import android.widget.ImageView;
+import android.widget.TextView;
+
+import com.android.internal.annotations.GuardedBy;
+import com.android.settingslib.drawable.CircleFramedDrawable;
+import com.android.systemui.R;
+import com.android.systemui.car.window.OverlayViewController;
+import com.android.systemui.car.window.OverlayViewGlobalStateController;
+import com.android.systemui.dagger.qualifiers.Main;
+
+import javax.inject.Inject;
+import javax.inject.Singleton;
+
+/**
+ * Handles showing and hiding UserSwitchTransitionView that is mounted to SystemUiOverlayWindow.
+ */
+@Singleton
+public class UserSwitchTransitionViewController extends OverlayViewController {
+ private static final String TAG = "UserSwitchTransitionViewController";
+ private static final String ENABLE_DEVELOPER_MESSAGE_TRUE = "true";
+
+ private final Context mContext;
+ private final Handler mHandler;
+ private final Resources mResources;
+ private final UserManager mUserManager;
+
+ @GuardedBy("this")
+ private boolean mShowing;
+ private int mPreviousUserId = UserHandle.USER_NULL;
+
+ @Inject
+ public UserSwitchTransitionViewController(
+ Context context,
+ @Main Handler handler,
+ @Main Resources resources,
+ UserManager userManager,
+ OverlayViewGlobalStateController overlayViewGlobalStateController) {
+
+ super(R.id.user_switching_dialog_stub, overlayViewGlobalStateController);
+
+ mContext = context;
+ mHandler = handler;
+ mResources = resources;
+ mUserManager = userManager;
+ }
+
+ /**
+ * Makes the user switch transition view appear and draws the content inside of it if a user
+ * that is different from the previous user is provided and if the dialog is not already
+ * showing.
+ */
+ void handleShow(@UserIdInt int newUserId) {
+ if (mPreviousUserId == newUserId || mShowing) return;
+ mShowing = true;
+ mHandler.post(() -> {
+ start();
+ populateDialog(mPreviousUserId, newUserId);
+ // next time a new user is selected, this current new user will be the previous user.
+ mPreviousUserId = newUserId;
+ });
+ }
+
+ void handleHide() {
+ if (!mShowing) return;
+ mShowing = false;
+ mHandler.post(this::stop);
+ }
+
+ private void populateDialog(@UserIdInt int previousUserId, @UserIdInt int newUserId) {
+ drawUserIcon(newUserId);
+ populateLoadingText(previousUserId, newUserId);
+ }
+
+ private void drawUserIcon(int newUserId) {
+ Bitmap bitmap = mUserManager.getUserIcon(newUserId);
+ if (bitmap != null) {
+ CircleFramedDrawable drawable = CircleFramedDrawable.getInstance(mContext, bitmap);
+ ((ImageView) getLayout().findViewById(R.id.user_loading_avatar))
+ .setImageDrawable(drawable);
+ }
+ }
+
+ private void populateLoadingText(@UserIdInt int previousUserId, @UserIdInt int newUserId) {
+ TextView msgView = getLayout().findViewById(R.id.user_loading);
+
+ boolean showInfo = ENABLE_DEVELOPER_MESSAGE_TRUE.equals(
+ Settings.Global.getString(mContext.getContentResolver(),
+ ENABLE_USER_SWITCH_DEVELOPER_MESSAGE));
+
+ if (showInfo && mPreviousUserId != UserHandle.USER_NULL) {
+ msgView.setText(
+ mResources.getString(R.string.car_loading_profile_developer_message,
+ previousUserId, newUserId));
+ } else {
+ msgView.setText(mResources.getString(R.string.car_loading_profile));
+ }
+ }
+}
diff --git a/packages/CarSystemUI/src/com/android/systemui/car/userswitcher/UserSwitchTransitionViewMediator.java b/packages/CarSystemUI/src/com/android/systemui/car/userswitcher/UserSwitchTransitionViewMediator.java
new file mode 100644
index 000000000000..aea691443290
--- /dev/null
+++ b/packages/CarSystemUI/src/com/android/systemui/car/userswitcher/UserSwitchTransitionViewMediator.java
@@ -0,0 +1,85 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.car.userswitcher;
+
+import android.app.ActivityManager;
+import android.car.Car;
+import android.car.user.CarUserManager;
+import android.util.Log;
+
+import com.android.internal.annotations.VisibleForTesting;
+import com.android.systemui.car.CarServiceProvider;
+import com.android.systemui.car.window.OverlayViewMediator;
+
+import javax.inject.Inject;
+
+/**
+ * Registers listeners that subscribe to events that show or hide CarUserSwitchingDialog that is
+ * mounted to SystemUiOverlayWindow.
+ */
+public class UserSwitchTransitionViewMediator implements OverlayViewMediator,
+ CarUserManager.UserSwitchUiCallback {
+ private static final String TAG = "UserSwitchTransitionViewMediator";
+
+ private final CarServiceProvider mCarServiceProvider;
+ private final UserSwitchTransitionViewController mUserSwitchTransitionViewController;
+
+ @Inject
+ public UserSwitchTransitionViewMediator(
+ CarServiceProvider carServiceProvider,
+ UserSwitchTransitionViewController userSwitchTransitionViewController) {
+ mCarServiceProvider = carServiceProvider;
+ mUserSwitchTransitionViewController = userSwitchTransitionViewController;
+ }
+
+ @Override
+ public void registerListeners() {
+ mCarServiceProvider.addListener(car -> {
+ CarUserManager carUserManager =
+ (CarUserManager) car.getCarManager(Car.CAR_USER_SERVICE);
+
+ if (carUserManager != null) {
+ carUserManager.setUserSwitchUiCallback(this);
+ carUserManager.addListener(Runnable::run, this::handleUserLifecycleEvent);
+ } else {
+ Log.e(TAG, "registerListeners: CarUserManager could not be obtained.");
+ }
+ });
+ }
+
+ @Override
+ public void setupOverlayContentViewControllers() {
+ // no-op.
+ }
+
+ @Override
+ public void showUserSwitchDialog(int userId) {
+ mUserSwitchTransitionViewController.handleShow(userId);
+ }
+
+ @VisibleForTesting
+ void handleUserLifecycleEvent(CarUserManager.UserLifecycleEvent event) {
+ if (event.getEventType() == CarUserManager.USER_LIFECYCLE_EVENT_TYPE_STARTING
+ && ActivityManager.getCurrentUser() == event.getUserId()) {
+ mUserSwitchTransitionViewController.handleShow(event.getUserId());
+ }
+
+ if (event.getEventType() == CarUserManager.USER_LIFECYCLE_EVENT_TYPE_SWITCHING) {
+ mUserSwitchTransitionViewController.handleHide();
+ }
+ }
+}
diff --git a/packages/CarSystemUI/src/com/android/systemui/car/window/OverlayViewMediator.java b/packages/CarSystemUI/src/com/android/systemui/car/window/OverlayViewMediator.java
index ac574eda4c9f..3e7b4a2665ee 100644
--- a/packages/CarSystemUI/src/com/android/systemui/car/window/OverlayViewMediator.java
+++ b/packages/CarSystemUI/src/com/android/systemui/car/window/OverlayViewMediator.java
@@ -23,6 +23,9 @@ public interface OverlayViewMediator {
/**
* Register listeners that could use ContentVisibilityAdjuster to show/hide content.
+ *
+ * Note that we do not unregister listeners because SystemUI components are expected to live
+ * for the lifecycle of the device.
*/
void registerListeners();
diff --git a/packages/CarSystemUI/src/com/android/systemui/car/window/OverlayWindowModule.java b/packages/CarSystemUI/src/com/android/systemui/car/window/OverlayWindowModule.java
index 484aa63e8bda..5a16efa3dd9b 100644
--- a/packages/CarSystemUI/src/com/android/systemui/car/window/OverlayWindowModule.java
+++ b/packages/CarSystemUI/src/com/android/systemui/car/window/OverlayWindowModule.java
@@ -21,6 +21,7 @@ import com.android.systemui.car.notification.BottomNotificationPanelViewMediator
import com.android.systemui.car.notification.NotificationPanelViewMediator;
import com.android.systemui.car.notification.TopNotificationPanelViewMediator;
import com.android.systemui.car.userswitcher.FullscreenUserSwitcherViewMediator;
+import com.android.systemui.car.userswitcher.UserSwitchTransitionViewMediator;
import dagger.Binds;
import dagger.Module;
@@ -67,4 +68,11 @@ public abstract class OverlayWindowModule {
@ClassKey(FullscreenUserSwitcherViewMediator.class)
public abstract OverlayViewMediator bindFullscreenUserSwitcherViewsMediator(
FullscreenUserSwitcherViewMediator overlayViewsMediator);
+
+ /** Injects CarUserSwitchingDialogMediator. */
+ @Binds
+ @IntoMap
+ @ClassKey(UserSwitchTransitionViewMediator.class)
+ public abstract OverlayViewMediator bindUserSwitchTransitionViewMediator(
+ UserSwitchTransitionViewMediator userSwitchTransitionViewMediator);
}
diff --git a/packages/CarSystemUI/tests/src/com/android/systemui/car/userswitcher/UserSwitchTransitionViewControllerTest.java b/packages/CarSystemUI/tests/src/com/android/systemui/car/userswitcher/UserSwitchTransitionViewControllerTest.java
new file mode 100644
index 000000000000..eab381c92d98
--- /dev/null
+++ b/packages/CarSystemUI/tests/src/com/android/systemui/car/userswitcher/UserSwitchTransitionViewControllerTest.java
@@ -0,0 +1,145 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.car.userswitcher;
+
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.verify;
+
+import android.content.Context;
+import android.content.res.Resources;
+import android.os.Handler;
+import android.os.UserManager;
+import android.test.suitebuilder.annotation.SmallTest;
+import android.testing.AndroidTestingRunner;
+import android.testing.TestableLooper;
+import android.testing.TestableResources;
+import android.view.LayoutInflater;
+import android.view.ViewGroup;
+
+import com.android.systemui.R;
+import com.android.systemui.SysuiTestCase;
+import com.android.systemui.car.window.OverlayViewGlobalStateController;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+@RunWith(AndroidTestingRunner.class)
+@TestableLooper.RunWithLooper
+@SmallTest
+public class UserSwitchTransitionViewControllerTest extends SysuiTestCase {
+ private static final int TEST_USER_1 = 100;
+ private static final int TEST_USER_2 = 110;
+
+ private TestableUserSwitchTransitionViewController mCarUserSwitchingDialogController;
+ private TestableResources mTestableResources;
+ @Mock
+ private OverlayViewGlobalStateController mOverlayViewGlobalStateController;
+
+ @Before
+ public void setUp() {
+ MockitoAnnotations.initMocks(this);
+ mTestableResources = mContext.getOrCreateTestableResources();
+ mCarUserSwitchingDialogController = new TestableUserSwitchTransitionViewController(
+ mContext,
+ Handler.getMain(),
+ mTestableResources.getResources(),
+ (UserManager) mContext.getSystemService(Context.USER_SERVICE),
+ mOverlayViewGlobalStateController
+ );
+
+ mCarUserSwitchingDialogController.inflate((ViewGroup) LayoutInflater.from(mContext).inflate(
+ R.layout.sysui_overlay_window, /* root= */ null));
+ }
+
+ @Test
+ public void onHandleShow_newUserSelected_showsDialog() {
+ mCarUserSwitchingDialogController.handleShow(/* currentUserId= */ TEST_USER_1);
+
+ verify(mOverlayViewGlobalStateController).showView(eq(mCarUserSwitchingDialogController),
+ any());
+ }
+
+ @Test
+ public void onHandleShow_alreadyShowing_ignoresRequest() {
+ mCarUserSwitchingDialogController.handleShow(/* currentUserId= */ TEST_USER_1);
+ mCarUserSwitchingDialogController.handleShow(/* currentUserId= */ TEST_USER_2);
+
+ // Verify that the request was processed only once.
+ verify(mOverlayViewGlobalStateController).showView(eq(mCarUserSwitchingDialogController),
+ any());
+ }
+
+ @Test
+ public void onHandleShow_sameUserSelected_ignoresRequest() {
+ mCarUserSwitchingDialogController.handleShow(/* currentUserId= */ TEST_USER_1);
+ mCarUserSwitchingDialogController.handleHide();
+ mCarUserSwitchingDialogController.handleShow(/* currentUserId= */ TEST_USER_1);
+
+ // Verify that the request was processed only once.
+ verify(mOverlayViewGlobalStateController).showView(eq(mCarUserSwitchingDialogController),
+ any());
+ }
+
+ @Test
+ public void onHide_currentlyShowing_hidesDialog() {
+ mCarUserSwitchingDialogController.handleShow(/* currentUserId= */ TEST_USER_1);
+ mCarUserSwitchingDialogController.handleHide();
+
+ verify(mOverlayViewGlobalStateController).hideView(eq(mCarUserSwitchingDialogController),
+ any());
+ }
+
+ @Test
+ public void onHide_notShowing_ignoresRequest() {
+ mCarUserSwitchingDialogController.handleShow(/* currentUserId= */ TEST_USER_1);
+ mCarUserSwitchingDialogController.handleHide();
+ mCarUserSwitchingDialogController.handleHide();
+
+ // Verify that the request was processed only once.
+ verify(mOverlayViewGlobalStateController).hideView(eq(mCarUserSwitchingDialogController),
+ any());
+ }
+
+ private final class TestableUserSwitchTransitionViewController extends
+ UserSwitchTransitionViewController {
+
+ private final Handler mHandler;
+
+ TestableUserSwitchTransitionViewController(Context context, Handler handler,
+ Resources resources, UserManager userManager,
+ OverlayViewGlobalStateController overlayViewGlobalStateController) {
+ super(context, handler, resources, userManager, overlayViewGlobalStateController);
+ mHandler = handler;
+ }
+
+ @Override
+ public void handleShow(int currentUserId) {
+ super.handleShow(currentUserId);
+ waitForIdleSync(mHandler);
+ }
+
+ @Override
+ public void handleHide() {
+ super.handleHide();
+ waitForIdleSync(mHandler);
+ }
+ }
+}
diff --git a/packages/CarSystemUI/tests/src/com/android/systemui/car/userswitcher/UserSwitchTransitionViewMediatorTest.java b/packages/CarSystemUI/tests/src/com/android/systemui/car/userswitcher/UserSwitchTransitionViewMediatorTest.java
new file mode 100644
index 000000000000..a808e2d40e26
--- /dev/null
+++ b/packages/CarSystemUI/tests/src/com/android/systemui/car/userswitcher/UserSwitchTransitionViewMediatorTest.java
@@ -0,0 +1,76 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.car.userswitcher;
+
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import android.car.user.CarUserManager;
+import android.test.suitebuilder.annotation.SmallTest;
+import android.testing.AndroidTestingRunner;
+import android.testing.TestableLooper;
+
+import com.android.systemui.car.CarServiceProvider;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+@RunWith(AndroidTestingRunner.class)
+@TestableLooper.RunWithLooper
+@SmallTest
+public class UserSwitchTransitionViewMediatorTest {
+ private static final int TEST_USER = 100;
+
+ private UserSwitchTransitionViewMediator mUserSwitchTransitionViewMediator;
+ @Mock
+ private CarServiceProvider mCarServiceProvider;
+ @Mock
+ private UserSwitchTransitionViewController mUserSwitchTransitionViewController;
+ @Mock
+ private CarUserManager.UserLifecycleEvent mUserLifecycleEvent;
+
+ @Before
+ public void setUp() {
+ MockitoAnnotations.initMocks(this);
+
+ mUserSwitchTransitionViewMediator = new UserSwitchTransitionViewMediator(
+ mCarServiceProvider, mUserSwitchTransitionViewController);
+
+ }
+
+ @Test
+ public void onUserLifecycleEvent_userStarting_callsHandleShow() {
+ when(mUserLifecycleEvent.getEventType()).thenReturn(
+ CarUserManager.USER_LIFECYCLE_EVENT_TYPE_STARTING);
+ when(mUserLifecycleEvent.getUserId()).thenReturn(TEST_USER);
+ mUserSwitchTransitionViewMediator.handleUserLifecycleEvent(mUserLifecycleEvent);
+
+ verify(mUserSwitchTransitionViewController).handleShow(TEST_USER);
+ }
+
+ @Test
+ public void onUserLifecycleEvent_userSwitching_callsHandleHide() {
+ when(mUserLifecycleEvent.getEventType()).thenReturn(
+ CarUserManager.USER_LIFECYCLE_EVENT_TYPE_SWITCHING);
+ mUserSwitchTransitionViewMediator.handleUserLifecycleEvent(mUserLifecycleEvent);
+
+ verify(mUserSwitchTransitionViewController).handleHide();
+ }
+}
diff --git a/services/core/java/com/android/server/am/CarUserSwitchingDialog.java b/services/core/java/com/android/server/am/CarUserSwitchingDialog.java
deleted file mode 100644
index 0e3480131952..000000000000
--- a/services/core/java/com/android/server/am/CarUserSwitchingDialog.java
+++ /dev/null
@@ -1,193 +0,0 @@
-/*
- * Copyright (C) 2018 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.server.am;
-
-import android.content.Context;
-import android.content.pm.UserInfo;
-import android.content.res.Resources;
-import android.graphics.Bitmap;
-import android.graphics.Canvas;
-import android.graphics.Color;
-import android.graphics.ColorFilter;
-import android.graphics.Paint;
-import android.graphics.Path;
-import android.graphics.PixelFormat;
-import android.graphics.PorterDuff;
-import android.graphics.PorterDuffXfermode;
-import android.graphics.Rect;
-import android.graphics.RectF;
-import android.graphics.drawable.Drawable;
-import android.os.UserManager;
-import android.provider.Settings;
-import android.view.LayoutInflater;
-import android.view.View;
-import android.view.WindowInsets;
-import android.widget.ImageView;
-import android.widget.TextView;
-
-import com.android.internal.R;
-
-
-/**
- * Dialog to show when a user switch it about to happen for the car. The intent is to snapshot the
- * screen immediately after the dialog shows so that the user is informed that something is
- * happening in the background rather than just freeze the screen and not know if the user-switch
- * affordance was being handled.
- */
-final class CarUserSwitchingDialog extends UserSwitchingDialog {
-
- private static final String TAG = "ActivityManagerCarUserSwitchingDialog";
- private View mView;
-
- public CarUserSwitchingDialog(ActivityManagerService service, Context context, UserInfo oldUser,
- UserInfo newUser, boolean aboveSystem, String switchingFromSystemUserMessage,
- String switchingToSystemUserMessage) {
- super(service, context, oldUser, newUser, aboveSystem, switchingFromSystemUserMessage,
- switchingToSystemUserMessage);
- }
-
- @Override
- void inflateContent() {
- // Set up the dialog contents
- setCancelable(false);
- Resources res = getContext().getResources();
- // Custom view due to alignment and font size requirements
- getContext().setTheme(R.style.Theme_DeviceDefault_Light_Dialog_Alert_UserSwitchingDialog);
- mView = LayoutInflater.from(getContext()).inflate(
- R.layout.car_user_switching_dialog,
- null);
-
- UserManager userManager =
- (UserManager) getContext().getSystemService(Context.USER_SERVICE);
- Bitmap bitmap = userManager.getUserIcon(mNewUser.id);
- if (bitmap != null) {
- CircleFramedDrawable drawable = CircleFramedDrawable.getInstance(bitmap,
- res.getDimension(R.dimen.car_fullscreen_user_pod_image_avatar_height));
- ((ImageView) mView.findViewById(R.id.user_loading_avatar))
- .setImageDrawable(drawable);
- }
-
- TextView msgView = mView.findViewById(R.id.user_loading);
-
- // TODO(b/145132885): use constant from CarSettings
- boolean showInfo = "true".equals(Settings.Global.getString(
- getContext().getContentResolver(),
- "android.car.ENABLE_USER_SWITCH_DEVELOPER_MESSAGE"));
-
- if (showInfo) {
- msgView.setText(res.getString(R.string.car_loading_profile) + " user\n(from "
- + mOldUser.id + " to " + mNewUser.id + ")");
- } else {
- msgView.setText(res.getString(R.string.car_loading_profile));
- }
- setView(mView);
- }
-
- @Override
- public void show() {
- super.show();
- hideNavigationBar();
- }
-
- private void hideNavigationBar() {
- mView.getWindowInsetsController().hide(WindowInsets.Type.navigationBars());
- }
-
- /**
- * Converts the user icon to a circularly clipped one. This is used in the User Picker and
- * Settings.
- */
- static class CircleFramedDrawable extends Drawable {
-
- private final Bitmap mBitmap;
- private final int mSize;
- private final Paint mPaint;
-
- private float mScale;
- private Rect mSrcRect;
- private RectF mDstRect;
-
- public static CircleFramedDrawable getInstance(Bitmap icon, float iconSize) {
- CircleFramedDrawable instance = new CircleFramedDrawable(icon, (int) iconSize);
- return instance;
- }
-
- public CircleFramedDrawable(Bitmap icon, int size) {
- super();
- mSize = size;
-
- mBitmap = Bitmap.createBitmap(mSize, mSize, Bitmap.Config.ARGB_8888);
- final Canvas canvas = new Canvas(mBitmap);
-
- final int width = icon.getWidth();
- final int height = icon.getHeight();
- final int square = Math.min(width, height);
-
- final Rect cropRect = new Rect((width - square) / 2, (height - square) / 2,
- square, square);
- final RectF circleRect = new RectF(0f, 0f, mSize, mSize);
-
- final Path fillPath = new Path();
- fillPath.addArc(circleRect, 0f, 360f);
-
- canvas.drawColor(0, PorterDuff.Mode.CLEAR);
-
- // opaque circle
- mPaint = new Paint();
- mPaint.setAntiAlias(true);
- mPaint.setColor(Color.BLACK);
- mPaint.setStyle(Paint.Style.FILL);
- canvas.drawPath(fillPath, mPaint);
-
- // mask in the icon where the bitmap is opaque
- mPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_IN));
- canvas.drawBitmap(icon, cropRect, circleRect, mPaint);
-
- // prepare paint for frame drawing
- mPaint.setXfermode(null);
-
- mScale = 1f;
-
- mSrcRect = new Rect(0, 0, mSize, mSize);
- mDstRect = new RectF(0, 0, mSize, mSize);
- }
-
- @Override
- public void draw(Canvas canvas) {
- final float inside = mScale * mSize;
- final float pad = (mSize - inside) / 2f;
-
- mDstRect.set(pad, pad, mSize - pad, mSize - pad);
- canvas.drawBitmap(mBitmap, mSrcRect, mDstRect, null);
- }
-
- @Override
- public int getOpacity() {
- return PixelFormat.TRANSLUCENT;
- }
-
- @Override
- public void setAlpha(int alpha) {
- // Needed to implement abstract method. Do nothing.
- }
-
- @Override
- public void setColorFilter(ColorFilter colorFilter) {
- // Needed to implement abstract method. Do nothing.
- }
- }
-}
diff --git a/services/core/java/com/android/server/am/UserController.java b/services/core/java/com/android/server/am/UserController.java
index 5b12933f7a40..fac4a1e95827 100644
--- a/services/core/java/com/android/server/am/UserController.java
+++ b/services/core/java/com/android/server/am/UserController.java
@@ -2736,19 +2736,13 @@ class UserController implements Handler.Callback {
void showUserSwitchingDialog(UserInfo fromUser, UserInfo toUser,
String switchingFromSystemUserMessage, String switchingToSystemUserMessage) {
- Dialog d;
if (!mService.mContext.getPackageManager()
.hasSystemFeature(PackageManager.FEATURE_AUTOMOTIVE)) {
- d = new UserSwitchingDialog(mService, mService.mContext, fromUser, toUser,
- true /* above system */, switchingFromSystemUserMessage,
- switchingToSystemUserMessage);
- } else {
- d = new CarUserSwitchingDialog(mService, mService.mContext, fromUser, toUser,
- true /* above system */, switchingFromSystemUserMessage,
- switchingToSystemUserMessage);
+ final Dialog d = new UserSwitchingDialog(mService, mService.mContext, fromUser,
+ toUser, true /* above system */, switchingFromSystemUserMessage,
+ switchingToSystemUserMessage);
+ d.show();
}
-
- d.show();
}
void reportGlobalUsageEventLocked(int event) {