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