diff options
| author | 2021-02-08 18:13:25 -0800 | |
|---|---|---|
| committer | 2021-02-15 13:13:21 -0800 | |
| commit | c93c1dec2ee94fe16f025c90f1cbace948b32ade (patch) | |
| tree | 6055ddf7f66bd7115f3c5903aeb4a5e55d33fe16 | |
| parent | bb62a307c0e0394c3dec85aa016762fbb443c170 (diff) | |
Add keyguard shortcut for opening QS user panel
 - Introduce config_keyguard_user_switch_opens_qs_details. When set to
   true, the user icon that appears when config_keyguardUserSwitcher=true
   will open the "user" QS panel instead of taking over the keyguard
 - Add user icon positioning calculation to
   KeyguardClockPositionAlgorithm
 - Add option to QS DetailAdapter for turning off the circular reveal
   animation
 - Add callback to QS DetailAdapter for when "Done" button is pressed
 - Fix typo: showDetailDapater -> showDetailAdapter
Test: Manual
Bug: 169783558
Change-Id: I50133feaf02ca0990c40aa9d8a046abd95ea9d4e
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, |