diff options
18 files changed, 673 insertions, 76 deletions
diff --git a/packages/SystemUI/plugin/src/com/android/systemui/plugins/qs/DetailAdapter.java b/packages/SystemUI/plugin/src/com/android/systemui/plugins/qs/DetailAdapter.java index d43aaf07c6be..beee03b52579 100644 --- a/packages/SystemUI/plugin/src/com/android/systemui/plugins/qs/DetailAdapter.java +++ b/packages/SystemUI/plugin/src/com/android/systemui/plugins/qs/DetailAdapter.java @@ -46,6 +46,21 @@ public interface DetailAdapter { return true; } + /** + * @return if detail panel should animate when shown or closed + */ + default boolean shouldAnimate() { + return true; + } + + /** + * @return true if the callback handled the event and wants to keep the detail panel open, false + * otherwise. Returning false will close the panel. + */ + default boolean onDoneButtonClicked() { + return false; + } + default UiEventLogger.UiEventEnum openDetailEvent() { return INVALID; } diff --git a/packages/SystemUI/res/layout/keyguard_qs_user_switch.xml b/packages/SystemUI/res/layout/keyguard_qs_user_switch.xml new file mode 100644 index 000000000000..3938b73d08ff --- /dev/null +++ b/packages/SystemUI/res/layout/keyguard_qs_user_switch.xml @@ -0,0 +1,32 @@ +<?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 + --> +<!-- This is a view that shows a user switcher in Keyguard. --> +<com.android.systemui.statusbar.phone.UserAvatarView + xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:systemui="http://schemas.android.com/apk/res-auto" + android:id="@+id/keyguard_qs_user_switch_view" + android:layout_width="@dimen/kg_framed_avatar_size" + android:layout_height="@dimen/kg_framed_avatar_size" + android:layout_centerHorizontal="true" + android:layout_gravity="center_horizontal|bottom" + systemui:avatarPadding="0dp" + systemui:badgeDiameter="18dp" + systemui:badgeMargin="1dp" + systemui:frameColor="@color/kg_user_avatar_frame" + systemui:framePadding="0dp" + systemui:frameWidth="0dp"> +</com.android.systemui.statusbar.phone.UserAvatarView> diff --git a/packages/SystemUI/res/layout/status_bar_expanded.xml b/packages/SystemUI/res/layout/status_bar_expanded.xml index 859d9048cee3..67a933df6692 100644 --- a/packages/SystemUI/res/layout/status_bar_expanded.xml +++ b/packages/SystemUI/res/layout/status_bar_expanded.xml @@ -32,6 +32,12 @@ android:visibility="gone" /> <ViewStub + android:id="@+id/keyguard_qs_user_switch_stub" + android:layout="@layout/keyguard_qs_user_switch" + android:layout_height="match_parent" + android:layout_width="match_parent" /> + + <ViewStub android:id="@+id/keyguard_user_switcher_stub" android:layout="@layout/keyguard_user_switcher" android:layout_height="match_parent" diff --git a/packages/SystemUI/res/values/config.xml b/packages/SystemUI/res/values/config.xml index 61962256f93d..78927f8bf8d4 100644 --- a/packages/SystemUI/res/values/config.xml +++ b/packages/SystemUI/res/values/config.xml @@ -279,6 +279,11 @@ <!-- Whether to show the full screen user switcher. --> <bool name="config_enableFullscreenUserSwitcher">false</bool> + <!-- Whether the multi-user switch on the keyguard opens QS user panel. If false, clicking the + user switch on the keyguard will replace the notifications and status area with the user + switcher. The multi-user switch is only shown if config_keyguardUserSwitcher=false. --> + <bool name="config_keyguard_user_switch_opens_qs_details">false</bool> + <!-- SystemUIFactory component --> <string name="config_systemUIFactoryComponent" translatable="false">com.android.systemui.SystemUIFactory</string> diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml index 594fbdf55d3c..0d92aea6ed6f 100644 --- a/packages/SystemUI/res/values/dimens.xml +++ b/packages/SystemUI/res/values/dimens.xml @@ -802,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">32dp</dimen> + <dimen name="kg_framed_avatar_size">48dp</dimen> <!-- Margin on the left side of the carrier text on Keyguard --> <dimen name="keyguard_carrier_text_margin">16dp</dimen> diff --git a/packages/SystemUI/src/com/android/keyguard/dagger/KeyguardQsUserSwitchComponent.java b/packages/SystemUI/src/com/android/keyguard/dagger/KeyguardQsUserSwitchComponent.java new file mode 100644 index 000000000000..3a0357d2a284 --- /dev/null +++ b/packages/SystemUI/src/com/android/keyguard/dagger/KeyguardQsUserSwitchComponent.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.phone.UserAvatarView; +import com.android.systemui.statusbar.policy.KeyguardQsUserSwitchController; + +import dagger.BindsInstance; +import dagger.Subcomponent; + +/** + * Subcomponent for helping work with KeyguardQsUserSwitch and its children. + */ +@Subcomponent(modules = {KeyguardUserSwitcherModule.class}) +@KeyguardUserSwitcherScope +public interface KeyguardQsUserSwitchComponent { + /** Simple factory for {@link KeyguardUserSwitcherComponent}. */ + @Subcomponent.Factory + interface Factory { + KeyguardQsUserSwitchComponent build( + @BindsInstance UserAvatarView userAvatarView); + } + + /** Builds a {@link KeyguardQsUserSwitchController}. */ + KeyguardQsUserSwitchController getKeyguardQsUserSwitchController(); +} 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 9e5b225fbefc..de2e7c476e18 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/dagger/KeyguardModule.java +++ b/packages/SystemUI/src/com/android/systemui/keyguard/dagger/KeyguardModule.java @@ -29,6 +29,7 @@ import com.android.internal.widget.LockPatternUtils; import com.android.keyguard.KeyguardDisplayManager; import com.android.keyguard.KeyguardUpdateMonitor; import com.android.keyguard.KeyguardViewController; +import com.android.keyguard.dagger.KeyguardQsUserSwitchComponent; import com.android.keyguard.dagger.KeyguardStatusViewComponent; import com.android.keyguard.dagger.KeyguardUserSwitcherComponent; import com.android.systemui.broadcast.BroadcastDispatcher; @@ -62,7 +63,8 @@ import dagger.Provides; /** * Dagger Module providing {@link StatusBar}. */ -@Module(subcomponents = {KeyguardStatusViewComponent.class, KeyguardUserSwitcherComponent.class}, +@Module(subcomponents = {KeyguardStatusViewComponent.class, + KeyguardQsUserSwitchComponent.class, KeyguardUserSwitcherComponent.class}, includes = {FalsingModule.class}) public class KeyguardModule { /** diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSDetail.java b/packages/SystemUI/src/com/android/systemui/qs/QSDetail.java index 619729e55314..9967936ac1bd 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/QSDetail.java +++ b/packages/SystemUI/src/com/android/systemui/qs/QSDetail.java @@ -72,6 +72,7 @@ public class QSDetail extends LinearLayout { private boolean mFullyExpanded; private QuickStatusBarHeader mHeader; private boolean mTriggeredExpand; + private boolean mShouldAnimate; private int mOpenX; private int mOpenY; private boolean mAnimatingOpen; @@ -108,16 +109,6 @@ public class QSDetail extends LinearLayout { updateDetailText(); mClipper = new QSDetailClipper(this); - - final OnClickListener doneListener = new OnClickListener() { - @Override - public void onClick(View v) { - announceForAccessibility( - mContext.getString(R.string.accessibility_desc_quick_settings)); - mQsPanelController.closeDetail(); - } - }; - mDetailDoneButton.setOnClickListener(doneListener); } /** */ @@ -169,6 +160,7 @@ public class QSDetail extends LinearLayout { public void handleShowingDetail(final DetailAdapter adapter, int x, int y, boolean toggleQs) { final boolean showingDetail = adapter != null; + final boolean wasShowingDetail = mDetailAdapter != null; setClickable(showingDetail); if (showingDetail) { setupDetailHeader(adapter); @@ -178,6 +170,7 @@ public class QSDetail extends LinearLayout { } else { mTriggeredExpand = false; } + mShouldAnimate = adapter.shouldAnimate(); mOpenX = x; mOpenY = y; } else { @@ -190,10 +183,10 @@ public class QSDetail extends LinearLayout { } } - boolean visibleDiff = (mDetailAdapter != null) != (adapter != null); - if (!visibleDiff && mDetailAdapter == adapter) return; // already in right state - AnimatorListener listener = null; - if (adapter != null) { + boolean visibleDiff = wasShowingDetail != showingDetail; + if (!visibleDiff && !wasShowingDetail) return; // already in right state + AnimatorListener listener; + if (showingDetail) { int viewCacheIndex = adapter.getMetricsCategory(); View detailView = adapter.createDetailView(mContext, mDetailViews.get(viewCacheIndex), mDetailContent); @@ -213,7 +206,7 @@ public class QSDetail extends LinearLayout { listener = mHideGridContentWhenDone; setVisibility(View.VISIBLE); } else { - if (mDetailAdapter != null) { + if (wasShowingDetail) { Dependency.get(MetricsLogger.class).hidden(mDetailAdapter.getMetricsCategory()); mUiEventLogger.log(mDetailAdapter.closeDetailEvent()); } @@ -227,7 +220,15 @@ public class QSDetail extends LinearLayout { } sendAccessibilityEvent(AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED); - animateDetailVisibleDiff(x, y, visibleDiff, listener); + if (mShouldAnimate) { + animateDetailVisibleDiff(x, y, visibleDiff, listener); + } else { + if (showingDetail) { + showImmediately(); + } else { + hideImmediately(); + } + } } protected void animateDetailVisibleDiff(int x, int y, boolean visibleDiff, AnimatorListener listener) { @@ -245,6 +246,17 @@ public class QSDetail extends LinearLayout { } } + void showImmediately() { + setVisibility(VISIBLE); + mClipper.cancelAnimator(); + mClipper.showBackground(); + } + + public void hideImmediately() { + mClipper.cancelAnimator(); + setVisibility(View.GONE); + } + protected void setupDetailFooter(DetailAdapter adapter) { final Intent settingsIntent = adapter.getSettingsIntent(); mDetailSettingsButton.setVisibility(settingsIntent != null ? VISIBLE : GONE); @@ -255,6 +267,13 @@ public class QSDetail extends LinearLayout { Dependency.get(ActivityStarter.class) .postStartActivityDismissingKeyguard(settingsIntent, 0); }); + mDetailDoneButton.setOnClickListener(v -> { + announceForAccessibility( + mContext.getString(R.string.accessibility_desc_quick_settings)); + if (!adapter.onDoneButtonClicked()) { + mQsPanelController.closeDetail(); + } + }); } protected void setupDetailHeader(final DetailAdapter adapter) { diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSDetailDisplayer.java b/packages/SystemUI/src/com/android/systemui/qs/QSDetailDisplayer.java index 7d87e174d95d..b50af004aff9 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/QSDetailDisplayer.java +++ b/packages/SystemUI/src/com/android/systemui/qs/QSDetailDisplayer.java @@ -39,7 +39,7 @@ public class QSDetailDisplayer { /** Show the supplied DetailAdapter in the Quick Settings. */ public void showDetailAdapter(DetailAdapter detailAdapter, int x, int y) { if (mQsPanelController != null) { - mQsPanelController.showDetailDapater(detailAdapter, x, y); + mQsPanelController.showDetailAdapter(detailAdapter, x, y); } } } diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSPanelController.java b/packages/SystemUI/src/com/android/systemui/qs/QSPanelController.java index 782092161418..fcb35e2040ea 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/QSPanelController.java +++ b/packages/SystemUI/src/com/android/systemui/qs/QSPanelController.java @@ -311,7 +311,7 @@ public class QSPanelController extends QSPanelControllerBase<QSPanel> { } /** */ - public void showDetailDapater(DetailAdapter detailAdapter, int x, int y) { + public void showDetailAdapter(DetailAdapter detailAdapter, int x, int y) { mView.showDetailAdapter(true, detailAdapter, new int[]{x, y}); } diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/UserTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/UserTile.java index 26adfdcd8539..a6cddd3367d3 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/tiles/UserTile.java +++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/UserTile.java @@ -82,7 +82,7 @@ public class UserTile extends QSTileImpl<State> implements UserInfoController.On @Override public DetailAdapter getDetailAdapter() { - return mUserSwitcherController.userDetailAdapter; + return mUserSwitcherController.mUserDetailAdapter; } @Override 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 e0df4f8bfea9..a6daed5a0850 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardClockPositionAlgorithm.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardClockPositionAlgorithm.java @@ -56,10 +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. + * Height of user avatar used by the multi-user switcher. This could either be the + * {@link KeyguardUserSwitcherListView} when it is closed and only the current user's icon is + * visible, or it could be height of the avatar used by the + * {@link com.android.systemui.statusbar.policy.KeyguardQsUserSwitchController}. */ - private int mKeyguardUserSwitcherHeight; + private int mUserSwitchHeight; /** * Preferred Y position of clock. @@ -67,6 +69,11 @@ public class KeyguardClockPositionAlgorithm { private int mClockPreferredY; /** + * Preferred Y position of user avatar used by the multi-user switcher. + */ + private int mUserSwitchPreferredY; + + /** * Whether or not there is a custom clock face on keyguard. */ private boolean mHasCustomClock; @@ -181,20 +188,21 @@ public class KeyguardClockPositionAlgorithm { */ public void setup(int statusBarMinHeight, int maxShadeBottom, int notificationStackHeight, 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) { + int userSwitchHeight, int clockPreferredY, int userSwitchPreferredY, + boolean hasCustomClock, boolean hasVisibleNotifs, float dark, float emptyDragAmount, + boolean bypassEnabled, int unlockedStackScrollerPadding, boolean showLockIcon, + float qsExpansion, int cutoutTopInset) { mMinTopMargin = statusBarMinHeight + (showLockIcon ? mContainerTopPaddingWithLockIcon : mContainerTopPaddingWithoutLockIcon) - + keyguardUserSwitcherHeight; + + userSwitchHeight; mMaxShadeBottom = maxShadeBottom; mNotificationStackHeight = notificationStackHeight; mPanelExpansion = panelExpansion; mHeight = parentHeight; mKeyguardStatusHeight = keyguardStatusHeight; - mKeyguardUserSwitcherHeight = keyguardUserSwitcherHeight; + mUserSwitchHeight = userSwitchHeight; mClockPreferredY = clockPreferredY; + mUserSwitchPreferredY = userSwitchPreferredY; mHasCustomClock = hasCustomClock; mHasVisibleNotifs = hasVisibleNotifs; mDarkAmount = dark; @@ -208,6 +216,7 @@ public class KeyguardClockPositionAlgorithm { public void run(Result result) { final int y = getClockY(mPanelExpansion, mDarkAmount); result.clockY = y; + result.userSwitchY = getUserSwitcherY(mPanelExpansion); result.clockYFullyDozing = getClockY( 1.0f /* panelExpansion */, 1.0f /* darkAmount */); result.clockAlpha = getClockAlpha(y); @@ -241,7 +250,7 @@ public class KeyguardClockPositionAlgorithm { private int getExpandedPreferredClockY() { if (mLockScreenMode != KeyguardUpdateMonitor.LOCK_SCREEN_MODE_NORMAL) { - return mMinTopMargin; + return mMinTopMargin + mUserSwitchHeight; } return (mHasCustomClock && (!mHasVisibleNotifs || mBypassEnabled)) ? getPreferredClockY() : getExpandedClockPosition(); @@ -257,7 +266,7 @@ public class KeyguardClockPositionAlgorithm { final int containerCenter = mMinTopMargin + availableHeight / 2; float y = containerCenter - - (mKeyguardStatusHeight + mKeyguardUserSwitcherHeight) * CLOCK_HEIGHT_WEIGHT + - (mKeyguardStatusHeight + mUserSwitchHeight) * CLOCK_HEIGHT_WEIGHT - mClockNotificationsMargin - mNotificationStackHeight / 2; if (y < mMinTopMargin) { y = mMinTopMargin; @@ -299,6 +308,17 @@ public class KeyguardClockPositionAlgorithm { return (int) (MathUtils.lerp(clockY, clockYDark, darkAmount) + mEmptyDragAmount); } + private int getUserSwitcherY(float panelExpansion) { + float userSwitchYRegular = mUserSwitchPreferredY; + float userSwitchYBouncer = -mKeyguardStatusHeight - mUserSwitchHeight; + + // Move user-switch up while collapsing the shade + float shadeExpansion = Interpolators.FAST_OUT_LINEAR_IN.getInterpolation(panelExpansion); + float userSwitchY = MathUtils.lerp(userSwitchYBouncer, userSwitchYRegular, shadeExpansion); + + return (int) (userSwitchY + mEmptyDragAmount); + } + /** * We might want to fade out the clock when the user is swiping up. * One exception is when the bouncer will become visible, in this cause the clock @@ -341,6 +361,11 @@ public class KeyguardClockPositionAlgorithm { public int clockY; /** + * The y translation of the multi-user switch. + */ + public int userSwitchY; + + /** * The y translation of the clock when we're fully dozing. */ public int clockYFullyDozing; 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 d9cb9ce21330..16f36b7b6b7e 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/MultiUserSwitch.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/MultiUserSwitch.java @@ -168,6 +168,6 @@ public class MultiUserSwitch extends FrameLayout implements View.OnClickListener } protected DetailAdapter getUserDetailAdapter() { - return mUserSwitcherController.userDetailAdapter; + return mUserSwitcherController.mUserDetailAdapter; } } 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 3b09eda4003e..738ac4d18c62 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelViewController.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelViewController.java @@ -77,6 +77,7 @@ import com.android.keyguard.KeyguardStatusView; import com.android.keyguard.KeyguardStatusViewController; import com.android.keyguard.KeyguardUpdateMonitor; import com.android.keyguard.KeyguardUpdateMonitorCallback; +import com.android.keyguard.dagger.KeyguardQsUserSwitchComponent; import com.android.keyguard.dagger.KeyguardStatusViewComponent; import com.android.keyguard.dagger.KeyguardUserSwitcherComponent; import com.android.systemui.DejankUtils; @@ -95,9 +96,11 @@ import com.android.systemui.fragments.FragmentHostManager.FragmentListener; import com.android.systemui.media.MediaDataManager; import com.android.systemui.media.MediaHierarchyManager; import com.android.systemui.plugins.FalsingManager; +import com.android.systemui.plugins.qs.DetailAdapter; 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; @@ -133,6 +136,7 @@ import com.android.systemui.statusbar.notification.stack.StackStateAnimator; import com.android.systemui.statusbar.phone.LockscreenGestureLogger.LockscreenUiEvent; import com.android.systemui.statusbar.phone.dagger.StatusBarComponent; import com.android.systemui.statusbar.policy.ConfigurationController; +import com.android.systemui.statusbar.policy.KeyguardQsUserSwitchController; import com.android.systemui.statusbar.policy.KeyguardStateController; import com.android.systemui.statusbar.policy.KeyguardUserSwitcherController; import com.android.systemui.statusbar.policy.KeyguardUserSwitcherView; @@ -292,14 +296,13 @@ public class NotificationPanelViewController extends PanelViewController { new KeyguardUserSwitcherController.KeyguardUserSwitcherListener() { @Override public void onKeyguardUserSwitcherChanged(boolean open) { - if (mKeyguardUserSwitcherController != null - && mKeyguardUserSwitcherController.isSimpleUserSwitcher()) { - return; + if (mKeyguardUserSwitcherController == null) { + updateUserSwitcherVisibility(false); + } else if (!mKeyguardUserSwitcherController.isSimpleUserSwitcher()) { + updateUserSwitcherVisibility(open + && mKeyguardStateController.isShowing() + && !mKeyguardStateController.isKeyguardFadingAway()); } - - updateUserSwitcherVisibility(open - && mKeyguardStateController.isShowing() - && !mKeyguardStateController.isKeyguardFadingAway()); } }; @@ -315,7 +318,9 @@ public class NotificationPanelViewController extends PanelViewController { private final MediaHierarchyManager mMediaHierarchyManager; private final StatusBarKeyguardViewManager mStatusBarKeyguardViewManager; private final KeyguardStatusViewComponent.Factory mKeyguardStatusViewComponentFactory; + private final KeyguardQsUserSwitchComponent.Factory mKeyguardQsUserSwitchComponentFactory; private final KeyguardUserSwitcherComponent.Factory mKeyguardUserSwitcherComponentFactory; + private final QSDetailDisplayer mQSDetailDisplayer; private final FeatureFlags mFeatureFlags; private final ScrimController mScrimController; private final ControlsComponent mControlsComponent; @@ -327,6 +332,8 @@ public class NotificationPanelViewController extends PanelViewController { private int mMaxAllowedKeyguardNotifications; private KeyguardAffordanceHelper mAffordanceHelper; + private KeyguardQsUserSwitchController mKeyguardQsUserSwitchController; + private boolean mKeyguardUserSwitcherIsShowing; private KeyguardUserSwitcherController mKeyguardUserSwitcherController; private KeyguardStatusBarView mKeyguardStatusBar; private ViewGroup mBigClockContainer; @@ -352,6 +359,7 @@ public class NotificationPanelViewController extends PanelViewController { private boolean mQsExpandedWhenExpandingStarted; private boolean mQsFullyExpanded; private boolean mKeyguardShowing; + private boolean mKeyguardQsUserSwitchEnabled; private boolean mKeyguardUserSwitcherEnabled; private boolean mDozing; private boolean mDozingOnDown; @@ -578,7 +586,9 @@ public class NotificationPanelViewController extends PanelViewController { StatusBarKeyguardViewManager statusBarKeyguardViewManager, NotificationStackScrollLayoutController notificationStackScrollLayoutController, KeyguardStatusViewComponent.Factory keyguardStatusViewComponentFactory, + KeyguardQsUserSwitchComponent.Factory keyguardQsUserSwitchComponentFactory, KeyguardUserSwitcherComponent.Factory keyguardUserSwitcherComponentFactory, + QSDetailDisplayer qsDetailDisplayer, NotificationGroupManagerLegacy groupManager, NotificationIconAreaController notificationIconAreaController, AuthController authController, @@ -605,9 +615,14 @@ public class NotificationPanelViewController extends PanelViewController { mNotificationIconAreaController = notificationIconAreaController; mKeyguardStatusViewComponentFactory = keyguardStatusViewComponentFactory; mFeatureFlags = featureFlags; + mKeyguardQsUserSwitchComponentFactory = keyguardQsUserSwitchComponentFactory; mKeyguardUserSwitcherComponentFactory = keyguardUserSwitcherComponentFactory; + mQSDetailDisplayer = qsDetailDisplayer; mKeyguardUserSwitcherEnabled = mResources.getBoolean( com.android.internal.R.bool.config_keyguardUserSwitcher); + mKeyguardQsUserSwitchEnabled = + mKeyguardUserSwitcherEnabled && mResources.getBoolean( + R.bool.config_keyguard_user_switch_opens_qs_details); mView.setWillNotDraw(!DEBUG); mLayoutInflater = layoutInflater; mFalsingManager = falsingManager; @@ -688,15 +703,21 @@ public class NotificationPanelViewController extends PanelViewController { mKeyguardStatusBar = mView.findViewById(R.id.keyguard_header); mBigClockContainer = mView.findViewById(R.id.big_clock_container); + UserAvatarView userAvatarView = null; KeyguardUserSwitcherView keyguardUserSwitcherView = null; if (mKeyguardUserSwitcherEnabled && mUserManager.isUserSwitcherEnabled()) { - ViewStub userSwitcherStub = mView.findViewById(R.id.keyguard_user_switcher_stub); - keyguardUserSwitcherView = (KeyguardUserSwitcherView) userSwitcherStub.inflate(); + if (mKeyguardQsUserSwitchEnabled) { + ViewStub stub = mView.findViewById(R.id.keyguard_qs_user_switch_stub); + userAvatarView = (UserAvatarView) stub.inflate(); + } else { + ViewStub stub = mView.findViewById(R.id.keyguard_user_switcher_stub); + keyguardUserSwitcherView = (KeyguardUserSwitcherView) stub.inflate(); + } } updateViewControllers(mView.findViewById(R.id.keyguard_status_view), - keyguardUserSwitcherView); + userAvatarView, keyguardUserSwitcherView); mNotificationContainerParent = mView.findViewById(R.id.notification_container_parent); NotificationStackScrollLayout stackScrollLayout = mView.findViewById( R.id.notification_stack_scroller); @@ -770,7 +791,7 @@ public class NotificationPanelViewController extends PanelViewController { } private void updateViewControllers(KeyguardStatusView keyguardStatusView, - KeyguardUserSwitcherView keyguardUserSwitcherView) { + UserAvatarView userAvatarView, KeyguardUserSwitcherView keyguardUserSwitcherView) { // Re-associate the KeyguardStatusViewController KeyguardStatusViewComponent statusViewComponent = mKeyguardStatusViewComponentFactory.build(keyguardStatusView); @@ -789,18 +810,27 @@ public class NotificationPanelViewController extends PanelViewController { mKeyguardUserSwitcherController.removeCallback(); } + mKeyguardQsUserSwitchController = null; + mKeyguardUserSwitcherController = null; + // Re-associate the KeyguardUserSwitcherController - if (keyguardUserSwitcherView != null) { + if (userAvatarView != null) { + KeyguardQsUserSwitchComponent userSwitcherComponent = + mKeyguardQsUserSwitchComponentFactory.build(userAvatarView); + mKeyguardQsUserSwitchController = + userSwitcherComponent.getKeyguardQsUserSwitchController(); + mKeyguardQsUserSwitchController.setNotificationPanelViewController(this); + mKeyguardQsUserSwitchController.init(); + mKeyguardStatusBar.setKeyguardUserSwitcherEnabled(true); + } else 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); } } @@ -856,6 +886,25 @@ public class NotificationPanelViewController extends PanelViewController { } } + private View reInflateStub(int viewId, int stubId, int layoutId, boolean enabled) { + View view = mView.findViewById(viewId); + if (view != null) { + int index = mView.indexOfChild(view); + mView.removeView(view); + if (enabled) { + view = mLayoutInflater.inflate(layoutId, mView, false); + mView.addView(view, index); + } else { + view = null; + } + } else if (enabled) { + // It's possible the stub was never inflated if the configuration changed + ViewStub stub = mView.findViewById(stubId); + view = stub.inflate(); + } + return view; + } + private void reInflateViews() { if (DEBUG) Log.d(TAG, "reInflateViews"); // Re-inflate the status view group. @@ -867,26 +916,26 @@ public class NotificationPanelViewController extends PanelViewController { 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(); - } + boolean isUserSwitcherEnabled = mUserManager.isUserSwitcherEnabled(); + boolean showQsUserSwitch = mKeyguardQsUserSwitchEnabled && isUserSwitcherEnabled; + boolean showKeyguardUserSwitcher = + !mKeyguardQsUserSwitchEnabled + && mKeyguardUserSwitcherEnabled + && isUserSwitcherEnabled; + UserAvatarView userAvatarView = (UserAvatarView) reInflateStub( + R.id.keyguard_qs_user_switch_view /* viewId */, + R.id.keyguard_qs_user_switch_stub /* stubId */, + R.layout.keyguard_qs_user_switch /* layoutId */, + showQsUserSwitch /* enabled */); + KeyguardUserSwitcherView keyguardUserSwitcherView = + (KeyguardUserSwitcherView) reInflateStub( + R.id.keyguard_user_switcher_view /* viewId */, + R.id.keyguard_user_switcher_stub /* stubId */, + R.layout.keyguard_user_switcher /* layoutId */, + showKeyguardUserSwitcher /* enabled */); mBigClockContainer.removeAllViews(); - updateViewControllers(keyguardStatusView, keyguardUserSwitcherView); + updateViewControllers(keyguardStatusView, userAvatarView, keyguardUserSwitcherView); // Update keyguard bottom area index = mView.indexOfChild(mKeyguardBottomArea); @@ -910,6 +959,13 @@ public class NotificationPanelViewController extends PanelViewController { false, false, mBarState); + if (mKeyguardQsUserSwitchController != null) { + mKeyguardQsUserSwitchController.setKeyguardQsUserSwitchVisibility( + mBarState, + false, + false, + mBarState); + } if (mKeyguardUserSwitcherController != null) { mKeyguardUserSwitcherController.setKeyguardUserSwitcherVisibility( mBarState, @@ -1009,10 +1065,15 @@ public class NotificationPanelViewController extends PanelViewController { int totalHeight = mView.getHeight(); int bottomPadding = Math.max(mIndicationBottomPadding, mAmbientIndicationBottomPadding); int clockPreferredY = mKeyguardStatusViewController.getClockPreferredY(totalHeight); + int userSwitcherPreferredY = mStatusBarMinHeight; boolean bypassEnabled = mKeyguardBypassController.getBypassEnabled(); final boolean hasVisibleNotifications = mNotificationStackScrollLayoutController .getVisibleNotificationCount() != 0 || mMediaDataManager.hasActiveMedia(); mKeyguardStatusViewController.setHasVisibleNotifications(hasVisibleNotifications); + int userIconHeight = mKeyguardQsUserSwitchController != null + ? mKeyguardQsUserSwitchController.getUserIconHeight() + : (mKeyguardUserSwitcherController != null + ? mKeyguardUserSwitcherController.getUserIconHeight() : 0); mClockPositionAlgorithm.setup(mStatusBarMinHeight, totalHeight - bottomPadding, mNotificationStackScrollLayoutController.getIntrinsicContentHeight(), getExpandedFraction(), @@ -1021,9 +1082,8 @@ public class NotificationPanelViewController extends PanelViewController { ? mKeyguardStatusViewController.getHeight() : (int) (mKeyguardStatusViewController.getHeight() - mShelfHeight / 2.0f - mDarkIconSize / 2.0f), - mKeyguardUserSwitcherController == null - ? 0 : mKeyguardUserSwitcherController.getUserIconHeight(), - clockPreferredY, hasCustomClock(), + userIconHeight, + clockPreferredY, userSwitcherPreferredY, hasCustomClock(), hasVisibleNotifications, mInterpolatedDarkAmount, mEmptyDragAmount, bypassEnabled, getUnlockedStackScrollerPadding(), mUpdateMonitor.canShowLockIcon(), @@ -1033,11 +1093,16 @@ public class NotificationPanelViewController extends PanelViewController { mKeyguardStatusViewController.updatePosition( mClockPositionResult.clockX, mClockPositionResult.clockY, mClockPositionResult.clockScale, animateClock); + if (mKeyguardQsUserSwitchController != null) { + mKeyguardQsUserSwitchController.updatePosition( + mClockPositionResult.clockX, + mClockPositionResult.userSwitchY, + animateClock); + } if (mKeyguardUserSwitcherController != null) { mKeyguardUserSwitcherController.updatePosition( mClockPositionResult.clockX, - mClockPositionResult.clockY - - mKeyguardUserSwitcherController.getUserIconHeight(), + mClockPositionResult.userSwitchY, animateClock); } updateNotificationTranslucency(); @@ -1180,6 +1245,9 @@ public class NotificationPanelViewController extends PanelViewController { private void updateClock() { mKeyguardStatusViewController.setAlpha(mClockPositionResult.clockAlpha); + if (mKeyguardQsUserSwitchController != null) { + mKeyguardQsUserSwitchController.setAlpha(mClockPositionResult.clockAlpha); + } if (mKeyguardUserSwitcherController != null) { mKeyguardUserSwitcherController.setAlpha(mClockPositionResult.clockAlpha); } @@ -1271,6 +1339,12 @@ public class NotificationPanelViewController extends PanelViewController { } } + public void expandWithQsDetail(DetailAdapter qsDetailAdapter) { + traceQsJank(true /* startTracing */, false /* wasCancelled */); + flingSettings(0 /* velocity */, FLING_EXPAND); + mQSDetailDisplayer.showDetailAdapter(qsDetailAdapter, 0, 0); + } + public void expandWithoutQs() { if (isQsExpanded()) { flingSettings(0 /* velocity */, FLING_COLLAPSE); @@ -3166,6 +3240,13 @@ public class NotificationPanelViewController extends PanelViewController { true /* keyguardFadingAway */, false /* goingToFullShade */, mBarState); + if (mKeyguardQsUserSwitchController != null) { + mKeyguardQsUserSwitchController.setKeyguardQsUserSwitchVisibility( + mBarState, + true /* keyguardFadingAway */, + false /* goingToFullShade */, + mBarState); + } if (mKeyguardUserSwitcherController != null) { mKeyguardUserSwitcherController.setKeyguardUserSwitcherVisibility( mBarState, @@ -3432,6 +3513,12 @@ public class NotificationPanelViewController extends PanelViewController { } private void updateUserSwitcherVisibility(boolean open) { + // Do not update if previously called with the same state. + if (mKeyguardUserSwitcherIsShowing == open) { + return; + } + mKeyguardUserSwitcherIsShowing = open; + if (open) { animateKeyguardStatusBarOut(); mKeyguardStatusViewController.setKeyguardStatusViewVisibility( diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardQsUserSwitchController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardQsUserSwitchController.java new file mode 100644 index 000000000000..38f3bc891394 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardQsUserSwitchController.java @@ -0,0 +1,345 @@ +/* + * 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.content.res.Resources; +import android.database.DataSetObserver; +import android.graphics.drawable.Drawable; +import android.graphics.drawable.LayerDrawable; +import android.os.UserManager; +import android.text.TextUtils; +import android.util.Log; +import android.view.View; +import android.view.ViewGroup; + +import com.android.internal.logging.UiEventLogger; +import com.android.keyguard.KeyguardConstants; +import com.android.keyguard.KeyguardVisibilityHelper; +import com.android.keyguard.dagger.KeyguardUserSwitcherScope; +import com.android.settingslib.drawable.CircleFramedDrawable; +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.statusbar.phone.NotificationPanelViewController; +import com.android.systemui.statusbar.phone.UserAvatarView; +import com.android.systemui.util.ViewController; + +import javax.inject.Inject; + +/** + * Manages the user switch on the Keyguard that is used for opening the QS user panel. + */ +@KeyguardUserSwitcherScope +public class KeyguardQsUserSwitchController extends ViewController<UserAvatarView> { + + private static final String TAG = "KeyguardQsUserSwitchController"; + 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 Resources mResources; + private final UserSwitcherController mUserSwitcherController; + private final ScreenLifecycle mScreenLifecycle; + private UserSwitcherController.BaseUserAdapter mAdapter; + private final KeyguardStateController mKeyguardStateController; + protected final SysuiStatusBarStateController mStatusBarStateController; + private final KeyguardVisibilityHelper mKeyguardVisibilityHelper; + private final KeyguardUserDetailAdapter mUserDetailAdapter; + private NotificationPanelViewController mNotificationPanelViewController; + private UserManager mUserManager; + UserSwitcherController.UserRecord mCurrentUser; + + // State info for the user switch and keyguard + private int mBarState; + private float mDarkAmount; + + 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; + + setKeyguardQsUserSwitchVisibility( + 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 KeyguardQsUserSwitchController( + UserAvatarView view, + Context context, + @Main Resources resources, + UserManager userManager, + ScreenLifecycle screenLifecycle, + UserSwitcherController userSwitcherController, + KeyguardStateController keyguardStateController, + SysuiStatusBarStateController statusBarStateController, + DozeParameters dozeParameters, + UiEventLogger uiEventLogger) { + super(view); + if (DEBUG) Log.d(TAG, "New KeyguardQsUserSwitchController"); + mContext = context; + mResources = resources; + mUserManager = userManager; + mScreenLifecycle = screenLifecycle; + mUserSwitcherController = userSwitcherController; + mKeyguardStateController = keyguardStateController; + mStatusBarStateController = statusBarStateController; + mKeyguardVisibilityHelper = new KeyguardVisibilityHelper(mView, + keyguardStateController, dozeParameters); + mUserDetailAdapter = new KeyguardUserDetailAdapter(mUserSwitcherController, mContext, + uiEventLogger); + } + + @Override + protected void onInit() { + super.onInit(); + if (DEBUG) Log.d(TAG, "onInit"); + mAdapter = new UserSwitcherController.BaseUserAdapter(mUserSwitcherController) { + @Override + public View getView(int position, View convertView, ViewGroup parent) { + return null; + } + }; + + mView.setOnClickListener(v -> { + if (isListAnimating()) { + return; + } + + // Tapping anywhere in the view will open QS user panel + openQsUserPanel(); + }); + + updateView(true /* forceUpdate */); + } + + @Override + protected void onViewAttached() { + if (DEBUG) Log.d(TAG, "onViewAttached"); + mAdapter.registerDataSetObserver(mDataSetObserver); + mDataSetObserver.onChanged(); + mStatusBarStateController.addCallback(mStatusBarStateListener); + } + + @Override + protected void onViewDetached() { + if (DEBUG) Log.d(TAG, "onViewDetached"); + + mAdapter.unregisterDataSetObserver(mDataSetObserver); + mStatusBarStateController.removeCallback(mStatusBarStateListener); + } + + public final DataSetObserver mDataSetObserver = new DataSetObserver() { + @Override + public void onChanged() { + updateView(false /* forceUpdate */); + } + }; + + /** + * @return true if the current user has changed + */ + private boolean updateCurrentUser() { + UserSwitcherController.UserRecord previousUser = mCurrentUser; + mCurrentUser = null; + for (int i = 0; i < mAdapter.getCount(); i++) { + UserSwitcherController.UserRecord r = mAdapter.getItem(i); + if (r.isCurrent) { + mCurrentUser = r; + return !mCurrentUser.equals(previousUser); + } + } + return mCurrentUser == null && previousUser != null; + } + + /** + * @param forceUpdate whether to update view even if current user did not change + */ + private void updateView(boolean forceUpdate) { + if (!updateCurrentUser() && !forceUpdate) { + return; + } + + if (mCurrentUser == null) { + mView.setVisibility(View.GONE); + return; + } + + mView.setVisibility(View.VISIBLE); + + String currentUserName = mCurrentUser.info.name; + String contentDescription = null; + + if (!TextUtils.isEmpty(currentUserName)) { + contentDescription = mContext.getString( + R.string.accessibility_quick_settings_user, + currentUserName); + } + + if (!TextUtils.equals(mView.getContentDescription(), contentDescription)) { + mView.setContentDescription(contentDescription); + } + + if (mCurrentUser.picture == null) { + mView.setDrawableWithBadge(getDrawable(mCurrentUser).mutate(), + mCurrentUser.resolveId()); + } else { + int avatarSize = + (int) mResources.getDimension(R.dimen.kg_framed_avatar_size); + Drawable drawable = new CircleFramedDrawable(mCurrentUser.picture, avatarSize); + drawable.setColorFilter( + mCurrentUser.isSwitchToEnabled ? null + : mAdapter.getDisabledUserAvatarColorFilter()); + mView.setDrawableWithBadge(drawable, mCurrentUser.info.id); + } + } + + Drawable getDrawable(UserSwitcherController.UserRecord item) { + Drawable drawable; + if (item.isCurrent && item.isGuest) { + drawable = mContext.getDrawable(R.drawable.ic_avatar_guest_user); + } else { + drawable = mAdapter.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; + } + + /** + * Get the height of the keyguard user switcher view when closed. + */ + public int getUserIconHeight() { + return mView.getHeight(); + } + + /** + * Set the visibility of the user avatar view based on some new state. + */ + public void setKeyguardQsUserSwitchVisibility( + 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(mView, AnimatableProperty.Y, y, ANIMATION_PROPERTIES, animate); + PropertyAnimator.setProperty(mView, AnimatableProperty.TRANSLATION_X, -Math.abs(x), + ANIMATION_PROPERTIES, animate); + } + + /** + * Set keyguard user avatar 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; + mView.setVisibility(isAwake ? View.VISIBLE : View.GONE); + } + + private boolean isListAnimating() { + return mKeyguardVisibilityHelper.isVisibilityAnimating(); + } + + private void openQsUserPanel() { + mNotificationPanelViewController.expandWithQsDetail(mUserDetailAdapter); + } + + public void setNotificationPanelViewController( + NotificationPanelViewController notificationPanelViewController) { + mNotificationPanelViewController = notificationPanelViewController; + } + + class KeyguardUserDetailAdapter extends UserSwitcherController.UserDetailAdapter { + KeyguardUserDetailAdapter(UserSwitcherController userSwitcherController, Context context, + UiEventLogger uiEventLogger) { + super(userSwitcherController, context, uiEventLogger); + } + + @Override + public boolean shouldAnimate() { + return false; + } + + @Override + public boolean onDoneButtonClicked() { + if (mNotificationPanelViewController != null) { + mNotificationPanelViewController.animateCloseQs(true /* animateAway */); + return true; + } else { + return false; + } + } + } +} 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 019ab479e28e..d4029e64036e 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/UserSwitcherController.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/UserSwitcherController.java @@ -121,6 +121,7 @@ public class UserSwitcherController implements Dumpable { private Intent mSecondaryUserServiceIntent; private SparseBooleanArray mForcePictureLoadForUserId = new SparseBooleanArray(2); private final UiEventLogger mUiEventLogger; + public final DetailAdapter mUserDetailAdapter; @Inject public UserSwitcherController(Context context, KeyguardStateController keyguardStateController, @@ -131,6 +132,7 @@ public class UserSwitcherController implements Dumpable { mBroadcastDispatcher = broadcastDispatcher; mActivityTaskManager = activityTaskManager; mUiEventLogger = uiEventLogger; + mUserDetailAdapter = new UserDetailAdapter(this, mContext, mUiEventLogger); if (!UserManager.isGuestUserEphemeral()) { mGuestResumeSessionReceiver.register(mBroadcastDispatcher); } @@ -781,9 +783,20 @@ public class UserSwitcherController implements Dumpable { } } - public final DetailAdapter userDetailAdapter = new DetailAdapter() { + public static class UserDetailAdapter implements DetailAdapter { private final Intent USER_SETTINGS_INTENT = new Intent(Settings.ACTION_USER_SETTINGS); + private final UserSwitcherController mUserSwitcherController; + private final Context mContext; + private final UiEventLogger mUiEventLogger; + + UserDetailAdapter(UserSwitcherController userSwitcherController, Context context, + UiEventLogger uiEventLogger) { + mUserSwitcherController = userSwitcherController; + mContext = context; + mUiEventLogger = uiEventLogger; + } + @Override public CharSequence getTitle() { return mContext.getString(R.string.quick_settings_user_title); @@ -794,7 +807,7 @@ public class UserSwitcherController implements Dumpable { UserDetailView v; if (!(convertView instanceof UserDetailView)) { v = UserDetailView.inflate(context, parent, false); - v.createAndSetAdapter(UserSwitcherController.this, mUiEventLogger); + v.createAndSetAdapter(mUserSwitcherController, mUiEventLogger); } else { v = (UserDetailView) convertView; } 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 4162884680a9..9b623f950505 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 @@ -394,8 +394,8 @@ public class KeyguardClockPositionAlgorithmTest extends SysuiTestCase { private void positionClock() { mClockPositionAlgorithm.setup(EMPTY_MARGIN, SCREEN_HEIGHT, mNotificationStackHeight, mPanelExpansion, SCREEN_HEIGHT, mKeyguardStatusHeight, - 0 /* keyguardUserSwitcherHeight */, mPreferredClockY, mHasCustomClock, - mHasVisibleNotifs, mDark, ZERO_DRAG, false /* bypassEnabled */, + 0 /* userSwitchHeight */, mPreferredClockY, 0 /* userSwitchPreferredY */, + 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 d0e70310810e..3f5a6992fcef 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 @@ -58,6 +58,7 @@ import com.android.keyguard.KeyguardClockSwitchController; import com.android.keyguard.KeyguardStatusView; import com.android.keyguard.KeyguardStatusViewController; import com.android.keyguard.KeyguardUpdateMonitor; +import com.android.keyguard.dagger.KeyguardQsUserSwitchComponent; import com.android.keyguard.dagger.KeyguardStatusViewComponent; import com.android.keyguard.dagger.KeyguardUserSwitcherComponent; import com.android.systemui.R; @@ -70,6 +71,7 @@ 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; @@ -194,7 +196,11 @@ public class NotificationPanelViewTest extends SysuiTestCase { @Mock private KeyguardStatusViewComponent.Factory mKeyguardStatusViewComponentFactory; @Mock - private KeyguardUserSwitcherComponent.Factory mKeyguardUserSwitcherComponent; + private KeyguardQsUserSwitchComponent.Factory mKeyguardQsUserSwitchComponentFactory; + @Mock + private KeyguardUserSwitcherComponent.Factory mKeyguardUserSwitcherComponentFactory; + @Mock + private QSDetailDisplayer mQSDetailDisplayer; @Mock private KeyguardStatusViewComponent mKeyguardStatusViewComponent; @Mock @@ -305,7 +311,9 @@ public class NotificationPanelViewTest extends SysuiTestCase { mBiometricUnlockController, mStatusBarKeyguardViewManager, mNotificationStackScrollLayoutController, mKeyguardStatusViewComponentFactory, - mKeyguardUserSwitcherComponent, + mKeyguardQsUserSwitchComponentFactory, + mKeyguardUserSwitcherComponentFactory, + mQSDetailDisplayer, mGroupManager, mNotificationAreaController, mAuthController, |