diff options
| author | 2021-02-11 16:32:54 +0000 | |
|---|---|---|
| committer | 2021-02-11 16:32:54 +0000 | |
| commit | 3dba81dfea20f1880ee1378f8821e1ba5c90ab3e (patch) | |
| tree | 4bb8d89a1edea5f8d092d310eee9bed631711bae | |
| parent | 7f89361004ada3fbdcb8f2a8680255d7c04666e0 (diff) | |
| parent | 1970915c2c88c05ca8d5f669a72ff22c2f4beef2 (diff) | |
Merge changes from topic "new-keyguard-user-switcher" into sc-dev
* changes:
New keyguard user switcher
Remove MultiUserSwitch from KeyguardStatusBarView
36 files changed, 1597 insertions, 756 deletions
diff --git a/packages/SystemUI/res/layout/keyguard_user_switcher_inner.xml b/packages/SystemUI/res/color/kg_user_avatar_frame.xml index 4c1042e70c1a..174981e2a660 100644 --- a/packages/SystemUI/res/layout/keyguard_user_switcher_inner.xml +++ b/packages/SystemUI/res/color/kg_user_avatar_frame.xml @@ -14,14 +14,10 @@ ~ See the License for the specific language governing permissions and ~ limitations under the License --> -<com.android.keyguard.AlphaOptimizedLinearLayout - xmlns:android="http://schemas.android.com/apk/res/android" - android:id="@+id/keyguard_user_switcher_inner" - android:orientation="vertical" - android:layout_height="wrap_content" - android:layout_width="wrap_content" - android:layout_marginTop="@dimen/status_bar_header_height_keyguard" - android:layout_gravity="end" - android:gravity="end" - android:paddingTop="4dp"> -</com.android.keyguard.AlphaOptimizedLinearLayout> + +<selector xmlns:android="http://schemas.android.com/apk/res/android"> + <item + android:state_activated="true" + android:color="@color/kg_user_switcher_avatar_background" /> + <item android:color="@color/kg_user_switcher_avatar_background" /> +</selector> diff --git a/packages/SystemUI/res/drawable/end_guest_button_background.xml b/packages/SystemUI/res/drawable/end_guest_button_background.xml new file mode 100644 index 000000000000..5644b657a609 --- /dev/null +++ b/packages/SystemUI/res/drawable/end_guest_button_background.xml @@ -0,0 +1,25 @@ +<?xml version="1.0" encoding="utf-8"?> + +<!-- + ~ Copyright (C) 2021 The Android Open Source Project + ~ + ~ Licensed under the Apache License, Version 2.0 (the "License"); + ~ you may not use this file except in compliance with the License. + ~ You may obtain a copy of the License at + ~ + ~ http://www.apache.org/licenses/LICENSE-2.0 + ~ + ~ Unless required by applicable law or agreed to in writing, software + ~ distributed under the License is distributed on an "AS IS" BASIS, + ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + ~ See the License for the specific language governing permissions and + ~ limitations under the License + --> + +<shape xmlns:android="http://schemas.android.com/apk/res/android" + android:shape="rectangle"> + <stroke + android:width="@dimen/end_guest_button_border_size" + android:color="?android:attr/colorControlHighlight" /> + <corners android:radius="@dimen/end_guest_button_corner_radius" /> +</shape> diff --git a/packages/SystemUI/res/drawable/kg_bg_avatar.xml b/packages/SystemUI/res/drawable/kg_bg_avatar.xml new file mode 100644 index 000000000000..addb3f7508f5 --- /dev/null +++ b/packages/SystemUI/res/drawable/kg_bg_avatar.xml @@ -0,0 +1,28 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + ~ Copyright (C) 2021 The Android Open Source Project + ~ + ~ Licensed under the Apache License, Version 2.0 (the "License"); + ~ you may not use this file except in compliance with the License. + ~ You may obtain a copy of the License at + ~ + ~ http://www.apache.org/licenses/LICENSE-2.0 + ~ + ~ Unless required by applicable law or agreed to in writing, software + ~ distributed under the License is distributed on an "AS IS" BASIS, + ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + ~ See the License for the specific language governing permissions and + ~ limitations under the License. + --> + +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:width="48dp" + android:height="48dp" + android:viewportWidth="100" + android:viewportHeight="100"> + + <path + android:fillColor="@color/kg_user_switcher_avatar_background" + android:pathData="M50,50m-50,0a50,50 0,1 1,100 0a50,50 0,1 1,-100 0"/> + +</vector> diff --git a/packages/SystemUI/res/layout/keyguard_status_bar.xml b/packages/SystemUI/res/layout/keyguard_status_bar.xml index 416ee8147e33..2789ed125b09 100644 --- a/packages/SystemUI/res/layout/keyguard_status_bar.xml +++ b/packages/SystemUI/res/layout/keyguard_status_bar.xml @@ -43,17 +43,12 @@ <include layout="@layout/system_icons" /> </FrameLayout> - <com.android.systemui.statusbar.phone.MultiUserSwitch android:id="@+id/multi_user_switch" - android:layout_width="@dimen/multi_user_switch_width_keyguard" - android:layout_height="match_parent" - android:background="@drawable/ripple_drawable" - android:layout_marginEnd="@dimen/multi_user_switch_keyguard_margin"> - <ImageView android:id="@+id/multi_user_avatar" - android:layout_width="@dimen/multi_user_avatar_keyguard_size" - android:layout_height="@dimen/multi_user_avatar_keyguard_size" - android:layout_gravity="center" - android:scaleType="centerInside"/> - </com.android.systemui.statusbar.phone.MultiUserSwitch> + + <ImageView android:id="@+id/multi_user_avatar" + android:layout_width="@dimen/multi_user_avatar_keyguard_size" + android:layout_height="@dimen/multi_user_avatar_keyguard_size" + android:layout_gravity="center" + android:scaleType="centerInside"/> </LinearLayout> <Space diff --git a/packages/SystemUI/res/layout/keyguard_user_switcher.xml b/packages/SystemUI/res/layout/keyguard_user_switcher.xml index 983ba6d5e240..253c03e9effb 100644 --- a/packages/SystemUI/res/layout/keyguard_user_switcher.xml +++ b/packages/SystemUI/res/layout/keyguard_user_switcher.xml @@ -14,10 +14,50 @@ ~ See the License for the specific language governing permissions and ~ limitations under the License --> -<view xmlns:android="http://schemas.android.com/apk/res/android" - class="com.android.systemui.statusbar.policy.KeyguardUserSwitcher$Container" - android:visibility="gone" - android:layout_height="match_parent" - android:layout_width="match_parent"> - <!-- KeyguardUserSwitcher loads keyguard_user_switcher_inner.xml here --> -</view>
\ No newline at end of file +<!-- This is a view that shows a user switcher in Keyguard. --> +<com.android.systemui.statusbar.policy.KeyguardUserSwitcherView + xmlns:android="http://schemas.android.com/apk/res/android" + android:id="@+id/keyguard_user_switcher_view" + android:layout_width="match_parent" + android:layout_height="match_parent" + android:layout_gravity="end"> + + <com.android.systemui.statusbar.policy.KeyguardUserSwitcherListView + android:id="@+id/keyguard_user_switcher_list" + android:orientation="vertical" + android:layout_height="wrap_content" + android:layout_width="wrap_content" + android:layout_gravity="top|end" + android:gravity="end" /> + + <LinearLayout + android:id="@+id/end_guest_button" + android:layout_height="@dimen/end_guest_button_layout_height" + android:layout_width="wrap_content" + android:layout_gravity="center_horizontal|bottom" + android:layout_centerHorizontal="true" + android:layout_marginBottom="@dimen/end_guest_button_margin_bottom" + android:orientation="horizontal" + android:gravity="center" + android:paddingLeft="@dimen/end_guest_button_padding_horizontal" + android:paddingRight="@dimen/end_guest_button_padding_horizontal" + android:background="@drawable/end_guest_button_background" + android:visibility="gone"> + <ImageView + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:gravity="center" + android:src="@drawable/ic_exit_to_app" + android:background="@android:color/transparent" + android:color="?attr/wallpaperTextColor" /> + <TextView + android:layout_height="wrap_content" + android:layout_width="wrap_content" + android:gravity="center" + android:fontFamily="@*android:string/config_bodyFontFamilyMedium" + android:textColor="?attr/wallpaperTextColor" + android:textSize="13sp" + android:text="@string/guest_exit_button" /> + </LinearLayout> + +</com.android.systemui.statusbar.policy.KeyguardUserSwitcherView> diff --git a/packages/SystemUI/res/layout/keyguard_user_switcher_item.xml b/packages/SystemUI/res/layout/keyguard_user_switcher_item.xml index 1cd1a04ab462..aaa372a5be6e 100644 --- a/packages/SystemUI/res/layout/keyguard_user_switcher_item.xml +++ b/packages/SystemUI/res/layout/keyguard_user_switcher_item.xml @@ -19,29 +19,30 @@ <!-- LinearLayout --> <com.android.systemui.statusbar.policy.KeyguardUserDetailItemView xmlns:android="http://schemas.android.com/apk/res/android" - xmlns:sysui="http://schemas.android.com/apk/res-auto" + xmlns:systemui="http://schemas.android.com/apk/res-auto" android:layout_width="wrap_content" android:layout_height="wrap_content" android:padding="8dp" android:layout_marginEnd="8dp" - android:gravity="center_vertical" + android:gravity="end|center_vertical" android:clickable="true" - android:background="@drawable/ripple_drawable" - sysui:regularTextAppearance="@style/TextAppearance.StatusBar.Expanded.UserSwitcher" - sysui:activatedTextAppearance="@style/TextAppearance.StatusBar.Expanded.UserSwitcher.Activated"> - <TextView android:id="@+id/user_name" - android:layout_width="wrap_content" - android:layout_height="wrap_content" - android:layout_marginEnd="13dp" - android:textAppearance="@style/TextAppearance.StatusBar.Expanded.UserSwitcher" - /> - <com.android.systemui.statusbar.phone.UserAvatarView android:id="@+id/user_picture" - android:layout_width="@dimen/kg_framed_avatar_size" - android:layout_height="@dimen/kg_framed_avatar_size" - android:contentDescription="@null" - sysui:frameWidth="@dimen/keyguard_user_switcher_border_thickness" - sysui:framePadding="2.5dp" - sysui:badgeDiameter="18dp" - sysui:badgeMargin="1dp" - sysui:frameColor="@color/kg_user_switcher_rounded_background_color" /> + android:background="@drawable/kg_user_switcher_rounded_bg" + systemui:activatedTextAppearance="@style/TextAppearance.StatusBar.Expanded.UserSwitcher" + systemui:regularTextAppearance="@style/TextAppearance.StatusBar.Expanded.UserSwitcher"> + <TextView + android:id="@+id/user_name" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_marginStart="20dp" + android:layout_marginEnd="16dp" /> + <com.android.systemui.statusbar.phone.UserAvatarView + android:id="@+id/user_picture" + android:layout_width="@dimen/kg_framed_avatar_size" + android:layout_height="@dimen/kg_framed_avatar_size" + systemui:avatarPadding="0dp" + systemui:badgeDiameter="18dp" + systemui:badgeMargin="1dp" + systemui:frameWidth="0dp" + systemui:framePadding="0dp" + systemui:frameColor="@color/kg_user_avatar_frame" /> </com.android.systemui.statusbar.policy.KeyguardUserDetailItemView> diff --git a/packages/SystemUI/res/layout/status_bar_expanded.xml b/packages/SystemUI/res/layout/status_bar_expanded.xml index d6385ffbcc0c..859d9048cee3 100644 --- a/packages/SystemUI/res/layout/status_bar_expanded.xml +++ b/packages/SystemUI/res/layout/status_bar_expanded.xml @@ -31,6 +31,12 @@ android:layout_height="match_parent" android:visibility="gone" /> + <ViewStub + android:id="@+id/keyguard_user_switcher_stub" + android:layout="@layout/keyguard_user_switcher" + android:layout_height="match_parent" + android:layout_width="match_parent" /> + <include layout="@layout/keyguard_status_view" android:visibility="gone" /> @@ -72,12 +78,6 @@ <include layout="@layout/photo_preview_overlay" /> - <ViewStub - android:id="@+id/keyguard_user_switcher" - android:layout="@layout/keyguard_user_switcher" - android:layout_height="match_parent" - android:layout_width="match_parent" /> - <include layout="@layout/keyguard_status_bar" android:visibility="invisible" /> diff --git a/packages/SystemUI/res/values-night/colors.xml b/packages/SystemUI/res/values-night/colors.xml index 3153d0d0123d..37ec576be4be 100644 --- a/packages/SystemUI/res/values-night/colors.xml +++ b/packages/SystemUI/res/values-night/colors.xml @@ -89,6 +89,8 @@ <color name="kg_user_switcher_avatar_icon_color">@android:color/background_light</color> <!-- Icon color for selected user avatars in keyguard user switcher --> <color name="kg_user_switcher_selected_avatar_icon_color">#202124</color> + <!-- Color of background circle of user avatars in keyguard user switcher --> + <color name="kg_user_switcher_avatar_background">#3C4043</color> <!-- Icon color for user avatars in quick settings user switcher --> <color name="qs_user_switcher_avatar_icon_color">@android:color/background_light</color> <!-- Icon color for selected user avatars in quick settings user switcher --> diff --git a/packages/SystemUI/res/values-sw600dp/styles.xml b/packages/SystemUI/res/values-sw600dp/styles.xml index 02bd60210e81..ee2b82dca811 100644 --- a/packages/SystemUI/res/values-sw600dp/styles.xml +++ b/packages/SystemUI/res/values-sw600dp/styles.xml @@ -23,13 +23,6 @@ <item name="numColumns">4</item> </style> - <style name="TextAppearance.StatusBar.Expanded.UserSwitcher"> - <item name="android:textSize">@dimen/kg_user_switcher_text_size</item> - <item name="android:textStyle">normal</item> - <item name="android:fontFamily">@*android:string/config_headlineFontFamily</item> - <item name="android:textColor">?attr/wallpaperTextColor</item> - </style> - <style name="TextAppearance.QS.UserSwitcher"> <item name="android:textSize">@dimen/kg_user_switcher_text_size</item> <item name="android:textColor">?android:attr/textColorSecondary</item> diff --git a/packages/SystemUI/res/values/colors.xml b/packages/SystemUI/res/values/colors.xml index 5fb6de7bb588..8bd9de919bee 100644 --- a/packages/SystemUI/res/values/colors.xml +++ b/packages/SystemUI/res/values/colors.xml @@ -66,9 +66,13 @@ <!-- Color for rounded background for activated user in keyguard user switcher --> <color name="kg_user_switcher_activated_background_color">#26000000</color> <!-- Icon color for user avatars in keyguard user switcher --> - <color name="kg_user_switcher_avatar_icon_color">@android:color/background_light</color> - <!-- Icon color for selected user avatars in keyguard user switcher --> - <color name="kg_user_switcher_selected_avatar_icon_color">@android:color/background_light</color> + <color name="kg_user_switcher_avatar_icon_color">@color/GM2_grey_800</color> + <!-- Icon color for user avatars in keyguard user switcher that restricted + (e.g. cannot be switched to) --> + <color name="kg_user_switcher_restricted_avatar_icon_color">@color/GM2_grey_600</color> + <!-- Color of background circle of user avatars in keyguard user switcher --> + <color name="kg_user_switcher_avatar_background">@color/GM2_grey_300</color> + <!-- Icon color for user avatars in user switcher quick settings --> <color name="qs_user_switcher_avatar_icon_color">#3C4043</color> <!-- Icon color for selected user avatars in user switcher quick settings --> diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml index 08cd6553e252..594fbdf55d3c 100644 --- a/packages/SystemUI/res/values/dimens.xml +++ b/packages/SystemUI/res/values/dimens.xml @@ -743,9 +743,6 @@ <!-- end margin for system icons if multi user switch is hidden --> <dimen name="system_icons_switcher_hidden_expanded_margin">16dp</dimen> - <!-- The thickness of the colored border around the current user. --> - <dimen name="keyguard_user_switcher_border_thickness">2dp</dimen> - <dimen name="data_usage_graph_marker_width">4dp</dimen> <!-- The padding bottom of the clock group when QS is expanded. --> @@ -805,7 +802,7 @@ <!-- Size of user icon + frame in the qs user picker (incl. frame) --> <dimen name="qs_framed_avatar_size">54dp</dimen> <!-- Size of user icon + frame in the keyguard user picker (incl. frame) --> - <dimen name="kg_framed_avatar_size">54dp</dimen> + <dimen name="kg_framed_avatar_size">32dp</dimen> <!-- Margin on the left side of the carrier text on Keyguard --> <dimen name="keyguard_carrier_text_margin">16dp</dimen> @@ -1324,8 +1321,16 @@ <dimen name="screenrecord_status_icon_height">17.5dp</dimen> <dimen name="screenrecord_status_icon_bg_radius">8dp</dimen> + <!-- Keyguard user switcher --> <dimen name="kg_user_switcher_text_size">16sp</dimen> + <!-- End guest session button --> + <dimen name="end_guest_button_layout_height">32dp</dimen> + <dimen name="end_guest_button_padding_horizontal">16dp</dimen> + <dimen name="end_guest_button_margin_bottom">96dp</dimen> + <dimen name="end_guest_button_border_size">1dp</dimen> + <dimen name="end_guest_button_corner_radius">16dp</dimen> + <!-- Opacity at which the background for the shutdown UI will be drawn. --> <item name="shutdown_scrim_behind_alpha" format="float" type="dimen">0.95</item> diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml index abcf4e802ab9..7c1c24bf280e 100644 --- a/packages/SystemUI/res/values/strings.xml +++ b/packages/SystemUI/res/values/strings.xml @@ -1112,6 +1112,9 @@ <!-- Name for a freshly added user [CHAR LIMIT=30] --> <string name="user_new_user_name">New user</string> + <!-- Label for button that exits guest session and clears the guest user data [CHAR LIMIT=50]--> + <string name="guest_exit_button">End guest session</string> + <!-- Title of the confirmation dialog when exiting guest session [CHAR LIMIT=NONE] --> <string name="guest_exit_guest_dialog_title">End guest session?</string> diff --git a/packages/SystemUI/res/values/styles.xml b/packages/SystemUI/res/values/styles.xml index afdf23b14a7a..85c470f8e706 100644 --- a/packages/SystemUI/res/values/styles.xml +++ b/packages/SystemUI/res/values/styles.xml @@ -114,12 +114,12 @@ <style name="TextAppearance.StatusBar.Expanded.UserSwitcher"> <item name="android:textSize">@dimen/kg_user_switcher_text_size</item> <item name="android:textStyle">normal</item> - <item name="android:textColor">?android:attr/textColorSecondary</item> + <item name="android:fontFamily">@*android:string/config_headlineFontFamily</item> + <item name="android:textColor">?attr/wallpaperTextColor</item> </style> <style name="TextAppearance.StatusBar.Expanded.UserSwitcher.Activated"> <item name="android:fontWeight">700</item> - <item name="android:textStyle">bold</item> </style> <style name="TextAppearance" /> diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardStatusViewController.java b/packages/SystemUI/src/com/android/keyguard/KeyguardStatusViewController.java index a5f364d30d7d..6fb6760be653 100644 --- a/packages/SystemUI/src/com/android/keyguard/KeyguardStatusViewController.java +++ b/packages/SystemUI/src/com/android/keyguard/KeyguardStatusViewController.java @@ -16,13 +16,9 @@ package com.android.keyguard; -import static com.android.systemui.statusbar.StatusBarState.KEYGUARD; - import android.util.Slog; import android.view.View; -import com.android.systemui.Interpolators; -import com.android.systemui.statusbar.StatusBarState; import com.android.systemui.statusbar.notification.AnimatableProperty; import com.android.systemui.statusbar.notification.PropertyAnimator; import com.android.systemui.statusbar.notification.stack.AnimationProperties; @@ -50,13 +46,12 @@ public class KeyguardStatusViewController extends ViewController<KeyguardStatusV private final KeyguardSliceViewController mKeyguardSliceViewController; private final KeyguardClockSwitchController mKeyguardClockSwitchController; - private final KeyguardStateController mKeyguardStateController; private final KeyguardUpdateMonitor mKeyguardUpdateMonitor; private final ConfigurationController mConfigurationController; private final NotificationIconAreaController mNotificationIconAreaController; private final DozeParameters mDozeParameters; + private final KeyguardVisibilityHelper mKeyguardVisibilityHelper; - private boolean mKeyguardStatusViewVisibilityAnimating; private int mLockScreenMode = KeyguardUpdateMonitor.LOCK_SCREEN_MODE_NORMAL; @Inject @@ -72,11 +67,12 @@ public class KeyguardStatusViewController extends ViewController<KeyguardStatusV super(keyguardStatusView); mKeyguardSliceViewController = keyguardSliceViewController; mKeyguardClockSwitchController = keyguardClockSwitchController; - mKeyguardStateController = keyguardStateController; mKeyguardUpdateMonitor = keyguardUpdateMonitor; mConfigurationController = configurationController; mNotificationIconAreaController = notificationIconAreaController; mDozeParameters = dozeParameters; + mKeyguardVisibilityHelper = new KeyguardVisibilityHelper(mView, keyguardStateController, + dozeParameters); } @Override @@ -144,7 +140,7 @@ public class KeyguardStatusViewController extends ViewController<KeyguardStatusV * Set keyguard status view alpha. */ public void setAlpha(float alpha) { - if (!mKeyguardStatusViewVisibilityAnimating) { + if (!mKeyguardVisibilityHelper.isVisibilityAnimating()) { mView.setAlpha(alpha); } } @@ -200,7 +196,7 @@ public class KeyguardStatusViewController extends ViewController<KeyguardStatusV public void updatePosition(int x, int y, float scale, boolean animate) { // We animate the status view visible/invisible using Y translation, so don't change it // while the animation is running. - if (!mKeyguardStatusViewVisibilityAnimating) { + if (!mKeyguardVisibilityHelper.isVisibilityAnimating()) { PropertyAnimator.setProperty(mView, AnimatableProperty.Y, y, CLOCK_ANIMATION_PROPERTIES, animate); } @@ -230,69 +226,8 @@ public class KeyguardStatusViewController extends ViewController<KeyguardStatusV boolean keyguardFadingAway, boolean goingToFullShade, int oldStatusBarState) { - mView.animate().cancel(); - mKeyguardStatusViewVisibilityAnimating = false; - if ((!keyguardFadingAway && oldStatusBarState == KEYGUARD - && statusBarState != KEYGUARD) || goingToFullShade) { - mKeyguardStatusViewVisibilityAnimating = true; - mView.animate() - .alpha(0f) - .setStartDelay(0) - .setDuration(160) - .setInterpolator(Interpolators.ALPHA_OUT) - .withEndAction( - mAnimateKeyguardStatusViewGoneEndRunnable); - if (keyguardFadingAway) { - mView.animate() - .setStartDelay(mKeyguardStateController.getKeyguardFadingAwayDelay()) - .setDuration(mKeyguardStateController.getShortenedFadingAwayDuration()) - .start(); - } - } else if (oldStatusBarState == StatusBarState.SHADE_LOCKED && statusBarState == KEYGUARD) { - mView.setVisibility(View.VISIBLE); - mKeyguardStatusViewVisibilityAnimating = true; - mView.setAlpha(0f); - mView.animate() - .alpha(1f) - .setStartDelay(0) - .setDuration(320) - .setInterpolator(Interpolators.ALPHA_IN) - .withEndAction(mAnimateKeyguardStatusViewVisibleEndRunnable); - } else if (statusBarState == KEYGUARD) { - if (keyguardFadingAway) { - mKeyguardStatusViewVisibilityAnimating = true; - mView.animate() - .alpha(0) - .translationYBy(-getHeight() * 0.05f) - .setInterpolator(Interpolators.FAST_OUT_LINEAR_IN) - .setDuration(125) - .setStartDelay(0) - .withEndAction(mAnimateKeyguardStatusViewInvisibleEndRunnable) - .start(); - } else if (mDozeParameters.shouldControlUnlockedScreenOff()) { - mKeyguardStatusViewVisibilityAnimating = true; - - mView.setVisibility(View.VISIBLE); - mView.setAlpha(0f); - - float curTranslationY = mView.getTranslationY(); - mView.setTranslationY(curTranslationY - getHeight() * 0.1f); - mView.animate() - .setStartDelay((int) (StackStateAnimator.ANIMATION_DURATION_WAKEUP * .6f)) - .setDuration(StackStateAnimator.ANIMATION_DURATION_WAKEUP) - .setInterpolator(Interpolators.FAST_OUT_SLOW_IN) - .alpha(1f) - .translationY(curTranslationY) - .withEndAction(mAnimateKeyguardStatusViewVisibleEndRunnable) - .start(); - } else { - mView.setVisibility(View.VISIBLE); - mView.setAlpha(1f); - } - } else { - mView.setVisibility(View.GONE); - mView.setAlpha(1f); - } + mKeyguardVisibilityHelper.setViewVisibility( + statusBarState, keyguardFadingAway, goingToFullShade, oldStatusBarState); } private void refreshTime() { @@ -393,19 +328,4 @@ public class KeyguardStatusViewController extends ViewController<KeyguardStatusV mView.updateLogoutView(); } }; - - private final Runnable mAnimateKeyguardStatusViewInvisibleEndRunnable = () -> { - mKeyguardStatusViewVisibilityAnimating = false; - mView.setVisibility(View.INVISIBLE); - }; - - - private final Runnable mAnimateKeyguardStatusViewGoneEndRunnable = () -> { - mKeyguardStatusViewVisibilityAnimating = false; - mView.setVisibility(View.GONE); - }; - - private final Runnable mAnimateKeyguardStatusViewVisibleEndRunnable = () -> { - mKeyguardStatusViewVisibilityAnimating = false; - }; } diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardVisibilityHelper.java b/packages/SystemUI/src/com/android/keyguard/KeyguardVisibilityHelper.java new file mode 100644 index 000000000000..724e1f660fb9 --- /dev/null +++ b/packages/SystemUI/src/com/android/keyguard/KeyguardVisibilityHelper.java @@ -0,0 +1,137 @@ +/* + * Copyright (C) 2021 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.keyguard; + +import static com.android.systemui.statusbar.StatusBarState.KEYGUARD; + +import android.view.View; + +import com.android.systemui.Interpolators; +import com.android.systemui.statusbar.StatusBarState; +import com.android.systemui.statusbar.notification.stack.StackStateAnimator; +import com.android.systemui.statusbar.phone.DozeParameters; +import com.android.systemui.statusbar.policy.KeyguardStateController; + +/** + * Helper class for updating visibility of keyguard views based on keyguard and status bar state. + * This logic is shared by both the keyguard status view and the keyguard user switcher. + */ +public class KeyguardVisibilityHelper { + + private View mView; + private final KeyguardStateController mKeyguardStateController; + private final DozeParameters mDozeParameters; + private boolean mKeyguardViewVisibilityAnimating; + + public KeyguardVisibilityHelper(View view, KeyguardStateController keyguardStateController, + DozeParameters dozeParameters) { + mView = view; + mKeyguardStateController = keyguardStateController; + mDozeParameters = dozeParameters; + } + + public boolean isVisibilityAnimating() { + return mKeyguardViewVisibilityAnimating; + } + + /** + * Set the visibility of a keyguard view based on some new state. + */ + public void setViewVisibility( + int statusBarState, + boolean keyguardFadingAway, + boolean goingToFullShade, + int oldStatusBarState) { + mView.animate().cancel(); + mKeyguardViewVisibilityAnimating = false; + if ((!keyguardFadingAway && oldStatusBarState == KEYGUARD + && statusBarState != KEYGUARD) || goingToFullShade) { + mKeyguardViewVisibilityAnimating = true; + mView.animate() + .alpha(0f) + .setStartDelay(0) + .setDuration(160) + .setInterpolator(Interpolators.ALPHA_OUT) + .withEndAction( + mAnimateKeyguardStatusViewGoneEndRunnable); + if (keyguardFadingAway) { + mView.animate() + .setStartDelay(mKeyguardStateController.getKeyguardFadingAwayDelay()) + .setDuration(mKeyguardStateController.getShortenedFadingAwayDuration()) + .start(); + } + } else if (oldStatusBarState == StatusBarState.SHADE_LOCKED && statusBarState == KEYGUARD) { + mView.setVisibility(View.VISIBLE); + mKeyguardViewVisibilityAnimating = true; + mView.setAlpha(0f); + mView.animate() + .alpha(1f) + .setStartDelay(0) + .setDuration(320) + .setInterpolator(Interpolators.ALPHA_IN) + .withEndAction(mAnimateKeyguardStatusViewVisibleEndRunnable); + } else if (statusBarState == KEYGUARD) { + if (keyguardFadingAway) { + mKeyguardViewVisibilityAnimating = true; + mView.animate() + .alpha(0) + .translationYBy(-mView.getHeight() * 0.05f) + .setInterpolator(Interpolators.FAST_OUT_LINEAR_IN) + .setDuration(125) + .setStartDelay(0) + .withEndAction(mAnimateKeyguardStatusViewInvisibleEndRunnable) + .start(); + } else if (mDozeParameters.shouldControlUnlockedScreenOff()) { + mKeyguardViewVisibilityAnimating = true; + + mView.setVisibility(View.VISIBLE); + mView.setAlpha(0f); + + float curTranslationY = mView.getTranslationY(); + mView.setTranslationY(curTranslationY - mView.getHeight() * 0.1f); + mView.animate() + .setStartDelay((int) (StackStateAnimator.ANIMATION_DURATION_WAKEUP * .6f)) + .setDuration(StackStateAnimator.ANIMATION_DURATION_WAKEUP) + .setInterpolator(Interpolators.FAST_OUT_SLOW_IN) + .alpha(1f) + .translationY(curTranslationY) + .withEndAction(mAnimateKeyguardStatusViewVisibleEndRunnable) + .start(); + } else { + mView.setVisibility(View.VISIBLE); + mView.setAlpha(1f); + } + } else { + mView.setVisibility(View.GONE); + mView.setAlpha(1f); + } + } + + private final Runnable mAnimateKeyguardStatusViewInvisibleEndRunnable = () -> { + mKeyguardViewVisibilityAnimating = false; + mView.setVisibility(View.INVISIBLE); + }; + + private final Runnable mAnimateKeyguardStatusViewGoneEndRunnable = () -> { + mKeyguardViewVisibilityAnimating = false; + mView.setVisibility(View.GONE); + }; + + private final Runnable mAnimateKeyguardStatusViewVisibleEndRunnable = () -> { + mKeyguardViewVisibilityAnimating = false; + }; +} diff --git a/packages/SystemUI/src/com/android/keyguard/dagger/KeyguardUserSwitcherComponent.java b/packages/SystemUI/src/com/android/keyguard/dagger/KeyguardUserSwitcherComponent.java new file mode 100644 index 000000000000..730c14dc9600 --- /dev/null +++ b/packages/SystemUI/src/com/android/keyguard/dagger/KeyguardUserSwitcherComponent.java @@ -0,0 +1,40 @@ +/* + * Copyright (C) 2021 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.keyguard.dagger; + +import com.android.systemui.statusbar.policy.KeyguardUserSwitcherController; +import com.android.systemui.statusbar.policy.KeyguardUserSwitcherView; + +import dagger.BindsInstance; +import dagger.Subcomponent; + +/** + * Subcomponent for helping work with KeyguardUserSwitcher and its children. + */ +@Subcomponent(modules = {KeyguardUserSwitcherModule.class}) +@KeyguardUserSwitcherScope +public interface KeyguardUserSwitcherComponent { + /** Simple factory for {@link KeyguardUserSwitcherComponent}. */ + @Subcomponent.Factory + interface Factory { + KeyguardUserSwitcherComponent build( + @BindsInstance KeyguardUserSwitcherView keyguardUserSwitcherView); + } + + /** Builds a {@link com.android.systemui.statusbar.policy.KeyguardUserSwitcherController}. */ + KeyguardUserSwitcherController getKeyguardUserSwitcherController(); +} diff --git a/packages/SystemUI/src/com/android/keyguard/dagger/KeyguardUserSwitcherModule.java b/packages/SystemUI/src/com/android/keyguard/dagger/KeyguardUserSwitcherModule.java new file mode 100644 index 000000000000..b9184f405bf9 --- /dev/null +++ b/packages/SystemUI/src/com/android/keyguard/dagger/KeyguardUserSwitcherModule.java @@ -0,0 +1,24 @@ +/* + * Copyright (C) 2021 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.keyguard.dagger; + +import dagger.Module; + +/** Dagger module for {@link KeyguardUserSwitcherComponent}. */ +@Module +public abstract class KeyguardUserSwitcherModule { +} diff --git a/packages/SystemUI/src/com/android/keyguard/dagger/KeyguardUserSwitcherScope.java b/packages/SystemUI/src/com/android/keyguard/dagger/KeyguardUserSwitcherScope.java new file mode 100644 index 000000000000..864472e53ce7 --- /dev/null +++ b/packages/SystemUI/src/com/android/keyguard/dagger/KeyguardUserSwitcherScope.java @@ -0,0 +1,32 @@ +/* + * Copyright (C) 2021 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.keyguard.dagger; + +import static java.lang.annotation.RetentionPolicy.RUNTIME; + +import java.lang.annotation.Documented; +import java.lang.annotation.Retention; + +import javax.inject.Scope; + +/** + * Scope annotation for singleton items within the KeyguardUserSwitcherComponent. + */ +@Documented +@Retention(RUNTIME) +@Scope +public @interface KeyguardUserSwitcherScope {} diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java index c55fdf4783e3..91cf7108c728 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java +++ b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java @@ -415,6 +415,7 @@ public class KeyguardViewMediator extends SystemUI implements Dumpable, @Override public void onUserSwitching(int userId) { + if (DEBUG) Log.d(TAG, String.format("onUserSwitching %d", userId)); // Note that the mLockPatternUtils user has already been updated from setCurrentUser. // We need to force a reset of the views, since lockNow (called by // ActivityManagerService) will not reconstruct the keyguard if it is already showing. @@ -432,6 +433,7 @@ public class KeyguardViewMediator extends SystemUI implements Dumpable, @Override public void onUserSwitchComplete(int userId) { + if (DEBUG) Log.d(TAG, String.format("onUserSwitchComplete %d", userId)); if (userId != UserHandle.USER_SYSTEM) { UserInfo info = UserManager.get(mContext).getUserInfo(userId); // Don't try to dismiss if the user has Pin/Patter/Password set diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/dagger/KeyguardModule.java b/packages/SystemUI/src/com/android/systemui/keyguard/dagger/KeyguardModule.java index 76281d8c0f00..9e5b225fbefc 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/dagger/KeyguardModule.java +++ b/packages/SystemUI/src/com/android/systemui/keyguard/dagger/KeyguardModule.java @@ -30,6 +30,7 @@ import com.android.keyguard.KeyguardDisplayManager; import com.android.keyguard.KeyguardUpdateMonitor; import com.android.keyguard.KeyguardViewController; import com.android.keyguard.dagger.KeyguardStatusViewComponent; +import com.android.keyguard.dagger.KeyguardUserSwitcherComponent; import com.android.systemui.broadcast.BroadcastDispatcher; import com.android.systemui.classifier.FalsingCollector; import com.android.systemui.classifier.FalsingModule; @@ -61,7 +62,7 @@ import dagger.Provides; /** * Dagger Module providing {@link StatusBar}. */ -@Module(subcomponents = {KeyguardStatusViewComponent.class}, +@Module(subcomponents = {KeyguardStatusViewComponent.class, KeyguardUserSwitcherComponent.class}, includes = {FalsingModule.class}) public class KeyguardModule { /** diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/UserDetailItemView.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/UserDetailItemView.java index 6a8c61491709..6ca550c9ddb2 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/tiles/UserDetailItemView.java +++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/UserDetailItemView.java @@ -41,7 +41,7 @@ public class UserDetailItemView extends LinearLayout { protected static int layoutResId = R.layout.qs_user_detail_item; private UserAvatarView mAvatar; - private TextView mName; + protected TextView mName; private int mActivatedStyle; private int mRegularStyle; private View mRestrictedPadlock; diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardClockPositionAlgorithm.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardClockPositionAlgorithm.java index 57a64e440bf6..e0df4f8bfea9 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardClockPositionAlgorithm.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardClockPositionAlgorithm.java @@ -27,6 +27,7 @@ import com.android.keyguard.KeyguardStatusView; import com.android.keyguard.KeyguardUpdateMonitor; import com.android.systemui.Interpolators; import com.android.systemui.R; +import com.android.systemui.statusbar.policy.KeyguardUserSwitcherListView; /** * Utility class to calculate the clock position and top padding of notifications on Keyguard. @@ -55,6 +56,12 @@ public class KeyguardClockPositionAlgorithm { private int mKeyguardStatusHeight; /** + * Height of {@link KeyguardUserSwitcherListView} when it + * is closed and only the current user's icon is visible. + */ + private int mKeyguardUserSwitcherHeight; + + /** * Preferred Y position of clock. */ private int mClockPreferredY; @@ -173,17 +180,20 @@ public class KeyguardClockPositionAlgorithm { * Sets up algorithm values. */ public void setup(int statusBarMinHeight, int maxShadeBottom, int notificationStackHeight, - float panelExpansion, int parentHeight, int keyguardStatusHeight, int clockPreferredY, - boolean hasCustomClock, boolean hasVisibleNotifs, float dark, float emptyDragAmount, - boolean bypassEnabled, int unlockedStackScrollerPadding, boolean showLockIcon, - float qsExpansion, int cutoutTopInset) { + float panelExpansion, int parentHeight, int keyguardStatusHeight, + int keyguardUserSwitcherHeight, int clockPreferredY, boolean hasCustomClock, + boolean hasVisibleNotifs, float dark, float emptyDragAmount, boolean bypassEnabled, + int unlockedStackScrollerPadding, boolean showLockIcon, float qsExpansion, + int cutoutTopInset) { mMinTopMargin = statusBarMinHeight + (showLockIcon - ? mContainerTopPaddingWithLockIcon : mContainerTopPaddingWithoutLockIcon); + ? mContainerTopPaddingWithLockIcon : mContainerTopPaddingWithoutLockIcon) + + keyguardUserSwitcherHeight; mMaxShadeBottom = maxShadeBottom; mNotificationStackHeight = notificationStackHeight; mPanelExpansion = panelExpansion; mHeight = parentHeight; mKeyguardStatusHeight = keyguardStatusHeight; + mKeyguardUserSwitcherHeight = keyguardUserSwitcherHeight; mClockPreferredY = clockPreferredY; mHasCustomClock = hasCustomClock; mHasVisibleNotifs = hasVisibleNotifs; @@ -246,7 +256,8 @@ public class KeyguardClockPositionAlgorithm { final int availableHeight = mMaxShadeBottom - mMinTopMargin; final int containerCenter = mMinTopMargin + availableHeight / 2; - float y = containerCenter - mKeyguardStatusHeight * CLOCK_HEIGHT_WEIGHT + float y = containerCenter + - (mKeyguardStatusHeight + mKeyguardUserSwitcherHeight) * CLOCK_HEIGHT_WEIGHT - mClockNotificationsMargin - mNotificationStackHeight / 2; if (y < mMinTopMargin) { y = mMinTopMargin; 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 5f547b5df671..33798d680d05 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardStatusBarView.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardStatusBarView.java @@ -16,6 +16,7 @@ package com.android.systemui.statusbar.phone; +import static com.android.systemui.DejankUtils.whitelistIpcs; import static com.android.systemui.ScreenDecorations.DisplayCutoutView.boundsFromDirection; import android.annotation.ColorInt; @@ -25,6 +26,7 @@ import android.content.res.Resources; import android.graphics.Color; import android.graphics.Rect; import android.graphics.drawable.Drawable; +import android.os.UserManager; import android.util.AttributeSet; import android.util.Pair; import android.util.TypedValue; @@ -45,18 +47,15 @@ import com.android.systemui.Dependency; import com.android.systemui.Interpolators; import com.android.systemui.R; import com.android.systemui.plugins.DarkIconDispatcher.DarkReceiver; -import com.android.systemui.qs.QSDetailDisplayer; import com.android.systemui.statusbar.CommandQueue; import com.android.systemui.statusbar.phone.StatusBarIconController.TintedIconManager; import com.android.systemui.statusbar.policy.BatteryController; import com.android.systemui.statusbar.policy.BatteryController.BatteryStateChangeCallback; import com.android.systemui.statusbar.policy.ConfigurationController; import com.android.systemui.statusbar.policy.ConfigurationController.ConfigurationListener; -import com.android.systemui.statusbar.policy.KeyguardUserSwitcher; import com.android.systemui.statusbar.policy.UserInfoController; import com.android.systemui.statusbar.policy.UserInfoController.OnUserInfoChangedListener; import com.android.systemui.statusbar.policy.UserInfoControllerImpl; -import com.android.systemui.statusbar.policy.UserSwitcherController; import java.io.FileDescriptor; import java.io.PrintWriter; @@ -75,18 +74,16 @@ public class KeyguardStatusBarView extends RelativeLayout private boolean mShowPercentAvailable; private boolean mBatteryCharging; - private boolean mKeyguardUserSwitcherShowing; private boolean mBatteryListening; private TextView mCarrierLabel; - private MultiUserSwitch mMultiUserSwitch; private ImageView mMultiUserAvatar; private BatteryMeterView mBatteryView; private StatusIconContainer mStatusIconContainer; private BatteryController mBatteryController; - private KeyguardUserSwitcher mKeyguardUserSwitcher; - private UserSwitcherController mUserSwitcherController; + private boolean mKeyguardUserSwitcherEnabled; + private final UserManager mUserManager; private int mSystemIconsSwitcherHiddenExpandedMargin; private int mSystemIconsBaseMargin; @@ -109,13 +106,13 @@ public class KeyguardStatusBarView extends RelativeLayout public KeyguardStatusBarView(Context context, AttributeSet attrs) { super(context, attrs); + mUserManager = UserManager.get(getContext()); } @Override protected void onFinishInflate() { super.onFinishInflate(); mSystemIconsContainer = findViewById(R.id.system_icons_container); - mMultiUserSwitch = findViewById(R.id.multi_user_switch); mMultiUserAvatar = findViewById(R.id.multi_user_avatar); mCarrierLabel = findViewById(R.id.keyguard_carrier_text); mBatteryView = mSystemIconsContainer.findViewById(R.id.battery); @@ -124,7 +121,6 @@ public class KeyguardStatusBarView extends RelativeLayout mStatusIconContainer = findViewById(R.id.statusIcons); loadDimens(); - updateUserSwitcher(); mBatteryController = Dependency.get(BatteryController.class); } @@ -137,14 +133,6 @@ public class KeyguardStatusBarView extends RelativeLayout R.dimen.multi_user_avatar_keyguard_size); mMultiUserAvatar.setLayoutParams(lp); - // Multi-user switch - lp = (MarginLayoutParams) mMultiUserSwitch.getLayoutParams(); - lp.width = getResources().getDimensionPixelSize( - R.dimen.multi_user_switch_width_keyguard); - lp.setMarginEnd(getResources().getDimensionPixelSize( - R.dimen.multi_user_switch_keyguard_margin)); - mMultiUserSwitch.setLayoutParams(lp); - // System icons lp = (MarginLayoutParams) mSystemIconsContainer.getLayoutParams(); lp.setMarginStart(getResources().getDimensionPixelSize( @@ -194,22 +182,28 @@ public class KeyguardStatusBarView extends RelativeLayout } private void updateVisibilities() { - if (mMultiUserSwitch.getParent() != mStatusIconArea && !mKeyguardUserSwitcherShowing) { - if (mMultiUserSwitch.getParent() != null) { - getOverlay().remove(mMultiUserSwitch); + if (mMultiUserAvatar.getParent() != mStatusIconArea + && !mKeyguardUserSwitcherEnabled) { + if (mMultiUserAvatar.getParent() != null) { + getOverlay().remove(mMultiUserAvatar); } - mStatusIconArea.addView(mMultiUserSwitch, 0); - } else if (mMultiUserSwitch.getParent() == mStatusIconArea && mKeyguardUserSwitcherShowing) { - mStatusIconArea.removeView(mMultiUserSwitch); + mStatusIconArea.addView(mMultiUserAvatar, 0); + } else if (mMultiUserAvatar.getParent() == mStatusIconArea + && mKeyguardUserSwitcherEnabled) { + mStatusIconArea.removeView(mMultiUserAvatar); } - if (mKeyguardUserSwitcher == null) { + if (!mKeyguardUserSwitcherEnabled) { // If we have no keyguard switcher, the screen width is under 600dp. In this case, // we only show the multi-user switch if it's enabled through UserManager as well as // by the user. - if (mMultiUserSwitch.isMultiUserEnabled()) { - mMultiUserSwitch.setVisibility(View.VISIBLE); + // TODO(b/138661450) Move IPC calls to background + boolean isMultiUserEnabled = whitelistIpcs(() -> mUserManager.isUserSwitcherEnabled( + mContext.getResources().getBoolean( + R.bool.qs_show_user_switcher_for_single_user))); + if (isMultiUserEnabled) { + mMultiUserAvatar.setVisibility(View.VISIBLE); } else { - mMultiUserSwitch.setVisibility(View.GONE); + mMultiUserAvatar.setVisibility(View.GONE); } } mBatteryView.setForceShowPercent(mBatteryCharging && mShowPercentAvailable); @@ -220,11 +214,12 @@ public class KeyguardStatusBarView extends RelativeLayout (LinearLayout.LayoutParams) mSystemIconsContainer.getLayoutParams(); // If the avatar icon is gone, we need to have some end margin to display the system icons // correctly. - int baseMarginEnd = mMultiUserSwitch.getVisibility() == View.GONE + int baseMarginEnd = mMultiUserAvatar.getVisibility() == View.GONE ? mSystemIconsBaseMargin : 0; - int marginEnd = mKeyguardUserSwitcherShowing ? mSystemIconsSwitcherHiddenExpandedMargin : - baseMarginEnd; + int marginEnd = + mKeyguardUserSwitcherEnabled ? mSystemIconsSwitcherHiddenExpandedMargin + : baseMarginEnd; marginEnd = calculateMargin(marginEnd, mPadding.second); if (marginEnd != lp.getMarginEnd()) { lp.setMarginEnd(marginEnd); @@ -334,20 +329,11 @@ public class KeyguardStatusBarView extends RelativeLayout } } - private void updateUserSwitcher() { - boolean keyguardSwitcherAvailable = mKeyguardUserSwitcher != null; - mMultiUserSwitch.setClickable(keyguardSwitcherAvailable); - mMultiUserSwitch.setFocusable(keyguardSwitcherAvailable); - mMultiUserSwitch.setKeyguardMode(keyguardSwitcherAvailable); - } - @Override protected void onAttachedToWindow() { super.onAttachedToWindow(); UserInfoController userInfoController = Dependency.get(UserInfoController.class); userInfoController.addCallback(this); - mUserSwitcherController = Dependency.get(UserSwitcherController.class); - mMultiUserSwitch.setUserSwitcherController(mUserSwitcherController); userInfoController.reloadUserInfo(); Dependency.get(ConfigurationController.class).addCallback(this); mIconManager = new TintedIconManager(findViewById(R.id.statusIcons), @@ -369,11 +355,6 @@ public class KeyguardStatusBarView extends RelativeLayout mMultiUserAvatar.setImageDrawable(picture); } - /** */ - public void setQSDetailDisplayer(QSDetailDisplayer detailDisplayer) { - mMultiUserSwitch.setQSDetailDisplayer(detailDisplayer); - } - @Override public void onBatteryLevelChanged(int level, boolean pluggedIn, boolean charging) { if (mBatteryCharging != charging) { @@ -387,54 +368,42 @@ public class KeyguardStatusBarView extends RelativeLayout // could not care less } - public void setKeyguardUserSwitcher(KeyguardUserSwitcher keyguardUserSwitcher) { - mKeyguardUserSwitcher = keyguardUserSwitcher; - mMultiUserSwitch.setKeyguardUserSwitcher(keyguardUserSwitcher); - updateUserSwitcher(); - } - - public void setKeyguardUserSwitcherShowing(boolean showing, boolean animate) { - mKeyguardUserSwitcherShowing = showing; - if (animate) { - animateNextLayoutChange(); - } - updateVisibilities(); - updateLayoutConsideringCutout(); - updateSystemIconsLayoutParams(); + public void setKeyguardUserSwitcherEnabled(boolean enabled) { + mKeyguardUserSwitcherEnabled = enabled; } private void animateNextLayoutChange() { final int systemIconsCurrentX = mSystemIconsContainer.getLeft(); - final boolean userSwitcherVisible = mMultiUserSwitch.getParent() == mStatusIconArea; + final boolean userAvatarVisible = mMultiUserAvatar.getParent() == mStatusIconArea; getViewTreeObserver().addOnPreDrawListener(new ViewTreeObserver.OnPreDrawListener() { @Override public boolean onPreDraw() { getViewTreeObserver().removeOnPreDrawListener(this); - boolean userSwitcherHiding = userSwitcherVisible - && mMultiUserSwitch.getParent() != mStatusIconArea; + boolean userAvatarHiding = userAvatarVisible + && mMultiUserAvatar.getParent() != mStatusIconArea; mSystemIconsContainer.setX(systemIconsCurrentX); mSystemIconsContainer.animate() .translationX(0) .setDuration(400) - .setStartDelay(userSwitcherHiding ? 300 : 0) + .setStartDelay(userAvatarHiding ? 300 : 0) .setInterpolator(Interpolators.FAST_OUT_SLOW_IN) .start(); - if (userSwitcherHiding) { - getOverlay().add(mMultiUserSwitch); - mMultiUserSwitch.animate() + if (userAvatarHiding) { + getOverlay().add(mMultiUserAvatar); + mMultiUserAvatar.animate() .alpha(0f) .setDuration(300) .setStartDelay(0) .setInterpolator(Interpolators.ALPHA_OUT) .withEndAction(() -> { - mMultiUserSwitch.setAlpha(1f); - getOverlay().remove(mMultiUserSwitch); + mMultiUserAvatar.setAlpha(1f); + getOverlay().remove(mMultiUserAvatar); }) .start(); } else { - mMultiUserSwitch.setAlpha(0f); - mMultiUserSwitch.animate() + mMultiUserAvatar.setAlpha(0f); + mMultiUserAvatar.animate() .alpha(1f) .setDuration(300) .setStartDelay(200) @@ -452,8 +421,8 @@ public class KeyguardStatusBarView extends RelativeLayout if (visibility != View.VISIBLE) { mSystemIconsContainer.animate().cancel(); mSystemIconsContainer.setTranslationX(0); - mMultiUserSwitch.animate().cancel(); - mMultiUserSwitch.setAlpha(1f); + mMultiUserAvatar.animate().cancel(); + mMultiUserAvatar.setAlpha(1f); } else { updateVisibilities(); updateSystemIconsLayoutParams(); @@ -523,9 +492,9 @@ public class KeyguardStatusBarView extends RelativeLayout public void dump(FileDescriptor fd, PrintWriter pw, String[] args) { pw.println("KeyguardStatusBarView:"); pw.println(" mBatteryCharging: " + mBatteryCharging); - pw.println(" mKeyguardUserSwitcherShowing: " + mKeyguardUserSwitcherShowing); pw.println(" mBatteryListening: " + mBatteryListening); pw.println(" mLayoutState: " + mLayoutState); + pw.println(" mKeyguardUserSwitcherEnabled: " + mKeyguardUserSwitcherEnabled); if (mBatteryView != null) { mBatteryView.dump(fd, pw, args); } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/MultiUserSwitch.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/MultiUserSwitch.java index 480d3f42ae77..d9cb9ce21330 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/MultiUserSwitch.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/MultiUserSwitch.java @@ -35,7 +35,6 @@ import com.android.systemui.Prefs.Key; import com.android.systemui.R; import com.android.systemui.plugins.qs.DetailAdapter; import com.android.systemui.qs.QSDetailDisplayer; -import com.android.systemui.statusbar.policy.KeyguardUserSwitcher; import com.android.systemui.statusbar.policy.UserSwitcherController; /** @@ -44,8 +43,6 @@ import com.android.systemui.statusbar.policy.UserSwitcherController; public class MultiUserSwitch extends FrameLayout implements View.OnClickListener { protected QSDetailDisplayer mQSDetailDisplayer; - private KeyguardUserSwitcher mKeyguardUserSwitcher; - private boolean mKeyguardMode; private UserSwitcherController.BaseUserAdapter mUserListener; final UserManager mUserManager; @@ -85,15 +82,6 @@ public class MultiUserSwitch extends FrameLayout implements View.OnClickListener refreshContentDescription(); } - public void setKeyguardUserSwitcher(KeyguardUserSwitcher keyguardUserSwitcher) { - mKeyguardUserSwitcher = keyguardUserSwitcher; - } - - public void setKeyguardMode(boolean keyguardShowing) { - mKeyguardMode = keyguardShowing; - registerListener(); - } - public boolean isMultiUserEnabled() { // TODO(b/138661450) Move IPC calls to background return whitelistIpcs(() -> mUserManager.isUserSwitcherEnabled( @@ -123,11 +111,7 @@ public class MultiUserSwitch extends FrameLayout implements View.OnClickListener @Override public void onClick(View v) { - if (mKeyguardMode) { - if (mKeyguardUserSwitcher != null) { - mKeyguardUserSwitcher.show(true /* animate */); - } - } else if (mQSDetailDisplayer != null && mUserSwitcherController != null) { + if (mQSDetailDisplayer != null && mUserSwitcherController != null) { View center = getChildCount() > 0 ? getChildAt(0) : this; int[] tmpInt = new int[2]; diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelViewController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelViewController.java index 0e40cc0de914..3b09eda4003e 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelViewController.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelViewController.java @@ -48,6 +48,7 @@ import android.hardware.biometrics.BiometricSourceType; import android.os.Bundle; import android.os.PowerManager; import android.os.SystemClock; +import android.os.UserManager; import android.util.Log; import android.util.MathUtils; import android.view.DisplayCutout; @@ -57,6 +58,7 @@ import android.view.VelocityTracker; import android.view.View; import android.view.ViewGroup; import android.view.ViewPropertyAnimator; +import android.view.ViewStub; import android.view.ViewTreeObserver; import android.view.WindowInsets; import android.view.accessibility.AccessibilityManager; @@ -76,6 +78,7 @@ import com.android.keyguard.KeyguardStatusViewController; import com.android.keyguard.KeyguardUpdateMonitor; import com.android.keyguard.KeyguardUpdateMonitorCallback; import com.android.keyguard.dagger.KeyguardStatusViewComponent; +import com.android.keyguard.dagger.KeyguardUserSwitcherComponent; import com.android.systemui.DejankUtils; import com.android.systemui.Interpolators; import com.android.systemui.R; @@ -95,7 +98,6 @@ import com.android.systemui.plugins.FalsingManager; import com.android.systemui.plugins.qs.QS; import com.android.systemui.plugins.statusbar.StatusBarStateController; import com.android.systemui.plugins.statusbar.StatusBarStateController.StateListener; -import com.android.systemui.qs.QSDetailDisplayer; import com.android.systemui.statusbar.CommandQueue; import com.android.systemui.statusbar.FeatureFlags; import com.android.systemui.statusbar.GestureRecorder; @@ -132,7 +134,8 @@ import com.android.systemui.statusbar.phone.LockscreenGestureLogger.LockscreenUi import com.android.systemui.statusbar.phone.dagger.StatusBarComponent; import com.android.systemui.statusbar.policy.ConfigurationController; import com.android.systemui.statusbar.policy.KeyguardStateController; -import com.android.systemui.statusbar.policy.KeyguardUserSwitcher; +import com.android.systemui.statusbar.policy.KeyguardUserSwitcherController; +import com.android.systemui.statusbar.policy.KeyguardUserSwitcherView; import com.android.systemui.statusbar.policy.OnHeadsUpChangedListener; import com.android.systemui.util.Utils; import com.android.wm.shell.animation.FlingAnimationUtils; @@ -284,6 +287,22 @@ public class NotificationPanelViewController extends PanelViewController { } }; + final KeyguardUserSwitcherController.KeyguardUserSwitcherListener + mKeyguardUserSwitcherListener = + new KeyguardUserSwitcherController.KeyguardUserSwitcherListener() { + @Override + public void onKeyguardUserSwitcherChanged(boolean open) { + if (mKeyguardUserSwitcherController != null + && mKeyguardUserSwitcherController.isSimpleUserSwitcher()) { + return; + } + + updateUserSwitcherVisibility(open + && mKeyguardStateController.isShowing() + && !mKeyguardStateController.isKeyguardFadingAway()); + } + }; + private final LayoutInflater mLayoutInflater; private final PowerManager mPowerManager; private final AccessibilityManager mAccessibilityManager; @@ -296,7 +315,7 @@ public class NotificationPanelViewController extends PanelViewController { private final MediaHierarchyManager mMediaHierarchyManager; private final StatusBarKeyguardViewManager mStatusBarKeyguardViewManager; private final KeyguardStatusViewComponent.Factory mKeyguardStatusViewComponentFactory; - private final QSDetailDisplayer mQSDetailDisplayer; + private final KeyguardUserSwitcherComponent.Factory mKeyguardUserSwitcherComponentFactory; private final FeatureFlags mFeatureFlags; private final ScrimController mScrimController; private final ControlsComponent mControlsComponent; @@ -308,7 +327,7 @@ public class NotificationPanelViewController extends PanelViewController { private int mMaxAllowedKeyguardNotifications; private KeyguardAffordanceHelper mAffordanceHelper; - private KeyguardUserSwitcher mKeyguardUserSwitcher; + private KeyguardUserSwitcherController mKeyguardUserSwitcherController; private KeyguardStatusBarView mKeyguardStatusBar; private ViewGroup mBigClockContainer; private QS mQs; @@ -333,6 +352,7 @@ public class NotificationPanelViewController extends PanelViewController { private boolean mQsExpandedWhenExpandingStarted; private boolean mQsFullyExpanded; private boolean mKeyguardShowing; + private boolean mKeyguardUserSwitcherEnabled; private boolean mDozing; private boolean mDozingOnDown; private int mBarState; @@ -465,6 +485,7 @@ public class NotificationPanelViewController extends PanelViewController { private final CommandQueue mCommandQueue; private final NotificationLockscreenUserManager mLockscreenUserManager; + private final UserManager mUserManager; private final ShadeController mShadeController; private final MediaDataManager mMediaDataManager; private int mDisplayId; @@ -557,11 +578,12 @@ public class NotificationPanelViewController extends PanelViewController { StatusBarKeyguardViewManager statusBarKeyguardViewManager, NotificationStackScrollLayoutController notificationStackScrollLayoutController, KeyguardStatusViewComponent.Factory keyguardStatusViewComponentFactory, + KeyguardUserSwitcherComponent.Factory keyguardUserSwitcherComponentFactory, NotificationGroupManagerLegacy groupManager, NotificationIconAreaController notificationIconAreaController, AuthController authController, - QSDetailDisplayer qsDetailDisplayer, ScrimController scrimController, + UserManager userManager, MediaDataManager mediaDataManager, AmbientState ambientState, FeatureFlags featureFlags, @@ -582,8 +604,10 @@ public class NotificationPanelViewController extends PanelViewController { mGroupManager = groupManager; mNotificationIconAreaController = notificationIconAreaController; mKeyguardStatusViewComponentFactory = keyguardStatusViewComponentFactory; - mQSDetailDisplayer = qsDetailDisplayer; mFeatureFlags = featureFlags; + mKeyguardUserSwitcherComponentFactory = keyguardUserSwitcherComponentFactory; + mKeyguardUserSwitcherEnabled = mResources.getBoolean( + com.android.internal.R.bool.config_keyguardUserSwitcher); mView.setWillNotDraw(!DEBUG); mLayoutInflater = layoutInflater; mFalsingManager = falsingManager; @@ -599,6 +623,7 @@ public class NotificationPanelViewController extends PanelViewController { mDozeParameters = dozeParameters; mBiometricUnlockController = biometricUnlockController; mScrimController = scrimController; + mUserManager = userManager; mMediaDataManager = mediaDataManager; mControlsComponent = controlsComponent; pulseExpansionHandler.setPulseExpandAbortListener(() -> { @@ -661,9 +686,17 @@ public class NotificationPanelViewController extends PanelViewController { private void onFinishInflate() { loadDimens(); mKeyguardStatusBar = mView.findViewById(R.id.keyguard_header); - mKeyguardStatusBar.setQSDetailDisplayer(mQSDetailDisplayer); mBigClockContainer = mView.findViewById(R.id.big_clock_container); - updateViewControllers(mView.findViewById(R.id.keyguard_status_view)); + + KeyguardUserSwitcherView keyguardUserSwitcherView = null; + + if (mKeyguardUserSwitcherEnabled && mUserManager.isUserSwitcherEnabled()) { + ViewStub userSwitcherStub = mView.findViewById(R.id.keyguard_user_switcher_stub); + keyguardUserSwitcherView = (KeyguardUserSwitcherView) userSwitcherStub.inflate(); + } + + updateViewControllers(mView.findViewById(R.id.keyguard_status_view), + keyguardUserSwitcherView); mNotificationContainerParent = mView.findViewById(R.id.notification_container_parent); NotificationStackScrollLayout stackScrollLayout = mView.findViewById( R.id.notification_stack_scroller); @@ -736,7 +769,8 @@ public class NotificationPanelViewController extends PanelViewController { R.dimen.heads_up_status_bar_padding); } - private void updateViewControllers(KeyguardStatusView keyguardStatusView) { + private void updateViewControllers(KeyguardStatusView keyguardStatusView, + KeyguardUserSwitcherView keyguardUserSwitcherView) { // Re-associate the KeyguardStatusViewController KeyguardStatusViewComponent statusViewComponent = mKeyguardStatusViewComponentFactory.build(keyguardStatusView); @@ -747,6 +781,28 @@ public class NotificationPanelViewController extends PanelViewController { KeyguardClockSwitchController keyguardClockSwitchController = statusViewComponent.getKeyguardClockSwitchController(); keyguardClockSwitchController.setBigClockContainer(mBigClockContainer); + + if (mKeyguardUserSwitcherController != null) { + // Try to close the switcher so that callbacks are triggered if necessary. + // Otherwise, NPV can get into a state where some of the views are still hidden + mKeyguardUserSwitcherController.closeSwitcherIfOpenAndNotSimple(false); + mKeyguardUserSwitcherController.removeCallback(); + } + + // Re-associate the KeyguardUserSwitcherController + if (keyguardUserSwitcherView != null) { + KeyguardUserSwitcherComponent userSwitcherComponent = + mKeyguardUserSwitcherComponentFactory.build(keyguardUserSwitcherView); + + mKeyguardUserSwitcherController = + userSwitcherComponent.getKeyguardUserSwitcherController(); + mKeyguardUserSwitcherController.setCallback(mKeyguardUserSwitcherListener); + mKeyguardUserSwitcherController.init(); + mKeyguardStatusBar.setKeyguardUserSwitcherEnabled(true); + } else { + mKeyguardUserSwitcherController = null; + mKeyguardStatusBar.setKeyguardUserSwitcherEnabled(false); + } } /** @@ -801,6 +857,7 @@ public class NotificationPanelViewController extends PanelViewController { } private void reInflateViews() { + if (DEBUG) Log.d(TAG, "reInflateViews"); // Re-inflate the status view group. KeyguardStatusView keyguardStatusView = mView.findViewById(R.id.keyguard_status_view); int index = mView.indexOfChild(keyguardStatusView); @@ -809,8 +866,27 @@ public class NotificationPanelViewController extends PanelViewController { R.layout.keyguard_status_view, mView, false); mView.addView(keyguardStatusView, index); + // Re-inflate the keyguard user switcher group. + boolean showUserSwitcher = + mKeyguardUserSwitcherEnabled && mUserManager.isUserSwitcherEnabled(); + KeyguardUserSwitcherView keyguardUserSwitcherView = mView.findViewById( + R.id.keyguard_user_switcher_view); + if (keyguardUserSwitcherView != null) { + index = mView.indexOfChild(keyguardUserSwitcherView); + mView.removeView(keyguardUserSwitcherView); + if (showUserSwitcher) { + keyguardUserSwitcherView = (KeyguardUserSwitcherView) mLayoutInflater.inflate( + R.layout.keyguard_user_switcher, mView, false); + mView.addView(keyguardUserSwitcherView, index); + } + } else if (showUserSwitcher) { + // It's possible the user switcher was never inflated if the configuration changed + ViewStub userSwitcherStub = mView.findViewById(R.id.keyguard_user_switcher_stub); + keyguardUserSwitcherView = (KeyguardUserSwitcherView) userSwitcherStub.inflate(); + } + mBigClockContainer.removeAllViews(); - updateViewControllers(keyguardStatusView); + updateViewControllers(keyguardStatusView, keyguardUserSwitcherView); // Update keyguard bottom area index = mView.indexOfChild(mKeyguardBottomArea); @@ -834,6 +910,13 @@ public class NotificationPanelViewController extends PanelViewController { false, false, mBarState); + if (mKeyguardUserSwitcherController != null) { + mKeyguardUserSwitcherController.setKeyguardUserSwitcherVisibility( + mBarState, + false, + false, + mBarState); + } setKeyguardBottomAreaVisibility(mBarState, false); } @@ -938,6 +1021,8 @@ public class NotificationPanelViewController extends PanelViewController { ? mKeyguardStatusViewController.getHeight() : (int) (mKeyguardStatusViewController.getHeight() - mShelfHeight / 2.0f - mDarkIconSize / 2.0f), + mKeyguardUserSwitcherController == null + ? 0 : mKeyguardUserSwitcherController.getUserIconHeight(), clockPreferredY, hasCustomClock(), hasVisibleNotifications, mInterpolatedDarkAmount, mEmptyDragAmount, bypassEnabled, getUnlockedStackScrollerPadding(), @@ -948,6 +1033,13 @@ public class NotificationPanelViewController extends PanelViewController { mKeyguardStatusViewController.updatePosition( mClockPositionResult.clockX, mClockPositionResult.clockY, mClockPositionResult.clockScale, animateClock); + if (mKeyguardUserSwitcherController != null) { + mKeyguardUserSwitcherController.updatePosition( + mClockPositionResult.clockX, + mClockPositionResult.clockY + - mKeyguardUserSwitcherController.getUserIconHeight(), + animateClock); + } updateNotificationTranslucency(); updateClock(); stackScrollerPadding = mClockPositionResult.stackScrollerPaddingExpanded; @@ -1088,6 +1180,9 @@ public class NotificationPanelViewController extends PanelViewController { private void updateClock() { mKeyguardStatusViewController.setAlpha(mClockPositionResult.clockAlpha); + if (mKeyguardUserSwitcherController != null) { + mKeyguardUserSwitcherController.setAlpha(mClockPositionResult.clockAlpha); + } } public void animateToFullShade(long delay) { @@ -1769,8 +1864,9 @@ public class NotificationPanelViewController extends PanelViewController { mBarState != KEYGUARD && (!mQsExpanded || mQsExpansionFromOverscroll)); - if (mKeyguardUserSwitcher != null && mQsExpanded && !mStackScrollerOverscrolling) { - mKeyguardUserSwitcher.hideIfNotSimple(true /* animate */); + if (mKeyguardUserSwitcherController != null && mQsExpanded + && !mStackScrollerOverscrolling) { + mKeyguardUserSwitcherController.closeSwitcherIfOpenAndNotSimple(true); } if (mQs == null) return; mQs.setExpanded(mQsExpanded); @@ -2604,10 +2700,6 @@ public class NotificationPanelViewController extends PanelViewController { } } - public void setKeyguardUserSwitcher(KeyguardUserSwitcher keyguardUserSwitcher) { - mKeyguardUserSwitcher = keyguardUserSwitcher; - } - public void onScreenTurningOn() { mKeyguardStatusViewController.dozeTimeTick(); } @@ -3074,6 +3166,13 @@ public class NotificationPanelViewController extends PanelViewController { true /* keyguardFadingAway */, false /* goingToFullShade */, mBarState); + if (mKeyguardUserSwitcherController != null) { + mKeyguardUserSwitcherController.setKeyguardUserSwitcherVisibility( + mBarState, + true /* keyguardFadingAway */, + false /* goingToFullShade */, + mBarState); + } } /** @@ -3316,6 +3415,44 @@ public class NotificationPanelViewController extends PanelViewController { return mNotificationStackScrollLayoutController; } + /** + * Close the keyguard user switcher if it is open and capable of closing. + * + * Has no effect if user switcher isn't supported, if the user switcher is already closed, or + * if the user switcher uses "simple" mode. The simple user switcher cannot be closed. + * + * @return true if the keyguard user switcher was open, and is now closed + */ + public boolean closeUserSwitcherIfOpen() { + if (mKeyguardUserSwitcherController != null) { + return mKeyguardUserSwitcherController.closeSwitcherIfOpenAndNotSimple( + true /* animate */); + } + return false; + } + + private void updateUserSwitcherVisibility(boolean open) { + if (open) { + animateKeyguardStatusBarOut(); + mKeyguardStatusViewController.setKeyguardStatusViewVisibility( + mBarState, + true /* keyguardFadingAway */, + true /* goingToFullShade */, + mBarState); + setKeyguardBottomAreaVisibility(mBarState, true); + mNotificationContainerParent.setVisibility(View.GONE); + } else { + animateKeyguardStatusBarIn(StackStateAnimator.ANIMATION_DURATION_STANDARD); + mKeyguardStatusViewController.setKeyguardStatusViewVisibility( + StatusBarState.KEYGUARD, + false, + false, + StatusBarState.SHADE_LOCKED); + setKeyguardBottomAreaVisibility(mBarState, false); + mNotificationContainerParent.setVisibility(View.VISIBLE); + } + } + private class OnHeightChangedListener implements ExpandableView.OnHeightChangedListener { @Override public void onHeightChanged(ExpandableView view, boolean needsAnimation) { @@ -3616,6 +3753,7 @@ public class NotificationPanelViewController extends PanelViewController { private class ConfigurationListener implements ConfigurationController.ConfigurationListener { @Override public void onThemeChanged() { + if (DEBUG) Log.d(TAG, "onThemeChanged"); final int themeResId = mView.getContext().getThemeResId(); if (mThemeResId == themeResId) { return; @@ -3627,11 +3765,15 @@ public class NotificationPanelViewController extends PanelViewController { @Override public void onOverlayChanged() { + if (DEBUG) Log.d(TAG, "onOverlayChanged"); reInflateViews(); } @Override - public void onUiModeChanged() {} + public void onDensityOrFontScaleChanged() { + if (DEBUG) Log.d(TAG, "onDensityOrFontScaleChanged"); + reInflateViews(); + } } private class StatusBarStateListener implements StateListener { diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationsQuickSettingsContainer.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationsQuickSettingsContainer.java index b36740620d08..e394ebc65a6b 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationsQuickSettingsContainer.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationsQuickSettingsContainer.java @@ -22,8 +22,6 @@ import android.content.res.Configuration; import android.graphics.Canvas; import android.util.AttributeSet; import android.view.View; -import android.view.ViewStub; -import android.view.ViewStub.OnInflateListener; import android.view.WindowInsets; import android.widget.FrameLayout; @@ -44,14 +42,11 @@ import java.util.Comparator; * The container with notification stack scroller and quick settings inside. */ public class NotificationsQuickSettingsContainer extends ConstraintLayout - implements OnInflateListener, FragmentListener, - AboveShelfObserver.HasViewAboveShelfChangedListener { + implements FragmentListener, AboveShelfObserver.HasViewAboveShelfChangedListener { private FrameLayout mQsFrame; - private View mUserSwitcher; private NotificationStackScrollLayout mStackScroller; private View mKeyguardStatusBar; - private boolean mInflated; private boolean mQsExpanded; private boolean mCustomizerAnimating; @@ -73,9 +68,6 @@ public class NotificationsQuickSettingsContainer extends ConstraintLayout mStackScroller = findViewById(R.id.notification_stack_scroller); mStackScrollerMargin = ((LayoutParams) mStackScroller.getLayoutParams()).bottomMargin; mKeyguardStatusBar = findViewById(R.id.keyguard_header); - ViewStub userSwitcher = findViewById(R.id.keyguard_user_switcher); - userSwitcher.setOnInflateListener(this); - mUserSwitcher = userSwitcher; } @Override @@ -119,10 +111,6 @@ public class NotificationsQuickSettingsContainer extends ConstraintLayout // touches first but the panel gets drawn above. mDrawingOrderedChildren.clear(); mLayoutDrawingOrder.clear(); - if (mInflated && mUserSwitcher.getVisibility() == View.VISIBLE) { - mDrawingOrderedChildren.add(mUserSwitcher); - mLayoutDrawingOrder.add(mUserSwitcher); - } if (mKeyguardStatusBar.getVisibility() == View.VISIBLE) { mDrawingOrderedChildren.add(mKeyguardStatusBar); mLayoutDrawingOrder.add(mKeyguardStatusBar); @@ -158,14 +146,6 @@ public class NotificationsQuickSettingsContainer extends ConstraintLayout } @Override - public void onInflate(ViewStub stub, View inflated) { - if (stub == mUserSwitcher) { - mUserSwitcher = inflated; - mInflated = true; - } - } - - @Override public void onFragmentViewCreated(String tag, Fragment fragment) { QS container = (QS) fragment; container.setContainer(this); diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java index 1e19beeff730..041a97e1d404 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java @@ -89,7 +89,6 @@ import android.os.SystemClock; import android.os.SystemProperties; import android.os.Trace; import android.os.UserHandle; -import android.os.UserManager; import android.os.VibrationEffect; import android.os.Vibrator; import android.provider.Settings; @@ -226,7 +225,6 @@ import com.android.systemui.statusbar.policy.DeviceProvisionedController; import com.android.systemui.statusbar.policy.DeviceProvisionedController.DeviceProvisionedListener; import com.android.systemui.statusbar.policy.ExtensionController; import com.android.systemui.statusbar.policy.KeyguardStateController; -import com.android.systemui.statusbar.policy.KeyguardUserSwitcher; import com.android.systemui.statusbar.policy.NetworkController; import com.android.systemui.statusbar.policy.OnHeadsUpChangedListener; import com.android.systemui.statusbar.policy.RemoteInputQuickSettingsDisabler; @@ -623,7 +621,6 @@ public class StatusBar extends SystemUI implements DemoMode, } }; - private KeyguardUserSwitcher mKeyguardUserSwitcher; private final UserSwitcherController mUserSwitcherController; private final NetworkController mNetworkController; private final LifecycleRegistry mLifecycle = new LifecycleRegistry(this); @@ -1212,9 +1209,6 @@ public class StatusBar extends SystemUI implements DemoMode, }); mNotificationPanelViewController.setUserSetupComplete(mUserSetup); - if (UserManager.get(mContext).isUserSwitcherEnabled()) { - createUserSwitcher(); - } // Set up the quick settings tile panel final View container = mNotificationShadeWindowView.findViewById(R.id.qs_frame); @@ -1441,9 +1435,6 @@ public class StatusBar extends SystemUI implements DemoMode, // TODO: Bring these out of StatusBar. mUserInfoControllerImpl.onDensityOrFontScaleChanged(); mUserSwitcherController.onDensityOrFontScaleChanged(); - if (mKeyguardUserSwitcher != null) { - mKeyguardUserSwitcher.onDensityOrFontScaleChanged(); - } mNotificationIconAreaController.onDensityOrFontScaleChanged(mContext); mHeadsUpManager.onDensityOrFontScaleChanged(); } @@ -1477,13 +1468,6 @@ public class StatusBar extends SystemUI implements DemoMode, } } - protected void createUserSwitcher() { - mKeyguardUserSwitcher = new KeyguardUserSwitcher(mContext, - mNotificationShadeWindowView.findViewById(R.id.keyguard_user_switcher), - mNotificationShadeWindowView.findViewById(R.id.keyguard_header), - mNotificationPanelViewController); - } - private void inflateStatusBarWindow() { mNotificationShadeWindowView = mSuperStatusBarViewFactory.getNotificationShadeWindowView(); StatusBarComponent statusBarComponent = mStatusBarComponentBuilder.get() @@ -3266,7 +3250,7 @@ public class StatusBar extends SystemUI implements DemoMode, mHandler.removeMessages(MSG_LAUNCH_TRANSITION_TIMEOUT); if (mUserSwitcherController != null && mUserSwitcherController.useFullscreenUserSwitcher()) { mStatusBarStateController.setState(StatusBarState.FULLSCREEN_USER_SWITCHER); - } else if (!mPulseExpansionHandler.isWakingToShadeLocked()){ + } else if (!mPulseExpansionHandler.isWakingToShadeLocked()) { mStatusBarStateController.setState(StatusBarState.KEYGUARD); } updatePanelExpansionForKeyguard(); @@ -3565,15 +3549,15 @@ public class StatusBar extends SystemUI implements DemoMode, } return true; } + if (mNotificationPanelViewController.closeUserSwitcherIfOpen()) { + return true; + } if (mState != StatusBarState.KEYGUARD && mState != StatusBarState.SHADE_LOCKED) { if (mNotificationPanelViewController.canPanelBeCollapsed()) { mShadeController.animateCollapsePanels(); } return true; } - if (mKeyguardUserSwitcher != null && mKeyguardUserSwitcher.hideIfNotSimple(true)) { - return true; - } return false; } @@ -3622,20 +3606,8 @@ public class StatusBar extends SystemUI implements DemoMode, updateTheme(); mNavigationBarController.touchAutoDim(mDisplayId); Trace.beginSection("StatusBar#updateKeyguardState"); - if (mState == StatusBarState.KEYGUARD) { - if (mKeyguardUserSwitcher != null) { - mKeyguardUserSwitcher.setKeyguard(true, - mStatusBarStateController.fromShadeLocked()); - } - if (mStatusBarView != null) mStatusBarView.removePendingHideExpandedRunnables(); - } else { - if (mKeyguardUserSwitcher != null) { - mKeyguardUserSwitcher.setKeyguard(false, - mStatusBarStateController.goingToFullShade() || - mState == StatusBarState.SHADE_LOCKED || - mStatusBarStateController.fromShadeLocked()); - } - + if (mState == StatusBarState.KEYGUARD && mStatusBarView != null) { + mStatusBarView.removePendingHideExpandedRunnables(); } updateDozingState(); checkBarModes(); diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardUserDetailItemView.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardUserDetailItemView.java index 07433e13104c..0649478a42aa 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardUserDetailItemView.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardUserDetailItemView.java @@ -17,8 +17,15 @@ package com.android.systemui.statusbar.policy; import android.content.Context; +import android.graphics.Color; import android.util.AttributeSet; +import android.util.Log; +import android.view.View; +import androidx.core.graphics.ColorUtils; + +import com.android.keyguard.KeyguardConstants; +import com.android.systemui.Interpolators; import com.android.systemui.R; import com.android.systemui.qs.tiles.UserDetailItemView; @@ -27,6 +34,14 @@ import com.android.systemui.qs.tiles.UserDetailItemView; */ public class KeyguardUserDetailItemView extends UserDetailItemView { + private static final String TAG = "KeyguardUserDetailItemView"; + private static final boolean DEBUG = KeyguardConstants.DEBUG; + + private static final int ANIMATION_DURATION_FADE_NAME = 240; + + private float mDarkAmount; + private int mTextColor; + public KeyguardUserDetailItemView(Context context) { this(context, null); } @@ -48,4 +63,89 @@ public class KeyguardUserDetailItemView extends UserDetailItemView { protected int getFontSizeDimen() { return R.dimen.kg_user_switcher_text_size; } + + @Override + protected void onFinishInflate() { + super.onFinishInflate(); + mTextColor = mName.getCurrentTextColor(); + updateDark(); + } + + /** + * Update visibility of this view. + * + * @param showItem If true, this item is visible on the screen to the user. Generally this + * means that the item would be clickable. If false, item visibility will be + * set to GONE and hidden entirely. + * @param showTextName Whether or not the name should be shown next to the icon. If false, + * only the icon is shown. + * @param animate Whether the transition should be animated. Note, this only applies to + * animating the text name. The item itself will not animate (i.e. fade in/out). + * Instead, we delegate that to the parent view. + */ + void updateVisibilities(boolean showItem, boolean showTextName, boolean animate) { + if (DEBUG) { + Log.d(TAG, String.format("updateVisibilities itemIsShown=%b nameIsShown=%b animate=%b", + showItem, showTextName, animate)); + } + + getBackground().setAlpha((showItem && showTextName) ? 255 : 0); + + if (showItem) { + if (showTextName) { + mName.setVisibility(View.VISIBLE); + if (animate) { + mName.setAlpha(0f); + mName.animate() + .alpha(1f) + .setDuration(ANIMATION_DURATION_FADE_NAME) + .setInterpolator(Interpolators.ALPHA_IN); + } else { + mName.setAlpha(1f); + } + } else { + if (animate) { + mName.setVisibility(View.VISIBLE); + mName.setAlpha(1f); + mName.animate() + .alpha(0f) + .setDuration(ANIMATION_DURATION_FADE_NAME) + .setInterpolator(Interpolators.ALPHA_OUT) + .withEndAction(() -> { + mName.setVisibility(View.GONE); + mName.setAlpha(1f); + }); + } else { + mName.setVisibility(View.GONE); + mName.setAlpha(1f); + } + } + setVisibility(View.VISIBLE); + setAlpha(1f); + } else { + // If item isn't shown, don't animate. The parent class will animate the view instead + setVisibility(View.GONE); + setAlpha(1f); + mName.setVisibility(showTextName ? View.VISIBLE : View.GONE); + mName.setAlpha(1f); + } + } + + /** + * Set the amount (ratio) that the device has transitioned to doze. + * + * @param darkAmount Amount of transition to doze: 1f for doze and 0f for awake. + */ + public void setDarkAmount(float darkAmount) { + if (mDarkAmount == darkAmount) { + return; + } + mDarkAmount = darkAmount; + updateDark(); + } + + private void updateDark() { + final int blendedTextColor = ColorUtils.blendARGB(mTextColor, Color.WHITE, mDarkAmount); + mName.setTextColor(blendedTextColor); + } } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardUserSwitcher.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardUserSwitcher.java deleted file mode 100644 index 90f557753132..000000000000 --- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardUserSwitcher.java +++ /dev/null @@ -1,414 +0,0 @@ -/* - * Copyright (C) 2014 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.statusbar.policy; - -import static com.android.systemui.statusbar.policy.UserSwitcherController.USER_SWITCH_DISABLED_ALPHA; -import static com.android.systemui.statusbar.policy.UserSwitcherController.USER_SWITCH_ENABLED_ALPHA; - -import android.animation.Animator; -import android.animation.AnimatorListenerAdapter; -import android.animation.ObjectAnimator; -import android.content.Context; -import android.database.DataSetObserver; -import android.graphics.drawable.Drawable; -import android.graphics.drawable.LayerDrawable; -import android.util.AttributeSet; -import android.view.LayoutInflater; -import android.view.MotionEvent; -import android.view.View; -import android.view.ViewGroup; -import android.view.ViewStub; -import android.widget.FrameLayout; - -import com.android.settingslib.animation.AppearAnimationUtils; -import com.android.settingslib.drawable.CircleFramedDrawable; -import com.android.systemui.Dependency; -import com.android.systemui.Interpolators; -import com.android.systemui.R; -import com.android.systemui.qs.tiles.UserDetailItemView; -import com.android.systemui.statusbar.phone.KeyguardStatusBarView; -import com.android.systemui.statusbar.phone.NotificationPanelViewController; - -import java.util.ArrayList; - -/** - * Manages the user switcher on the Keyguard. - */ -public class KeyguardUserSwitcher { - - private static final String TAG = "KeyguardUserSwitcher"; - private static final boolean ALWAYS_ON = false; - - private final Container mUserSwitcherContainer; - private final KeyguardStatusBarView mStatusBarView; - private final KeyguardUserAdapter mAdapter; - private final AppearAnimationUtils mAppearAnimationUtils; - private final KeyguardUserSwitcherScrim mBackground; - - private ViewGroup mUserSwitcher; - private ObjectAnimator mBgAnimator; - private UserSwitcherController mUserSwitcherController; - private boolean mAnimating; - - public KeyguardUserSwitcher(Context context, ViewStub userSwitcher, - KeyguardStatusBarView statusBarView, - NotificationPanelViewController panelViewController) { - boolean keyguardUserSwitcherEnabled = - context.getResources().getBoolean( - com.android.internal.R.bool.config_keyguardUserSwitcher) || ALWAYS_ON; - UserSwitcherController userSwitcherController = Dependency.get(UserSwitcherController.class); - if (userSwitcherController != null && keyguardUserSwitcherEnabled) { - mUserSwitcherContainer = (Container) userSwitcher.inflate(); - mBackground = new KeyguardUserSwitcherScrim(context); - reinflateViews(); - mStatusBarView = statusBarView; - mStatusBarView.setKeyguardUserSwitcher(this); - panelViewController.setKeyguardUserSwitcher(this); - mAdapter = new KeyguardUserAdapter(context, userSwitcherController, this); - mAdapter.registerDataSetObserver(mDataSetObserver); - mUserSwitcherController = userSwitcherController; - mAppearAnimationUtils = new AppearAnimationUtils(context, 400, -0.5f, 0.5f, - Interpolators.FAST_OUT_SLOW_IN); - mUserSwitcherContainer.setKeyguardUserSwitcher(this); - } else { - mUserSwitcherContainer = null; - mStatusBarView = null; - mAdapter = null; - mAppearAnimationUtils = null; - mBackground = null; - } - } - - private void reinflateViews() { - if (mUserSwitcher != null) { - mUserSwitcher.setBackground(null); - mUserSwitcher.removeOnLayoutChangeListener(mBackground); - } - mUserSwitcherContainer.removeAllViews(); - - LayoutInflater.from(mUserSwitcherContainer.getContext()) - .inflate(R.layout.keyguard_user_switcher_inner, mUserSwitcherContainer); - - mUserSwitcher = (ViewGroup) mUserSwitcherContainer.findViewById( - R.id.keyguard_user_switcher_inner); - mUserSwitcher.addOnLayoutChangeListener(mBackground); - mUserSwitcher.setBackground(mBackground); - } - - public void setKeyguard(boolean keyguard, boolean animate) { - if (mUserSwitcher != null) { - if (keyguard && shouldExpandByDefault()) { - show(animate); - } else { - hide(animate); - } - } - } - - /** - * @return true if the user switcher should be expanded by default on the lock screen. - * @see android.os.UserManager#isUserSwitcherEnabled() - */ - private boolean shouldExpandByDefault() { - return (mUserSwitcherController != null) && mUserSwitcherController.isSimpleUserSwitcher(); - } - - public void show(boolean animate) { - if (mUserSwitcher != null && mUserSwitcherContainer.getVisibility() != View.VISIBLE) { - cancelAnimations(); - mAdapter.refresh(); - mUserSwitcherContainer.setVisibility(View.VISIBLE); - mStatusBarView.setKeyguardUserSwitcherShowing(true, animate); - if (animate) { - startAppearAnimation(); - } - } - } - - private boolean hide(boolean animate) { - if (mUserSwitcher != null && mUserSwitcherContainer.getVisibility() == View.VISIBLE) { - cancelAnimations(); - if (animate) { - startDisappearAnimation(); - } else { - mUserSwitcherContainer.setVisibility(View.GONE); - } - mStatusBarView.setKeyguardUserSwitcherShowing(false, animate); - return true; - } - return false; - } - - private void cancelAnimations() { - int count = mUserSwitcher.getChildCount(); - for (int i = 0; i < count; i++) { - mUserSwitcher.getChildAt(i).animate().cancel(); - } - if (mBgAnimator != null) { - mBgAnimator.cancel(); - } - mUserSwitcher.animate().cancel(); - mAnimating = false; - } - - private void startAppearAnimation() { - int count = mUserSwitcher.getChildCount(); - View[] objects = new View[count]; - for (int i = 0; i < count; i++) { - objects[i] = mUserSwitcher.getChildAt(i); - } - mUserSwitcher.setClipChildren(false); - mUserSwitcher.setClipToPadding(false); - mAppearAnimationUtils.startAnimation(objects, new Runnable() { - @Override - public void run() { - mUserSwitcher.setClipChildren(true); - mUserSwitcher.setClipToPadding(true); - } - }); - mAnimating = true; - mBgAnimator = ObjectAnimator.ofInt(mBackground, "alpha", 0, 255); - mBgAnimator.setDuration(400); - mBgAnimator.setInterpolator(Interpolators.ALPHA_IN); - mBgAnimator.addListener(new AnimatorListenerAdapter() { - @Override - public void onAnimationEnd(Animator animation) { - mBgAnimator = null; - mAnimating = false; - } - }); - mBgAnimator.start(); - } - - private void startDisappearAnimation() { - mAnimating = true; - mUserSwitcher.animate() - .alpha(0f) - .setDuration(300) - .setInterpolator(Interpolators.ALPHA_OUT) - .withEndAction(new Runnable() { - @Override - public void run() { - mUserSwitcherContainer.setVisibility(View.GONE); - mUserSwitcher.setAlpha(1f); - mAnimating = false; - } - }); - } - - private void refresh() { - final int childCount = mUserSwitcher.getChildCount(); - final int adapterCount = mAdapter.getCount(); - final int N = Math.max(childCount, adapterCount); - for (int i = 0; i < N; i++) { - if (i < adapterCount) { - View oldView = null; - if (i < childCount) { - oldView = mUserSwitcher.getChildAt(i); - } - View newView = mAdapter.getView(i, oldView, mUserSwitcher); - if (oldView == null) { - // We ran out of existing views. Add it at the end. - mUserSwitcher.addView(newView); - } else if (oldView != newView) { - // We couldn't rebind the view. Replace it. - mUserSwitcher.removeViewAt(i); - mUserSwitcher.addView(newView, i); - } - } else { - int lastIndex = mUserSwitcher.getChildCount() - 1; - mUserSwitcher.removeViewAt(lastIndex); - } - } - } - - public boolean hideIfNotSimple(boolean animate) { - if (mUserSwitcherContainer != null && !mUserSwitcherController.isSimpleUserSwitcher()) { - return hide(animate); - } - return false; - } - - boolean isAnimating() { - return mAnimating; - } - - public final DataSetObserver mDataSetObserver = new DataSetObserver() { - @Override - public void onChanged() { - refresh(); - } - }; - - public void onDensityOrFontScaleChanged() { - if (mUserSwitcherContainer != null) { - reinflateViews(); - refresh(); - } - } - - static class KeyguardUserAdapter extends - UserSwitcherController.BaseUserAdapter implements View.OnClickListener { - - private Context mContext; - private KeyguardUserSwitcher mKeyguardUserSwitcher; - private View mCurrentUserView; - // List of users where the first entry is always the current user - private ArrayList<UserSwitcherController.UserRecord> mUsersOrdered = new ArrayList<>(); - - KeyguardUserAdapter(Context context, UserSwitcherController controller, - KeyguardUserSwitcher kgu) { - super(controller); - mContext = context; - mKeyguardUserSwitcher = kgu; - } - - @Override - public void notifyDataSetChanged() { - refreshUserOrder(); - super.notifyDataSetChanged(); - } - - void refreshUserOrder() { - ArrayList<UserSwitcherController.UserRecord> users = super.getUsers(); - mUsersOrdered = new ArrayList<>(users.size()); - for (int i = 0; i < users.size(); i++) { - UserSwitcherController.UserRecord record = users.get(i); - if (record.isCurrent) { - mUsersOrdered.add(0, record); - } else { - mUsersOrdered.add(record); - } - } - } - - @Override - protected ArrayList<UserSwitcherController.UserRecord> getUsers() { - return mUsersOrdered; - } - - @Override - public View getView(int position, View convertView, ViewGroup parent) { - UserSwitcherController.UserRecord item = getItem(position); - return createUserDetailItemView(convertView, parent, item); - } - - KeyguardUserDetailItemView convertOrInflate(View convertView, ViewGroup parent) { - if (!(convertView instanceof KeyguardUserDetailItemView) - || !(convertView.getTag() instanceof UserSwitcherController.UserRecord)) { - convertView = LayoutInflater.from(mContext).inflate( - R.layout.keyguard_user_switcher_item, parent, false); - } - return (KeyguardUserDetailItemView) convertView; - } - - UserDetailItemView createUserDetailItemView(View convertView, ViewGroup parent, - UserSwitcherController.UserRecord item) { - KeyguardUserDetailItemView v = convertOrInflate(convertView, parent); - if (!item.isCurrent || item.isGuest) { - v.setOnClickListener(this); - } else { - v.setOnClickListener(null); - v.setClickable(false); - } - - String name = getName(mContext, item); - if (item.picture == null) { - v.bind(name, getDrawable(mContext, item).mutate(), item.resolveId()); - } else { - int avatarSize = - (int) mContext.getResources().getDimension(R.dimen.kg_framed_avatar_size); - Drawable drawable = new CircleFramedDrawable(item.picture, avatarSize); - drawable.setColorFilter( - item.isSwitchToEnabled ? null : getDisabledUserAvatarColorFilter()); - v.bind(name, drawable, item.info.id); - } - v.setActivated(item.isCurrent); - v.setDisabledByAdmin(item.isDisabledByAdmin); - v.setEnabled(item.isSwitchToEnabled); - v.setAlpha(v.isEnabled() ? USER_SWITCH_ENABLED_ALPHA : USER_SWITCH_DISABLED_ALPHA); - - if (item.isCurrent) { - mCurrentUserView = v; - } - v.setTag(item); - return v; - } - - private static Drawable getDrawable(Context context, - UserSwitcherController.UserRecord item) { - Drawable drawable = getIconDrawable(context, item); - int iconColorRes; - if (item.isCurrent) { - iconColorRes = R.color.kg_user_switcher_selected_avatar_icon_color; - } else if (!item.isSwitchToEnabled) { - iconColorRes = R.color.GM2_grey_600; - } else { - iconColorRes = R.color.kg_user_switcher_avatar_icon_color; - } - drawable.setTint(context.getResources().getColor(iconColorRes, context.getTheme())); - - if (item.isCurrent) { - Drawable bg = context.getDrawable(R.drawable.bg_avatar_selected); - drawable = new LayerDrawable(new Drawable[]{bg, drawable}); - } - - return drawable; - } - - @Override - public void onClick(View v) { - UserSwitcherController.UserRecord user = (UserSwitcherController.UserRecord) v.getTag(); - if (user.isCurrent && !user.isGuest) { - // Close the switcher if tapping the current user. Guest is excluded because - // tapping the guest user while it's current clears the session. - mKeyguardUserSwitcher.hideIfNotSimple(true /* animate */); - } else if (user.isSwitchToEnabled) { - if (!user.isAddUser && !user.isRestricted && !user.isDisabledByAdmin) { - if (mCurrentUserView != null) { - mCurrentUserView.setActivated(false); - } - v.setActivated(true); - } - onUserListItemClicked(user); - } - } - } - - public static class Container extends FrameLayout { - - private KeyguardUserSwitcher mKeyguardUserSwitcher; - - public Container(Context context, AttributeSet attrs) { - super(context, attrs); - setClipChildren(false); - } - - public void setKeyguardUserSwitcher(KeyguardUserSwitcher keyguardUserSwitcher) { - mKeyguardUserSwitcher = keyguardUserSwitcher; - } - - @Override - public boolean onTouchEvent(MotionEvent ev) { - // Hide switcher if it didn't handle the touch event (and let the event go through). - if (mKeyguardUserSwitcher != null && !mKeyguardUserSwitcher.isAnimating()) { - mKeyguardUserSwitcher.hideIfNotSimple(true /* animate */); - } - return false; - } - } -} diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardUserSwitcherController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardUserSwitcherController.java new file mode 100644 index 000000000000..b76e451cb681 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardUserSwitcherController.java @@ -0,0 +1,639 @@ +/* + * Copyright (C) 2021 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.systemui.statusbar.policy; + +import static com.android.systemui.statusbar.policy.UserSwitcherController.USER_SWITCH_DISABLED_ALPHA; +import static com.android.systemui.statusbar.policy.UserSwitcherController.USER_SWITCH_ENABLED_ALPHA; + +import android.content.Context; +import android.content.res.Resources; +import android.database.DataSetObserver; +import android.graphics.drawable.Drawable; +import android.graphics.drawable.LayerDrawable; +import android.os.UserHandle; +import android.util.Log; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.LinearLayout; + +import com.android.keyguard.KeyguardConstants; +import com.android.keyguard.KeyguardUpdateMonitor; +import com.android.keyguard.KeyguardUpdateMonitorCallback; +import com.android.keyguard.KeyguardVisibilityHelper; +import com.android.keyguard.dagger.KeyguardUserSwitcherScope; +import com.android.settingslib.drawable.CircleFramedDrawable; +import com.android.systemui.Interpolators; +import com.android.systemui.R; +import com.android.systemui.dagger.qualifiers.Main; +import com.android.systemui.keyguard.ScreenLifecycle; +import com.android.systemui.plugins.statusbar.StatusBarStateController; +import com.android.systemui.statusbar.SysuiStatusBarStateController; +import com.android.systemui.statusbar.notification.AnimatableProperty; +import com.android.systemui.statusbar.notification.PropertyAnimator; +import com.android.systemui.statusbar.notification.stack.AnimationProperties; +import com.android.systemui.statusbar.notification.stack.StackStateAnimator; +import com.android.systemui.statusbar.phone.DozeParameters; +import com.android.systemui.util.ViewController; + +import java.lang.ref.WeakReference; +import java.util.ArrayList; + +import javax.inject.Inject; + +/** + * Manages the user switcher on the Keyguard. + */ +@KeyguardUserSwitcherScope +public class KeyguardUserSwitcherController extends ViewController<KeyguardUserSwitcherView> { + + private static final String TAG = "KeyguardUserSwitcherController"; + private static final boolean DEBUG = KeyguardConstants.DEBUG; + + private static final AnimationProperties ANIMATION_PROPERTIES = + new AnimationProperties().setDuration(StackStateAnimator.ANIMATION_DURATION_STANDARD); + + private final Context mContext; + private final UserSwitcherController mUserSwitcherController; + private final ScreenLifecycle mScreenLifecycle; + private final KeyguardUserAdapter mAdapter; + private final KeyguardStateController mKeyguardStateController; + private final KeyguardUpdateMonitor mKeyguardUpdateMonitor; + private WeakReference<KeyguardUserSwitcherListener> mKeyguardUserSwitcherCallback; + protected final SysuiStatusBarStateController mStatusBarStateController; + private final KeyguardVisibilityHelper mKeyguardVisibilityHelper; + + // Child views of KeyguardUserSwitcherView + private KeyguardUserSwitcherListView mListView; + private LinearLayout mEndGuestButton; + + // State info for the user switcher + private boolean mUserSwitcherOpen; + private int mCurrentUserId = UserHandle.USER_NULL; + private boolean mCurrentUserIsGuest; + private int mBarState; + private float mDarkAmount; + + private final KeyguardUpdateMonitorCallback mInfoCallback = + new KeyguardUpdateMonitorCallback() { + @Override + public void onKeyguardVisibilityChanged(boolean showing) { + if (DEBUG) Log.d(TAG, String.format("onKeyguardVisibilityChanged %b", showing)); + // Any time the keyguard is hidden, try to close the user switcher menu to + // restore keyguard to the default state + if (!showing) { + closeSwitcherIfOpenAndNotSimple(false); + } + } + + @Override + public void onUserSwitching(int userId) { + closeSwitcherIfOpenAndNotSimple(false); + } + }; + + private final ScreenLifecycle.Observer mScreenObserver = new ScreenLifecycle.Observer() { + @Override + public void onScreenTurnedOff() { + if (DEBUG) Log.d(TAG, "onScreenTurnedOff"); + closeSwitcherIfOpenAndNotSimple(false); + } + }; + + private final StatusBarStateController.StateListener mStatusBarStateListener = + new StatusBarStateController.StateListener() { + @Override + public void onStateChanged(int newState) { + if (DEBUG) Log.d(TAG, String.format("onStateChanged: newState=%d", newState)); + + boolean goingToFullShade = mStatusBarStateController.goingToFullShade(); + boolean keyguardFadingAway = mKeyguardStateController.isKeyguardFadingAway(); + int oldState = mBarState; + mBarState = newState; + + if (mStatusBarStateController.goingToFullShade() + || mKeyguardStateController.isKeyguardFadingAway()) { + closeSwitcherIfOpenAndNotSimple(true); + } + + setKeyguardUserSwitcherVisibility( + newState, + keyguardFadingAway, + goingToFullShade, + oldState); + } + + @Override + public void onDozeAmountChanged(float linearAmount, float amount) { + if (DEBUG) { + Log.d(TAG, String.format("onDozeAmountChanged: linearAmount=%f amount=%f", + linearAmount, amount)); + } + setDarkAmount(amount); + } + }; + + @Inject + public KeyguardUserSwitcherController( + KeyguardUserSwitcherView keyguardUserSwitcherView, + Context context, + @Main Resources resources, + LayoutInflater layoutInflater, + ScreenLifecycle screenLifecycle, + UserSwitcherController userSwitcherController, + KeyguardStateController keyguardStateController, + SysuiStatusBarStateController statusBarStateController, + KeyguardUpdateMonitor keyguardUpdateMonitor, + DozeParameters dozeParameters) { + super(keyguardUserSwitcherView); + if (DEBUG) Log.d(TAG, "New KeyguardUserSwitcherController"); + mContext = context; + mScreenLifecycle = screenLifecycle; + mUserSwitcherController = userSwitcherController; + mKeyguardStateController = keyguardStateController; + mStatusBarStateController = statusBarStateController; + mKeyguardUpdateMonitor = keyguardUpdateMonitor; + mAdapter = new KeyguardUserAdapter(mContext, resources, layoutInflater, + mUserSwitcherController, this); + mKeyguardVisibilityHelper = new KeyguardVisibilityHelper(mView, + keyguardStateController, dozeParameters); + } + + @Override + protected void onInit() { + super.onInit(); + + if (DEBUG) Log.d(TAG, "onInit"); + + mListView = mView.findViewById(R.id.keyguard_user_switcher_list); + mEndGuestButton = mView.findViewById(R.id.end_guest_button); + + mEndGuestButton.setOnClickListener(v -> { + mUserSwitcherController.showExitGuestDialog(mCurrentUserId); + }); + + mView.setOnTouchListener((v, event) -> { + if (!isListAnimating()) { + // Hide switcher if it didn't handle the touch event (and block the event from + // going through). + return closeSwitcherIfOpenAndNotSimple(true); + } + return false; + }); + } + + @Override + protected void onViewAttached() { + if (DEBUG) Log.d(TAG, "onViewAttached"); + mAdapter.registerDataSetObserver(mDataSetObserver); + mDataSetObserver.onChanged(); + mKeyguardUpdateMonitor.registerCallback(mInfoCallback); + mStatusBarStateController.addCallback(mStatusBarStateListener); + mScreenLifecycle.addObserver(mScreenObserver); + } + + @Override + protected void onViewDetached() { + if (DEBUG) Log.d(TAG, "onViewDetached"); + + // Detaching the view will always close the switcher + closeSwitcherIfOpenAndNotSimple(false); + + mAdapter.unregisterDataSetObserver(mDataSetObserver); + mKeyguardUpdateMonitor.removeCallback(mInfoCallback); + mStatusBarStateController.removeCallback(mStatusBarStateListener); + mScreenLifecycle.removeObserver(mScreenObserver); + } + + /** + * See: + * + * <ul> + * <li>{@link com.android.internal.R.bool.config_expandLockScreenUserSwitcher}</li> + * <li>{@link UserSwitcherController.SIMPLE_USER_SWITCHER_GLOBAL_SETTING}</li> + * </ul> + * + * @return true if the user switcher should be open by default on the lock screen. + * @see android.os.UserManager#isUserSwitcherEnabled() + */ + public boolean isSimpleUserSwitcher() { + return mUserSwitcherController.isSimpleUserSwitcher(); + } + + /** + * @param animate if the transition should be animated + * @return true if the switcher state changed + */ + public boolean closeSwitcherIfOpenAndNotSimple(boolean animate) { + if (isUserSwitcherOpen() && !isSimpleUserSwitcher()) { + setUserSwitcherOpened(false /* open */, animate); + return true; + } + return false; + } + + public final DataSetObserver mDataSetObserver = new DataSetObserver() { + @Override + public void onChanged() { + refreshUserList(); + } + }; + + void refreshUserList() { + final int childCount = mListView.getChildCount(); + final int adapterCount = mAdapter.getCount(); + final int count = Math.max(childCount, adapterCount); + + if (DEBUG) { + Log.d(TAG, String.format("refreshUserList childCount=%d adapterCount=%d", childCount, + adapterCount)); + } + + boolean foundCurrentUser = false; + for (int i = 0; i < count; i++) { + if (i < adapterCount) { + View oldView = null; + if (i < childCount) { + oldView = mListView.getChildAt(i); + } + KeyguardUserDetailItemView newView = (KeyguardUserDetailItemView) + mAdapter.getView(i, oldView, mListView); + UserSwitcherController.UserRecord userTag = + (UserSwitcherController.UserRecord) newView.getTag(); + if (userTag.isCurrent) { + if (i != 0) { + Log.w(TAG, "Current user is not the first view in the list"); + } + foundCurrentUser = true; + mCurrentUserId = userTag.info.id; + mCurrentUserIsGuest = userTag.isGuest; + // Current user is always visible + newView.updateVisibilities(true /* showItem */, + mUserSwitcherOpen /* showTextName */, false /* animate */); + } else { + // Views for non-current users are always expanded (e.g. they should the name + // next to the user icon). However, they could be hidden entirely if the list + // is closed. + newView.updateVisibilities(mUserSwitcherOpen /* showItem */, + true /* showTextName */, false /* animate */); + } + newView.setDarkAmount(mDarkAmount); + if (oldView == null) { + // We ran out of existing views. Add it at the end. + mListView.addView(newView); + } else if (oldView != newView) { + // We couldn't rebind the view. Replace it. + mListView.replaceView(newView, i); + } + } else { + mListView.removeLastView(); + } + } + if (!foundCurrentUser) { + Log.w(TAG, "Current user is not listed"); + mCurrentUserId = UserHandle.USER_NULL; + mCurrentUserIsGuest = false; + } + } + + /** + * Get the height of the keyguard user switcher view when closed. + */ + public int getUserIconHeight() { + View firstChild = mListView.getChildAt(0); + return firstChild == null ? 0 : firstChild.getHeight(); + } + + /** + * Set the visibility of the keyguard user switcher view based on some new state. + */ + public void setKeyguardUserSwitcherVisibility( + int statusBarState, + boolean keyguardFadingAway, + boolean goingToFullShade, + int oldStatusBarState) { + mKeyguardVisibilityHelper.setViewVisibility( + statusBarState, keyguardFadingAway, goingToFullShade, oldStatusBarState); + } + + /** + * Update position of the view with an optional animation + */ + public void updatePosition(int x, int y, boolean animate) { + PropertyAnimator.setProperty(mListView, AnimatableProperty.Y, y, ANIMATION_PROPERTIES, + animate); + PropertyAnimator.setProperty(mListView, AnimatableProperty.TRANSLATION_X, -Math.abs(x), + ANIMATION_PROPERTIES, animate); + } + + /** + * Set keyguard user switcher view alpha. + */ + public void setAlpha(float alpha) { + if (!mKeyguardVisibilityHelper.isVisibilityAnimating()) { + mView.setAlpha(alpha); + } + } + + /** + * Set the amount (ratio) that the device has transitioned to doze. + * + * @param darkAmount Amount of transition to doze: 1f for doze and 0f for awake. + */ + private void setDarkAmount(float darkAmount) { + boolean isAwake = darkAmount != 0; + if (darkAmount == mDarkAmount) { + return; + } + mDarkAmount = darkAmount; + mListView.setDarkAmount(darkAmount); + mView.setVisibility(isAwake ? View.VISIBLE : View.GONE); + if (!isAwake) { + closeSwitcherIfOpenAndNotSimple(false); + } + } + + private boolean isListAnimating() { + return mKeyguardVisibilityHelper.isVisibilityAnimating() || mListView.isAnimating(); + } + + /** + * Remove the callback if it exists. + */ + public void removeCallback() { + if (DEBUG) Log.d(TAG, "removeCallback"); + mKeyguardUserSwitcherCallback = null; + } + + /** + * Register to receive notifications about keyguard user switcher state + * (see {@link KeyguardUserSwitcherListener}. + * + * Only one callback can be used at a time. + * + * @param callback The callback to register + */ + public void setCallback(KeyguardUserSwitcherListener callback) { + if (DEBUG) Log.d(TAG, "setCallback"); + mKeyguardUserSwitcherCallback = new WeakReference<>(callback); + } + + /** + * If user switcher state changes, notifies all {@link KeyguardUserSwitcherListener}. + * Switcher state is updatd before animations finish. + * + * @param animate true to animate transition. The user switcher state (i.e. + * {@link #isUserSwitcherOpen()}) is updated before animation is finished. + */ + private void setUserSwitcherOpened(boolean open, boolean animate) { + boolean wasOpen = mUserSwitcherOpen; + if (DEBUG) { + Log.d(TAG, String.format("setUserSwitcherOpened: %b -> %b (animate=%b)", wasOpen, + open, animate)); + } + mUserSwitcherOpen = open; + if (mUserSwitcherOpen != wasOpen) { + notifyUserSwitcherStateChanged(); + } + updateVisibilities(animate); + } + + private void updateVisibilities(boolean animate) { + if (DEBUG) Log.d(TAG, String.format("updateVisibilities: animate=%b", animate)); + mEndGuestButton.animate().cancel(); + if (mUserSwitcherOpen && mCurrentUserIsGuest) { + // Show the "End guest session" button + mEndGuestButton.setVisibility(View.VISIBLE); + if (animate) { + mEndGuestButton.setAlpha(0f); + mEndGuestButton.animate() + .alpha(1f) + .setDuration(360) + .setInterpolator(Interpolators.ALPHA_IN) + .withEndAction(() -> { + mEndGuestButton.setClickable(true); + }); + } else { + mEndGuestButton.setClickable(true); + mEndGuestButton.setAlpha(1f); + } + } else { + // Hide the "End guest session" button. If it's already GONE, don't try to + // animate it or it will appear again for an instant. + mEndGuestButton.setClickable(false); + if (animate && mEndGuestButton.getVisibility() != View.GONE) { + mEndGuestButton.setVisibility(View.VISIBLE); + mEndGuestButton.setAlpha(1f); + mEndGuestButton.animate() + .alpha(0f) + .setDuration(360) + .setInterpolator(Interpolators.ALPHA_OUT) + .withEndAction(() -> { + mEndGuestButton.setVisibility(View.GONE); + mEndGuestButton.setAlpha(1f); + }); + } else { + mEndGuestButton.setVisibility(View.GONE); + mEndGuestButton.setAlpha(1f); + } + } + + mListView.updateVisibilities(mUserSwitcherOpen, animate); + } + + private boolean isUserSwitcherOpen() { + return mUserSwitcherOpen; + } + + private void notifyUserSwitcherStateChanged() { + if (DEBUG) { + Log.d(TAG, String.format("notifyUserSwitcherStateChanged: mUserSwitcherOpen=%b", + mUserSwitcherOpen)); + } + if (mKeyguardUserSwitcherCallback != null) { + KeyguardUserSwitcherListener cb = mKeyguardUserSwitcherCallback.get(); + if (cb != null) { + cb.onKeyguardUserSwitcherChanged(mUserSwitcherOpen); + } + } + } + + /** + * Callback for keyguard user switcher state information + */ + public interface KeyguardUserSwitcherListener { + + /** + * Called when the keyguard enters or leaves user switcher mode. This will be called + * before the animations are finished. + * + * @param open if true, keyguard is showing the user switcher or transitioning from/to user + * switcher mode. + */ + void onKeyguardUserSwitcherChanged(boolean open); + } + + static class KeyguardUserAdapter extends + UserSwitcherController.BaseUserAdapter implements View.OnClickListener { + + private final Context mContext; + private final Resources mResources; + private final LayoutInflater mLayoutInflater; + private KeyguardUserSwitcherController mKeyguardUserSwitcherController; + private View mCurrentUserView; + // List of users where the first entry is always the current user + private ArrayList<UserSwitcherController.UserRecord> mUsersOrdered = new ArrayList<>(); + + KeyguardUserAdapter(Context context, Resources resources, LayoutInflater layoutInflater, + UserSwitcherController controller, + KeyguardUserSwitcherController keyguardUserSwitcherController) { + super(controller); + mContext = context; + mResources = resources; + mLayoutInflater = layoutInflater; + mKeyguardUserSwitcherController = keyguardUserSwitcherController; + } + + @Override + public void notifyDataSetChanged() { + // At this point, value of isSimpleUserSwitcher() may have changed in addition to the + // data set + refreshUserOrder(); + super.notifyDataSetChanged(); + } + + void refreshUserOrder() { + ArrayList<UserSwitcherController.UserRecord> users = super.getUsers(); + mUsersOrdered = new ArrayList<>(users.size()); + for (int i = 0; i < users.size(); i++) { + UserSwitcherController.UserRecord record = users.get(i); + if (record.isCurrent) { + mUsersOrdered.add(0, record); + } else { + mUsersOrdered.add(record); + } + } + } + + @Override + protected ArrayList<UserSwitcherController.UserRecord> getUsers() { + return mUsersOrdered; + } + + @Override + public View getView(int position, View convertView, ViewGroup parent) { + UserSwitcherController.UserRecord item = getItem(position); + return createUserDetailItemView(convertView, parent, item); + } + + @Override + public String getName(Context context, UserSwitcherController.UserRecord item) { + if (item.isGuest) { + return context.getString(com.android.settingslib.R.string.guest_nickname); + } else { + return super.getName(context, item); + } + } + + KeyguardUserDetailItemView convertOrInflate(View convertView, ViewGroup parent) { + if (!(convertView instanceof KeyguardUserDetailItemView) + || !(convertView.getTag() instanceof UserSwitcherController.UserRecord)) { + convertView = mLayoutInflater.inflate( + R.layout.keyguard_user_switcher_item, parent, false); + } + return (KeyguardUserDetailItemView) convertView; + } + + KeyguardUserDetailItemView createUserDetailItemView(View convertView, ViewGroup parent, + UserSwitcherController.UserRecord item) { + KeyguardUserDetailItemView v = convertOrInflate(convertView, parent); + v.setOnClickListener(this); + + String name = getName(mContext, item); + if (item.picture == null) { + v.bind(name, getDrawable(item).mutate(), item.resolveId()); + } else { + int avatarSize = + (int) mResources.getDimension(R.dimen.kg_framed_avatar_size); + Drawable drawable = new CircleFramedDrawable(item.picture, avatarSize); + drawable.setColorFilter( + item.isSwitchToEnabled ? null : getDisabledUserAvatarColorFilter()); + v.bind(name, drawable, item.info.id); + } + v.setActivated(item.isCurrent); + v.setDisabledByAdmin(item.isDisabledByAdmin); + v.setEnabled(item.isSwitchToEnabled); + v.setAlpha(v.isEnabled() ? USER_SWITCH_ENABLED_ALPHA : USER_SWITCH_DISABLED_ALPHA); + + if (item.isCurrent) { + mCurrentUserView = v; + } + v.setTag(item); + return v; + } + + private Drawable getDrawable(UserSwitcherController.UserRecord item) { + Drawable drawable; + if (item.isCurrent && item.isGuest) { + drawable = mContext.getDrawable(R.drawable.ic_avatar_guest_user); + } else { + drawable = getIconDrawable(mContext, item); + } + + int iconColorRes; + if (item.isSwitchToEnabled) { + iconColorRes = R.color.kg_user_switcher_avatar_icon_color; + } else { + iconColorRes = R.color.kg_user_switcher_restricted_avatar_icon_color; + } + drawable.setTint(mResources.getColor(iconColorRes, mContext.getTheme())); + + Drawable bg = mContext.getDrawable(R.drawable.kg_bg_avatar); + drawable = new LayerDrawable(new Drawable[]{bg, drawable}); + return drawable; + } + + @Override + public void onClick(View v) { + UserSwitcherController.UserRecord user = (UserSwitcherController.UserRecord) v.getTag(); + + if (mKeyguardUserSwitcherController.isListAnimating()) { + return; + } + + if (mKeyguardUserSwitcherController.isUserSwitcherOpen()) { + if (user.isCurrent) { + // Close the switcher if tapping the current user + mKeyguardUserSwitcherController.setUserSwitcherOpened( + false /* open */, true /* animate */); + } else if (user.isSwitchToEnabled) { + if (!user.isAddUser && !user.isRestricted && !user.isDisabledByAdmin) { + if (mCurrentUserView != null) { + mCurrentUserView.setActivated(false); + } + v.setActivated(true); + } + onUserListItemClicked(user); + } + } else { + // If switcher is closed, tapping anywhere in the view will open it + mKeyguardUserSwitcherController.setUserSwitcherOpened( + true /* open */, true /* animate */); + } + } + } +} diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardUserSwitcherListView.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardUserSwitcherListView.java new file mode 100644 index 000000000000..7c82c116eb3d --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardUserSwitcherListView.java @@ -0,0 +1,168 @@ +/* + * Copyright (C) 2021 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.systemui.statusbar.policy; + +import android.content.Context; +import android.util.AttributeSet; +import android.util.Log; +import android.view.View; + +import com.android.keyguard.AlphaOptimizedLinearLayout; +import com.android.keyguard.KeyguardConstants; +import com.android.settingslib.animation.AppearAnimationUtils; +import com.android.settingslib.animation.DisappearAnimationUtils; +import com.android.systemui.Interpolators; + +/** + * The container for the user switcher on Keyguard. + */ +public class KeyguardUserSwitcherListView extends AlphaOptimizedLinearLayout { + + private static final String TAG = "KeyguardUserSwitcherListView"; + private static final boolean DEBUG = KeyguardConstants.DEBUG; + + private static final int ANIMATION_DURATION_OPENING = 360; + private static final int ANIMATION_DURATION_CLOSING = 240; + + private boolean mAnimating; + private final AppearAnimationUtils mAppearAnimationUtils; + private final DisappearAnimationUtils mDisappearAnimationUtils; + + public KeyguardUserSwitcherListView(Context context, AttributeSet attrs) { + super(context, attrs); + setClipChildren(false); + mAppearAnimationUtils = new AppearAnimationUtils(context, ANIMATION_DURATION_OPENING, + -0.5f, 0.5f, Interpolators.FAST_OUT_SLOW_IN); + mDisappearAnimationUtils = new DisappearAnimationUtils(context, ANIMATION_DURATION_CLOSING, + 0.5f, 0.5f, Interpolators.FAST_OUT_LINEAR_IN); + } + + /** + * Set the amount (ratio) that the device has transitioned to doze. + * + * @param darkAmount Amount of transition to doze: 1f for doze and 0f for awake. + */ + void setDarkAmount(float darkAmount) { + int childCount = getChildCount(); + for (int i = 0; i < childCount; i++) { + View v = getChildAt(i); + if (v instanceof KeyguardUserDetailItemView) { + ((KeyguardUserDetailItemView) v).setDarkAmount(darkAmount); + } + } + } + + boolean isAnimating() { + return mAnimating; + } + + /** + * Update visibilities of this view and child views for when the user list is open or closed. + * If closed, this hides everything but the first item (which is always the current user). + */ + void updateVisibilities(boolean open, boolean animate) { + if (DEBUG) { + Log.d(TAG, String.format("updateVisibilities: open=%b animate=%b childCount=%d", + open, animate, getChildCount())); + } + + mAnimating = false; + + int userListCount = getChildCount(); + if (userListCount > 0) { + // The first child is always the current user. + KeyguardUserDetailItemView currentUserView = ((KeyguardUserDetailItemView) getChildAt( + 0)); + currentUserView.updateVisibilities(true /* showItem */, open /* showTextName */, + animate); + currentUserView.setClickable(true); + currentUserView.clearAnimation(); + } + + if (userListCount <= 1) { + return; + } + + if (animate) { + // Create an array of all the remaining users (that aren't the current user). + KeyguardUserDetailItemView[] otherUserViews = + new KeyguardUserDetailItemView[userListCount - 1]; + for (int i = 1, n = 0; i < userListCount; i++, n++) { + otherUserViews[n] = (KeyguardUserDetailItemView) getChildAt(i); + + // Update clickable state immediately so that the menu feels more responsive + otherUserViews[n].setClickable(open); + + // Before running the animation, ensure visibility is set correctly + otherUserViews[n].updateVisibilities( + true /* showItem */, true /* showTextName */, false /* animate */); + otherUserViews[n].clearAnimation(); + } + + setClipChildren(false); + setClipToPadding(false); + + mAnimating = true; + + final int nonCurrentUserCount = otherUserViews.length; + if (open) { + mAppearAnimationUtils.startAnimation(otherUserViews, () -> { + setClipChildren(true); + setClipToPadding(true); + mAnimating = false; + }); + } else { + mDisappearAnimationUtils.startAnimation(otherUserViews, () -> { + setClipChildren(true); + setClipToPadding(true); + for (int i = 0; i < nonCurrentUserCount; i++) { + otherUserViews[i].updateVisibilities( + false /* showItem */, true /* showTextName */, false /* animate */); + } + mAnimating = false; + }); + } + } else { + for (int i = 1; i < userListCount; i++) { + KeyguardUserDetailItemView nonCurrentUserView = + ((KeyguardUserDetailItemView) getChildAt(i)); + nonCurrentUserView.clearAnimation(); + nonCurrentUserView.updateVisibilities( + open /* showItem */, true /* showTextName */, false /* animate */); + nonCurrentUserView.setClickable(open); + } + } + } + + /** + * Replaces the view at the specified position in the group. + * + * @param index the position in the group of the view to remove + */ + void replaceView(KeyguardUserDetailItemView newView, int index) { + removeViewAt(index); + addView(newView, index); + } + + /** + * Removes the last view in the group. + */ + void removeLastView() { + int lastIndex = getChildCount() - 1; + removeViewAt(lastIndex); + } +} diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardUserSwitcherView.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardUserSwitcherView.java new file mode 100644 index 000000000000..3f0e23f7c72e --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardUserSwitcherView.java @@ -0,0 +1,31 @@ +/* + * Copyright (C) 2021 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.systemui.statusbar.policy; + +import android.content.Context; +import android.util.AttributeSet; +import android.widget.FrameLayout; + +/** + * The container for the user switcher on Keyguard. + */ +public class KeyguardUserSwitcherView extends FrameLayout { + + public KeyguardUserSwitcherView(Context context, AttributeSet attrs) { + super(context, attrs); + } +} diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/UserSwitcherController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/UserSwitcherController.java index 68d74ef760b4..1838391ce2ae 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/UserSwitcherController.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/UserSwitcherController.java @@ -423,7 +423,7 @@ public class UserSwitcherController implements Dumpable { } } - private void showExitGuestDialog(int id) { + protected void showExitGuestDialog(int id) { int newId = UserHandle.USER_SYSTEM; if (mResumeUserOnGuestLogout && mLastNonGuestUser != UserHandle.USER_SYSTEM) { UserInfo info = mUserManager.getUserInfo(mLastNonGuestUser); diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/KeyguardClockPositionAlgorithmTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/KeyguardClockPositionAlgorithmTest.java index ee1d758e7ae2..4162884680a9 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/KeyguardClockPositionAlgorithmTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/KeyguardClockPositionAlgorithmTest.java @@ -393,10 +393,11 @@ public class KeyguardClockPositionAlgorithmTest extends SysuiTestCase { private void positionClock() { mClockPositionAlgorithm.setup(EMPTY_MARGIN, SCREEN_HEIGHT, mNotificationStackHeight, - mPanelExpansion, SCREEN_HEIGHT, mKeyguardStatusHeight, mPreferredClockY, - mHasCustomClock, mHasVisibleNotifs, mDark, ZERO_DRAG, false /* bypassEnabled */, - 0 /* unlockedStackScrollerPadding */, false /* udfpsEnrolled */, - mQsExpansion, mCutoutTopInset); + mPanelExpansion, SCREEN_HEIGHT, mKeyguardStatusHeight, + 0 /* keyguardUserSwitcherHeight */, mPreferredClockY, mHasCustomClock, + mHasVisibleNotifs, mDark, ZERO_DRAG, false /* bypassEnabled */, + 0 /* unlockedStackScrollerPadding */, false /* udfpsEnrolled */, mQsExpansion, + mCutoutTopInset); mClockPositionAlgorithm.run(mClockPosition); } } diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationPanelViewTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationPanelViewTest.java index c07ba723ab43..d0e70310810e 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationPanelViewTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationPanelViewTest.java @@ -37,6 +37,7 @@ import android.content.res.Configuration; import android.content.res.Resources; import android.hardware.biometrics.BiometricSourceType; import android.os.PowerManager; +import android.os.UserManager; import android.testing.AndroidTestingRunner; import android.testing.TestableLooper; import android.util.DisplayMetrics; @@ -58,6 +59,7 @@ import com.android.keyguard.KeyguardStatusView; import com.android.keyguard.KeyguardStatusViewController; import com.android.keyguard.KeyguardUpdateMonitor; import com.android.keyguard.dagger.KeyguardStatusViewComponent; +import com.android.keyguard.dagger.KeyguardUserSwitcherComponent; import com.android.systemui.R; import com.android.systemui.SysuiTestCase; import com.android.systemui.biometrics.AuthController; @@ -68,7 +70,6 @@ import com.android.systemui.controls.dagger.ControlsComponent; import com.android.systemui.doze.DozeLog; import com.android.systemui.media.MediaDataManager; import com.android.systemui.media.MediaHierarchyManager; -import com.android.systemui.qs.QSDetailDisplayer; import com.android.systemui.statusbar.CommandQueue; import com.android.systemui.statusbar.FeatureFlags; import com.android.systemui.statusbar.KeyguardAffordanceView; @@ -193,6 +194,8 @@ public class NotificationPanelViewTest extends SysuiTestCase { @Mock private KeyguardStatusViewComponent.Factory mKeyguardStatusViewComponentFactory; @Mock + private KeyguardUserSwitcherComponent.Factory mKeyguardUserSwitcherComponent; + @Mock private KeyguardStatusViewComponent mKeyguardStatusViewComponent; @Mock private KeyguardClockSwitchController mKeyguardClockSwitchController; @@ -216,6 +219,9 @@ public class NotificationPanelViewTest extends SysuiTestCase { private NotificationsQuickSettingsContainer mNotificationContainerParent; @Mock private AmbientState mAmbientState; + @Mock + private UserManager mUserManager; + private NotificationPanelViewController mNotificationPanelViewController; private View.AccessibilityDelegate mAccessibiltyDelegate; @@ -299,11 +305,12 @@ public class NotificationPanelViewTest extends SysuiTestCase { mBiometricUnlockController, mStatusBarKeyguardViewManager, mNotificationStackScrollLayoutController, mKeyguardStatusViewComponentFactory, + mKeyguardUserSwitcherComponent, mGroupManager, mNotificationAreaController, mAuthController, - new QSDetailDisplayer(), mScrimController, + mUserManager, mMediaDataManager, mAmbientState, mFeatureFlags, diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/KeyguardUserSwitcherAdapterTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/KeyguardUserSwitcherAdapterTest.kt index fc1a79105db1..e479882ac50a 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/KeyguardUserSwitcherAdapterTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/KeyguardUserSwitcherAdapterTest.kt @@ -60,9 +60,9 @@ class KeyguardUserSwitcherAdapterTest : SysuiTestCase() { @Mock private lateinit var layoutInflater: LayoutInflater @Mock - private lateinit var keyguardUserSwitcher: KeyguardUserSwitcher + private lateinit var keyguardUserSwitcherController: KeyguardUserSwitcherController - private lateinit var adapter: KeyguardUserSwitcher.KeyguardUserAdapter + private lateinit var adapter: KeyguardUserSwitcherController.KeyguardUserAdapter private lateinit var picture: Bitmap @Before @@ -72,8 +72,11 @@ class KeyguardUserSwitcherAdapterTest : SysuiTestCase() { mContext.addMockSystemService(Context.LAYOUT_INFLATER_SERVICE, layoutInflater) `when`(layoutInflater.inflate(anyInt(), any(ViewGroup::class.java), anyBoolean())) .thenReturn(inflatedUserDetailItemView) - adapter = KeyguardUserSwitcher.KeyguardUserAdapter(mContext, userSwitcherController, - keyguardUserSwitcher) + adapter = KeyguardUserSwitcherController.KeyguardUserAdapter( + mContext, + mContext.resources, + LayoutInflater.from(mContext), + userSwitcherController, keyguardUserSwitcherController) picture = UserIcons.convertToBitmap(mContext.getDrawable(R.drawable.ic_avatar_user)) } @@ -118,11 +121,11 @@ class KeyguardUserSwitcherAdapterTest : SysuiTestCase() { } @Test - fun shouldRemoveOnClickListener_currentUser_notGuestUser_oldViewIsSameType() { + fun shouldSetOnOnClickListener_currentUser_notGuestUser_oldViewIsSameType() { val v: UserDetailItemView? = createViewFromSameType( isCurrentUser = true, isGuestUser = false) assertNotNull(v) - verify(v)!!.setOnClickListener(null) + verify(v)!!.setOnClickListener(adapter) } @Test @@ -150,11 +153,11 @@ class KeyguardUserSwitcherAdapterTest : SysuiTestCase() { } @Test - fun shouldRemoveOnClickListener_currentUser_notGuestUser_oldViewIsDifferentType() { + fun shouldSetOnOnClickListener_currentUser_notGuestUser_oldViewIsDifferentType() { val v: UserDetailItemView? = createViewFromDifferentType( isCurrentUser = true, isGuestUser = false) assertNotNull(v) - verify(v)!!.setOnClickListener(null) + verify(v)!!.setOnClickListener(adapter) } @Test |