Add some fakes to SystemUI-test-utils am: e496b54c21

Original change: https://googleplex-android-review.googlesource.com/c/platform/frameworks/base/+/19675484

Change-Id: Idb853d64168c87cf4dbd8e3006dd3283ec90745e
Signed-off-by: Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>
This commit is contained in:
Jordan Demeulenaere
2022-08-26 07:08:52 +00:00
committed by Automerger Merge Worker
10 changed files with 499 additions and 55 deletions

View File

@@ -68,9 +68,73 @@ import java.util.Objects
import java.util.concurrent.Executor
import javax.inject.Inject
import kotlin.math.max
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.asStateFlow
/** A controller for the dealing with services running in the foreground. */
interface FgsManagerController {
/** Whether the TaskManager (and therefore this controller) is actually available. */
val isAvailable: StateFlow<Boolean>
/** The number of packages with a service running in the foreground. */
val numRunningPackages: Int
/**
* Whether there were new changes to the foreground services since the last [shown][showDialog]
* dialog was dismissed.
*/
val newChangesSinceDialogWasDismissed: Boolean
/**
* Whether we should show a dot to indicate when [newChangesSinceDialogWasDismissed] is true.
*/
val showFooterDot: StateFlow<Boolean>
/**
* Initialize this controller. This should be called once, before this controller is used for
* the first time.
*/
fun init()
/**
* Show the foreground services dialog. The dialog will be expanded from [viewLaunchedFrom] if
* it's not `null`.
*/
fun showDialog(viewLaunchedFrom: View?)
/** Add a [OnNumberOfPackagesChangedListener]. */
fun addOnNumberOfPackagesChangedListener(listener: OnNumberOfPackagesChangedListener)
/** Remove a [OnNumberOfPackagesChangedListener]. */
fun removeOnNumberOfPackagesChangedListener(listener: OnNumberOfPackagesChangedListener)
/** Add a [OnDialogDismissedListener]. */
fun addOnDialogDismissedListener(listener: OnDialogDismissedListener)
/** Remove a [OnDialogDismissedListener]. */
fun removeOnDialogDismissedListener(listener: OnDialogDismissedListener)
/** Whether we should update the footer visibility. */
// TODO(b/242040009): Remove this.
fun shouldUpdateFooterVisibility(): Boolean
@VisibleForTesting
fun visibleButtonsCount(): Int
interface OnNumberOfPackagesChangedListener {
/** Called when [numRunningPackages] changed. */
fun onNumberOfPackagesChanged(numPackages: Int)
}
interface OnDialogDismissedListener {
/** Called when a dialog shown using [showDialog] was dismissed. */
fun onDialogDismissed()
}
}
@SysUISingleton
class FgsManagerController @Inject constructor(
class FgsManagerControllerImpl @Inject constructor(
private val context: Context,
@Main private val mainExecutor: Executor,
@Background private val backgroundExecutor: Executor,
@@ -82,25 +146,32 @@ class FgsManagerController @Inject constructor(
private val dialogLaunchAnimator: DialogLaunchAnimator,
private val broadcastDispatcher: BroadcastDispatcher,
private val dumpManager: DumpManager
) : IForegroundServiceObserver.Stub(), Dumpable {
) : IForegroundServiceObserver.Stub(), Dumpable, FgsManagerController {
companion object {
private const val INTERACTION_JANK_TAG = "active_background_apps"
private val LOG_TAG = FgsManagerController::class.java.simpleName
private const val DEFAULT_TASK_MANAGER_ENABLED = true
private const val DEFAULT_TASK_MANAGER_SHOW_FOOTER_DOT = false
private const val DEFAULT_TASK_MANAGER_SHOW_STOP_BUTTON_FOR_USER_ALLOWLISTED_APPS = true
}
var changesSinceDialog = false
override var newChangesSinceDialogWasDismissed = false
private set
var isAvailable = false
private set
var showFooterDot = false
private set
var showStopBtnForUserAllowlistedApps = false
private set
val _isAvailable = MutableStateFlow(false)
override val isAvailable: StateFlow<Boolean> = _isAvailable.asStateFlow()
val _showFooterDot = MutableStateFlow(false)
override val showFooterDot: StateFlow<Boolean> = _showFooterDot.asStateFlow()
private var showStopBtnForUserAllowlistedApps = false
override val numRunningPackages: Int
get() {
synchronized(lock) {
return getNumVisiblePackagesLocked()
}
}
private val lock = Any()
@@ -138,15 +209,7 @@ class FgsManagerController @Inject constructor(
}
}
interface OnNumberOfPackagesChangedListener {
fun onNumberOfPackagesChanged(numPackages: Int)
}
interface OnDialogDismissedListener {
fun onDialogDismissed()
}
fun init() {
override fun init() {
synchronized(lock) {
if (initialized) {
return
@@ -165,19 +228,19 @@ class FgsManagerController @Inject constructor(
NAMESPACE_SYSTEMUI,
backgroundExecutor
) {
isAvailable = it.getBoolean(TASK_MANAGER_ENABLED, isAvailable)
showFooterDot =
it.getBoolean(TASK_MANAGER_SHOW_FOOTER_DOT, showFooterDot)
_isAvailable.value = it.getBoolean(TASK_MANAGER_ENABLED, _isAvailable.value)
_showFooterDot.value =
it.getBoolean(TASK_MANAGER_SHOW_FOOTER_DOT, _showFooterDot.value)
showStopBtnForUserAllowlistedApps = it.getBoolean(
TASK_MANAGER_SHOW_STOP_BUTTON_FOR_USER_ALLOWLISTED_APPS,
showStopBtnForUserAllowlistedApps)
}
isAvailable = deviceConfigProxy.getBoolean(
_isAvailable.value = deviceConfigProxy.getBoolean(
NAMESPACE_SYSTEMUI,
TASK_MANAGER_ENABLED, DEFAULT_TASK_MANAGER_ENABLED
)
showFooterDot = deviceConfigProxy.getBoolean(
_showFooterDot.value = deviceConfigProxy.getBoolean(
NAMESPACE_SYSTEMUI,
TASK_MANAGER_SHOW_FOOTER_DOT, DEFAULT_TASK_MANAGER_SHOW_FOOTER_DOT
)
@@ -232,42 +295,45 @@ class FgsManagerController @Inject constructor(
}
@GuardedBy("lock")
val onNumberOfPackagesChangedListeners: MutableSet<OnNumberOfPackagesChangedListener> =
mutableSetOf()
private val onNumberOfPackagesChangedListeners =
mutableSetOf<FgsManagerController.OnNumberOfPackagesChangedListener>()
@GuardedBy("lock")
val onDialogDismissedListeners: MutableSet<OnDialogDismissedListener> = mutableSetOf()
private val onDialogDismissedListeners =
mutableSetOf<FgsManagerController.OnDialogDismissedListener>()
fun addOnNumberOfPackagesChangedListener(listener: OnNumberOfPackagesChangedListener) {
override fun addOnNumberOfPackagesChangedListener(
listener: FgsManagerController.OnNumberOfPackagesChangedListener
) {
synchronized(lock) {
onNumberOfPackagesChangedListeners.add(listener)
}
}
fun removeOnNumberOfPackagesChangedListener(listener: OnNumberOfPackagesChangedListener) {
override fun removeOnNumberOfPackagesChangedListener(
listener: FgsManagerController.OnNumberOfPackagesChangedListener
) {
synchronized(lock) {
onNumberOfPackagesChangedListeners.remove(listener)
}
}
fun addOnDialogDismissedListener(listener: OnDialogDismissedListener) {
override fun addOnDialogDismissedListener(
listener: FgsManagerController.OnDialogDismissedListener
) {
synchronized(lock) {
onDialogDismissedListeners.add(listener)
}
}
fun removeOnDialogDismissedListener(listener: OnDialogDismissedListener) {
override fun removeOnDialogDismissedListener(
listener: FgsManagerController.OnDialogDismissedListener
) {
synchronized(lock) {
onDialogDismissedListeners.remove(listener)
}
}
fun getNumRunningPackages(): Int {
synchronized(lock) {
return getNumVisiblePackagesLocked()
}
}
private fun getNumVisiblePackagesLocked(): Int {
return runningServiceTokens.keys.count {
it.uiControl != UIControl.HIDE_ENTRY && currentProfileIds.contains(it.userId)
@@ -278,7 +344,7 @@ class FgsManagerController @Inject constructor(
val num = getNumVisiblePackagesLocked()
if (num != lastNumberOfVisiblePackages) {
lastNumberOfVisiblePackages = num
changesSinceDialog = true
newChangesSinceDialogWasDismissed = true
onNumberOfPackagesChangedListeners.forEach {
backgroundExecutor.execute {
it.onNumberOfPackagesChanged(num)
@@ -287,9 +353,7 @@ class FgsManagerController @Inject constructor(
}
}
@VisibleForTesting
@JvmName("getNumVisibleButtons")
internal fun getNumVisibleButtons(): Int {
override fun visibleButtonsCount(): Int {
synchronized(lock) {
return getNumVisibleButtonsLocked()
}
@@ -301,9 +365,9 @@ class FgsManagerController @Inject constructor(
}
}
fun shouldUpdateFooterVisibility() = dialog == null
override fun shouldUpdateFooterVisibility() = dialog == null
fun showDialog(viewLaunchedFrom: View?) {
override fun showDialog(viewLaunchedFrom: View?) {
synchronized(lock) {
if (dialog == null) {
@@ -328,7 +392,7 @@ class FgsManagerController @Inject constructor(
this.dialog = dialog
dialog.setOnDismissListener {
changesSinceDialog = false
newChangesSinceDialogWasDismissed = false
synchronized(lock) {
this.dialog = null
updateAppItemsLocked()
@@ -656,7 +720,7 @@ class FgsManagerController @Inject constructor(
val pw = IndentingPrintWriter(printwriter)
synchronized(lock) {
pw.println("current user profiles = $currentProfileIds")
pw.println("changesSinceDialog=$changesSinceDialog")
pw.println("newChangesSinceDialogWasShown=$newChangesSinceDialogWasDismissed")
pw.println("Running service tokens: [")
pw.indentIfPossible {
runningServiceTokens.forEach { (userPackage, startTimeAndTokens) ->

View File

@@ -149,9 +149,11 @@ public class QSFgsManagerFooter implements View.OnClickListener,
mNumberView.setContentDescription(text);
if (mFgsManagerController.shouldUpdateFooterVisibility()) {
mRootView.setVisibility(mNumPackages > 0
&& mFgsManagerController.isAvailable() ? View.VISIBLE : View.GONE);
int dotVis = mFgsManagerController.getShowFooterDot()
&& mFgsManagerController.getChangesSinceDialog() ? View.VISIBLE : View.GONE;
&& mFgsManagerController.isAvailable().getValue() ? View.VISIBLE
: View.GONE);
int dotVis = mFgsManagerController.getShowFooterDot().getValue()
&& mFgsManagerController.getNewChangesSinceDialogWasDismissed()
? View.VISIBLE : View.GONE;
mDotView.setVisibility(dotVis);
mCollapsedDotView.setVisibility(dotVis);
if (mVisibilityChangedListener != null) {

View File

@@ -28,6 +28,8 @@ import com.android.systemui.battery.BatteryMeterView;
import com.android.systemui.dagger.qualifiers.RootView;
import com.android.systemui.plugins.qs.QS;
import com.android.systemui.privacy.OngoingPrivacyChip;
import com.android.systemui.qs.FgsManagerController;
import com.android.systemui.qs.FgsManagerControllerImpl;
import com.android.systemui.qs.FooterActionsView;
import com.android.systemui.qs.QSContainerImpl;
import com.android.systemui.qs.QSFooter;
@@ -194,4 +196,8 @@ public interface QSFragmentModule {
) {
return layoutInflater.inflate(R.layout.fgs_footer, footerActionsView, false);
}
/** */
@Binds
FgsManagerController bindFgsManagerController(FgsManagerControllerImpl impl);
}

View File

@@ -188,9 +188,9 @@ public class FgsManagerControllerTest extends SysuiTestCase {
public void testChangesSinceLastDialog() throws RemoteException {
setUserProfiles(0);
Assert.assertFalse(mFmc.getChangesSinceDialog());
Assert.assertFalse(mFmc.getNewChangesSinceDialogWasDismissed());
mIForegroundServiceObserver.onForegroundStateChanged(new Binder(), "pkg", 0, true);
Assert.assertTrue(mFmc.getChangesSinceDialog());
Assert.assertTrue(mFmc.getNewChangesSinceDialogWasDismissed());
}
@Test
@@ -233,14 +233,14 @@ public class FgsManagerControllerTest extends SysuiTestCase {
final Binder binder = new Binder();
setShowStopButtonForUserAllowlistedApps(true);
mIForegroundServiceObserver.onForegroundStateChanged(binder, "pkg", 0, true);
Assert.assertEquals(1, mFmc.getNumVisibleButtons());
Assert.assertEquals(1, mFmc.visibleButtonsCount());
mIForegroundServiceObserver.onForegroundStateChanged(binder, "pkg", 0, false);
Assert.assertEquals(0, mFmc.getNumVisibleButtons());
Assert.assertEquals(0, mFmc.visibleButtonsCount());
setShowStopButtonForUserAllowlistedApps(false);
mIForegroundServiceObserver.onForegroundStateChanged(binder, "pkg", 0, true);
Assert.assertEquals(0, mFmc.getNumVisibleButtons());
Assert.assertEquals(0, mFmc.visibleButtonsCount());
}
private void setShowStopButtonForUserAllowlistedApps(boolean enable) {
@@ -269,7 +269,7 @@ public class FgsManagerControllerTest extends SysuiTestCase {
ArgumentCaptor<BroadcastReceiver> showFgsManagerReceiverArgumentCaptor =
ArgumentCaptor.forClass(BroadcastReceiver.class);
FgsManagerController result = new FgsManagerController(
FgsManagerController result = new FgsManagerControllerImpl(
mContext,
mMainExecutor,
mBackgroundExecutor,

View File

@@ -56,7 +56,6 @@ class FakeFeatureFlags : FeatureFlags {
stringFlags.put(flag.id, value)
}
override fun isEnabled(flag: UnreleasedFlag): Boolean = requireBooleanValue(flag.id)
override fun isEnabled(flag: ReleasedFlag): Boolean = requireBooleanValue(flag.id)

View File

@@ -0,0 +1,80 @@
/*
* 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.qs
import android.view.View
import com.android.systemui.qs.FgsManagerController.OnDialogDismissedListener
import com.android.systemui.qs.FgsManagerController.OnNumberOfPackagesChangedListener
import kotlinx.coroutines.flow.MutableStateFlow
/** A fake [FgsManagerController] to be used in tests. */
class FakeFgsManagerController(
isAvailable: Boolean = true,
showFooterDot: Boolean = false,
numRunningPackages: Int = 0,
) : FgsManagerController {
override val isAvailable: MutableStateFlow<Boolean> = MutableStateFlow(isAvailable)
override var numRunningPackages = numRunningPackages
set(value) {
if (value != field) {
field = value
newChangesSinceDialogWasDismissed = true
numRunningPackagesListeners.forEach { it.onNumberOfPackagesChanged(value) }
}
}
override var newChangesSinceDialogWasDismissed = false
private set
override val showFooterDot: MutableStateFlow<Boolean> = MutableStateFlow(showFooterDot)
private val numRunningPackagesListeners = LinkedHashSet<OnNumberOfPackagesChangedListener>()
private val dialogDismissedListeners = LinkedHashSet<OnDialogDismissedListener>()
/** Simulate that a fgs dialog was just dismissed. */
fun simulateDialogDismiss() {
newChangesSinceDialogWasDismissed = false
dialogDismissedListeners.forEach { it.onDialogDismissed() }
}
override fun init() {}
override fun showDialog(viewLaunchedFrom: View?) {}
override fun addOnNumberOfPackagesChangedListener(listener: OnNumberOfPackagesChangedListener) {
numRunningPackagesListeners.add(listener)
}
override fun removeOnNumberOfPackagesChangedListener(
listener: OnNumberOfPackagesChangedListener
) {
numRunningPackagesListeners.remove(listener)
}
override fun addOnDialogDismissedListener(listener: OnDialogDismissedListener) {
dialogDismissedListeners.add(listener)
}
override fun removeOnDialogDismissedListener(listener: OnDialogDismissedListener) {
dialogDismissedListeners.remove(listener)
}
override fun shouldUpdateFooterVisibility(): Boolean = false
override fun visibleButtonsCount(): Int = 0
}

View File

@@ -0,0 +1,58 @@
/*
* 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.settings
import android.content.ContentResolver
import android.content.Context
import android.content.pm.UserInfo
import android.os.UserHandle
import android.test.mock.MockContentResolver
import com.android.systemui.util.mockito.mock
import java.util.concurrent.Executor
/** A fake [UserTracker] to be used in tests. */
class FakeUserTracker(
userId: Int = 0,
userHandle: UserHandle = UserHandle.of(userId),
userInfo: UserInfo = mock(),
userProfiles: List<UserInfo> = emptyList(),
userContentResolver: ContentResolver = MockContentResolver(),
userContext: Context = mock(),
private val onCreateCurrentUserContext: (Context) -> Context = { mock() },
) : UserTracker {
val callbacks = mutableListOf<UserTracker.Callback>()
override val userId: Int = userId
override val userHandle: UserHandle = userHandle
override val userInfo: UserInfo = userInfo
override val userProfiles: List<UserInfo> = userProfiles
override val userContentResolver: ContentResolver = userContentResolver
override val userContext: Context = userContext
override fun addCallback(callback: UserTracker.Callback, executor: Executor) {
callbacks.add(callback)
}
override fun removeCallback(callback: UserTracker.Callback) {
callbacks.remove(callback)
}
override fun createCurrentUserContext(context: Context): Context {
return onCreateCurrentUserContext(context)
}
}

View File

@@ -0,0 +1,118 @@
/*
* 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.policy
import android.app.admin.DeviceAdminInfo
import android.content.ComponentName
import android.graphics.drawable.Drawable
import java.io.PrintWriter
/** A fake [SecurityController] to be used in tests. */
class FakeSecurityController(
private val fakeState: FakeState = FakeState(),
) : SecurityController {
private val callbacks = LinkedHashSet<SecurityController.SecurityControllerCallback>()
override fun addCallback(callback: SecurityController.SecurityControllerCallback) {
callbacks.add(callback)
}
override fun removeCallback(callback: SecurityController.SecurityControllerCallback) {
callbacks.remove(callback)
}
/** Update [fakeState], then notify the callbacks. */
fun updateState(f: FakeState.() -> Unit) {
fakeState.f()
callbacks.forEach { it.onStateChanged() }
}
override fun dump(pw: PrintWriter, args: Array<out String>) {}
override fun isDeviceManaged(): Boolean = fakeState.isDeviceManaged
override fun hasProfileOwner(): Boolean = fakeState.hasProfileOwner
override fun hasWorkProfile(): Boolean = fakeState.hasWorkProfile
override fun isWorkProfileOn(): Boolean = fakeState.isWorkProfileOn
override fun isProfileOwnerOfOrganizationOwnedDevice(): Boolean =
fakeState.isProfileOwnerOfOrganizationOwnedDevice
override fun getDeviceOwnerName(): String? = fakeState.deviceOwnerName
override fun getProfileOwnerName(): String? = fakeState.profileOwnerName
override fun getDeviceOwnerOrganizationName(): String? = fakeState.deviceOwnerOrganizationName
override fun getWorkProfileOrganizationName(): String? = fakeState.workProfileOrganizationName
override fun getDeviceOwnerComponentOnAnyUser(): ComponentName? =
fakeState.deviceOwnerComponentOnAnyUser
override fun getDeviceOwnerType(admin: ComponentName?): Int = 0
override fun isNetworkLoggingEnabled(): Boolean = fakeState.isNetworkLoggingEnabled
override fun isVpnEnabled(): Boolean = fakeState.isVpnEnabled
override fun isVpnRestricted(): Boolean = fakeState.isVpnRestricted
override fun isVpnBranded(): Boolean = fakeState.isVpnBranded
override fun getPrimaryVpnName(): String? = fakeState.primaryVpnName
override fun getWorkProfileVpnName(): String? = fakeState.workProfileVpnName
override fun hasCACertInCurrentUser(): Boolean = fakeState.hasCACertInCurrentUser
override fun hasCACertInWorkProfile(): Boolean = fakeState.hasCACertInWorkProfile
override fun onUserSwitched(newUserId: Int) {}
override fun isParentalControlsEnabled(): Boolean = fakeState.isParentalControlsEnabled
override fun getDeviceAdminInfo(): DeviceAdminInfo? = fakeState.deviceAdminInfo
override fun getIcon(info: DeviceAdminInfo?): Drawable? = null
override fun getLabel(info: DeviceAdminInfo?): CharSequence? = null
class FakeState(
var isDeviceManaged: Boolean = false,
var hasProfileOwner: Boolean = false,
var hasWorkProfile: Boolean = false,
var isWorkProfileOn: Boolean = false,
var isProfileOwnerOfOrganizationOwnedDevice: Boolean = false,
var deviceOwnerName: String? = null,
var profileOwnerName: String? = null,
var deviceOwnerOrganizationName: String? = null,
var workProfileOrganizationName: String? = null,
var deviceOwnerComponentOnAnyUser: ComponentName? = null,
var isNetworkLoggingEnabled: Boolean = false,
var isVpnEnabled: Boolean = false,
var isVpnRestricted: Boolean = false,
var isVpnBranded: Boolean = false,
var primaryVpnName: String? = null,
var workProfileVpnName: String? = null,
var hasCACertInCurrentUser: Boolean = false,
var hasCACertInWorkProfile: Boolean = false,
var isParentalControlsEnabled: Boolean = false,
var deviceAdminInfo: DeviceAdminInfo? = null,
)
}

View File

@@ -0,0 +1,58 @@
/*
* 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.policy
import android.graphics.drawable.Drawable
import com.android.systemui.util.mockito.mock
/** A fake [UserInfoController] to be used in tests. */
class FakeUserInfoController(
private val fakeInfo: FakeInfo = FakeInfo(),
) : UserInfoController {
private val listeners = LinkedHashSet<UserInfoController.OnUserInfoChangedListener>()
/** Update [fakeInfo], then notify the listeners. */
fun updateInfo(f: FakeInfo.() -> Unit) {
fakeInfo.f()
notifyListeners()
}
private fun notifyListeners() {
listeners.forEach { listener ->
listener.onUserInfoChanged(fakeInfo.name, fakeInfo.picture, fakeInfo.userAccount)
}
}
override fun addCallback(listener: UserInfoController.OnUserInfoChangedListener) {
listeners.add(listener)
// The actual implementation notifies the listener when adding it.
listener.onUserInfoChanged(fakeInfo.name, fakeInfo.picture, fakeInfo.userAccount)
}
override fun removeCallback(listener: UserInfoController.OnUserInfoChangedListener) {
listeners.remove(listener)
}
override fun reloadUserInfo() {}
class FakeInfo(
var name: String = "",
var picture: Drawable = mock(),
var userAccount: String = "",
)
}

View File

@@ -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.statusbar.policy
import com.android.systemui.statusbar.policy.UserSwitcherController.UserSwitchCallback
import com.android.systemui.util.mockito.any
import com.android.systemui.util.mockito.mock
import org.mockito.Mockito.`when` as whenever
/**
* A wrapper around a mocked [UserSwitcherController] to be used in tests.
*
* Note that this was implemented as a mock wrapper instead of fake implementation of a common
* interface given how big the UserSwitcherController grew.
*/
class MockUserSwitcherControllerWrapper(
currentUserName: String = "",
) {
val controller: UserSwitcherController = mock()
private val callbacks = LinkedHashSet<UserSwitchCallback>()
var currentUserName = currentUserName
set(value) {
if (value != field) {
field = value
notifyCallbacks()
}
}
private fun notifyCallbacks() {
callbacks.forEach { it.onUserSwitched() }
}
init {
whenever(controller.addUserSwitchCallback(any())).then { invocation ->
callbacks.add(invocation.arguments.first() as UserSwitchCallback)
}
whenever(controller.removeUserSwitchCallback(any())).then { invocation ->
callbacks.remove(invocation.arguments.first() as UserSwitchCallback)
}
whenever(controller.currentUserName).thenAnswer { this.currentUserName }
}
}