Merge "Only show packages for the current user in FgsManager" into tm-dev am: a82c616519
Original change: https://googleplex-android-review.googlesource.com/c/platform/frameworks/base/+/17298359 Change-Id: I28595fe831f651542aa5e6f98ed8e53ac3efc956 Signed-off-by: Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>
This commit is contained in:
@@ -23,10 +23,12 @@ import android.content.Context
|
|||||||
import android.content.Intent
|
import android.content.Intent
|
||||||
import android.content.IntentFilter
|
import android.content.IntentFilter
|
||||||
import android.content.pm.PackageManager
|
import android.content.pm.PackageManager
|
||||||
|
import android.content.pm.UserInfo
|
||||||
import android.graphics.drawable.Drawable
|
import android.graphics.drawable.Drawable
|
||||||
import android.os.IBinder
|
import android.os.IBinder
|
||||||
import android.os.PowerExemptionManager
|
import android.os.PowerExemptionManager
|
||||||
import android.os.RemoteException
|
import android.os.RemoteException
|
||||||
|
import android.os.UserHandle
|
||||||
import android.provider.DeviceConfig.NAMESPACE_SYSTEMUI
|
import android.provider.DeviceConfig.NAMESPACE_SYSTEMUI
|
||||||
import android.text.format.DateUtils
|
import android.text.format.DateUtils
|
||||||
import android.util.ArrayMap
|
import android.util.ArrayMap
|
||||||
@@ -51,6 +53,7 @@ import com.android.systemui.dagger.qualifiers.Background
|
|||||||
import com.android.systemui.dagger.qualifiers.Main
|
import com.android.systemui.dagger.qualifiers.Main
|
||||||
import com.android.systemui.dump.DumpManager
|
import com.android.systemui.dump.DumpManager
|
||||||
import com.android.systemui.shared.system.SysUiStatsLog
|
import com.android.systemui.shared.system.SysUiStatsLog
|
||||||
|
import com.android.systemui.settings.UserTracker
|
||||||
import com.android.systemui.statusbar.phone.SystemUIDialog
|
import com.android.systemui.statusbar.phone.SystemUIDialog
|
||||||
import com.android.systemui.util.DeviceConfigProxy
|
import com.android.systemui.util.DeviceConfigProxy
|
||||||
import com.android.systemui.util.indentIfPossible
|
import com.android.systemui.util.indentIfPossible
|
||||||
@@ -69,6 +72,7 @@ class FgsManagerController @Inject constructor(
|
|||||||
private val systemClock: SystemClock,
|
private val systemClock: SystemClock,
|
||||||
private val activityManager: IActivityManager,
|
private val activityManager: IActivityManager,
|
||||||
private val packageManager: PackageManager,
|
private val packageManager: PackageManager,
|
||||||
|
private val userTracker: UserTracker,
|
||||||
private val deviceConfigProxy: DeviceConfigProxy,
|
private val deviceConfigProxy: DeviceConfigProxy,
|
||||||
private val dialogLaunchAnimator: DialogLaunchAnimator,
|
private val dialogLaunchAnimator: DialogLaunchAnimator,
|
||||||
private val broadcastDispatcher: BroadcastDispatcher,
|
private val broadcastDispatcher: BroadcastDispatcher,
|
||||||
@@ -82,13 +86,20 @@ class FgsManagerController @Inject constructor(
|
|||||||
var changesSinceDialog = false
|
var changesSinceDialog = false
|
||||||
private set
|
private set
|
||||||
|
|
||||||
private var isAvailable = false
|
var isAvailable = false
|
||||||
|
private set
|
||||||
|
|
||||||
private val lock = Any()
|
private val lock = Any()
|
||||||
|
|
||||||
@GuardedBy("lock")
|
@GuardedBy("lock")
|
||||||
var initialized = false
|
var initialized = false
|
||||||
|
|
||||||
|
@GuardedBy("lock")
|
||||||
|
private var lastNumberOfVisiblePackages = 0
|
||||||
|
|
||||||
|
@GuardedBy("lock")
|
||||||
|
private var currentProfileIds = mutableSetOf<Int>()
|
||||||
|
|
||||||
@GuardedBy("lock")
|
@GuardedBy("lock")
|
||||||
private val runningServiceTokens = mutableMapOf<UserPackage, StartTimeAndTokens>()
|
private val runningServiceTokens = mutableMapOf<UserPackage, StartTimeAndTokens>()
|
||||||
|
|
||||||
@@ -101,6 +112,19 @@ class FgsManagerController @Inject constructor(
|
|||||||
@GuardedBy("lock")
|
@GuardedBy("lock")
|
||||||
private var runningApps: ArrayMap<UserPackage, RunningApp> = ArrayMap()
|
private var runningApps: ArrayMap<UserPackage, RunningApp> = ArrayMap()
|
||||||
|
|
||||||
|
private val userTrackerCallback = object : UserTracker.Callback {
|
||||||
|
override fun onUserChanged(newUser: Int, userContext: Context) {}
|
||||||
|
|
||||||
|
override fun onProfilesChanged(profiles: List<UserInfo>) {
|
||||||
|
synchronized(lock) {
|
||||||
|
currentProfileIds.clear()
|
||||||
|
currentProfileIds.addAll(profiles.map { it.id })
|
||||||
|
lastNumberOfVisiblePackages = 0
|
||||||
|
updateNumberOfVisibleRunningPackagesLocked()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
interface OnNumberOfPackagesChangedListener {
|
interface OnNumberOfPackagesChangedListener {
|
||||||
fun onNumberOfPackagesChanged(numPackages: Int)
|
fun onNumberOfPackagesChanged(numPackages: Int)
|
||||||
}
|
}
|
||||||
@@ -120,6 +144,10 @@ class FgsManagerController @Inject constructor(
|
|||||||
e.rethrowFromSystemServer()
|
e.rethrowFromSystemServer()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
userTracker.addCallback(userTrackerCallback, backgroundExecutor)
|
||||||
|
|
||||||
|
currentProfileIds.addAll(userTracker.userProfiles.map { it.id })
|
||||||
|
|
||||||
deviceConfigProxy.addOnPropertiesChangedListener(NAMESPACE_SYSTEMUI,
|
deviceConfigProxy.addOnPropertiesChangedListener(NAMESPACE_SYSTEMUI,
|
||||||
backgroundExecutor) {
|
backgroundExecutor) {
|
||||||
isAvailable = it.getBoolean(TASK_MANAGER_ENABLED, isAvailable)
|
isAvailable = it.getBoolean(TASK_MANAGER_ENABLED, isAvailable)
|
||||||
@@ -153,10 +181,9 @@ class FgsManagerController @Inject constructor(
|
|||||||
isForeground: Boolean
|
isForeground: Boolean
|
||||||
) {
|
) {
|
||||||
synchronized(lock) {
|
synchronized(lock) {
|
||||||
val numPackagesBefore = getNumRunningPackagesLocked()
|
|
||||||
val userPackageKey = UserPackage(userId, packageName)
|
val userPackageKey = UserPackage(userId, packageName)
|
||||||
if (isForeground) {
|
if (isForeground) {
|
||||||
runningServiceTokens.getOrPut(userPackageKey, { StartTimeAndTokens(systemClock) })
|
runningServiceTokens.getOrPut(userPackageKey) { StartTimeAndTokens(systemClock) }
|
||||||
.addToken(token)
|
.addToken(token)
|
||||||
} else {
|
} else {
|
||||||
if (runningServiceTokens[userPackageKey]?.also {
|
if (runningServiceTokens[userPackageKey]?.also {
|
||||||
@@ -165,14 +192,7 @@ class FgsManagerController @Inject constructor(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
val numPackagesAfter = getNumRunningPackagesLocked()
|
updateNumberOfVisibleRunningPackagesLocked()
|
||||||
|
|
||||||
if (numPackagesAfter != numPackagesBefore) {
|
|
||||||
changesSinceDialog = true
|
|
||||||
onNumberOfPackagesChangedListeners.forEach {
|
|
||||||
backgroundExecutor.execute { it.onNumberOfPackagesChanged(numPackagesAfter) }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
updateAppItemsLocked()
|
updateAppItemsLocked()
|
||||||
}
|
}
|
||||||
@@ -209,18 +229,30 @@ class FgsManagerController @Inject constructor(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun isAvailable(): Boolean {
|
|
||||||
return isAvailable
|
|
||||||
}
|
|
||||||
|
|
||||||
fun getNumRunningPackages(): Int {
|
fun getNumRunningPackages(): Int {
|
||||||
synchronized(lock) {
|
synchronized(lock) {
|
||||||
return getNumRunningPackagesLocked()
|
return getNumVisiblePackagesLocked()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun getNumRunningPackagesLocked() =
|
private fun getNumVisiblePackagesLocked(): Int {
|
||||||
runningServiceTokens.keys.count { it.uiControl != UIControl.HIDE_ENTRY }
|
return runningServiceTokens.keys.count {
|
||||||
|
it.uiControl != UIControl.HIDE_ENTRY && currentProfileIds.contains(it.userId)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun updateNumberOfVisibleRunningPackagesLocked() {
|
||||||
|
val num = getNumVisiblePackagesLocked()
|
||||||
|
if (num != lastNumberOfVisiblePackages) {
|
||||||
|
lastNumberOfVisiblePackages = num
|
||||||
|
changesSinceDialog = true
|
||||||
|
onNumberOfPackagesChangedListeners.forEach {
|
||||||
|
backgroundExecutor.execute {
|
||||||
|
it.onNumberOfPackagesChanged(num)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fun shouldUpdateFooterVisibility() = dialog == null
|
fun shouldUpdateFooterVisibility() = dialog == null
|
||||||
|
|
||||||
@@ -289,7 +321,9 @@ class FgsManagerController @Inject constructor(
|
|||||||
val ai = packageManager.getApplicationInfoAsUser(it.packageName, 0, it.userId)
|
val ai = packageManager.getApplicationInfoAsUser(it.packageName, 0, it.userId)
|
||||||
runningApps[it] = RunningApp(it.userId, it.packageName,
|
runningApps[it] = RunningApp(it.userId, it.packageName,
|
||||||
runningServiceTokens[it]!!.startTime, it.uiControl,
|
runningServiceTokens[it]!!.startTime, it.uiControl,
|
||||||
ai.loadLabel(packageManager), ai.loadIcon(packageManager))
|
packageManager.getApplicationLabel(ai),
|
||||||
|
packageManager.getUserBadgedIcon(
|
||||||
|
packageManager.getApplicationIcon(ai), UserHandle.of(it.userId)))
|
||||||
logEvent(stopped = false, it.packageName, it.userId, runningApps[it]!!.timeStarted)
|
logEvent(stopped = false, it.packageName, it.userId, runningApps[it]!!.timeStarted)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -404,6 +438,7 @@ class FgsManagerController @Inject constructor(
|
|||||||
val packageName: String
|
val packageName: String
|
||||||
) {
|
) {
|
||||||
val uid by lazy { packageManager.getPackageUidAsUser(packageName, userId) }
|
val uid by lazy { packageManager.getPackageUidAsUser(packageName, userId) }
|
||||||
|
var backgroundRestrictionExemptionReason = PowerExemptionManager.REASON_DENIED
|
||||||
|
|
||||||
private var uiControlInitialized = false
|
private var uiControlInitialized = false
|
||||||
var uiControl: UIControl = UIControl.NORMAL
|
var uiControl: UIControl = UIControl.NORMAL
|
||||||
@@ -416,7 +451,9 @@ class FgsManagerController @Inject constructor(
|
|||||||
private set
|
private set
|
||||||
|
|
||||||
fun updateUiControl() {
|
fun updateUiControl() {
|
||||||
uiControl = when (activityManager.getBackgroundRestrictionExemptionReason(uid)) {
|
backgroundRestrictionExemptionReason =
|
||||||
|
activityManager.getBackgroundRestrictionExemptionReason(uid)
|
||||||
|
uiControl = when (backgroundRestrictionExemptionReason) {
|
||||||
PowerExemptionManager.REASON_SYSTEM_UID,
|
PowerExemptionManager.REASON_SYSTEM_UID,
|
||||||
PowerExemptionManager.REASON_DEVICE_DEMO_MODE -> UIControl.HIDE_ENTRY
|
PowerExemptionManager.REASON_DEVICE_DEMO_MODE -> UIControl.HIDE_ENTRY
|
||||||
|
|
||||||
@@ -448,7 +485,7 @@ class FgsManagerController @Inject constructor(
|
|||||||
pw.indentIfPossible {
|
pw.indentIfPossible {
|
||||||
pw.println("userId=$userId")
|
pw.println("userId=$userId")
|
||||||
pw.println("packageName=$packageName")
|
pw.println("packageName=$packageName")
|
||||||
pw.println("uiControl=$uiControl")
|
pw.println("uiControl=$uiControl (reason=$backgroundRestrictionExemptionReason)")
|
||||||
}
|
}
|
||||||
pw.println("]")
|
pw.println("]")
|
||||||
}
|
}
|
||||||
@@ -525,7 +562,7 @@ class FgsManagerController @Inject constructor(
|
|||||||
pw.println("userId=$userId")
|
pw.println("userId=$userId")
|
||||||
pw.println("packageName=$packageName")
|
pw.println("packageName=$packageName")
|
||||||
pw.println("timeStarted=$timeStarted (time since start =" +
|
pw.println("timeStarted=$timeStarted (time since start =" +
|
||||||
" ${systemClock.elapsedRealtime() - timeStarted}ms)\"")
|
" ${systemClock.elapsedRealtime() - timeStarted}ms)")
|
||||||
pw.println("uiControl=$uiControl")
|
pw.println("uiControl=$uiControl")
|
||||||
pw.println("appLabel=$appLabel")
|
pw.println("appLabel=$appLabel")
|
||||||
pw.println("icon=$icon")
|
pw.println("icon=$icon")
|
||||||
@@ -542,6 +579,7 @@ class FgsManagerController @Inject constructor(
|
|||||||
override fun dump(printwriter: PrintWriter, args: Array<out String>) {
|
override fun dump(printwriter: PrintWriter, args: Array<out String>) {
|
||||||
val pw = IndentingPrintWriter(printwriter)
|
val pw = IndentingPrintWriter(printwriter)
|
||||||
synchronized(lock) {
|
synchronized(lock) {
|
||||||
|
pw.println("current user profiles = $currentProfileIds")
|
||||||
pw.println("changesSinceDialog=$changesSinceDialog")
|
pw.println("changesSinceDialog=$changesSinceDialog")
|
||||||
pw.println("Running service tokens: [")
|
pw.println("Running service tokens: [")
|
||||||
pw.indentIfPossible {
|
pw.indentIfPossible {
|
||||||
@@ -560,8 +598,10 @@ class FgsManagerController @Inject constructor(
|
|||||||
pw.indentIfPossible {
|
pw.indentIfPossible {
|
||||||
runningApps.forEach { (userPackage, runningApp) ->
|
runningApps.forEach { (userPackage, runningApp) ->
|
||||||
pw.println("{")
|
pw.println("{")
|
||||||
userPackage.dump(pw)
|
pw.indentIfPossible {
|
||||||
runningApp.dump(pw, systemClock)
|
userPackage.dump(pw)
|
||||||
|
runningApp.dump(pw, systemClock)
|
||||||
|
}
|
||||||
pw.println("}")
|
pw.println("}")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,285 @@
|
|||||||
|
/*
|
||||||
|
* 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 static org.mockito.ArgumentMatchers.anyInt;
|
||||||
|
import static org.mockito.ArgumentMatchers.argThat;
|
||||||
|
import static org.mockito.ArgumentMatchers.eq;
|
||||||
|
import static org.mockito.ArgumentMatchers.isNull;
|
||||||
|
import static org.mockito.Mockito.mock;
|
||||||
|
import static org.mockito.Mockito.never;
|
||||||
|
import static org.mockito.Mockito.times;
|
||||||
|
import static org.mockito.Mockito.verify;
|
||||||
|
|
||||||
|
import android.app.IActivityManager;
|
||||||
|
import android.app.IForegroundServiceObserver;
|
||||||
|
import android.content.BroadcastReceiver;
|
||||||
|
import android.content.Context;
|
||||||
|
import android.content.Intent;
|
||||||
|
import android.content.pm.PackageManager;
|
||||||
|
import android.content.pm.UserInfo;
|
||||||
|
import android.os.Binder;
|
||||||
|
import android.os.RemoteException;
|
||||||
|
import android.provider.DeviceConfig;
|
||||||
|
import android.testing.AndroidTestingRunner;
|
||||||
|
import android.testing.TestableLooper;
|
||||||
|
|
||||||
|
import androidx.test.filters.SmallTest;
|
||||||
|
|
||||||
|
import com.android.internal.config.sysui.SystemUiDeviceConfigFlags;
|
||||||
|
import com.android.systemui.SysuiTestCase;
|
||||||
|
import com.android.systemui.animation.DialogLaunchAnimator;
|
||||||
|
import com.android.systemui.broadcast.BroadcastDispatcher;
|
||||||
|
import com.android.systemui.dump.DumpManager;
|
||||||
|
import com.android.systemui.settings.UserTracker;
|
||||||
|
import com.android.systemui.util.DeviceConfigProxyFake;
|
||||||
|
import com.android.systemui.util.concurrency.FakeExecutor;
|
||||||
|
import com.android.systemui.util.time.FakeSystemClock;
|
||||||
|
|
||||||
|
import org.junit.Assert;
|
||||||
|
import org.junit.Before;
|
||||||
|
import org.junit.Test;
|
||||||
|
import org.junit.runner.RunWith;
|
||||||
|
import org.mockito.ArgumentCaptor;
|
||||||
|
import org.mockito.ArgumentMatchers;
|
||||||
|
import org.mockito.Mock;
|
||||||
|
import org.mockito.Mockito;
|
||||||
|
import org.mockito.MockitoAnnotations;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
@RunWith(AndroidTestingRunner.class)
|
||||||
|
@TestableLooper.RunWithLooper
|
||||||
|
@SmallTest
|
||||||
|
public class FgsManagerControllerTest extends SysuiTestCase {
|
||||||
|
|
||||||
|
FakeSystemClock mSystemClock;
|
||||||
|
FakeExecutor mMainExecutor;
|
||||||
|
FakeExecutor mBackgroundExecutor;
|
||||||
|
DeviceConfigProxyFake mDeviceConfigProxyFake;
|
||||||
|
|
||||||
|
@Mock
|
||||||
|
IActivityManager mIActivityManager;
|
||||||
|
@Mock
|
||||||
|
PackageManager mPackageManager;
|
||||||
|
@Mock
|
||||||
|
UserTracker mUserTracker;
|
||||||
|
@Mock
|
||||||
|
DialogLaunchAnimator mDialogLaunchAnimator;
|
||||||
|
@Mock
|
||||||
|
BroadcastDispatcher mBroadcastDispatcher;
|
||||||
|
@Mock
|
||||||
|
DumpManager mDumpManager;
|
||||||
|
|
||||||
|
private FgsManagerController mFmc;
|
||||||
|
|
||||||
|
private IForegroundServiceObserver mIForegroundServiceObserver;
|
||||||
|
private UserTracker.Callback mUserTrackerCallback;
|
||||||
|
private BroadcastReceiver mShowFgsManagerReceiver;
|
||||||
|
|
||||||
|
private List<UserInfo> mUserProfiles;
|
||||||
|
|
||||||
|
@Before
|
||||||
|
public void setUp() throws RemoteException {
|
||||||
|
MockitoAnnotations.initMocks(this);
|
||||||
|
|
||||||
|
mDeviceConfigProxyFake = new DeviceConfigProxyFake();
|
||||||
|
mDeviceConfigProxyFake.setProperty(DeviceConfig.NAMESPACE_SYSTEMUI,
|
||||||
|
SystemUiDeviceConfigFlags.TASK_MANAGER_ENABLED, "true", false);
|
||||||
|
mSystemClock = new FakeSystemClock();
|
||||||
|
mMainExecutor = new FakeExecutor(mSystemClock);
|
||||||
|
mBackgroundExecutor = new FakeExecutor(mSystemClock);
|
||||||
|
|
||||||
|
mUserProfiles = new ArrayList<>();
|
||||||
|
Mockito.doReturn(mUserProfiles).when(mUserTracker).getUserProfiles();
|
||||||
|
|
||||||
|
mFmc = createFgsManagerController();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testNumPackages() throws RemoteException {
|
||||||
|
setUserProfiles(0);
|
||||||
|
|
||||||
|
Binder b1 = new Binder();
|
||||||
|
Binder b2 = new Binder();
|
||||||
|
Assert.assertEquals(0, mFmc.getNumRunningPackages());
|
||||||
|
mIForegroundServiceObserver.onForegroundStateChanged(b1, "pkg1", 0, true);
|
||||||
|
Assert.assertEquals(1, mFmc.getNumRunningPackages());
|
||||||
|
mIForegroundServiceObserver.onForegroundStateChanged(b2, "pkg2", 0, true);
|
||||||
|
Assert.assertEquals(2, mFmc.getNumRunningPackages());
|
||||||
|
mIForegroundServiceObserver.onForegroundStateChanged(b1, "pkg1", 0, false);
|
||||||
|
Assert.assertEquals(1, mFmc.getNumRunningPackages());
|
||||||
|
mIForegroundServiceObserver.onForegroundStateChanged(b2, "pkg2", 0, false);
|
||||||
|
Assert.assertEquals(0, mFmc.getNumRunningPackages());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testNumPackagesDoesNotChangeWhenSecondFgsIsStarted() throws RemoteException {
|
||||||
|
setUserProfiles(0);
|
||||||
|
|
||||||
|
// Different tokens == different services
|
||||||
|
Binder b1 = new Binder();
|
||||||
|
Binder b2 = new Binder();
|
||||||
|
Assert.assertEquals(0, mFmc.getNumRunningPackages());
|
||||||
|
mIForegroundServiceObserver.onForegroundStateChanged(b1, "pkg1", 0, true);
|
||||||
|
Assert.assertEquals(1, mFmc.getNumRunningPackages());
|
||||||
|
mIForegroundServiceObserver.onForegroundStateChanged(b2, "pkg1", 0, true);
|
||||||
|
Assert.assertEquals(1, mFmc.getNumRunningPackages());
|
||||||
|
mIForegroundServiceObserver.onForegroundStateChanged(b1, "pkg1", 0, false);
|
||||||
|
Assert.assertEquals(1, mFmc.getNumRunningPackages());
|
||||||
|
mIForegroundServiceObserver.onForegroundStateChanged(b2, "pkg1", 0, false);
|
||||||
|
Assert.assertEquals(0, mFmc.getNumRunningPackages());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testNumPackagesListener() throws RemoteException {
|
||||||
|
setUserProfiles(0);
|
||||||
|
|
||||||
|
FgsManagerController.OnNumberOfPackagesChangedListener onNumberOfPackagesChangedListener =
|
||||||
|
Mockito.mock(FgsManagerController.OnNumberOfPackagesChangedListener.class);
|
||||||
|
|
||||||
|
mFmc.addOnNumberOfPackagesChangedListener(onNumberOfPackagesChangedListener);
|
||||||
|
|
||||||
|
Binder b1 = new Binder();
|
||||||
|
Binder b2 = new Binder();
|
||||||
|
|
||||||
|
verify(onNumberOfPackagesChangedListener, never()).onNumberOfPackagesChanged(anyInt());
|
||||||
|
|
||||||
|
mIForegroundServiceObserver.onForegroundStateChanged(b1, "pkg1", 0, true);
|
||||||
|
mBackgroundExecutor.advanceClockToLast();
|
||||||
|
mBackgroundExecutor.runAllReady();
|
||||||
|
verify(onNumberOfPackagesChangedListener).onNumberOfPackagesChanged(1);
|
||||||
|
|
||||||
|
mIForegroundServiceObserver.onForegroundStateChanged(b2, "pkg2", 0, true);
|
||||||
|
mBackgroundExecutor.advanceClockToLast();
|
||||||
|
mBackgroundExecutor.runAllReady();
|
||||||
|
verify(onNumberOfPackagesChangedListener).onNumberOfPackagesChanged(2);
|
||||||
|
|
||||||
|
mIForegroundServiceObserver.onForegroundStateChanged(b1, "pkg1", 0, false);
|
||||||
|
mBackgroundExecutor.advanceClockToLast();
|
||||||
|
mBackgroundExecutor.runAllReady();
|
||||||
|
verify(onNumberOfPackagesChangedListener, times(2)).onNumberOfPackagesChanged(1);
|
||||||
|
|
||||||
|
mIForegroundServiceObserver.onForegroundStateChanged(b2, "pkg2", 0, false);
|
||||||
|
mBackgroundExecutor.advanceClockToLast();
|
||||||
|
mBackgroundExecutor.runAllReady();
|
||||||
|
verify(onNumberOfPackagesChangedListener).onNumberOfPackagesChanged(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testChangesSinceLastDialog() throws RemoteException {
|
||||||
|
setUserProfiles(0);
|
||||||
|
|
||||||
|
Assert.assertFalse(mFmc.getChangesSinceDialog());
|
||||||
|
mIForegroundServiceObserver.onForegroundStateChanged(new Binder(), "pkg", 0, true);
|
||||||
|
Assert.assertTrue(mFmc.getChangesSinceDialog());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testProfilePackagesCounted() throws RemoteException {
|
||||||
|
setUserProfiles(0, 10);
|
||||||
|
|
||||||
|
mIForegroundServiceObserver.onForegroundStateChanged(new Binder(), "pkg1", 0, true);
|
||||||
|
mIForegroundServiceObserver.onForegroundStateChanged(new Binder(), "pkg2", 10, true);
|
||||||
|
Assert.assertEquals(2, mFmc.getNumRunningPackages());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testSecondaryUserPackagesAreNotCounted() throws RemoteException {
|
||||||
|
setUserProfiles(0);
|
||||||
|
|
||||||
|
mIForegroundServiceObserver.onForegroundStateChanged(new Binder(), "pkg1", 0, true);
|
||||||
|
mIForegroundServiceObserver.onForegroundStateChanged(new Binder(), "pkg2", 10, true);
|
||||||
|
Assert.assertEquals(1, mFmc.getNumRunningPackages());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testSecondaryUserPackagesAreCountedWhenUserSwitch() throws RemoteException {
|
||||||
|
setUserProfiles(0);
|
||||||
|
|
||||||
|
mIForegroundServiceObserver.onForegroundStateChanged(new Binder(), "pkg1", 0, true);
|
||||||
|
mIForegroundServiceObserver.onForegroundStateChanged(new Binder(), "pkg2", 10, true);
|
||||||
|
mIForegroundServiceObserver.onForegroundStateChanged(new Binder(), "pkg3", 10, true);
|
||||||
|
|
||||||
|
Assert.assertEquals(1, mFmc.getNumRunningPackages());
|
||||||
|
|
||||||
|
setUserProfiles(10);
|
||||||
|
Assert.assertEquals(2, mFmc.getNumRunningPackages());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
FgsManagerController createFgsManagerController() throws RemoteException {
|
||||||
|
ArgumentCaptor<IForegroundServiceObserver> iForegroundServiceObserverArgumentCaptor =
|
||||||
|
ArgumentCaptor.forClass(IForegroundServiceObserver.class);
|
||||||
|
ArgumentCaptor<UserTracker.Callback> userTrackerCallbackArgumentCaptor =
|
||||||
|
ArgumentCaptor.forClass(UserTracker.Callback.class);
|
||||||
|
ArgumentCaptor<BroadcastReceiver> showFgsManagerReceiverArgumentCaptor =
|
||||||
|
ArgumentCaptor.forClass(BroadcastReceiver.class);
|
||||||
|
|
||||||
|
FgsManagerController result = new FgsManagerController(
|
||||||
|
mContext,
|
||||||
|
mMainExecutor,
|
||||||
|
mBackgroundExecutor,
|
||||||
|
mSystemClock,
|
||||||
|
mIActivityManager,
|
||||||
|
mPackageManager,
|
||||||
|
mUserTracker,
|
||||||
|
mDeviceConfigProxyFake,
|
||||||
|
mDialogLaunchAnimator,
|
||||||
|
mBroadcastDispatcher,
|
||||||
|
mDumpManager
|
||||||
|
);
|
||||||
|
result.init();
|
||||||
|
|
||||||
|
verify(mIActivityManager).registerForegroundServiceObserver(
|
||||||
|
iForegroundServiceObserverArgumentCaptor.capture()
|
||||||
|
);
|
||||||
|
verify(mUserTracker).addCallback(
|
||||||
|
userTrackerCallbackArgumentCaptor.capture(),
|
||||||
|
ArgumentMatchers.eq(mBackgroundExecutor)
|
||||||
|
);
|
||||||
|
verify(mBroadcastDispatcher).registerReceiver(
|
||||||
|
showFgsManagerReceiverArgumentCaptor.capture(),
|
||||||
|
argThat(fltr -> fltr.matchAction(Intent.ACTION_SHOW_FOREGROUND_SERVICE_MANAGER)),
|
||||||
|
eq(mMainExecutor),
|
||||||
|
isNull(),
|
||||||
|
eq(Context.RECEIVER_NOT_EXPORTED),
|
||||||
|
isNull()
|
||||||
|
);
|
||||||
|
|
||||||
|
mIForegroundServiceObserver = iForegroundServiceObserverArgumentCaptor.getValue();
|
||||||
|
mUserTrackerCallback = userTrackerCallbackArgumentCaptor.getValue();
|
||||||
|
mShowFgsManagerReceiver = showFgsManagerReceiverArgumentCaptor.getValue();
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void setUserProfiles(int current, int... profileUserIds) {
|
||||||
|
mUserProfiles.clear();
|
||||||
|
mUserProfiles.add(new UserInfo(current, "current:" + current, 0));
|
||||||
|
for (int id : profileUserIds) {
|
||||||
|
mUserProfiles.add(new UserInfo(id, "profile:" + id, 0));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mUserTrackerCallback != null) {
|
||||||
|
mUserTrackerCallback.onUserChanged(current, mock(Context.class));
|
||||||
|
mUserTrackerCallback.onProfilesChanged(mUserProfiles);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user