summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--packages/SystemUI/plugin/src/com/android/systemui/plugins/qs/DetailAdapter.java15
-rw-r--r--packages/SystemUI/res/layout/keyguard_qs_user_switch.xml32
-rw-r--r--packages/SystemUI/res/layout/status_bar_expanded.xml6
-rw-r--r--packages/SystemUI/res/values/config.xml5
-rw-r--r--packages/SystemUI/res/values/dimens.xml2
-rw-r--r--packages/SystemUI/src/com/android/keyguard/dagger/KeyguardQsUserSwitchComponent.java40
-rw-r--r--packages/SystemUI/src/com/android/systemui/keyguard/dagger/KeyguardModule.java4
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/QSDetail.java51
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/QSDetailDisplayer.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/QSPanelController.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/tiles/UserTile.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardClockPositionAlgorithm.java47
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/MultiUserSwitch.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelViewController.java161
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardQsUserSwitchController.java345
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/policy/UserSwitcherController.java17
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/KeyguardClockPositionAlgorithmTest.java4
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationPanelViewTest.java12
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,