Merge "Add the user switcher chip to the status bar"

This commit is contained in:
Evan Laird
2022-02-07 15:27:11 +00:00
committed by Android (Google) Code Review
17 changed files with 552 additions and 9 deletions

View File

@@ -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>

View File

@@ -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" />

View File

@@ -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>

View File

@@ -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">

View File

@@ -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>

View File

@@ -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);
}

View File

@@ -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

View File

@@ -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);
}

View File

@@ -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. */

View File

@@ -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
)

View File

@@ -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

View File

@@ -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) {}
}

View File

@@ -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)
}
}

View File

@@ -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"

View File

@@ -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)
}

View File

@@ -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);
}

View File

@@ -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()