Merge changes I8d766f4a,I3f5e212f,Ia78513a0 into tm-qpr-dev
* changes: Update status bar user chip view spec Replace StatusBarUserSwitcherController with UserInteractor Move showUserSwitcher to UserInteractor
This commit is contained in:
@@ -34,30 +34,13 @@
|
||||
android:paddingTop="@dimen/status_bar_padding_top"
|
||||
android:layout_alignParentEnd="true"
|
||||
android:gravity="center_vertical|end" >
|
||||
<com.android.systemui.statusbar.phone.userswitcher.StatusBarUserSwitcherContainer
|
||||
|
||||
<include
|
||||
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>
|
||||
android:layout_marginEnd="@dimen/status_bar_user_chip_end_margin"
|
||||
layout="@layout/status_bar_user_chip_container" />
|
||||
|
||||
<FrameLayout android:id="@+id/system_icons_container"
|
||||
android:layout_width="wrap_content"
|
||||
|
||||
@@ -136,31 +136,12 @@
|
||||
android:gravity="center_vertical|end"
|
||||
android:clipChildren="false">
|
||||
|
||||
<com.android.systemui.statusbar.phone.userswitcher.StatusBarUserSwitcherContainer
|
||||
<include
|
||||
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>
|
||||
android:layout_marginEnd="@dimen/status_bar_user_chip_end_margin"
|
||||
layout="@layout/status_bar_user_chip_container" />
|
||||
|
||||
<include layout="@layout/system_icons" />
|
||||
</com.android.keyguard.AlphaOptimizedLinearLayout>
|
||||
|
||||
@@ -0,0 +1,40 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!--
|
||||
~ 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.
|
||||
-->
|
||||
|
||||
<com.android.systemui.statusbar.phone.userswitcher.StatusBarUserSwitcherContainer
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:id="@+id/user_switcher_container"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:gravity="center"
|
||||
android:orientation="horizontal"
|
||||
android:layout_marginEnd="@dimen/status_bar_user_chip_end_margin"
|
||||
android:background="@drawable/status_bar_user_chip_bg"
|
||||
android:visibility="visible" >
|
||||
<ImageView android:id="@+id/current_user_avatar"
|
||||
android:layout_width="@dimen/status_bar_user_chip_avatar_size"
|
||||
android:layout_height="@dimen/status_bar_user_chip_avatar_size"
|
||||
android:layout_margin="4dp"
|
||||
android:scaleType="centerInside" />
|
||||
|
||||
<TextView android:id="@+id/current_user_name"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:paddingEnd="8dp"
|
||||
android:textAppearance="@style/TextAppearance.StatusBar.UserChip"
|
||||
/>
|
||||
</com.android.systemui.statusbar.phone.userswitcher.StatusBarUserSwitcherContainer>
|
||||
@@ -1404,6 +1404,11 @@
|
||||
<dimen name="ongoing_call_chip_icon_text_padding">4dp</dimen>
|
||||
<dimen name="ongoing_call_chip_corner_radius">28dp</dimen>
|
||||
|
||||
<!-- Status bar user chip -->
|
||||
<dimen name="status_bar_user_chip_avatar_size">16dp</dimen>
|
||||
<dimen name="status_bar_user_chip_end_margin">12dp</dimen>
|
||||
<dimen name="status_bar_user_chip_text_size">12sp</dimen>
|
||||
|
||||
<!-- Internet panel related dimensions -->
|
||||
<dimen name="internet_dialog_list_max_height">662dp</dimen>
|
||||
<!-- The height of the WiFi network in Internet panel. -->
|
||||
|
||||
@@ -23,6 +23,12 @@
|
||||
<item name="android:textColor">@color/status_bar_clock_color</item>
|
||||
</style>
|
||||
|
||||
<style name="TextAppearance.StatusBar.UserChip" parent="@*android:style/TextAppearance.StatusBar.Icon">
|
||||
<item name="android:textSize">@dimen/status_bar_user_chip_text_size</item>
|
||||
<item name="android:fontFamily">@*android:string/config_headlineFontFamilyMedium</item>
|
||||
<item name="android:textColor">@color/status_bar_clock_color</item>
|
||||
</style>
|
||||
|
||||
<style name="TextAppearance.StatusBar.Expanded" parent="@*android:style/TextAppearance.StatusBar">
|
||||
<item name="android:textColor">?android:attr/textColorTertiary</item>
|
||||
</style>
|
||||
|
||||
@@ -21,10 +21,7 @@ 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;
|
||||
|
||||
@@ -50,10 +47,4 @@ public abstract class KeyguardStatusBarViewModule {
|
||||
static StatusBarUserSwitcherContainer getUserSwitcherContainer(KeyguardStatusBarView view) {
|
||||
return view.findViewById(R.id.user_switcher_container);
|
||||
}
|
||||
|
||||
/** */
|
||||
@Binds
|
||||
@KeyguardStatusBarViewScope
|
||||
abstract StatusBarUserSwitcherController bindStatusBarUserSwitcherController(
|
||||
StatusBarUserSwitcherControllerImpl controller);
|
||||
}
|
||||
|
||||
@@ -32,8 +32,6 @@ import com.android.systemui.animation.Expandable
|
||||
import com.android.systemui.broadcast.BroadcastDispatcher
|
||||
import com.android.systemui.dagger.SysUISingleton
|
||||
import com.android.systemui.dagger.qualifiers.Background
|
||||
import com.android.systemui.flags.FeatureFlags
|
||||
import com.android.systemui.flags.Flags
|
||||
import com.android.systemui.globalactions.GlobalActionsDialogLite
|
||||
import com.android.systemui.plugins.ActivityStarter
|
||||
import com.android.systemui.qs.FgsManagerController
|
||||
@@ -42,10 +40,9 @@ import com.android.systemui.qs.footer.data.model.UserSwitcherStatusModel
|
||||
import com.android.systemui.qs.footer.data.repository.ForegroundServicesRepository
|
||||
import com.android.systemui.qs.footer.data.repository.UserSwitcherRepository
|
||||
import com.android.systemui.qs.footer.domain.model.SecurityButtonConfig
|
||||
import com.android.systemui.qs.user.UserSwitchDialogController
|
||||
import com.android.systemui.security.data.repository.SecurityRepository
|
||||
import com.android.systemui.statusbar.policy.DeviceProvisionedController
|
||||
import com.android.systemui.user.UserSwitcherActivity
|
||||
import com.android.systemui.user.domain.interactor.UserInteractor
|
||||
import javax.inject.Inject
|
||||
import kotlinx.coroutines.CoroutineDispatcher
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
@@ -100,13 +97,12 @@ class FooterActionsInteractorImpl
|
||||
@Inject
|
||||
constructor(
|
||||
private val activityStarter: ActivityStarter,
|
||||
private val featureFlags: FeatureFlags,
|
||||
private val metricsLogger: MetricsLogger,
|
||||
private val uiEventLogger: UiEventLogger,
|
||||
private val deviceProvisionedController: DeviceProvisionedController,
|
||||
private val qsSecurityFooterUtils: QSSecurityFooterUtils,
|
||||
private val fgsManagerController: FgsManagerController,
|
||||
private val userSwitchDialogController: UserSwitchDialogController,
|
||||
private val userInteractor: UserInteractor,
|
||||
securityRepository: SecurityRepository,
|
||||
foregroundServicesRepository: ForegroundServicesRepository,
|
||||
userSwitcherRepository: UserSwitcherRepository,
|
||||
@@ -182,22 +178,6 @@ constructor(
|
||||
}
|
||||
|
||||
override fun showUserSwitcher(context: Context, expandable: Expandable) {
|
||||
if (!featureFlags.isEnabled(Flags.FULL_SCREEN_USER_SWITCHER)) {
|
||||
userSwitchDialogController.showDialog(context, expandable)
|
||||
return
|
||||
}
|
||||
|
||||
val intent =
|
||||
Intent(context, UserSwitcherActivity::class.java).apply {
|
||||
addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP or Intent.FLAG_ACTIVITY_NEW_TASK)
|
||||
}
|
||||
|
||||
activityStarter.startActivity(
|
||||
intent,
|
||||
true /* dismissShade */,
|
||||
expandable.activityLaunchController(),
|
||||
true /* showOverlockscreenwhenlocked */,
|
||||
UserHandle.SYSTEM,
|
||||
)
|
||||
userInteractor.showUserSwitcher(context, expandable)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -48,6 +48,9 @@ import com.android.systemui.R;
|
||||
import com.android.systemui.animation.Interpolators;
|
||||
import com.android.systemui.battery.BatteryMeterView;
|
||||
import com.android.systemui.plugins.DarkIconDispatcher.DarkReceiver;
|
||||
import com.android.systemui.statusbar.phone.userswitcher.StatusBarUserSwitcherContainer;
|
||||
import com.android.systemui.user.ui.binder.StatusBarUserChipViewBinder;
|
||||
import com.android.systemui.user.ui.viewmodel.StatusBarUserChipViewModel;
|
||||
|
||||
import java.io.PrintWriter;
|
||||
import java.util.ArrayList;
|
||||
@@ -70,7 +73,7 @@ public class KeyguardStatusBarView extends RelativeLayout {
|
||||
private ImageView mMultiUserAvatar;
|
||||
private BatteryMeterView mBatteryView;
|
||||
private StatusIconContainer mStatusIconContainer;
|
||||
private ViewGroup mUserSwitcherContainer;
|
||||
private StatusBarUserSwitcherContainer mUserSwitcherContainer;
|
||||
|
||||
private boolean mKeyguardUserSwitcherEnabled;
|
||||
private boolean mKeyguardUserAvatarEnabled;
|
||||
@@ -121,8 +124,12 @@ public class KeyguardStatusBarView extends RelativeLayout {
|
||||
loadDimens();
|
||||
}
|
||||
|
||||
public ViewGroup getUserSwitcherContainer() {
|
||||
return mUserSwitcherContainer;
|
||||
/**
|
||||
* Should only be called from {@link KeyguardStatusBarViewController}
|
||||
* @param viewModel view model for the status bar user chip
|
||||
*/
|
||||
void init(StatusBarUserChipViewModel viewModel) {
|
||||
StatusBarUserChipViewBinder.bind(mUserSwitcherContainer, viewModel);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -304,10 +311,7 @@ public class KeyguardStatusBarView extends RelativeLayout {
|
||||
lp = (LayoutParams) mStatusIconArea.getLayoutParams();
|
||||
lp.removeRule(RelativeLayout.RIGHT_OF);
|
||||
lp.width = LayoutParams.WRAP_CONTENT;
|
||||
|
||||
LinearLayout.LayoutParams llp =
|
||||
(LinearLayout.LayoutParams) mSystemIconsContainer.getLayoutParams();
|
||||
llp.setMarginStart(getResources().getDimensionPixelSize(
|
||||
lp.setMarginStart(getResources().getDimensionPixelSize(
|
||||
R.dimen.system_icons_super_container_margin_start));
|
||||
return true;
|
||||
}
|
||||
@@ -339,10 +343,7 @@ public class KeyguardStatusBarView extends RelativeLayout {
|
||||
lp = (LayoutParams) mStatusIconArea.getLayoutParams();
|
||||
lp.addRule(RelativeLayout.RIGHT_OF, R.id.cutout_space_view);
|
||||
lp.width = LayoutParams.MATCH_PARENT;
|
||||
|
||||
LinearLayout.LayoutParams llp =
|
||||
(LinearLayout.LayoutParams) mSystemIconsContainer.getLayoutParams();
|
||||
llp.setMarginStart(0);
|
||||
lp.setMarginStart(0);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@@ -59,13 +59,11 @@ import com.android.systemui.statusbar.notification.stack.AnimationProperties;
|
||||
import com.android.systemui.statusbar.notification.stack.StackStateAnimator;
|
||||
import com.android.systemui.statusbar.phone.fragment.StatusBarIconBlocklistKt;
|
||||
import com.android.systemui.statusbar.phone.fragment.StatusBarSystemEventAnimator;
|
||||
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;
|
||||
import com.android.systemui.statusbar.policy.UserInfoController;
|
||||
import com.android.systemui.user.ui.viewmodel.StatusBarUserChipViewModel;
|
||||
import com.android.systemui.util.ViewController;
|
||||
import com.android.systemui.util.settings.SecureSettings;
|
||||
|
||||
@@ -110,9 +108,7 @@ 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 StatusBarUserChipViewModel mStatusBarUserChipViewModel;
|
||||
private final SecureSettings mSecureSettings;
|
||||
private final CommandQueue mCommandQueue;
|
||||
private final Executor mMainExecutor;
|
||||
@@ -276,9 +272,7 @@ public class KeyguardStatusBarViewController extends ViewController<KeyguardStat
|
||||
SysuiStatusBarStateController statusBarStateController,
|
||||
StatusBarContentInsetsProvider statusBarContentInsetsProvider,
|
||||
UserManager userManager,
|
||||
StatusBarUserSwitcherFeatureController featureController,
|
||||
StatusBarUserSwitcherController userSwitcherController,
|
||||
StatusBarUserInfoTracker statusBarUserInfoTracker,
|
||||
StatusBarUserChipViewModel userChipViewModel,
|
||||
SecureSettings secureSettings,
|
||||
CommandQueue commandQueue,
|
||||
@Main Executor mainExecutor,
|
||||
@@ -301,9 +295,7 @@ public class KeyguardStatusBarViewController extends ViewController<KeyguardStat
|
||||
mStatusBarStateController = statusBarStateController;
|
||||
mInsetsProvider = statusBarContentInsetsProvider;
|
||||
mUserManager = userManager;
|
||||
mFeatureController = featureController;
|
||||
mUserSwitcherController = userSwitcherController;
|
||||
mStatusBarUserInfoTracker = statusBarUserInfoTracker;
|
||||
mStatusBarUserChipViewModel = userChipViewModel;
|
||||
mSecureSettings = secureSettings;
|
||||
mCommandQueue = commandQueue;
|
||||
mMainExecutor = mainExecutor;
|
||||
@@ -328,8 +320,7 @@ public class KeyguardStatusBarViewController extends ViewController<KeyguardStat
|
||||
R.dimen.header_notifications_collide_distance);
|
||||
|
||||
mView.setKeyguardUserAvatarEnabled(
|
||||
!mFeatureController.isStatusBarUserSwitcherFeatureEnabled());
|
||||
mFeatureController.addCallback(enabled -> mView.setKeyguardUserAvatarEnabled(!enabled));
|
||||
!mStatusBarUserChipViewModel.getChipEnabled());
|
||||
mSystemEventAnimator = new StatusBarSystemEventAnimator(mView, r);
|
||||
|
||||
mDisableStateTracker = new DisableStateTracker(
|
||||
@@ -344,11 +335,11 @@ public class KeyguardStatusBarViewController extends ViewController<KeyguardStat
|
||||
super.onInit();
|
||||
mCarrierTextController.init();
|
||||
mBatteryMeterViewController.init();
|
||||
mUserSwitcherController.init();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onViewAttached() {
|
||||
mView.init(mStatusBarUserChipViewModel);
|
||||
mConfigurationController.addCallback(mConfigurationListener);
|
||||
mAnimationScheduler.addCallback(mAnimationCallback);
|
||||
mUserInfoController.addCallback(mOnUserInfoChangedListener);
|
||||
@@ -394,9 +385,6 @@ 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. */
|
||||
|
||||
@@ -38,6 +38,9 @@ import com.android.systemui.Dependency;
|
||||
import com.android.systemui.R;
|
||||
import com.android.systemui.plugins.DarkIconDispatcher;
|
||||
import com.android.systemui.plugins.DarkIconDispatcher.DarkReceiver;
|
||||
import com.android.systemui.statusbar.phone.userswitcher.StatusBarUserSwitcherContainer;
|
||||
import com.android.systemui.user.ui.binder.StatusBarUserChipViewBinder;
|
||||
import com.android.systemui.user.ui.viewmodel.StatusBarUserChipViewModel;
|
||||
import com.android.systemui.util.leak.RotationUtils;
|
||||
|
||||
import java.util.Objects;
|
||||
@@ -73,6 +76,11 @@ public class PhoneStatusBarView extends FrameLayout {
|
||||
mTouchEventHandler = handler;
|
||||
}
|
||||
|
||||
void init(StatusBarUserChipViewModel viewModel) {
|
||||
StatusBarUserSwitcherContainer container = findViewById(R.id.user_switcher_container);
|
||||
StatusBarUserChipViewBinder.bind(container, viewModel);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFinishInflate() {
|
||||
super.onFinishInflate();
|
||||
|
||||
@@ -23,11 +23,11 @@ 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.user.ui.viewmodel.StatusBarUserChipViewModel
|
||||
import com.android.systemui.util.ViewController
|
||||
import com.android.systemui.util.kotlin.getOrNull
|
||||
import com.android.systemui.util.view.ViewUtil
|
||||
@@ -40,7 +40,7 @@ class PhoneStatusBarViewController private constructor(
|
||||
view: PhoneStatusBarView,
|
||||
@Named(UNFOLD_STATUS_BAR) private val progressProvider: ScopedUnfoldTransitionProgressProvider?,
|
||||
private val moveFromCenterAnimationController: StatusBarMoveFromCenterAnimationController?,
|
||||
private val userSwitcherController: StatusBarUserSwitcherController,
|
||||
private val userChipViewModel: StatusBarUserChipViewModel,
|
||||
private val viewUtil: ViewUtil,
|
||||
touchEventHandler: PhoneStatusBarView.TouchEventHandler,
|
||||
private val configurationController: ConfigurationController
|
||||
@@ -91,10 +91,10 @@ class PhoneStatusBarViewController private constructor(
|
||||
|
||||
init {
|
||||
mView.setTouchEventHandler(touchEventHandler)
|
||||
mView.init(userChipViewModel)
|
||||
}
|
||||
|
||||
override fun onInit() {
|
||||
userSwitcherController.init()
|
||||
}
|
||||
|
||||
fun setImportantForAccessibility(mode: Int) {
|
||||
@@ -156,9 +156,9 @@ class PhoneStatusBarViewController private constructor(
|
||||
private val unfoldComponent: Optional<SysUIUnfoldComponent>,
|
||||
@Named(UNFOLD_STATUS_BAR)
|
||||
private val progressProvider: Optional<ScopedUnfoldTransitionProgressProvider>,
|
||||
private val userSwitcherController: StatusBarUserSwitcherController,
|
||||
private val userChipViewModel: StatusBarUserChipViewModel,
|
||||
private val viewUtil: ViewUtil,
|
||||
private val configurationController: ConfigurationController
|
||||
private val configurationController: ConfigurationController,
|
||||
) {
|
||||
fun create(
|
||||
view: PhoneStatusBarView,
|
||||
@@ -168,7 +168,7 @@ class PhoneStatusBarViewController private constructor(
|
||||
view,
|
||||
progressProvider.getOrNull(),
|
||||
unfoldComponent.getOrNull()?.getStatusBarMoveFromCenterAnimationController(),
|
||||
userSwitcherController,
|
||||
userChipViewModel,
|
||||
viewUtil,
|
||||
touchEventHandler,
|
||||
configurationController
|
||||
|
||||
@@ -29,8 +29,6 @@ import com.android.systemui.statusbar.phone.PhoneStatusBarViewController;
|
||||
import com.android.systemui.statusbar.phone.StatusBarBoundsProvider;
|
||||
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;
|
||||
|
||||
@@ -39,7 +37,6 @@ import java.util.Set;
|
||||
|
||||
import javax.inject.Named;
|
||||
|
||||
import dagger.Binds;
|
||||
import dagger.Module;
|
||||
import dagger.Provides;
|
||||
import dagger.multibindings.Multibinds;
|
||||
@@ -125,12 +122,6 @@ public interface StatusBarFragmentModule {
|
||||
return view.findViewById(R.id.user_switcher_container);
|
||||
}
|
||||
|
||||
/** */
|
||||
@Binds
|
||||
@StatusBarFragmentScope
|
||||
StatusBarUserSwitcherController bindStatusBarUserSwitcherController(
|
||||
StatusBarUserSwitcherControllerImpl controller);
|
||||
|
||||
/** */
|
||||
@Provides
|
||||
@StatusBarFragmentScope
|
||||
|
||||
@@ -1,134 +0,0 @@
|
||||
/*
|
||||
* 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.Dumpable
|
||||
import com.android.systemui.dagger.SysUISingleton
|
||||
import com.android.systemui.dagger.qualifiers.Background
|
||||
import com.android.systemui.dagger.qualifiers.Main
|
||||
import com.android.systemui.dump.DumpManager
|
||||
import com.android.systemui.statusbar.policy.CallbackController
|
||||
import com.android.systemui.statusbar.policy.UserInfoController
|
||||
import com.android.systemui.statusbar.policy.UserInfoController.OnUserInfoChangedListener
|
||||
import java.io.PrintWriter
|
||||
import java.util.concurrent.Executor
|
||||
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,
|
||||
private val dumpManager: DumpManager,
|
||||
@Main private val mainExecutor: Executor,
|
||||
@Background private val backgroundExecutor: Executor
|
||||
) : CallbackController<CurrentUserChipInfoUpdatedListener>, Dumpable {
|
||||
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 {
|
||||
dumpManager.registerDumpable(TAG, this)
|
||||
}
|
||||
|
||||
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)
|
||||
}
|
||||
|
||||
/**
|
||||
* Force a check to [UserManager.isUserSwitcherEnabled], and update listeners if the value has
|
||||
* changed
|
||||
*/
|
||||
fun checkEnabled() {
|
||||
backgroundExecutor.execute {
|
||||
// Check on a background thread to avoid main thread Binder calls
|
||||
val wasEnabled = userSwitcherEnabled
|
||||
userSwitcherEnabled = userManager.isUserSwitcherEnabled
|
||||
|
||||
if (wasEnabled != userSwitcherEnabled) {
|
||||
mainExecutor.execute {
|
||||
notifyListenersSettingChanged()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun dump(pw: PrintWriter, args: Array<out String>) {
|
||||
pw.println(" userSwitcherEnabled=$userSwitcherEnabled")
|
||||
pw.println(" listening=$listening")
|
||||
}
|
||||
}
|
||||
|
||||
interface CurrentUserChipInfoUpdatedListener {
|
||||
fun onCurrentUserChipInfoUpdated()
|
||||
fun onStatusBarUserSwitcherSettingChanged(enabled: Boolean) {}
|
||||
}
|
||||
|
||||
private const val TAG = "StatusBarUserInfoTracker"
|
||||
@@ -1,112 +0,0 @@
|
||||
/*
|
||||
* 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.Intent
|
||||
import android.os.UserHandle
|
||||
import android.view.View
|
||||
import com.android.systemui.animation.Expandable
|
||||
import com.android.systemui.flags.FeatureFlags
|
||||
import com.android.systemui.flags.Flags
|
||||
import com.android.systemui.plugins.ActivityStarter
|
||||
import com.android.systemui.plugins.FalsingManager
|
||||
|
||||
import com.android.systemui.qs.user.UserSwitchDialogController
|
||||
import com.android.systemui.user.UserSwitcherActivity
|
||||
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,
|
||||
private val featureFlags: FeatureFlags,
|
||||
private val activityStarter: ActivityStarter,
|
||||
private val falsingManager: FalsingManager
|
||||
) : 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()
|
||||
}
|
||||
}
|
||||
|
||||
public override fun onViewAttached() {
|
||||
tracker.addCallback(listener)
|
||||
featureController.addCallback(featureFlagListener)
|
||||
mView.setOnClickListener { view: View ->
|
||||
if (falsingManager.isFalseTap(FalsingManager.LOW_PENALTY)) {
|
||||
return@setOnClickListener
|
||||
}
|
||||
|
||||
if (featureFlags.isEnabled(Flags.FULL_SCREEN_USER_SWITCHER)) {
|
||||
val intent = Intent(context, UserSwitcherActivity::class.java)
|
||||
intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP or Intent.FLAG_ACTIVITY_NEW_TASK)
|
||||
|
||||
activityStarter.startActivity(intent, true /* dismissShade */,
|
||||
null /* ActivityLaunchAnimator.Controller */,
|
||||
true /* showOverlockscreenwhenlocked */, UserHandle.SYSTEM)
|
||||
} else {
|
||||
userSwitcherDialogController.showDialog(view.context, Expandable.fromView(view))
|
||||
}
|
||||
}
|
||||
|
||||
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"
|
||||
@@ -1,63 +0,0 @@
|
||||
/*
|
||||
* 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)
|
||||
}
|
||||
@@ -23,6 +23,7 @@ import android.os.UserHandle
|
||||
import android.os.UserManager
|
||||
import android.provider.Settings
|
||||
import androidx.annotation.VisibleForTesting
|
||||
import com.android.systemui.R
|
||||
import com.android.systemui.common.coroutine.ChannelExt.trySendWithFailureLogging
|
||||
import com.android.systemui.common.coroutine.ConflatedCallbackFlow.conflatedCallbackFlow
|
||||
import com.android.systemui.dagger.SysUISingleton
|
||||
@@ -79,6 +80,9 @@ interface UserRepository {
|
||||
/** Whether we've scheduled the creation of a guest user. */
|
||||
val isGuestUserCreationScheduled: AtomicBoolean
|
||||
|
||||
/** Whether to enable the status bar user chip (which launches the user switcher) */
|
||||
val isStatusBarUserChipEnabled: Boolean
|
||||
|
||||
/** The user of the secondary service. */
|
||||
var secondaryUserId: Int
|
||||
|
||||
@@ -127,6 +131,9 @@ constructor(
|
||||
|
||||
override val isGuestUserCreationScheduled = AtomicBoolean()
|
||||
|
||||
override val isStatusBarUserChipEnabled: Boolean =
|
||||
appContext.resources.getBoolean(R.bool.flag_user_switcher_chip)
|
||||
|
||||
override var secondaryUserId: Int = UserHandle.USER_NULL
|
||||
|
||||
override var isRefreshUsersPaused: Boolean = false
|
||||
|
||||
@@ -34,15 +34,19 @@ import android.util.Log
|
||||
import com.android.internal.util.UserIcons
|
||||
import com.android.systemui.R
|
||||
import com.android.systemui.SystemUISecondaryUserService
|
||||
import com.android.systemui.animation.Expandable
|
||||
import com.android.systemui.broadcast.BroadcastDispatcher
|
||||
import com.android.systemui.common.shared.model.Text
|
||||
import com.android.systemui.dagger.SysUISingleton
|
||||
import com.android.systemui.dagger.qualifiers.Application
|
||||
import com.android.systemui.dagger.qualifiers.Background
|
||||
import com.android.systemui.flags.FeatureFlags
|
||||
import com.android.systemui.flags.Flags
|
||||
import com.android.systemui.keyguard.domain.interactor.KeyguardInteractor
|
||||
import com.android.systemui.plugins.ActivityStarter
|
||||
import com.android.systemui.qs.user.UserSwitchDialogController
|
||||
import com.android.systemui.telephony.domain.interactor.TelephonyInteractor
|
||||
import com.android.systemui.user.UserSwitcherActivity
|
||||
import com.android.systemui.user.data.model.UserSwitcherSettingsModel
|
||||
import com.android.systemui.user.data.repository.UserRepository
|
||||
import com.android.systemui.user.data.source.UserRecord
|
||||
@@ -81,6 +85,7 @@ constructor(
|
||||
private val repository: UserRepository,
|
||||
private val activityStarter: ActivityStarter,
|
||||
private val keyguardInteractor: KeyguardInteractor,
|
||||
private val featureFlags: FeatureFlags,
|
||||
private val manager: UserManager,
|
||||
@Application private val applicationScope: CoroutineScope,
|
||||
telephonyInteractor: TelephonyInteractor,
|
||||
@@ -256,6 +261,9 @@ constructor(
|
||||
/** Whether the guest user is currently being reset. */
|
||||
val isGuestUserResetting: Boolean = guestUserInteractor.isGuestUserResetting
|
||||
|
||||
/** Whether to enable the user chip in the status bar */
|
||||
val isStatusBarUserChipEnabled: Boolean = repository.isStatusBarUserChipEnabled
|
||||
|
||||
private val _dialogShowRequests = MutableStateFlow<ShowDialogRequestModel?>(null)
|
||||
val dialogShowRequests: Flow<ShowDialogRequestModel?> = _dialogShowRequests.asStateFlow()
|
||||
|
||||
@@ -468,6 +476,26 @@ constructor(
|
||||
}
|
||||
}
|
||||
|
||||
fun showUserSwitcher(context: Context, expandable: Expandable) {
|
||||
if (!featureFlags.isEnabled(Flags.FULL_SCREEN_USER_SWITCHER)) {
|
||||
showDialog(ShowDialogRequestModel.ShowUserSwitcherDialog)
|
||||
return
|
||||
}
|
||||
|
||||
val intent =
|
||||
Intent(context, UserSwitcherActivity::class.java).apply {
|
||||
addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP or Intent.FLAG_ACTIVITY_NEW_TASK)
|
||||
}
|
||||
|
||||
activityStarter.startActivity(
|
||||
intent,
|
||||
true /* dismissShade */,
|
||||
expandable.activityLaunchController(),
|
||||
true /* showOverlockscreenwhenlocked */,
|
||||
UserHandle.SYSTEM,
|
||||
)
|
||||
}
|
||||
|
||||
private fun showDialog(request: ShowDialogRequestModel) {
|
||||
_dialogShowRequests.value = request
|
||||
}
|
||||
|
||||
@@ -43,4 +43,7 @@ sealed class ShowDialogRequestModel(
|
||||
val onExitGuestUser: (guestId: Int, targetId: Int, forceRemoveGuest: Boolean) -> Unit,
|
||||
override val dialogShower: UserSwitchDialogController.DialogShower?,
|
||||
) : ShowDialogRequestModel(dialogShower)
|
||||
|
||||
/** Show the user switcher dialog */
|
||||
object ShowUserSwitcherDialog : ShowDialogRequestModel()
|
||||
}
|
||||
|
||||
@@ -0,0 +1,65 @@
|
||||
/*
|
||||
* 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.user.ui.binder
|
||||
|
||||
import androidx.core.view.isVisible
|
||||
import androidx.lifecycle.Lifecycle
|
||||
import androidx.lifecycle.repeatOnLifecycle
|
||||
import com.android.systemui.animation.Expandable
|
||||
import com.android.systemui.common.ui.binder.TextViewBinder
|
||||
import com.android.systemui.lifecycle.repeatWhenAttached
|
||||
import com.android.systemui.statusbar.phone.userswitcher.StatusBarUserSwitcherContainer
|
||||
import com.android.systemui.user.ui.viewmodel.StatusBarUserChipViewModel
|
||||
import kotlinx.coroutines.InternalCoroutinesApi
|
||||
import kotlinx.coroutines.flow.collect
|
||||
import kotlinx.coroutines.launch
|
||||
|
||||
@OptIn(InternalCoroutinesApi::class)
|
||||
object StatusBarUserChipViewBinder {
|
||||
/** Binds the status bar user chip view model to the given view */
|
||||
@JvmStatic
|
||||
fun bind(
|
||||
view: StatusBarUserSwitcherContainer,
|
||||
viewModel: StatusBarUserChipViewModel,
|
||||
) {
|
||||
view.repeatWhenAttached {
|
||||
repeatOnLifecycle(Lifecycle.State.STARTED) {
|
||||
launch {
|
||||
viewModel.isChipVisible.collect { isVisible -> view.isVisible = isVisible }
|
||||
}
|
||||
|
||||
launch {
|
||||
viewModel.userName.collect { name -> TextViewBinder.bind(view.text, name) }
|
||||
}
|
||||
|
||||
launch {
|
||||
viewModel.userAvatar.collect { avatar -> view.avatar.setImageDrawable(avatar) }
|
||||
}
|
||||
|
||||
bindButton(view, viewModel)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun bindButton(
|
||||
view: StatusBarUserSwitcherContainer,
|
||||
viewModel: StatusBarUserChipViewModel,
|
||||
) {
|
||||
view.setOnClickListener { viewModel.onClick(Expandable.fromView(view)) }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,68 @@
|
||||
package com.android.systemui.user.ui.dialog
|
||||
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.provider.Settings
|
||||
import android.view.LayoutInflater
|
||||
import com.android.internal.logging.UiEventLogger
|
||||
import com.android.systemui.R
|
||||
import com.android.systemui.animation.DialogLaunchAnimator
|
||||
import com.android.systemui.plugins.ActivityStarter
|
||||
import com.android.systemui.plugins.FalsingManager
|
||||
import com.android.systemui.qs.QSUserSwitcherEvent
|
||||
import com.android.systemui.qs.tiles.UserDetailView
|
||||
import com.android.systemui.statusbar.phone.SystemUIDialog
|
||||
|
||||
/**
|
||||
* Extracted from the old UserSwitchDialogController. This is the dialog version of the full-screen
|
||||
* user switcher. See config_enableFullscreenUserSwitcher
|
||||
*/
|
||||
class UserSwitchDialog(
|
||||
context: Context,
|
||||
adapter: UserDetailView.Adapter,
|
||||
uiEventLogger: UiEventLogger,
|
||||
falsingManager: FalsingManager,
|
||||
activityStarter: ActivityStarter,
|
||||
dialogLaunchAnimator: DialogLaunchAnimator,
|
||||
) : SystemUIDialog(context) {
|
||||
init {
|
||||
setShowForAllUsers(true)
|
||||
setCanceledOnTouchOutside(true)
|
||||
setTitle(R.string.qs_user_switch_dialog_title)
|
||||
setPositiveButton(R.string.quick_settings_done) { _, _ ->
|
||||
uiEventLogger.log(QSUserSwitcherEvent.QS_USER_DETAIL_CLOSE)
|
||||
}
|
||||
setNeutralButton(
|
||||
R.string.quick_settings_more_user_settings,
|
||||
{ _, _ ->
|
||||
if (!falsingManager.isFalseTap(FalsingManager.LOW_PENALTY)) {
|
||||
uiEventLogger.log(QSUserSwitcherEvent.QS_USER_MORE_SETTINGS)
|
||||
val controller =
|
||||
dialogLaunchAnimator.createActivityLaunchController(
|
||||
getButton(BUTTON_NEUTRAL)
|
||||
)
|
||||
|
||||
if (controller == null) {
|
||||
dismiss()
|
||||
}
|
||||
|
||||
activityStarter.postStartActivityDismissingKeyguard(
|
||||
USER_SETTINGS_INTENT,
|
||||
0,
|
||||
controller
|
||||
)
|
||||
}
|
||||
},
|
||||
false /* dismissOnClick */
|
||||
)
|
||||
val gridFrame =
|
||||
LayoutInflater.from(this.context).inflate(R.layout.qs_user_dialog_content, null)
|
||||
setView(gridFrame)
|
||||
|
||||
adapter.linkToViewGroup(gridFrame.findViewById(R.id.grid))
|
||||
}
|
||||
|
||||
companion object {
|
||||
private val USER_SETTINGS_INTENT = Intent(Settings.ACTION_USER_SETTINGS)
|
||||
}
|
||||
}
|
||||
@@ -20,6 +20,7 @@ package com.android.systemui.user.ui.dialog
|
||||
import android.app.Dialog
|
||||
import android.content.Context
|
||||
import com.android.internal.jank.InteractionJankMonitor
|
||||
import com.android.internal.logging.UiEventLogger
|
||||
import com.android.settingslib.users.UserCreatingDialog
|
||||
import com.android.systemui.CoreStartable
|
||||
import com.android.systemui.animation.DialogCuj
|
||||
@@ -27,11 +28,14 @@ import com.android.systemui.animation.DialogLaunchAnimator
|
||||
import com.android.systemui.broadcast.BroadcastSender
|
||||
import com.android.systemui.dagger.SysUISingleton
|
||||
import com.android.systemui.dagger.qualifiers.Application
|
||||
import com.android.systemui.plugins.ActivityStarter
|
||||
import com.android.systemui.plugins.FalsingManager
|
||||
import com.android.systemui.qs.tiles.UserDetailView
|
||||
import com.android.systemui.user.domain.interactor.UserInteractor
|
||||
import com.android.systemui.user.domain.model.ShowDialogRequestModel
|
||||
import dagger.Lazy
|
||||
import javax.inject.Inject
|
||||
import javax.inject.Provider
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.flow.filterNotNull
|
||||
import kotlinx.coroutines.launch
|
||||
@@ -47,6 +51,9 @@ constructor(
|
||||
private val broadcastSender: Lazy<BroadcastSender>,
|
||||
private val dialogLaunchAnimator: Lazy<DialogLaunchAnimator>,
|
||||
private val interactor: Lazy<UserInteractor>,
|
||||
private val userDetailAdapterProvider: Provider<UserDetailView.Adapter>,
|
||||
private val eventLogger: Lazy<UiEventLogger>,
|
||||
private val activityStarter: Lazy<ActivityStarter>,
|
||||
) : CoreStartable {
|
||||
|
||||
private var currentDialog: Dialog? = null
|
||||
@@ -108,6 +115,21 @@ constructor(
|
||||
INTERACTION_JANK_EXIT_GUEST_MODE_TAG,
|
||||
),
|
||||
)
|
||||
is ShowDialogRequestModel.ShowUserSwitcherDialog ->
|
||||
Pair(
|
||||
UserSwitchDialog(
|
||||
context = context.get(),
|
||||
adapter = userDetailAdapterProvider.get(),
|
||||
uiEventLogger = eventLogger.get(),
|
||||
falsingManager = falsingManager.get(),
|
||||
activityStarter = activityStarter.get(),
|
||||
dialogLaunchAnimator = dialogLaunchAnimator.get(),
|
||||
),
|
||||
DialogCuj(
|
||||
InteractionJankMonitor.CUJ_USER_DIALOG_OPEN,
|
||||
INTERACTION_JANK_EXIT_GUEST_MODE_TAG,
|
||||
),
|
||||
)
|
||||
}
|
||||
currentDialog = dialog
|
||||
|
||||
|
||||
@@ -0,0 +1,59 @@
|
||||
/*
|
||||
* 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.user.ui.viewmodel
|
||||
|
||||
import android.content.Context
|
||||
import android.graphics.drawable.Drawable
|
||||
import com.android.systemui.animation.Expandable
|
||||
import com.android.systemui.common.shared.model.Text
|
||||
import com.android.systemui.dagger.qualifiers.Application
|
||||
import com.android.systemui.user.domain.interactor.UserInteractor
|
||||
import javax.inject.Inject
|
||||
import kotlinx.coroutines.ExperimentalCoroutinesApi
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
import kotlinx.coroutines.flow.flowOf
|
||||
import kotlinx.coroutines.flow.mapLatest
|
||||
|
||||
@OptIn(ExperimentalCoroutinesApi::class)
|
||||
class StatusBarUserChipViewModel
|
||||
@Inject
|
||||
constructor(
|
||||
@Application private val context: Context,
|
||||
interactor: UserInteractor,
|
||||
) {
|
||||
/** Whether the status bar chip ui should be available */
|
||||
val chipEnabled: Boolean = interactor.isStatusBarUserChipEnabled
|
||||
|
||||
/** Whether or not the chip should be showing, based on the number of users */
|
||||
val isChipVisible: Flow<Boolean> =
|
||||
if (!chipEnabled) {
|
||||
flowOf(false)
|
||||
} else {
|
||||
interactor.users.mapLatest { users -> users.size > 1 }
|
||||
}
|
||||
|
||||
/** The display name of the current user */
|
||||
val userName: Flow<Text> = interactor.selectedUser.mapLatest { userModel -> userModel.name }
|
||||
|
||||
/** Avatar for the current user */
|
||||
val userAvatar: Flow<Drawable> =
|
||||
interactor.selectedUser.mapLatest { userModel -> userModel.image }
|
||||
|
||||
/** Action to execute on click. Should launch the user switcher */
|
||||
val onClick: (Expandable) -> Unit = { interactor.showUserSwitcher(context, it) }
|
||||
}
|
||||
@@ -16,10 +16,8 @@
|
||||
|
||||
package com.android.systemui.qs.footer.domain.interactor
|
||||
|
||||
import android.content.ComponentName
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.os.UserHandle
|
||||
import android.provider.Settings
|
||||
import android.testing.AndroidTestingRunner
|
||||
import android.testing.TestableLooper
|
||||
@@ -30,17 +28,13 @@ import com.android.internal.logging.testing.UiEventLoggerFake
|
||||
import com.android.systemui.SysuiTestCase
|
||||
import com.android.systemui.animation.ActivityLaunchAnimator
|
||||
import com.android.systemui.animation.Expandable
|
||||
import com.android.systemui.flags.FakeFeatureFlags
|
||||
import com.android.systemui.flags.Flags
|
||||
import com.android.systemui.globalactions.GlobalActionsDialogLite
|
||||
import com.android.systemui.plugins.ActivityStarter
|
||||
import com.android.systemui.qs.QSSecurityFooterUtils
|
||||
import com.android.systemui.qs.footer.FooterActionsTestUtils
|
||||
import com.android.systemui.qs.user.UserSwitchDialogController
|
||||
import com.android.systemui.statusbar.policy.DeviceProvisionedController
|
||||
import com.android.systemui.truth.correspondence.FakeUiEvent
|
||||
import com.android.systemui.truth.correspondence.LogMaker
|
||||
import com.android.systemui.user.UserSwitcherActivity
|
||||
import com.android.systemui.util.mockito.any
|
||||
import com.android.systemui.util.mockito.argumentCaptor
|
||||
import com.android.systemui.util.mockito.eq
|
||||
@@ -156,54 +150,4 @@ class FooterActionsInteractorTest : SysuiTestCase() {
|
||||
// We only unlock the device.
|
||||
verify(activityStarter).postQSRunnableDismissingKeyguard(any())
|
||||
}
|
||||
|
||||
@Test
|
||||
fun showUserSwitcher_fullScreenDisabled() {
|
||||
val featureFlags = FakeFeatureFlags().apply { set(Flags.FULL_SCREEN_USER_SWITCHER, false) }
|
||||
val userSwitchDialogController = mock<UserSwitchDialogController>()
|
||||
val underTest =
|
||||
utils.footerActionsInteractor(
|
||||
featureFlags = featureFlags,
|
||||
userSwitchDialogController = userSwitchDialogController,
|
||||
)
|
||||
|
||||
val expandable = mock<Expandable>()
|
||||
underTest.showUserSwitcher(context, expandable)
|
||||
|
||||
// Dialog is shown.
|
||||
verify(userSwitchDialogController).showDialog(context, expandable)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun showUserSwitcher_fullScreenEnabled() {
|
||||
val featureFlags = FakeFeatureFlags().apply { set(Flags.FULL_SCREEN_USER_SWITCHER, true) }
|
||||
val activityStarter = mock<ActivityStarter>()
|
||||
val underTest =
|
||||
utils.footerActionsInteractor(
|
||||
featureFlags = featureFlags,
|
||||
activityStarter = activityStarter,
|
||||
)
|
||||
|
||||
// The clicked expandable.
|
||||
val expandable = mock<Expandable>()
|
||||
underTest.showUserSwitcher(context, expandable)
|
||||
|
||||
// Dialog is shown.
|
||||
val intentCaptor = argumentCaptor<Intent>()
|
||||
verify(activityStarter)
|
||||
.startActivity(
|
||||
intentCaptor.capture(),
|
||||
/* dismissShade= */ eq(true),
|
||||
/* ActivityLaunchAnimator.Controller= */ nullable(),
|
||||
/* showOverLockscreenWhenLocked= */ eq(true),
|
||||
eq(UserHandle.SYSTEM),
|
||||
)
|
||||
assertThat(intentCaptor.value.component)
|
||||
.isEqualTo(
|
||||
ComponentName(
|
||||
context,
|
||||
UserSwitcherActivity::class.java,
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -56,14 +56,12 @@ import com.android.systemui.shade.NotificationPanelViewController;
|
||||
import com.android.systemui.statusbar.CommandQueue;
|
||||
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;
|
||||
import com.android.systemui.statusbar.policy.KeyguardStateController;
|
||||
import com.android.systemui.statusbar.policy.UserInfoController;
|
||||
import com.android.systemui.user.ui.viewmodel.StatusBarUserChipViewModel;
|
||||
import com.android.systemui.util.concurrency.FakeExecutor;
|
||||
import com.android.systemui.util.settings.SecureSettings;
|
||||
import com.android.systemui.util.time.FakeSystemClock;
|
||||
@@ -112,16 +110,12 @@ public class KeyguardStatusBarViewControllerTest extends SysuiTestCase {
|
||||
private StatusBarContentInsetsProvider mStatusBarContentInsetsProvider;
|
||||
@Mock
|
||||
private UserManager mUserManager;
|
||||
@Mock
|
||||
private StatusBarUserChipViewModel mStatusBarUserChipViewModel;
|
||||
@Captor
|
||||
private ArgumentCaptor<ConfigurationListener> mConfigurationListenerCaptor;
|
||||
@Captor
|
||||
private ArgumentCaptor<KeyguardUpdateMonitorCallback> mKeyguardCallbackCaptor;
|
||||
@Mock
|
||||
private StatusBarUserSwitcherFeatureController mStatusBarUserSwitcherFeatureController;
|
||||
@Mock
|
||||
private StatusBarUserSwitcherController mStatusBarUserSwitcherController;
|
||||
@Mock
|
||||
private StatusBarUserInfoTracker mStatusBarUserInfoTracker;
|
||||
@Mock private SecureSettings mSecureSettings;
|
||||
@Mock private CommandQueue mCommandQueue;
|
||||
@Mock private KeyguardLogger mLogger;
|
||||
@@ -169,9 +163,7 @@ public class KeyguardStatusBarViewControllerTest extends SysuiTestCase {
|
||||
mStatusBarStateController,
|
||||
mStatusBarContentInsetsProvider,
|
||||
mUserManager,
|
||||
mStatusBarUserSwitcherFeatureController,
|
||||
mStatusBarUserSwitcherController,
|
||||
mStatusBarUserInfoTracker,
|
||||
mStatusBarUserChipViewModel,
|
||||
mSecureSettings,
|
||||
mCommandQueue,
|
||||
mFakeExecutor,
|
||||
@@ -479,8 +471,7 @@ public class KeyguardStatusBarViewControllerTest extends SysuiTestCase {
|
||||
@Test
|
||||
public void testNewUserSwitcherDisablesAvatar_newUiOn() {
|
||||
// GIVEN the status bar user switcher chip is enabled
|
||||
when(mStatusBarUserSwitcherFeatureController.isStatusBarUserSwitcherFeatureEnabled())
|
||||
.thenReturn(true);
|
||||
when(mStatusBarUserChipViewModel.getChipEnabled()).thenReturn(true);
|
||||
|
||||
// WHEN the controller is created
|
||||
mController = createController();
|
||||
@@ -492,8 +483,7 @@ public class KeyguardStatusBarViewControllerTest extends SysuiTestCase {
|
||||
@Test
|
||||
public void testNewUserSwitcherDisablesAvatar_newUiOff() {
|
||||
// GIVEN the status bar user switcher chip is disabled
|
||||
when(mStatusBarUserSwitcherFeatureController.isStatusBarUserSwitcherFeatureEnabled())
|
||||
.thenReturn(false);
|
||||
when(mStatusBarUserChipViewModel.getChipEnabled()).thenReturn(false);
|
||||
|
||||
// WHEN the controller is created
|
||||
mController = createController();
|
||||
|
||||
@@ -27,11 +27,11 @@ import androidx.test.platform.app.InstrumentationRegistry
|
||||
import com.android.systemui.R
|
||||
import com.android.systemui.SysuiTestCase
|
||||
import com.android.systemui.shade.NotificationPanelViewController
|
||||
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
|
||||
import com.android.systemui.unfold.util.ScopedUnfoldTransitionProgressProvider
|
||||
import com.android.systemui.user.ui.viewmodel.StatusBarUserChipViewModel
|
||||
import com.android.systemui.util.mockito.any
|
||||
import com.android.systemui.util.view.ViewUtil
|
||||
import com.google.common.truth.Truth.assertThat
|
||||
@@ -64,7 +64,7 @@ class PhoneStatusBarViewControllerTest : SysuiTestCase() {
|
||||
@Mock
|
||||
private lateinit var configurationController: ConfigurationController
|
||||
@Mock
|
||||
private lateinit var userSwitcherController: StatusBarUserSwitcherController
|
||||
private lateinit var userChipViewModel: StatusBarUserChipViewModel
|
||||
@Mock
|
||||
private lateinit var viewUtil: ViewUtil
|
||||
|
||||
@@ -79,14 +79,13 @@ class PhoneStatusBarViewControllerTest : SysuiTestCase() {
|
||||
`when`(notificationPanelViewController.view).thenReturn(panelView)
|
||||
`when`(sysuiUnfoldComponent.getStatusBarMoveFromCenterAnimationController())
|
||||
.thenReturn(moveFromCenterAnimation)
|
||||
// create the view on main thread as it requires main looper
|
||||
// create the view and controller on main thread as it requires main looper
|
||||
InstrumentationRegistry.getInstrumentation().runOnMainSync {
|
||||
val parent = FrameLayout(mContext) // add parent to keep layout params
|
||||
view = LayoutInflater.from(mContext)
|
||||
.inflate(R.layout.status_bar, parent, false) as PhoneStatusBarView
|
||||
controller = createAndInitController(view)
|
||||
}
|
||||
|
||||
controller = createAndInitController(view)
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -106,7 +105,10 @@ class PhoneStatusBarViewControllerTest : SysuiTestCase() {
|
||||
val view = createViewMock()
|
||||
val argumentCaptor = ArgumentCaptor.forClass(OnPreDrawListener::class.java)
|
||||
unfoldConfig.isEnabled = true
|
||||
controller = createAndInitController(view)
|
||||
// create the controller on main thread as it requires main looper
|
||||
InstrumentationRegistry.getInstrumentation().runOnMainSync {
|
||||
controller = createAndInitController(view)
|
||||
}
|
||||
|
||||
verify(view.viewTreeObserver).addOnPreDrawListener(argumentCaptor.capture())
|
||||
argumentCaptor.value.onPreDraw()
|
||||
@@ -126,7 +128,7 @@ class PhoneStatusBarViewControllerTest : SysuiTestCase() {
|
||||
return PhoneStatusBarViewController.Factory(
|
||||
Optional.of(sysuiUnfoldComponent),
|
||||
Optional.of(progressProvider),
|
||||
userSwitcherController,
|
||||
userChipViewModel,
|
||||
viewUtil,
|
||||
configurationController
|
||||
).create(view, touchEventHandler).also {
|
||||
|
||||
@@ -1,102 +0,0 @@
|
||||
/*
|
||||
* 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.Intent
|
||||
import android.os.UserHandle
|
||||
import android.testing.AndroidTestingRunner
|
||||
import android.testing.TestableLooper
|
||||
import androidx.test.filters.SmallTest
|
||||
import com.android.systemui.SysuiTestCase
|
||||
import com.android.systemui.flags.FeatureFlags
|
||||
import com.android.systemui.flags.Flags
|
||||
import com.android.systemui.plugins.ActivityStarter
|
||||
import com.android.systemui.plugins.FalsingManager
|
||||
import com.android.systemui.qs.user.UserSwitchDialogController
|
||||
import com.android.systemui.util.mockito.any
|
||||
import com.android.systemui.util.mockito.eq
|
||||
import org.junit.Before
|
||||
import org.junit.Test
|
||||
import org.junit.runner.RunWith
|
||||
import org.mockito.Mock
|
||||
import org.mockito.Mockito.`when`
|
||||
import org.mockito.Mockito.verify
|
||||
import org.mockito.MockitoAnnotations
|
||||
|
||||
@RunWith(AndroidTestingRunner::class)
|
||||
@TestableLooper.RunWithLooper
|
||||
@SmallTest
|
||||
class StatusBarUserSwitcherControllerOldImplTest : SysuiTestCase() {
|
||||
@Mock
|
||||
private lateinit var tracker: StatusBarUserInfoTracker
|
||||
|
||||
@Mock
|
||||
private lateinit var featureController: StatusBarUserSwitcherFeatureController
|
||||
|
||||
@Mock
|
||||
private lateinit var userSwitcherDialogController: UserSwitchDialogController
|
||||
|
||||
@Mock
|
||||
private lateinit var featureFlags: FeatureFlags
|
||||
|
||||
@Mock
|
||||
private lateinit var activityStarter: ActivityStarter
|
||||
|
||||
@Mock
|
||||
private lateinit var falsingManager: FalsingManager
|
||||
|
||||
private lateinit var statusBarUserSwitcherContainer: StatusBarUserSwitcherContainer
|
||||
private lateinit var controller: StatusBarUserSwitcherControllerImpl
|
||||
|
||||
@Before
|
||||
fun setup() {
|
||||
MockitoAnnotations.initMocks(this)
|
||||
statusBarUserSwitcherContainer = StatusBarUserSwitcherContainer(mContext, null)
|
||||
statusBarUserSwitcherContainer
|
||||
controller = StatusBarUserSwitcherControllerImpl(
|
||||
statusBarUserSwitcherContainer,
|
||||
tracker,
|
||||
featureController,
|
||||
userSwitcherDialogController,
|
||||
featureFlags,
|
||||
activityStarter,
|
||||
falsingManager
|
||||
)
|
||||
controller.init()
|
||||
controller.onViewAttached()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testFalsingManager() {
|
||||
statusBarUserSwitcherContainer.callOnClick()
|
||||
verify(falsingManager).isFalseTap(FalsingManager.LOW_PENALTY)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testStartActivity() {
|
||||
`when`(featureFlags.isEnabled(Flags.FULL_SCREEN_USER_SWITCHER)).thenReturn(false)
|
||||
statusBarUserSwitcherContainer.callOnClick()
|
||||
verify(userSwitcherDialogController).showDialog(any(), any())
|
||||
`when`(featureFlags.isEnabled(Flags.FULL_SCREEN_USER_SWITCHER)).thenReturn(true)
|
||||
statusBarUserSwitcherContainer.callOnClick()
|
||||
verify(activityStarter).startActivity(any(Intent::class.java),
|
||||
eq(true) /* dismissShade */,
|
||||
eq(null) /* animationController */,
|
||||
eq(true) /* showOverLockscreenWhenLocked */,
|
||||
eq(UserHandle.SYSTEM))
|
||||
}
|
||||
}
|
||||
@@ -19,6 +19,7 @@ package com.android.systemui.user.domain.interactor
|
||||
|
||||
import android.app.ActivityManager
|
||||
import android.app.admin.DevicePolicyManager
|
||||
import android.content.ComponentName
|
||||
import android.content.Intent
|
||||
import android.content.pm.UserInfo
|
||||
import android.graphics.Bitmap
|
||||
@@ -33,7 +34,10 @@ import com.android.systemui.GuestResetOrExitSessionReceiver
|
||||
import com.android.systemui.GuestResumeSessionReceiver
|
||||
import com.android.systemui.R
|
||||
import com.android.systemui.SysuiTestCase
|
||||
import com.android.systemui.animation.Expandable
|
||||
import com.android.systemui.common.shared.model.Text
|
||||
import com.android.systemui.flags.FakeFeatureFlags
|
||||
import com.android.systemui.flags.Flags
|
||||
import com.android.systemui.keyguard.data.repository.FakeKeyguardRepository
|
||||
import com.android.systemui.keyguard.domain.interactor.KeyguardInteractor
|
||||
import com.android.systemui.plugins.ActivityStarter
|
||||
@@ -41,6 +45,7 @@ import com.android.systemui.qs.user.UserSwitchDialogController
|
||||
import com.android.systemui.statusbar.policy.DeviceProvisionedController
|
||||
import com.android.systemui.telephony.data.repository.FakeTelephonyRepository
|
||||
import com.android.systemui.telephony.domain.interactor.TelephonyInteractor
|
||||
import com.android.systemui.user.UserSwitcherActivity
|
||||
import com.android.systemui.user.data.model.UserSwitcherSettingsModel
|
||||
import com.android.systemui.user.data.repository.FakeUserRepository
|
||||
import com.android.systemui.user.data.source.UserRecord
|
||||
@@ -48,9 +53,11 @@ import com.android.systemui.user.domain.model.ShowDialogRequestModel
|
||||
import com.android.systemui.user.shared.model.UserActionModel
|
||||
import com.android.systemui.user.shared.model.UserModel
|
||||
import com.android.systemui.util.mockito.any
|
||||
import com.android.systemui.util.mockito.argumentCaptor
|
||||
import com.android.systemui.util.mockito.eq
|
||||
import com.android.systemui.util.mockito.kotlinArgumentCaptor
|
||||
import com.android.systemui.util.mockito.mock
|
||||
import com.android.systemui.util.mockito.nullable
|
||||
import com.android.systemui.util.mockito.whenever
|
||||
import com.google.common.truth.Truth.assertThat
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
@@ -90,6 +97,7 @@ class UserInteractorTest : SysuiTestCase() {
|
||||
private lateinit var userRepository: FakeUserRepository
|
||||
private lateinit var keyguardRepository: FakeKeyguardRepository
|
||||
private lateinit var telephonyRepository: FakeTelephonyRepository
|
||||
private lateinit var featureFlags: FakeFeatureFlags
|
||||
|
||||
@Before
|
||||
fun setUp() {
|
||||
@@ -104,6 +112,7 @@ class UserInteractorTest : SysuiTestCase() {
|
||||
SUPERVISED_USER_CREATION_APP_PACKAGE,
|
||||
)
|
||||
|
||||
featureFlags = FakeFeatureFlags()
|
||||
userRepository = FakeUserRepository()
|
||||
keyguardRepository = FakeKeyguardRepository()
|
||||
telephonyRepository = FakeTelephonyRepository()
|
||||
@@ -147,7 +156,8 @@ class UserInteractorTest : SysuiTestCase() {
|
||||
uiEventLogger = uiEventLogger,
|
||||
resumeSessionReceiver = resumeSessionReceiver,
|
||||
resetOrExitSessionReceiver = resetOrExitSessionReceiver,
|
||||
)
|
||||
),
|
||||
featureFlags = featureFlags,
|
||||
)
|
||||
}
|
||||
|
||||
@@ -715,6 +725,52 @@ class UserInteractorTest : SysuiTestCase() {
|
||||
job.cancel()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `show user switcher - full screen disabled - shows dialog switcher`() =
|
||||
runBlocking(IMMEDIATE) {
|
||||
featureFlags.set(Flags.FULL_SCREEN_USER_SWITCHER, false)
|
||||
|
||||
var dialogRequest: ShowDialogRequestModel? = null
|
||||
val expandable = mock<Expandable>()
|
||||
underTest.showUserSwitcher(context, expandable)
|
||||
|
||||
val job = underTest.dialogShowRequests.onEach { dialogRequest = it }.launchIn(this)
|
||||
|
||||
// Dialog is shown.
|
||||
assertThat(dialogRequest).isEqualTo(ShowDialogRequestModel.ShowUserSwitcherDialog)
|
||||
|
||||
underTest.onDialogShown()
|
||||
assertThat(dialogRequest).isNull()
|
||||
|
||||
job.cancel()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `show user switcher - full screen enabled - launches activity`() {
|
||||
featureFlags.set(Flags.FULL_SCREEN_USER_SWITCHER, true)
|
||||
|
||||
val expandable = mock<Expandable>()
|
||||
underTest.showUserSwitcher(context, expandable)
|
||||
|
||||
// Dialog is shown.
|
||||
val intentCaptor = argumentCaptor<Intent>()
|
||||
verify(activityStarter)
|
||||
.startActivity(
|
||||
intentCaptor.capture(),
|
||||
/* dismissShade= */ eq(true),
|
||||
/* ActivityLaunchAnimator.Controller= */ nullable(),
|
||||
/* showOverLockscreenWhenLocked= */ eq(true),
|
||||
eq(UserHandle.SYSTEM),
|
||||
)
|
||||
assertThat(intentCaptor.value.component)
|
||||
.isEqualTo(
|
||||
ComponentName(
|
||||
context,
|
||||
UserSwitcherActivity::class.java,
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
private fun assertUsers(
|
||||
models: List<UserModel>?,
|
||||
count: Int,
|
||||
|
||||
@@ -0,0 +1,306 @@
|
||||
/*
|
||||
* 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.user.ui.viewmodel
|
||||
|
||||
import android.app.ActivityManager
|
||||
import android.app.admin.DevicePolicyManager
|
||||
import android.content.pm.UserInfo
|
||||
import android.graphics.Bitmap
|
||||
import android.graphics.drawable.BitmapDrawable
|
||||
import android.os.UserManager
|
||||
import androidx.test.filters.SmallTest
|
||||
import com.android.internal.logging.UiEventLogger
|
||||
import com.android.systemui.GuestResetOrExitSessionReceiver
|
||||
import com.android.systemui.GuestResumeSessionReceiver
|
||||
import com.android.systemui.SysuiTestCase
|
||||
import com.android.systemui.common.shared.model.Text
|
||||
import com.android.systemui.flags.FakeFeatureFlags
|
||||
import com.android.systemui.keyguard.data.repository.FakeKeyguardRepository
|
||||
import com.android.systemui.keyguard.domain.interactor.KeyguardInteractor
|
||||
import com.android.systemui.plugins.ActivityStarter
|
||||
import com.android.systemui.statusbar.policy.DeviceProvisionedController
|
||||
import com.android.systemui.telephony.data.repository.FakeTelephonyRepository
|
||||
import com.android.systemui.telephony.domain.interactor.TelephonyInteractor
|
||||
import com.android.systemui.user.data.model.UserSwitcherSettingsModel
|
||||
import com.android.systemui.user.data.repository.FakeUserRepository
|
||||
import com.android.systemui.user.domain.interactor.GuestUserInteractor
|
||||
import com.android.systemui.user.domain.interactor.RefreshUsersScheduler
|
||||
import com.android.systemui.user.domain.interactor.UserInteractor
|
||||
import com.android.systemui.util.mockito.mock
|
||||
import com.google.common.truth.Truth.assertThat
|
||||
import kotlinx.coroutines.ExperimentalCoroutinesApi
|
||||
import kotlinx.coroutines.flow.launchIn
|
||||
import kotlinx.coroutines.flow.onEach
|
||||
import kotlinx.coroutines.flow.toList
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlinx.coroutines.test.TestScope
|
||||
import kotlinx.coroutines.test.UnconfinedTestDispatcher
|
||||
import kotlinx.coroutines.test.advanceUntilIdle
|
||||
import kotlinx.coroutines.test.runTest
|
||||
import kotlinx.coroutines.yield
|
||||
import org.junit.Before
|
||||
import org.junit.Test
|
||||
import org.junit.runner.RunWith
|
||||
import org.junit.runners.JUnit4
|
||||
import org.mockito.ArgumentMatchers.anyInt
|
||||
import org.mockito.Mock
|
||||
import org.mockito.Mockito.doAnswer
|
||||
import org.mockito.MockitoAnnotations
|
||||
|
||||
@OptIn(ExperimentalCoroutinesApi::class)
|
||||
@SmallTest
|
||||
@RunWith(JUnit4::class)
|
||||
class StatusBarUserChipViewModelTest : SysuiTestCase() {
|
||||
@Mock private lateinit var activityStarter: ActivityStarter
|
||||
@Mock private lateinit var activityManager: ActivityManager
|
||||
@Mock private lateinit var manager: UserManager
|
||||
@Mock private lateinit var deviceProvisionedController: DeviceProvisionedController
|
||||
@Mock private lateinit var devicePolicyManager: DevicePolicyManager
|
||||
@Mock private lateinit var uiEventLogger: UiEventLogger
|
||||
@Mock private lateinit var resumeSessionReceiver: GuestResumeSessionReceiver
|
||||
@Mock private lateinit var resetOrExitSessionReceiver: GuestResetOrExitSessionReceiver
|
||||
|
||||
private lateinit var underTest: StatusBarUserChipViewModel
|
||||
|
||||
private val userRepository = FakeUserRepository()
|
||||
private val keyguardRepository = FakeKeyguardRepository()
|
||||
private val featureFlags = FakeFeatureFlags()
|
||||
private lateinit var guestUserInteractor: GuestUserInteractor
|
||||
private lateinit var refreshUsersScheduler: RefreshUsersScheduler
|
||||
|
||||
private val testDispatcher = UnconfinedTestDispatcher()
|
||||
private val testScope = TestScope(testDispatcher)
|
||||
|
||||
@Before
|
||||
fun setUp() {
|
||||
MockitoAnnotations.initMocks(this)
|
||||
|
||||
doAnswer { invocation ->
|
||||
val userId = invocation.arguments[0] as Int
|
||||
when (userId) {
|
||||
USER_ID_0 -> return@doAnswer USER_IMAGE_0
|
||||
USER_ID_1 -> return@doAnswer USER_IMAGE_1
|
||||
USER_ID_2 -> return@doAnswer USER_IMAGE_2
|
||||
else -> return@doAnswer mock<Bitmap>()
|
||||
}
|
||||
}
|
||||
.`when`(manager)
|
||||
.getUserIcon(anyInt())
|
||||
|
||||
userRepository.isStatusBarUserChipEnabled = true
|
||||
|
||||
refreshUsersScheduler =
|
||||
RefreshUsersScheduler(
|
||||
applicationScope = testScope.backgroundScope,
|
||||
mainDispatcher = testDispatcher,
|
||||
repository = userRepository,
|
||||
)
|
||||
guestUserInteractor =
|
||||
GuestUserInteractor(
|
||||
applicationContext = context,
|
||||
applicationScope = testScope.backgroundScope,
|
||||
mainDispatcher = testDispatcher,
|
||||
backgroundDispatcher = testDispatcher,
|
||||
manager = manager,
|
||||
repository = userRepository,
|
||||
deviceProvisionedController = deviceProvisionedController,
|
||||
devicePolicyManager = devicePolicyManager,
|
||||
refreshUsersScheduler = refreshUsersScheduler,
|
||||
uiEventLogger = uiEventLogger,
|
||||
resumeSessionReceiver = resumeSessionReceiver,
|
||||
resetOrExitSessionReceiver = resetOrExitSessionReceiver,
|
||||
)
|
||||
|
||||
underTest = viewModel()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `config is false - chip is disabled`() {
|
||||
// the enabled bit is set at SystemUI startup, so recreate the view model here
|
||||
userRepository.isStatusBarUserChipEnabled = false
|
||||
underTest = viewModel()
|
||||
|
||||
assertThat(underTest.chipEnabled).isFalse()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `config is true - chip is enabled`() {
|
||||
// the enabled bit is set at SystemUI startup, so recreate the view model here
|
||||
userRepository.isStatusBarUserChipEnabled = true
|
||||
underTest = viewModel()
|
||||
|
||||
assertThat(underTest.chipEnabled).isTrue()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `should show chip criteria - single user`() =
|
||||
testScope.runTest {
|
||||
userRepository.setUserInfos(listOf(USER_0))
|
||||
userRepository.setSelectedUserInfo(USER_0)
|
||||
userRepository.setSettings(UserSwitcherSettingsModel(isUserSwitcherEnabled = true))
|
||||
|
||||
val values = mutableListOf<Boolean>()
|
||||
|
||||
val job = launch { underTest.isChipVisible.toList(values) }
|
||||
advanceUntilIdle()
|
||||
|
||||
assertThat(values).containsExactly(false)
|
||||
|
||||
job.cancel()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `should show chip criteria - multiple users`() =
|
||||
testScope.runTest {
|
||||
setMultipleUsers()
|
||||
|
||||
var latest: Boolean? = null
|
||||
val job = underTest.isChipVisible.onEach { latest = it }.launchIn(this)
|
||||
yield()
|
||||
|
||||
assertThat(latest).isTrue()
|
||||
|
||||
job.cancel()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `user chip name - shows selected user info`() =
|
||||
testScope.runTest {
|
||||
setMultipleUsers()
|
||||
|
||||
var latest: Text? = null
|
||||
val job = underTest.userName.onEach { latest = it }.launchIn(this)
|
||||
|
||||
userRepository.setSelectedUserInfo(USER_0)
|
||||
assertThat(latest).isEqualTo(USER_NAME_0)
|
||||
|
||||
userRepository.setSelectedUserInfo(USER_1)
|
||||
assertThat(latest).isEqualTo(USER_NAME_1)
|
||||
|
||||
userRepository.setSelectedUserInfo(USER_2)
|
||||
assertThat(latest).isEqualTo(USER_NAME_2)
|
||||
|
||||
job.cancel()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `user chip avatar - shows selected user info`() =
|
||||
testScope.runTest {
|
||||
setMultipleUsers()
|
||||
|
||||
// A little hacky. System server passes us bitmaps and we wrap them in the interactor.
|
||||
// Unwrap them to make sure we're always tracking the current user's bitmap
|
||||
var latest: Bitmap? = null
|
||||
val job =
|
||||
underTest.userAvatar
|
||||
.onEach {
|
||||
if (it !is BitmapDrawable) {
|
||||
latest = null
|
||||
}
|
||||
|
||||
latest = (it as BitmapDrawable).bitmap
|
||||
}
|
||||
.launchIn(this)
|
||||
|
||||
userRepository.setSelectedUserInfo(USER_0)
|
||||
assertThat(latest).isEqualTo(USER_IMAGE_0)
|
||||
|
||||
userRepository.setSelectedUserInfo(USER_1)
|
||||
assertThat(latest).isEqualTo(USER_IMAGE_1)
|
||||
|
||||
userRepository.setSelectedUserInfo(USER_2)
|
||||
assertThat(latest).isEqualTo(USER_IMAGE_2)
|
||||
|
||||
job.cancel()
|
||||
}
|
||||
|
||||
private fun viewModel(): StatusBarUserChipViewModel {
|
||||
return StatusBarUserChipViewModel(
|
||||
context = context,
|
||||
interactor =
|
||||
UserInteractor(
|
||||
applicationContext = context,
|
||||
repository = userRepository,
|
||||
activityStarter = activityStarter,
|
||||
keyguardInteractor =
|
||||
KeyguardInteractor(
|
||||
repository = keyguardRepository,
|
||||
),
|
||||
featureFlags = featureFlags,
|
||||
manager = manager,
|
||||
applicationScope = testScope.backgroundScope,
|
||||
telephonyInteractor =
|
||||
TelephonyInteractor(
|
||||
repository = FakeTelephonyRepository(),
|
||||
),
|
||||
broadcastDispatcher = fakeBroadcastDispatcher,
|
||||
backgroundDispatcher = testDispatcher,
|
||||
activityManager = activityManager,
|
||||
refreshUsersScheduler = refreshUsersScheduler,
|
||||
guestUserInteractor = guestUserInteractor,
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
private suspend fun setMultipleUsers() {
|
||||
userRepository.setUserInfos(listOf(USER_0, USER_1, USER_2))
|
||||
userRepository.setSelectedUserInfo(USER_0)
|
||||
userRepository.setSettings(UserSwitcherSettingsModel(isUserSwitcherEnabled = true))
|
||||
}
|
||||
|
||||
companion object {
|
||||
private const val USER_ID_0 = 0
|
||||
private val USER_IMAGE_0 = Bitmap.createBitmap(1, 1, Bitmap.Config.ARGB_8888)
|
||||
private val USER_NAME_0 = Text.Loaded("zero")
|
||||
|
||||
private const val USER_ID_1 = 1
|
||||
private val USER_IMAGE_1 = Bitmap.createBitmap(1, 1, Bitmap.Config.ARGB_8888)
|
||||
private val USER_NAME_1 = Text.Loaded("one")
|
||||
|
||||
private const val USER_ID_2 = 2
|
||||
private val USER_IMAGE_2 = Bitmap.createBitmap(1, 1, Bitmap.Config.ARGB_8888)
|
||||
private val USER_NAME_2 = Text.Loaded("two")
|
||||
|
||||
private val USER_0 =
|
||||
UserInfo(
|
||||
USER_ID_0,
|
||||
USER_NAME_0.text!!,
|
||||
/* iconPath */ "",
|
||||
/* flags */ 0,
|
||||
/* userType */ UserManager.USER_TYPE_FULL_SYSTEM
|
||||
)
|
||||
|
||||
private val USER_1 =
|
||||
UserInfo(
|
||||
USER_ID_1,
|
||||
USER_NAME_1.text!!,
|
||||
/* iconPath */ "",
|
||||
/* flags */ 0,
|
||||
/* userType */ UserManager.USER_TYPE_FULL_SYSTEM
|
||||
)
|
||||
|
||||
private val USER_2 =
|
||||
UserInfo(
|
||||
USER_ID_2,
|
||||
USER_NAME_2.text!!,
|
||||
/* iconPath */ "",
|
||||
/* flags */ 0,
|
||||
/* userType */ UserManager.USER_TYPE_FULL_SYSTEM
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -27,6 +27,7 @@ import com.android.systemui.GuestResetOrExitSessionReceiver
|
||||
import com.android.systemui.GuestResumeSessionReceiver
|
||||
import com.android.systemui.SysuiTestCase
|
||||
import com.android.systemui.common.shared.model.Text
|
||||
import com.android.systemui.flags.FakeFeatureFlags
|
||||
import com.android.systemui.keyguard.data.repository.FakeKeyguardRepository
|
||||
import com.android.systemui.keyguard.domain.interactor.KeyguardInteractor
|
||||
import com.android.systemui.plugins.ActivityStarter
|
||||
@@ -147,6 +148,7 @@ class UserSwitcherViewModelTest : SysuiTestCase() {
|
||||
KeyguardInteractor(
|
||||
repository = keyguardRepository,
|
||||
),
|
||||
featureFlags = FakeFeatureFlags(),
|
||||
manager = manager,
|
||||
applicationScope = injectedScope,
|
||||
telephonyInteractor =
|
||||
|
||||
@@ -28,8 +28,6 @@ import com.android.internal.logging.testing.UiEventLoggerFake
|
||||
import com.android.systemui.broadcast.BroadcastDispatcher
|
||||
import com.android.systemui.classifier.FalsingManagerFake
|
||||
import com.android.systemui.dagger.qualifiers.Application
|
||||
import com.android.systemui.flags.FakeFeatureFlags
|
||||
import com.android.systemui.flags.FeatureFlags
|
||||
import com.android.systemui.globalactions.GlobalActionsDialogLite
|
||||
import com.android.systemui.plugins.ActivityStarter
|
||||
import com.android.systemui.plugins.FalsingManager
|
||||
@@ -43,7 +41,6 @@ import com.android.systemui.qs.footer.data.repository.UserSwitcherRepositoryImpl
|
||||
import com.android.systemui.qs.footer.domain.interactor.FooterActionsInteractor
|
||||
import com.android.systemui.qs.footer.domain.interactor.FooterActionsInteractorImpl
|
||||
import com.android.systemui.qs.footer.ui.viewmodel.FooterActionsViewModel
|
||||
import com.android.systemui.qs.user.UserSwitchDialogController
|
||||
import com.android.systemui.security.data.repository.SecurityRepository
|
||||
import com.android.systemui.security.data.repository.SecurityRepositoryImpl
|
||||
import com.android.systemui.settings.FakeUserTracker
|
||||
@@ -54,6 +51,7 @@ import com.android.systemui.statusbar.policy.FakeUserInfoController
|
||||
import com.android.systemui.statusbar.policy.SecurityController
|
||||
import com.android.systemui.statusbar.policy.UserInfoController
|
||||
import com.android.systemui.statusbar.policy.UserSwitcherController
|
||||
import com.android.systemui.user.domain.interactor.UserInteractor
|
||||
import com.android.systemui.util.mockito.mock
|
||||
import com.android.systemui.util.settings.FakeSettings
|
||||
import com.android.systemui.util.settings.GlobalSettings
|
||||
@@ -97,13 +95,12 @@ class FooterActionsTestUtils(
|
||||
/** Create a [FooterActionsInteractor] to be used in tests. */
|
||||
fun footerActionsInteractor(
|
||||
activityStarter: ActivityStarter = mock(),
|
||||
featureFlags: FeatureFlags = FakeFeatureFlags(),
|
||||
metricsLogger: MetricsLogger = FakeMetricsLogger(),
|
||||
uiEventLogger: UiEventLogger = UiEventLoggerFake(),
|
||||
deviceProvisionedController: DeviceProvisionedController = mock(),
|
||||
qsSecurityFooterUtils: QSSecurityFooterUtils = mock(),
|
||||
fgsManagerController: FgsManagerController = mock(),
|
||||
userSwitchDialogController: UserSwitchDialogController = mock(),
|
||||
userInteractor: UserInteractor = mock(),
|
||||
securityRepository: SecurityRepository = securityRepository(),
|
||||
foregroundServicesRepository: ForegroundServicesRepository = foregroundServicesRepository(),
|
||||
userSwitcherRepository: UserSwitcherRepository = userSwitcherRepository(),
|
||||
@@ -112,13 +109,12 @@ class FooterActionsTestUtils(
|
||||
): FooterActionsInteractor {
|
||||
return FooterActionsInteractorImpl(
|
||||
activityStarter,
|
||||
featureFlags,
|
||||
metricsLogger,
|
||||
uiEventLogger,
|
||||
deviceProvisionedController,
|
||||
qsSecurityFooterUtils,
|
||||
fgsManagerController,
|
||||
userSwitchDialogController,
|
||||
userInteractor,
|
||||
securityRepository,
|
||||
foregroundServicesRepository,
|
||||
userSwitcherRepository,
|
||||
|
||||
@@ -49,6 +49,8 @@ class FakeUserRepository : UserRepository {
|
||||
|
||||
override val isGuestUserCreationScheduled = AtomicBoolean()
|
||||
|
||||
override var isStatusBarUserChipEnabled: Boolean = false
|
||||
|
||||
override var secondaryUserId: Int = UserHandle.USER_NULL
|
||||
|
||||
override var isRefreshUsersPaused: Boolean = false
|
||||
|
||||
Reference in New Issue
Block a user