Merge "Add the user switcher chip to the status bar"
This commit is contained in:
@@ -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>
|
||||
@@ -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" />
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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">
|
||||
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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. */
|
||||
|
||||
@@ -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
|
||||
)
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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) {}
|
||||
}
|
||||
@@ -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)
|
||||
}
|
||||
}
|
||||
@@ -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"
|
||||
@@ -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)
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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()
|
||||
|
||||
Reference in New Issue
Block a user