From e4314893008d5cb9fa922e716e1be439ed6f7813 Mon Sep 17 00:00:00 2001 From: Evan Laird Date: Wed, 19 Jan 2022 11:13:40 -0500 Subject: [PATCH] Add the user switcher chip to the status bar Add a StatusBarUserSwitcherContainer (plus a view controller) which can show the current user information and present the user switcher when tapped. This CL also aggregates all of the current user information into the StatusBarUserInfoTracker so that the view controllers are lightweight and reusable in the keyguard and unlocked statusbar. Test: atest SystemUITests; manual Bug: 217250837 Change-Id: I5fffb01e191d7bcd95d3a0651208bf0ca8eb45f8 --- .../drawable/status_bar_user_chip_bg.xml | 20 +++ .../res/layout/keyguard_status_bar.xml | 27 +++- packages/SystemUI/res/layout/status_bar.xml | 26 ++++ packages/SystemUI/res/layout/system_icons.xml | 2 +- packages/SystemUI/res/values/flags.xml | 4 + .../dagger/KeyguardStatusBarViewModule.java | 17 +++ .../src/com/android/systemui/flags/Flags.java | 4 +- .../phone/KeyguardStatusBarView.java | 47 ++++++- .../KeyguardStatusBarViewController.java | 22 +++- .../phone/PhoneStatusBarViewController.kt | 11 ++ .../dagger/StatusBarFragmentModule.java | 18 +++ .../userswitcher/StatusBarUserInfoTracker.kt | 122 ++++++++++++++++++ .../StatusBarUserSwitcherContainer.kt | 40 ++++++ .../StatusBarUserSwitcherController.kt | 88 +++++++++++++ .../StatusBarUserSwitcherFeatureController.kt | 63 +++++++++ .../KeyguardStatusBarViewControllerTest.java | 46 ++++++- .../phone/PhoneStatusBarViewControllerTest.kt | 4 + 17 files changed, 552 insertions(+), 9 deletions(-) create mode 100644 packages/SystemUI/res-keyguard/drawable/status_bar_user_chip_bg.xml create mode 100644 packages/SystemUI/src/com/android/systemui/statusbar/phone/userswitcher/StatusBarUserInfoTracker.kt create mode 100644 packages/SystemUI/src/com/android/systemui/statusbar/phone/userswitcher/StatusBarUserSwitcherContainer.kt create mode 100644 packages/SystemUI/src/com/android/systemui/statusbar/phone/userswitcher/StatusBarUserSwitcherController.kt create mode 100644 packages/SystemUI/src/com/android/systemui/statusbar/phone/userswitcher/StatusBarUserSwitcherFeatureController.kt 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 0000000000000..989115697d6f2 --- /dev/null +++ b/packages/SystemUI/res-keyguard/drawable/status_bar_user_chip_bg.xml @@ -0,0 +1,20 @@ + + + + + + diff --git a/packages/SystemUI/res/layout/keyguard_status_bar.xml b/packages/SystemUI/res/layout/keyguard_status_bar.xml index 850b017173084..e47eed9ea04a6 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" > + + + + + + diff --git a/packages/SystemUI/res/layout/status_bar.xml b/packages/SystemUI/res/layout/status_bar.xml index 8b244c757649c..af98019362070 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" > + + + + + + diff --git a/packages/SystemUI/res/layout/system_icons.xml b/packages/SystemUI/res/layout/system_icons.xml index 6d5c7d40a5f82..4f4bae49b275b 100644 --- a/packages/SystemUI/res/layout/system_icons.xml +++ b/packages/SystemUI/res/layout/system_icons.xml @@ -17,7 +17,7 @@ diff --git a/packages/SystemUI/res/values/flags.xml b/packages/SystemUI/res/values/flags.xml index 2a70645e49ec0..49dd574af8298 100644 --- a/packages/SystemUI/res/values/flags.xml +++ b/packages/SystemUI/res/values/flags.xml @@ -32,4 +32,8 @@ false + + false + diff --git a/packages/SystemUI/src/com/android/keyguard/dagger/KeyguardStatusBarViewModule.java b/packages/SystemUI/src/com/android/keyguard/dagger/KeyguardStatusBarViewModule.java index fc14b6a99008a..8fc86004c400e 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 c894b7023d756..d67815f485e03 100644 --- a/packages/SystemUI/src/com/android/systemui/flags/Flags.java +++ b/packages/SystemUI/src/com/android/systemui/flags/Flags.java @@ -112,8 +112,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 2ec5f250eb48c..b8e9875be7e22 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 ee97fd6318189..1df1aff385939 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 mView.setKeyguardUserAvatarEnabled(!enabled)); } @Override @@ -293,6 +309,7 @@ public class KeyguardStatusBarViewController extends ViewController(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, @Named(UNFOLD_STATUS_BAR) private val progressProvider: Optional, + 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 dea1b43f579f1..e2dc9057e49d8 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; @@ -80,6 +84,20 @@ public interface StatusBarFragmentModule { return view.findViewById(R.id.clock); } + /** */ + @Provides + @StatusBarFragmentScope + static StatusBarUserSwitcherContainer provideStatusBarUserSwitcherContainer( + @RootView PhoneStatusBarView view) { + return view.findViewById(R.id.user_switcher_container); + } + + /** */ + @Binds + @StatusBarFragmentScope + StatusBarUserSwitcherController bindStatusBarUserSwitcherController( + StatusBarUserSwitcherControllerImpl controller); + /** */ @Provides @StatusBarFragmentScope 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 0000000000000..2dbc19c653f7b --- /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 { + 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() + + 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 0000000000000..2c8677dee4d9c --- /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 0000000000000..a1247539c6605 --- /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(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 0000000000000..7bae9ff727603 --- /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 { + private val listeners = mutableListOf() + + 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 01e9822e0484d..7de35458a893d 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 mConfigurationListenerCaptor; @Captor private ArgumentCaptor 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 c65a6b6cde1af..5891161847103 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()