diff options
| author | 2022-02-07 15:27:11 +0000 | |
|---|---|---|
| committer | 2022-02-07 15:27:11 +0000 | |
| commit | a95d48154593b6c8effa0942a4c6b427569c5599 (patch) | |
| tree | a609d174dfcd8ba63644f6af80da525eb2327dba | |
| parent | a04c237023d8595e039607c11e3cade43b0ebbfc (diff) | |
| parent | e4314893008d5cb9fa922e716e1be439ed6f7813 (diff) | |
Merge "Add the user switcher chip to the status bar"
17 files changed, 552 insertions, 9 deletions
diff --git a/packages/SystemUI/res-keyguard/drawable/status_bar_user_chip_bg.xml b/packages/SystemUI/res-keyguard/drawable/status_bar_user_chip_bg.xml new file mode 100644 index 000000000000..989115697d6f --- /dev/null +++ b/packages/SystemUI/res-keyguard/drawable/status_bar_user_chip_bg.xml @@ -0,0 +1,20 @@ +<!-- + ~ Copyright (C) 2022 The Android Open Source Project + ~ + ~ Licensed under the Apache License, Version 2.0 (the "License"); + ~ you may not use this file except in compliance with the License. + ~ You may obtain a copy of the License at + ~ + ~ http://www.apache.org/licenses/LICENSE-2.0 + ~ + ~ Unless required by applicable law or agreed to in writing, software + ~ distributed under the License is distributed on an "AS IS" BASIS, + ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + ~ See the License for the specific language governing permissions and + ~ limitations under the License. + --> + +<shape xmlns:android="http://schemas.android.com/apk/res/android"> + <solid android:color="@android:color/system_neutral1_800" /> + <corners android:radius="@dimen/ongoing_call_chip_corner_radius" /> +</shape> diff --git a/packages/SystemUI/res/layout/keyguard_status_bar.xml b/packages/SystemUI/res/layout/keyguard_status_bar.xml index 850b01717308..e47eed9ea04a 100644 --- a/packages/SystemUI/res/layout/keyguard_status_bar.xml +++ b/packages/SystemUI/res/layout/keyguard_status_bar.xml @@ -30,14 +30,39 @@ android:id="@+id/status_icon_area" android:layout_width="wrap_content" android:layout_height="match_parent" + android:layout_marginStart="@dimen/system_icons_super_container_margin_start" android:paddingTop="@dimen/status_bar_padding_top" android:layout_alignParentEnd="true" android:gravity="center_vertical|end" > + <com.android.systemui.statusbar.phone.userswitcher.StatusBarUserSwitcherContainer + android:id="@+id/user_switcher_container" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:gravity="center" + android:orientation="horizontal" + android:paddingTop="4dp" + android:paddingBottom="4dp" + android:paddingStart="8dp" + android:paddingEnd="8dp" + android:background="@drawable/status_bar_user_chip_bg" + android:visibility="visible" > + <ImageView android:id="@+id/current_user_avatar" + android:layout_width="@dimen/multi_user_avatar_keyguard_size" + android:layout_height="@dimen/multi_user_avatar_keyguard_size" + android:scaleType="centerInside" + android:paddingEnd="4dp" /> + + <TextView android:id="@+id/current_user_name" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:textAppearance="@style/TextAppearance.StatusBar.Clock" + /> + </com.android.systemui.statusbar.phone.userswitcher.StatusBarUserSwitcherContainer> + <FrameLayout android:id="@+id/system_icons_container" android:layout_width="0dp" android:layout_height="match_parent" android:layout_weight="1" - android:layout_marginStart="@dimen/system_icons_super_container_margin_start" android:layout_marginEnd="@dimen/status_bar_padding_end" android:gravity="center_vertical|end"> <include layout="@layout/system_icons" /> diff --git a/packages/SystemUI/res/layout/status_bar.xml b/packages/SystemUI/res/layout/status_bar.xml index 8b244c757649..af9801936207 100644 --- a/packages/SystemUI/res/layout/status_bar.xml +++ b/packages/SystemUI/res/layout/status_bar.xml @@ -119,6 +119,32 @@ android:gravity="center_vertical|end" > + <com.android.systemui.statusbar.phone.userswitcher.StatusBarUserSwitcherContainer + android:id="@+id/user_switcher_container" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:gravity="center" + android:orientation="horizontal" + android:paddingTop="4dp" + android:paddingBottom="4dp" + android:paddingStart="8dp" + android:paddingEnd="8dp" + android:layout_marginEnd="16dp" + android:background="@drawable/status_bar_user_chip_bg" + android:visibility="visible" > + <ImageView android:id="@+id/current_user_avatar" + android:layout_width="@dimen/multi_user_avatar_keyguard_size" + android:layout_height="@dimen/multi_user_avatar_keyguard_size" + android:scaleType="centerInside" + android:paddingEnd="4dp" /> + + <TextView android:id="@+id/current_user_name" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:textAppearance="@style/TextAppearance.StatusBar.Clock" + /> + </com.android.systemui.statusbar.phone.userswitcher.StatusBarUserSwitcherContainer> + <include layout="@layout/system_icons" /> </com.android.keyguard.AlphaOptimizedLinearLayout> </LinearLayout> diff --git a/packages/SystemUI/res/layout/system_icons.xml b/packages/SystemUI/res/layout/system_icons.xml index 6d5c7d40a5f8..4f4bae49b275 100644 --- a/packages/SystemUI/res/layout/system_icons.xml +++ b/packages/SystemUI/res/layout/system_icons.xml @@ -17,7 +17,7 @@ <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:systemui="http://schemas.android.com/apk/res-auto" android:id="@+id/system_icons" - android:layout_width="match_parent" + android:layout_width="wrap_content" android:layout_height="match_parent" android:gravity="center_vertical"> diff --git a/packages/SystemUI/res/values/flags.xml b/packages/SystemUI/res/values/flags.xml index 2a70645e49ec..49dd574af829 100644 --- a/packages/SystemUI/res/values/flags.xml +++ b/packages/SystemUI/res/values/flags.xml @@ -32,4 +32,8 @@ <bool name="flag_smartspace">false</bool> + <!-- Whether the user switcher chip shows in the status bar. When true, the multi user + avatar will no longer show on the lockscreen --> + <bool name="flag_user_switcher_chip">false</bool> + </resources> diff --git a/packages/SystemUI/src/com/android/keyguard/dagger/KeyguardStatusBarViewModule.java b/packages/SystemUI/src/com/android/keyguard/dagger/KeyguardStatusBarViewModule.java index fc14b6a99008..8fc86004c400 100644 --- a/packages/SystemUI/src/com/android/keyguard/dagger/KeyguardStatusBarViewModule.java +++ b/packages/SystemUI/src/com/android/keyguard/dagger/KeyguardStatusBarViewModule.java @@ -20,7 +20,11 @@ import com.android.keyguard.CarrierText; import com.android.systemui.R; import com.android.systemui.battery.BatteryMeterView; import com.android.systemui.statusbar.phone.KeyguardStatusBarView; +import com.android.systemui.statusbar.phone.userswitcher.StatusBarUserSwitcherContainer; +import com.android.systemui.statusbar.phone.userswitcher.StatusBarUserSwitcherController; +import com.android.systemui.statusbar.phone.userswitcher.StatusBarUserSwitcherControllerImpl; +import dagger.Binds; import dagger.Module; import dagger.Provides; @@ -39,4 +43,17 @@ public abstract class KeyguardStatusBarViewModule { static BatteryMeterView getBatteryMeterView(KeyguardStatusBarView view) { return view.findViewById(R.id.battery); } + + /** */ + @Provides + @KeyguardStatusBarViewScope + static StatusBarUserSwitcherContainer getUserSwitcherContainer(KeyguardStatusBarView view) { + return view.findViewById(R.id.user_switcher_container); + } + + /** */ + @Binds + @KeyguardStatusBarViewScope + abstract StatusBarUserSwitcherController bindStatusBarUserSwitcherController( + StatusBarUserSwitcherControllerImpl controller); } diff --git a/packages/SystemUI/src/com/android/systemui/flags/Flags.java b/packages/SystemUI/src/com/android/systemui/flags/Flags.java index e1f8f0718077..12c6e003bb92 100644 --- a/packages/SystemUI/src/com/android/systemui/flags/Flags.java +++ b/packages/SystemUI/src/com/android/systemui/flags/Flags.java @@ -114,8 +114,8 @@ public class Flags { public static final BooleanFlag COMBINED_STATUS_BAR_SIGNAL_ICONS = new BooleanFlag(601, false); - public static final BooleanFlag STATUS_BAR_USER_SWITCHER = - new BooleanFlag(602, false); + public static final ResourceBooleanFlag STATUS_BAR_USER_SWITCHER = + new ResourceBooleanFlag(602, R.bool.flag_user_switcher_chip); /***************************************/ // 700 - dialer/calls diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardStatusBarView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardStatusBarView.java index 2ec5f250eb48..b8e9875be7e2 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardStatusBarView.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardStatusBarView.java @@ -40,6 +40,8 @@ import android.widget.LinearLayout; import android.widget.RelativeLayout; import android.widget.TextView; +import androidx.annotation.VisibleForTesting; + import com.android.settingslib.Utils; import com.android.systemui.R; import com.android.systemui.animation.Interpolators; @@ -67,8 +69,10 @@ public class KeyguardStatusBarView extends RelativeLayout { private ImageView mMultiUserAvatar; private BatteryMeterView mBatteryView; private StatusIconContainer mStatusIconContainer; + private ViewGroup mUserSwitcherContainer; private boolean mKeyguardUserSwitcherEnabled; + private boolean mKeyguardUserAvatarEnabled; private boolean mIsPrivacyDotEnabled; private int mSystemIconsSwitcherHiddenExpandedMargin; @@ -111,10 +115,15 @@ public class KeyguardStatusBarView extends RelativeLayout { mCutoutSpace = findViewById(R.id.cutout_space_view); mStatusIconArea = findViewById(R.id.status_icon_area); mStatusIconContainer = findViewById(R.id.statusIcons); + mUserSwitcherContainer = findViewById(R.id.user_switcher_container); mIsPrivacyDotEnabled = mContext.getResources().getBoolean(R.bool.config_enablePrivacyDot); loadDimens(); } + public ViewGroup getUserSwitcherContainer() { + return mUserSwitcherContainer; + } + @Override protected void onConfigurationChanged(Configuration newConfig) { super.onConfigurationChanged(newConfig); @@ -186,6 +195,17 @@ public class KeyguardStatusBarView extends RelativeLayout { } private void updateVisibilities() { + // Multi user avatar is disabled in favor of the user switcher chip + if (!mKeyguardUserAvatarEnabled) { + if (mMultiUserAvatar.getParent() == mStatusIconArea) { + mStatusIconArea.removeView(mMultiUserAvatar); + } else if (mMultiUserAvatar.getParent() != null) { + getOverlay().remove(mMultiUserAvatar); + } + + return; + } + if (mMultiUserAvatar.getParent() != mStatusIconArea && !mKeyguardUserSwitcherEnabled) { if (mMultiUserAvatar.getParent() != null) { @@ -346,6 +366,16 @@ public class KeyguardStatusBarView extends RelativeLayout { mKeyguardUserSwitcherEnabled = enabled; } + void setKeyguardUserAvatarEnabled(boolean enabled) { + mKeyguardUserAvatarEnabled = enabled; + updateVisibilities(); + } + + @VisibleForTesting + boolean isKeyguardUserAvatarEnabled() { + return mKeyguardUserAvatarEnabled; + } + private void animateNextLayoutChange() { final int systemIconsCurrentX = mSystemIconsContainer.getLeft(); final boolean userAvatarVisible = mMultiUserAvatar.getParent() == mStatusIconArea; @@ -416,9 +446,14 @@ public class KeyguardStatusBarView extends RelativeLayout { /** Should only be called from {@link KeyguardStatusBarViewController}. */ void onOverlayChanged() { - mCarrierLabel.setTextAppearance( - Utils.getThemeAttr(mContext, com.android.internal.R.attr.textAppearanceSmall)); + int theme = Utils.getThemeAttr(mContext, com.android.internal.R.attr.textAppearanceSmall); + mCarrierLabel.setTextAppearance(theme); mBatteryView.updatePercentView(); + + TextView userSwitcherName = mUserSwitcherContainer.findViewById(R.id.current_user_name); + if (userSwitcherName != null) { + userSwitcherName.setTextAppearance(theme); + } } private void updateIconsAndTextColors(StatusBarIconController.TintedIconManager iconManager) { @@ -429,6 +464,14 @@ public class KeyguardStatusBarView extends RelativeLayout { R.color.light_mode_icon_color_single_tone); float intensity = textColor == Color.WHITE ? 0 : 1; mCarrierLabel.setTextColor(iconColor); + + TextView userSwitcherName = mUserSwitcherContainer.findViewById(R.id.current_user_name); + if (userSwitcherName != null) { + userSwitcherName.setTextColor(Utils.getColorStateListDefaultColor( + mContext, + R.color.light_mode_icon_color_single_tone)); + } + if (iconManager != null) { iconManager.setTint(iconColor); } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardStatusBarViewController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardStatusBarViewController.java index ee97fd631818..1df1aff38593 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardStatusBarViewController.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardStatusBarViewController.java @@ -47,6 +47,9 @@ 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.userswitcher.StatusBarUserInfoTracker; +import com.android.systemui.statusbar.phone.userswitcher.StatusBarUserSwitcherController; +import com.android.systemui.statusbar.phone.userswitcher.StatusBarUserSwitcherFeatureController; import com.android.systemui.statusbar.policy.BatteryController; import com.android.systemui.statusbar.policy.ConfigurationController; import com.android.systemui.statusbar.policy.KeyguardStateController; @@ -95,6 +98,9 @@ public class KeyguardStatusBarViewController extends ViewController<KeyguardStat private final SysuiStatusBarStateController mStatusBarStateController; private final StatusBarContentInsetsProvider mInsetsProvider; private final UserManager mUserManager; + private final StatusBarUserSwitcherFeatureController mFeatureController; + private final StatusBarUserSwitcherController mUserSwitcherController; + private final StatusBarUserInfoTracker mStatusBarUserInfoTracker; private final ConfigurationController.ConfigurationListener mConfigurationListener = new ConfigurationController.ConfigurationListener() { @@ -246,7 +252,10 @@ public class KeyguardStatusBarViewController extends ViewController<KeyguardStat BiometricUnlockController biometricUnlockController, SysuiStatusBarStateController statusBarStateController, StatusBarContentInsetsProvider statusBarContentInsetsProvider, - UserManager userManager + UserManager userManager, + StatusBarUserSwitcherFeatureController featureController, + StatusBarUserSwitcherController userSwitcherController, + StatusBarUserInfoTracker statusBarUserInfoTracker ) { super(view); mCarrierTextController = carrierTextController; @@ -265,6 +274,9 @@ public class KeyguardStatusBarViewController extends ViewController<KeyguardStat mStatusBarStateController = statusBarStateController; mInsetsProvider = statusBarContentInsetsProvider; mUserManager = userManager; + mFeatureController = featureController; + mUserSwitcherController = userSwitcherController; + mStatusBarUserInfoTracker = statusBarUserInfoTracker; mFirstBypassAttempt = mKeyguardBypassController.getBypassEnabled(); mKeyguardStateController.addCallback( @@ -286,6 +298,10 @@ public class KeyguardStatusBarViewController extends ViewController<KeyguardStat r.getString(com.android.internal.R.string.status_bar_call_strength))); mNotificationsHeaderCollideDistance = r.getDimensionPixelSize( R.dimen.header_notifications_collide_distance); + + mView.setKeyguardUserAvatarEnabled( + !mFeatureController.isStatusBarUserSwitcherFeatureEnabled()); + mFeatureController.addCallback(enabled -> mView.setKeyguardUserAvatarEnabled(!enabled)); } @Override @@ -293,6 +309,7 @@ public class KeyguardStatusBarViewController extends ViewController<KeyguardStat super.onInit(); mCarrierTextController.init(); mBatteryMeterViewController.init(); + mUserSwitcherController.init(); } @Override @@ -334,6 +351,9 @@ public class KeyguardStatusBarViewController extends ViewController<KeyguardStat /** Sets whether user switcher is enabled. */ public void setKeyguardUserSwitcherEnabled(boolean enabled) { mView.setKeyguardUserSwitcherEnabled(enabled); + // We don't have a listener for when the user switcher setting changes, so this is + // where we re-check the state + mStatusBarUserInfoTracker.checkEnabled(); } /** Sets whether this controller should listen to battery updates. */ diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarViewController.kt b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarViewController.kt index d6bf5f21c834..224b2e45bfe5 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarViewController.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarViewController.kt @@ -21,15 +21,19 @@ import android.view.MotionEvent import android.view.View import android.view.ViewGroup import android.view.ViewTreeObserver + import com.android.systemui.R import com.android.systemui.shared.animation.UnfoldMoveFromCenterAnimator +import com.android.systemui.statusbar.phone.userswitcher.StatusBarUserSwitcherController import com.android.systemui.statusbar.policy.ConfigurationController import com.android.systemui.unfold.SysUIUnfoldComponent import com.android.systemui.unfold.UNFOLD_STATUS_BAR import com.android.systemui.unfold.util.ScopedUnfoldTransitionProgressProvider import com.android.systemui.util.ViewController import com.android.systemui.util.kotlin.getOrNull + import java.util.Optional + import javax.inject.Inject import javax.inject.Named @@ -38,6 +42,7 @@ class PhoneStatusBarViewController private constructor( view: PhoneStatusBarView, @Named(UNFOLD_STATUS_BAR) private val progressProvider: ScopedUnfoldTransitionProgressProvider?, private val moveFromCenterAnimationController: StatusBarMoveFromCenterAnimationController?, + private val userSwitcherController: StatusBarUserSwitcherController, touchEventHandler: PhoneStatusBarView.TouchEventHandler, private val configurationController: ConfigurationController ) : ViewController<PhoneStatusBarView>(view) { @@ -89,6 +94,10 @@ class PhoneStatusBarViewController private constructor( mView.setTouchEventHandler(touchEventHandler) } + override fun onInit() { + userSwitcherController.init() + } + fun setImportantForAccessibility(mode: Int) { mView.importantForAccessibility = mode } @@ -153,6 +162,7 @@ class PhoneStatusBarViewController private constructor( private val unfoldComponent: Optional<SysUIUnfoldComponent>, @Named(UNFOLD_STATUS_BAR) private val progressProvider: Optional<ScopedUnfoldTransitionProgressProvider>, + private val userSwitcherController: StatusBarUserSwitcherController, private val configurationController: ConfigurationController ) { fun create( @@ -163,6 +173,7 @@ class PhoneStatusBarViewController private constructor( view, progressProvider.getOrNull(), unfoldComponent.getOrNull()?.getStatusBarMoveFromCenterAnimationController(), + userSwitcherController, touchEventHandler, configurationController ) diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/fragment/dagger/StatusBarFragmentModule.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/fragment/dagger/StatusBarFragmentModule.java index dea1b43f579f..e2dc9057e49d 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/fragment/dagger/StatusBarFragmentModule.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/fragment/dagger/StatusBarFragmentModule.java @@ -26,11 +26,15 @@ import com.android.systemui.statusbar.phone.PhoneStatusBarTransitions; import com.android.systemui.statusbar.phone.PhoneStatusBarView; import com.android.systemui.statusbar.phone.PhoneStatusBarViewController; import com.android.systemui.statusbar.phone.fragment.CollapsedStatusBarFragment; +import com.android.systemui.statusbar.phone.userswitcher.StatusBarUserSwitcherContainer; +import com.android.systemui.statusbar.phone.userswitcher.StatusBarUserSwitcherController; +import com.android.systemui.statusbar.phone.userswitcher.StatusBarUserSwitcherControllerImpl; import com.android.systemui.statusbar.policy.Clock; import com.android.systemui.statusbar.window.StatusBarWindowController; import javax.inject.Named; +import dagger.Binds; import dagger.Module; import dagger.Provides; @@ -83,6 +87,20 @@ public interface StatusBarFragmentModule { /** */ @Provides @StatusBarFragmentScope + static StatusBarUserSwitcherContainer provideStatusBarUserSwitcherContainer( + @RootView PhoneStatusBarView view) { + return view.findViewById(R.id.user_switcher_container); + } + + /** */ + @Binds + @StatusBarFragmentScope + StatusBarUserSwitcherController bindStatusBarUserSwitcherController( + StatusBarUserSwitcherControllerImpl controller); + + /** */ + @Provides + @StatusBarFragmentScope static PhoneStatusBarViewController providePhoneStatusBarViewController( PhoneStatusBarViewController.Factory phoneStatusBarViewControllerFactory, @RootView PhoneStatusBarView phoneStatusBarView, diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/userswitcher/StatusBarUserInfoTracker.kt b/packages/SystemUI/src/com/android/systemui/statusbar/phone/userswitcher/StatusBarUserInfoTracker.kt new file mode 100644 index 000000000000..2dbc19c653f7 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/userswitcher/StatusBarUserInfoTracker.kt @@ -0,0 +1,122 @@ +/* + * Copyright (C) 2022 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.phone.userswitcher + +import android.graphics.drawable.Drawable +import android.os.UserManager + +import com.android.systemui.DejankUtils.whitelistIpcs +import com.android.systemui.dagger.SysUISingleton +import com.android.systemui.statusbar.policy.CallbackController +import com.android.systemui.statusbar.policy.UserInfoController +import com.android.systemui.statusbar.policy.UserInfoController.OnUserInfoChangedListener + +import javax.inject.Inject + +/** + * Since every user switcher chip will user the exact same information and logic on whether or not + * to show, and what data to show, it makes sense to create a single tracker here + */ +@SysUISingleton +class StatusBarUserInfoTracker @Inject constructor( + private val userInfoController: UserInfoController, + private val userManager: UserManager +) : CallbackController<CurrentUserChipInfoUpdatedListener> { + var currentUserName: String? = null + private set + var currentUserAvatar: Drawable? = null + private set + var userSwitcherEnabled = false + private set + private var listening = false + + private val listeners = mutableListOf<CurrentUserChipInfoUpdatedListener>() + + private val userInfoChangedListener = OnUserInfoChangedListener { name, picture, _ -> + currentUserAvatar = picture + currentUserName = name + notifyListenersUserInfoChanged() + } + + init { + startListening() + } + + override fun addCallback(listener: CurrentUserChipInfoUpdatedListener) { + if (listeners.isEmpty()) { + startListening() + } + + if (!listeners.contains(listener)) { + listeners.add(listener) + } + } + + override fun removeCallback(listener: CurrentUserChipInfoUpdatedListener) { + listeners.remove(listener) + + if (listeners.isEmpty()) { + stopListening() + } + } + + private fun notifyListenersUserInfoChanged() { + listeners.forEach { + it.onCurrentUserChipInfoUpdated() + } + } + + private fun notifyListenersSettingChanged() { + listeners.forEach { + it.onStatusBarUserSwitcherSettingChanged(userSwitcherEnabled) + } + } + + private fun startListening() { + listening = true + userInfoController.addCallback(userInfoChangedListener) + } + + private fun stopListening() { + listening = false + userInfoController.removeCallback(userInfoChangedListener) + } + + private fun checkUserSwitcherEnabled() { + whitelistIpcs { + userSwitcherEnabled = userManager.isUserSwitcherEnabled + } + } + + /** + * Force a check to [UserManager.isUserSwitcherEnabled], and update listeners if the value has + * changed + */ + fun checkEnabled() { + val wasEnabled = userSwitcherEnabled + checkUserSwitcherEnabled() + + if (wasEnabled != userSwitcherEnabled) { + notifyListenersSettingChanged() + } + } +} + +interface CurrentUserChipInfoUpdatedListener { + fun onCurrentUserChipInfoUpdated() + fun onStatusBarUserSwitcherSettingChanged(enabled: Boolean) {} +} diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/userswitcher/StatusBarUserSwitcherContainer.kt b/packages/SystemUI/src/com/android/systemui/statusbar/phone/userswitcher/StatusBarUserSwitcherContainer.kt new file mode 100644 index 000000000000..2c8677dee4d9 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/userswitcher/StatusBarUserSwitcherContainer.kt @@ -0,0 +1,40 @@ +/* + * Copyright (C) 2022 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.phone.userswitcher + +import android.content.Context +import android.util.AttributeSet +import android.widget.ImageView +import android.widget.LinearLayout +import android.widget.TextView +import com.android.systemui.R + +class StatusBarUserSwitcherContainer( + context: Context?, + attrs: AttributeSet? +) : LinearLayout(context, attrs) { + lateinit var text: TextView + private set + lateinit var avatar: ImageView + private set + + override fun onFinishInflate() { + super.onFinishInflate() + text = findViewById(R.id.current_user_name) + avatar = findViewById(R.id.current_user_avatar) + } +}
\ No newline at end of file diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/userswitcher/StatusBarUserSwitcherController.kt b/packages/SystemUI/src/com/android/systemui/statusbar/phone/userswitcher/StatusBarUserSwitcherController.kt new file mode 100644 index 000000000000..a1247539c660 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/userswitcher/StatusBarUserSwitcherController.kt @@ -0,0 +1,88 @@ +/* + * Copyright (C) 2022 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.phone.userswitcher + +import android.view.View + +import com.android.systemui.qs.user.UserSwitchDialogController +import com.android.systemui.util.ViewController + +import javax.inject.Inject + +/** + * ViewController for [StatusBarUserSwitcherContainer] + */ +class StatusBarUserSwitcherControllerImpl @Inject constructor( + view: StatusBarUserSwitcherContainer, + private val tracker: StatusBarUserInfoTracker, + private val featureController: StatusBarUserSwitcherFeatureController, + private val userSwitcherDialogController: UserSwitchDialogController +) : ViewController<StatusBarUserSwitcherContainer>(view), + StatusBarUserSwitcherController { + private val listener = object : CurrentUserChipInfoUpdatedListener { + override fun onCurrentUserChipInfoUpdated() { + updateChip() + } + + override fun onStatusBarUserSwitcherSettingChanged(enabled: Boolean) { + updateEnabled() + } + } + + private val featureFlagListener = object : OnUserSwitcherPreferenceChangeListener { + override fun onUserSwitcherPreferenceChange(enabled: Boolean) { + updateEnabled() + } + } + + override fun onViewAttached() { + tracker.addCallback(listener) + featureController.addCallback(featureFlagListener) + mView.setOnClickListener { + userSwitcherDialogController.showDialog(it) + } + + updateEnabled() + } + + override fun onViewDetached() { + tracker.removeCallback(listener) + featureController.removeCallback(featureFlagListener) + mView.setOnClickListener(null) + } + + private fun updateChip() { + mView.text.text = tracker.currentUserName + mView.avatar.setImageDrawable(tracker.currentUserAvatar) + } + + private fun updateEnabled() { + if (featureController.isStatusBarUserSwitcherFeatureEnabled() && + tracker.userSwitcherEnabled) { + mView.visibility = View.VISIBLE + updateChip() + } else { + mView.visibility = View.GONE + } + } +} + +interface StatusBarUserSwitcherController { + fun init() +} + +private const val TAG = "SbUserSwitcherController" diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/userswitcher/StatusBarUserSwitcherFeatureController.kt b/packages/SystemUI/src/com/android/systemui/statusbar/phone/userswitcher/StatusBarUserSwitcherFeatureController.kt new file mode 100644 index 000000000000..7bae9ff72760 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/userswitcher/StatusBarUserSwitcherFeatureController.kt @@ -0,0 +1,63 @@ +/* + * Copyright (C) 2022 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.phone.userswitcher + +import com.android.systemui.dagger.SysUISingleton +import com.android.systemui.flags.FeatureFlags +import com.android.systemui.flags.Flags +import com.android.systemui.statusbar.policy.CallbackController + +import javax.inject.Inject + +@SysUISingleton +class StatusBarUserSwitcherFeatureController @Inject constructor( + private val flags: FeatureFlags +) : CallbackController<OnUserSwitcherPreferenceChangeListener> { + private val listeners = mutableListOf<OnUserSwitcherPreferenceChangeListener>() + + init { + flags.addListener(Flags.STATUS_BAR_USER_SWITCHER) { + it.requestNoRestart() + notifyListeners() + } + } + + fun isStatusBarUserSwitcherFeatureEnabled(): Boolean { + return flags.isEnabled(Flags.STATUS_BAR_USER_SWITCHER) + } + + override fun addCallback(listener: OnUserSwitcherPreferenceChangeListener) { + if (!listeners.contains(listener)) { + listeners.add(listener) + } + } + + override fun removeCallback(listener: OnUserSwitcherPreferenceChangeListener) { + listeners.remove(listener) + } + + private fun notifyListeners() { + val enabled = flags.isEnabled(Flags.STATUS_BAR_USER_SWITCHER) + listeners.forEach { + it.onUserSwitcherPreferenceChange(enabled) + } + } +} + +interface OnUserSwitcherPreferenceChangeListener { + fun onUserSwitcherPreferenceChange(enabled: Boolean) +} diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/KeyguardStatusBarViewControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/KeyguardStatusBarViewControllerTest.java index 01e9822e0484..7de35458a893 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/KeyguardStatusBarViewControllerTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/KeyguardStatusBarViewControllerTest.java @@ -47,6 +47,9 @@ import com.android.systemui.flags.FeatureFlags; import com.android.systemui.plugins.statusbar.StatusBarStateController; import com.android.systemui.statusbar.SysuiStatusBarStateController; import com.android.systemui.statusbar.events.SystemStatusAnimationScheduler; +import com.android.systemui.statusbar.phone.userswitcher.StatusBarUserInfoTracker; +import com.android.systemui.statusbar.phone.userswitcher.StatusBarUserSwitcherController; +import com.android.systemui.statusbar.phone.userswitcher.StatusBarUserSwitcherFeatureController; import com.android.systemui.statusbar.policy.BatteryController; import com.android.systemui.statusbar.policy.ConfigurationController; import com.android.systemui.statusbar.policy.ConfigurationController.ConfigurationListener; @@ -99,6 +102,12 @@ public class KeyguardStatusBarViewControllerTest extends SysuiTestCase { private ArgumentCaptor<ConfigurationListener> mConfigurationListenerCaptor; @Captor private ArgumentCaptor<KeyguardUpdateMonitorCallback> mKeyguardCallbackCaptor; + @Mock + private StatusBarUserSwitcherFeatureController mStatusBarUserSwitcherFeatureController; + @Mock + private StatusBarUserSwitcherController mStatusBarUserSwitcherController; + @Mock + private StatusBarUserInfoTracker mStatusBarUserInfoTracker; private TestNotificationPanelViewStateProvider mNotificationPanelViewStateProvider; private KeyguardStatusBarView mKeyguardStatusBarView; @@ -117,7 +126,11 @@ public class KeyguardStatusBarViewControllerTest extends SysuiTestCase { .inflate(R.layout.keyguard_status_bar, null)); }); - mController = new KeyguardStatusBarViewController( + mController = createController(); + } + + private KeyguardStatusBarViewController createController() { + return new KeyguardStatusBarViewController( mKeyguardStatusBarView, mCarrierTextController, mConfigurationController, @@ -134,7 +147,10 @@ public class KeyguardStatusBarViewControllerTest extends SysuiTestCase { mBiometricUnlockController, mStatusBarStateController, mStatusBarContentInsetsProvider, - mUserManager + mUserManager, + mStatusBarUserSwitcherFeatureController, + mStatusBarUserSwitcherController, + mStatusBarUserInfoTracker ); } @@ -356,6 +372,32 @@ public class KeyguardStatusBarViewControllerTest extends SysuiTestCase { assertThat(mKeyguardStatusBarView.getVisibility()).isEqualTo(View.VISIBLE); } + @Test + public void testNewUserSwitcherDisablesAvatar_newUiOn() { + // GIVEN the status bar user switcher chip is enabled + when(mStatusBarUserSwitcherFeatureController.isStatusBarUserSwitcherFeatureEnabled()) + .thenReturn(true); + + // WHEN the controller is created + mController = createController(); + + // THEN keyguard status bar view avatar is disabled + assertThat(mKeyguardStatusBarView.isKeyguardUserAvatarEnabled()).isFalse(); + } + + @Test + public void testNewUserSwitcherDisablesAvatar_newUiOff() { + // GIVEN the status bar user switcher chip is disabled + when(mStatusBarUserSwitcherFeatureController.isStatusBarUserSwitcherFeatureEnabled()) + .thenReturn(false); + + // WHEN the controller is created + mController = createController(); + + // THEN keyguard status bar view avatar is enabled + assertThat(mKeyguardStatusBarView.isKeyguardUserAvatarEnabled()).isTrue(); + } + private void updateStateToNotKeyguard() { updateStatusBarState(SHADE); } diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/PhoneStatusBarViewControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/PhoneStatusBarViewControllerTest.kt index c65a6b6cde1a..589116184710 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/PhoneStatusBarViewControllerTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/PhoneStatusBarViewControllerTest.kt @@ -26,6 +26,7 @@ import androidx.test.filters.SmallTest import androidx.test.platform.app.InstrumentationRegistry import com.android.systemui.R import com.android.systemui.SysuiTestCase +import com.android.systemui.statusbar.phone.userswitcher.StatusBarUserSwitcherController import com.android.systemui.statusbar.policy.ConfigurationController import com.android.systemui.unfold.SysUIUnfoldComponent import com.android.systemui.unfold.config.UnfoldTransitionConfig @@ -60,6 +61,8 @@ class PhoneStatusBarViewControllerTest : SysuiTestCase() { private lateinit var progressProvider: ScopedUnfoldTransitionProgressProvider @Mock private lateinit var configurationController: ConfigurationController + @Mock + private lateinit var userSwitcherController: StatusBarUserSwitcherController private lateinit var view: PhoneStatusBarView private lateinit var controller: PhoneStatusBarViewController @@ -187,6 +190,7 @@ class PhoneStatusBarViewControllerTest : SysuiTestCase() { return PhoneStatusBarViewController.Factory( Optional.of(sysuiUnfoldComponent), Optional.of(progressProvider), + userSwitcherController, configurationController ).create(view, touchEventHandler).also { it.init() |