Initialize UserTracker with boot user
UserManager provides getBootUser(), which can be used to set
the initial value of the UserTracker, rather than always
default to user 0. This can help keyguard (and others) start
in the right state and reduce jank on boot with HSUM.
Bug: 268416867
Bug: 361730315
Test: atest UserTrackerImplTest
Flag: EXEMPT bugfix
Change-Id: Ie5cae1a5114647b5071cb9587faa4455ed4fc377
diff --git a/packages/SystemUI/src/com/android/systemui/settings/MultiUserUtilsModule.java b/packages/SystemUI/src/com/android/systemui/settings/MultiUserUtilsModule.java
index 05f19ef..cc470a6 100644
--- a/packages/SystemUI/src/com/android/systemui/settings/MultiUserUtilsModule.java
+++ b/packages/SystemUI/src/com/android/systemui/settings/MultiUserUtilsModule.java
@@ -67,7 +67,7 @@
@Background CoroutineDispatcher backgroundDispatcher,
@Background Handler handler
) {
- int startingUser = ActivityManager.getCurrentUser();
+ int startingUser = userManager.getBootUser().getIdentifier();
UserTrackerImpl tracker = new UserTrackerImpl(context, featureFlagsProvider, userManager,
iActivityManager, dumpManager, appScope, backgroundDispatcher, handler);
tracker.initialize(startingUser);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/settings/UserTrackerImplReceiveTest.kt b/packages/SystemUI/tests/src/com/android/systemui/settings/UserTrackerImplReceiveTest.kt
index 263b001..a82e5c4 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/settings/UserTrackerImplReceiveTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/settings/UserTrackerImplReceiveTest.kt
@@ -14,6 +14,7 @@
import com.android.systemui.flags.FakeFeatureFlagsClassic
import com.android.systemui.util.mockito.any
import com.android.systemui.util.mockito.capture
+import com.android.systemui.util.mockito.whenever
import com.google.common.truth.Truth.assertThat
import java.util.concurrent.Executor
import kotlinx.coroutines.test.StandardTestDispatcher
@@ -29,7 +30,6 @@
import org.mockito.Mock
import org.mockito.Mockito.times
import org.mockito.Mockito.verify
-import org.mockito.Mockito.`when`
import org.mockito.MockitoAnnotations
@SmallTest
@@ -73,8 +73,8 @@
fun setUp() {
MockitoAnnotations.initMocks(this)
- `when`(context.user).thenReturn(UserHandle.SYSTEM)
- `when`(context.createContextAsUser(ArgumentMatchers.any(), anyInt())).thenReturn(context)
+ whenever(context.user).thenReturn(UserHandle.SYSTEM)
+ whenever(context.createContextAsUser(ArgumentMatchers.any(), anyInt())).thenReturn(context)
}
@Test
@@ -94,7 +94,7 @@
tracker.addCallback(callback, executor)
val profileID = tracker.userId + 10
- `when`(userManager.getProfiles(anyInt())).thenAnswer { invocation ->
+ whenever(userManager.getProfiles(anyInt())).thenAnswer { invocation ->
val id = invocation.getArgument<Int>(0)
val info = UserInfo(id, "", UserInfo.FLAG_FULL)
val infoProfile =
diff --git a/packages/SystemUI/tests/src/com/android/systemui/settings/UserTrackerImplTest.kt b/packages/SystemUI/tests/src/com/android/systemui/settings/UserTrackerImplTest.kt
index 774aa51..2e2ac3e 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/settings/UserTrackerImplTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/settings/UserTrackerImplTest.kt
@@ -33,9 +33,11 @@
import com.android.systemui.flags.Flags
import com.android.systemui.util.concurrency.FakeExecutor
import com.android.systemui.util.mockito.capture
+import com.android.systemui.util.mockito.whenever
import com.android.systemui.util.time.FakeSystemClock
import com.google.common.truth.Truth.assertThat
import com.google.common.truth.TruthJUnit.assume
+import java.util.concurrent.Executor
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.test.StandardTestDispatcher
import kotlinx.coroutines.test.TestScope
@@ -54,10 +56,7 @@
import org.mockito.Mock
import org.mockito.Mockito.never
import org.mockito.Mockito.verify
-import org.mockito.Mockito.`when`
import org.mockito.MockitoAnnotations
-import java.util.concurrent.Executor
-
@OptIn(ExperimentalCoroutinesApi::class)
@SmallTest
@@ -71,27 +70,19 @@
fun isBackgroundUserTrackerEnabled(): Iterable<Boolean> = listOf(true, false)
}
- @Mock
- private lateinit var context: Context
+ @Mock private lateinit var context: Context
- @Mock
- private lateinit var userManager: UserManager
+ @Mock private lateinit var userManager: UserManager
- @Mock
- private lateinit var iActivityManager: IActivityManager
+ @Mock private lateinit var iActivityManager: IActivityManager
- @Mock
- private lateinit var userSwitchingReply: IRemoteCallback
+ @Mock private lateinit var userSwitchingReply: IRemoteCallback
- @Mock(stubOnly = true)
- private lateinit var dumpManager: DumpManager
+ @Mock(stubOnly = true) private lateinit var dumpManager: DumpManager
- @Mock(stubOnly = true)
- private lateinit var handler: Handler
+ @Mock(stubOnly = true) private lateinit var handler: Handler
- @Parameterized.Parameter
- @JvmField
- var isBackgroundUserTrackerEnabled: Boolean = false
+ @Parameterized.Parameter @JvmField var isBackgroundUserTrackerEnabled: Boolean = false
private val testScope = TestScope()
private val testDispatcher = StandardTestDispatcher(testScope.testScheduler)
@@ -104,365 +95,379 @@
fun setUp() {
MockitoAnnotations.initMocks(this)
- `when`(context.userId).thenReturn(UserHandle.USER_SYSTEM)
- `when`(context.user).thenReturn(UserHandle.SYSTEM)
- `when`(context.createContextAsUser(any(), anyInt())).thenAnswer { invocation ->
+ whenever(context.userId).thenReturn(UserHandle.USER_SYSTEM)
+ whenever(context.user).thenReturn(UserHandle.SYSTEM)
+ whenever(context.createContextAsUser(any(), anyInt())).thenAnswer { invocation ->
val user = invocation.getArgument<UserHandle>(0)
- `when`(context.user).thenReturn(user)
- `when`(context.userId).thenReturn(user.identifier)
+ whenever(context.user).thenReturn(user)
+ whenever(context.userId).thenReturn(user.identifier)
context
}
- `when`(userManager.getProfiles(anyInt())).thenAnswer { invocation ->
+ whenever(userManager.getProfiles(anyInt())).thenAnswer { invocation ->
val info = UserInfo(invocation.getArgument<Int>(0), "", UserInfo.FLAG_FULL)
listOf(info)
}
featureFlags.set(Flags.USER_TRACKER_BACKGROUND_CALLBACKS, isBackgroundUserTrackerEnabled)
tracker =
- UserTrackerImpl(
- context,
- { featureFlags },
- userManager,
- iActivityManager,
- dumpManager,
- testScope.backgroundScope,
- testDispatcher,
- handler,
- )
+ UserTrackerImpl(
+ context,
+ { featureFlags },
+ userManager,
+ iActivityManager,
+ dumpManager,
+ testScope.backgroundScope,
+ testDispatcher,
+ handler,
+ )
}
+ @Test fun testNotInitialized() = testScope.runTest { assertThat(tracker.initialized).isFalse() }
+
+ @Test(expected = IllegalStateException::class)
+ fun testGetUserIdBeforeInitThrowsException() = testScope.runTest { tracker.userId }
+
+ @Test(expected = IllegalStateException::class)
+ fun testGetUserHandleBeforeInitThrowsException() = testScope.runTest { tracker.userHandle }
+
+ @Test(expected = IllegalStateException::class)
+ fun testGetUserContextBeforeInitThrowsException() = testScope.runTest { tracker.userContext }
+
+ @Test(expected = IllegalStateException::class)
+ fun testGetUserContentResolverBeforeInitThrowsException() =
+ testScope.runTest { tracker.userContentResolver }
+
+ @Test(expected = IllegalStateException::class)
+ fun testGetUserProfilesBeforeInitThrowsException() = testScope.runTest { tracker.userProfiles }
+
@Test
- fun testNotInitialized() = testScope.runTest {
- assertThat(tracker.initialized).isFalse()
- }
+ fun testInitialize() =
+ testScope.runTest {
+ tracker.initialize(0)
- @Test(expected = IllegalStateException::class)
- fun testGetUserIdBeforeInitThrowsException() = testScope.runTest {
- tracker.userId
- }
-
- @Test(expected = IllegalStateException::class)
- fun testGetUserHandleBeforeInitThrowsException() = testScope.runTest {
- tracker.userHandle
- }
-
- @Test(expected = IllegalStateException::class)
- fun testGetUserContextBeforeInitThrowsException() = testScope.runTest {
- tracker.userContext
- }
-
- @Test(expected = IllegalStateException::class)
- fun testGetUserContentResolverBeforeInitThrowsException() = testScope.runTest {
- tracker.userContentResolver
- }
-
- @Test(expected = IllegalStateException::class)
- fun testGetUserProfilesBeforeInitThrowsException() = testScope.runTest {
- tracker.userProfiles
- }
+ assertThat(tracker.initialized).isTrue()
+ }
@Test
- fun testInitialize() = testScope.runTest {
- tracker.initialize(0)
+ fun testReceiverRegisteredOnInitialize() =
+ testScope.runTest {
+ tracker.initialize(0)
- assertThat(tracker.initialized).isTrue()
- }
+ val captor = ArgumentCaptor.forClass(IntentFilter::class.java)
- @Test
- fun testReceiverRegisteredOnInitialize() = testScope.runTest {
- tracker.initialize(0)
-
- val captor = ArgumentCaptor.forClass(IntentFilter::class.java)
-
- verify(context)
+ verify(context)
.registerReceiverForAllUsers(eq(tracker), capture(captor), isNull(), eq(handler))
- with(captor.value) {
- assertThat(countActions()).isEqualTo(11)
- assertThat(hasAction(Intent.ACTION_LOCALE_CHANGED)).isTrue()
- assertThat(hasAction(Intent.ACTION_USER_INFO_CHANGED)).isTrue()
- assertThat(hasAction(Intent.ACTION_MANAGED_PROFILE_AVAILABLE)).isTrue()
- assertThat(hasAction(Intent.ACTION_MANAGED_PROFILE_UNAVAILABLE)).isTrue()
- assertThat(hasAction(Intent.ACTION_MANAGED_PROFILE_ADDED)).isTrue()
- assertThat(hasAction(Intent.ACTION_MANAGED_PROFILE_REMOVED)).isTrue()
- assertThat(hasAction(Intent.ACTION_MANAGED_PROFILE_UNLOCKED)).isTrue()
- assertThat(hasAction(Intent.ACTION_PROFILE_ADDED)).isTrue()
- assertThat(hasAction(Intent.ACTION_PROFILE_REMOVED)).isTrue()
- assertThat(hasAction(Intent.ACTION_PROFILE_AVAILABLE)).isTrue()
- assertThat(hasAction(Intent.ACTION_PROFILE_UNAVAILABLE)).isTrue()
- }
- }
-
- @Test
- fun testInitialValuesSet() = testScope.runTest {
- val testID = 4
- tracker.initialize(testID)
-
- verify(userManager).getProfiles(testID)
-
- assertThat(tracker.userId).isEqualTo(testID)
- assertThat(tracker.userHandle).isEqualTo(UserHandle.of(testID))
- assertThat(tracker.userContext.userId).isEqualTo(testID)
- assertThat(tracker.userContext.user).isEqualTo(UserHandle.of(testID))
- assertThat(tracker.userProfiles).hasSize(1)
-
- val info = tracker.userProfiles[0]
- assertThat(info.id).isEqualTo(testID)
- }
-
- @Test
- fun testUserSwitch() = testScope.runTest {
- tracker.initialize(0)
- val newID = 5
-
- val captor = ArgumentCaptor.forClass(IUserSwitchObserver::class.java)
- verify(iActivityManager).registerUserSwitchObserver(capture(captor), anyString())
- captor.value.onBeforeUserSwitching(newID)
- captor.value.onUserSwitching(newID, userSwitchingReply)
- runCurrent()
- verify(userSwitchingReply).sendResult(any())
-
- verify(userManager).getProfiles(newID)
-
- assertThat(tracker.userId).isEqualTo(newID)
- assertThat(tracker.userHandle).isEqualTo(UserHandle.of(newID))
- assertThat(tracker.userContext.userId).isEqualTo(newID)
- assertThat(tracker.userContext.user).isEqualTo(UserHandle.of(newID))
- assertThat(tracker.userProfiles).hasSize(1)
-
- val info = tracker.userProfiles[0]
- assertThat(info.id).isEqualTo(newID)
- }
-
- @Test
- fun testManagedProfileAvailable() = testScope.runTest {
- tracker.initialize(0)
- val profileID = tracker.userId + 10
-
- `when`(userManager.getProfiles(anyInt())).thenAnswer { invocation ->
- val id = invocation.getArgument<Int>(0)
- val info = UserInfo(id, "", UserInfo.FLAG_FULL)
- val infoProfile = UserInfo(
- id + 10,
- "",
- "",
- UserInfo.FLAG_MANAGED_PROFILE,
- UserManager.USER_TYPE_PROFILE_MANAGED
- )
- infoProfile.profileGroupId = id
- listOf(info, infoProfile)
+ with(captor.value) {
+ assertThat(countActions()).isEqualTo(11)
+ assertThat(hasAction(Intent.ACTION_LOCALE_CHANGED)).isTrue()
+ assertThat(hasAction(Intent.ACTION_USER_INFO_CHANGED)).isTrue()
+ assertThat(hasAction(Intent.ACTION_MANAGED_PROFILE_AVAILABLE)).isTrue()
+ assertThat(hasAction(Intent.ACTION_MANAGED_PROFILE_UNAVAILABLE)).isTrue()
+ assertThat(hasAction(Intent.ACTION_MANAGED_PROFILE_ADDED)).isTrue()
+ assertThat(hasAction(Intent.ACTION_MANAGED_PROFILE_REMOVED)).isTrue()
+ assertThat(hasAction(Intent.ACTION_MANAGED_PROFILE_UNLOCKED)).isTrue()
+ assertThat(hasAction(Intent.ACTION_PROFILE_ADDED)).isTrue()
+ assertThat(hasAction(Intent.ACTION_PROFILE_REMOVED)).isTrue()
+ assertThat(hasAction(Intent.ACTION_PROFILE_AVAILABLE)).isTrue()
+ assertThat(hasAction(Intent.ACTION_PROFILE_UNAVAILABLE)).isTrue()
+ }
}
- val intent = Intent(Intent.ACTION_MANAGED_PROFILE_AVAILABLE)
- .putExtra(Intent.EXTRA_USER, UserHandle.of(profileID))
- tracker.onReceive(context, intent)
-
- assertThat(tracker.userProfiles.map { it.id }).containsExactly(tracker.userId, profileID)
- }
-
@Test
- fun testManagedProfileUnavailable() = testScope.runTest {
- tracker.initialize(0)
- val profileID = tracker.userId + 10
+ fun testInitialValuesSet() =
+ testScope.runTest {
+ val testID = 4
+ tracker.initialize(testID)
- `when`(userManager.getProfiles(anyInt())).thenAnswer { invocation ->
- val id = invocation.getArgument<Int>(0)
- val info = UserInfo(id, "", UserInfo.FLAG_FULL)
- val infoProfile = UserInfo(
- id + 10,
- "",
- "",
- UserInfo.FLAG_MANAGED_PROFILE or UserInfo.FLAG_QUIET_MODE,
- UserManager.USER_TYPE_PROFILE_MANAGED
- )
- infoProfile.profileGroupId = id
- listOf(info, infoProfile)
+ verify(userManager).getProfiles(testID)
+
+ assertThat(tracker.userId).isEqualTo(testID)
+ assertThat(tracker.userHandle).isEqualTo(UserHandle.of(testID))
+ assertThat(tracker.userContext.userId).isEqualTo(testID)
+ assertThat(tracker.userContext.user).isEqualTo(UserHandle.of(testID))
+ assertThat(tracker.userProfiles).hasSize(1)
+
+ val info = tracker.userProfiles[0]
+ assertThat(info.id).isEqualTo(testID)
}
- val intent = Intent(Intent.ACTION_MANAGED_PROFILE_UNAVAILABLE)
- .putExtra(Intent.EXTRA_USER, UserHandle.of(profileID))
- tracker.onReceive(context, intent)
-
- assertThat(tracker.userProfiles.map { it.id }).containsExactly(tracker.userId, profileID)
- }
-
@Test
- fun testManagedProfileStartedAndRemoved() = testScope.runTest {
- tracker.initialize(0)
- val profileID = tracker.userId + 10
+ fun testUserSwitch() =
+ testScope.runTest {
+ tracker.initialize(0)
+ val newID = 5
- `when`(userManager.getProfiles(anyInt())).thenAnswer { invocation ->
- val id = invocation.getArgument<Int>(0)
- val info = UserInfo(id, "", UserInfo.FLAG_FULL)
- val infoProfile = UserInfo(
- id + 10,
- "",
- "",
- UserInfo.FLAG_MANAGED_PROFILE,
- UserManager.USER_TYPE_PROFILE_MANAGED
- )
- infoProfile.profileGroupId = id
- listOf(info, infoProfile)
+ val captor = ArgumentCaptor.forClass(IUserSwitchObserver::class.java)
+ verify(iActivityManager).registerUserSwitchObserver(capture(captor), anyString())
+ captor.value.onBeforeUserSwitching(newID)
+ captor.value.onUserSwitching(newID, userSwitchingReply)
+ runCurrent()
+ verify(userSwitchingReply).sendResult(any())
+
+ verify(userManager).getProfiles(newID)
+
+ assertThat(tracker.userId).isEqualTo(newID)
+ assertThat(tracker.userHandle).isEqualTo(UserHandle.of(newID))
+ assertThat(tracker.userContext.userId).isEqualTo(newID)
+ assertThat(tracker.userContext.user).isEqualTo(UserHandle.of(newID))
+ assertThat(tracker.userProfiles).hasSize(1)
+
+ val info = tracker.userProfiles[0]
+ assertThat(info.id).isEqualTo(newID)
}
- // Managed profile started
- val intent = Intent(Intent.ACTION_MANAGED_PROFILE_UNLOCKED)
- .putExtra(Intent.EXTRA_USER, UserHandle.of(profileID))
- tracker.onReceive(context, intent)
+ @Test
+ fun testManagedProfileAvailable() =
+ testScope.runTest {
+ tracker.initialize(0)
+ val profileID = tracker.userId + 10
- assertThat(tracker.userProfiles.map { it.id }).containsExactly(tracker.userId, profileID)
+ whenever(userManager.getProfiles(anyInt())).thenAnswer { invocation ->
+ val id = invocation.getArgument<Int>(0)
+ val info = UserInfo(id, "", UserInfo.FLAG_FULL)
+ val infoProfile =
+ UserInfo(
+ id + 10,
+ "",
+ "",
+ UserInfo.FLAG_MANAGED_PROFILE,
+ UserManager.USER_TYPE_PROFILE_MANAGED
+ )
+ infoProfile.profileGroupId = id
+ listOf(info, infoProfile)
+ }
- `when`(userManager.getProfiles(anyInt())).thenAnswer { invocation ->
- listOf(UserInfo(invocation.getArgument(0), "", UserInfo.FLAG_FULL))
+ val intent =
+ Intent(Intent.ACTION_MANAGED_PROFILE_AVAILABLE)
+ .putExtra(Intent.EXTRA_USER, UserHandle.of(profileID))
+ tracker.onReceive(context, intent)
+
+ assertThat(tracker.userProfiles.map { it.id })
+ .containsExactly(tracker.userId, profileID)
}
- val intent2 = Intent(Intent.ACTION_MANAGED_PROFILE_REMOVED)
- .putExtra(Intent.EXTRA_USER, UserHandle.of(profileID))
- tracker.onReceive(context, intent2)
-
- assertThat(tracker.userProfiles.map { it.id }).containsExactly(tracker.userId)
- }
-
@Test
- fun testCallbackNotCalledOnAdd() = testScope.runTest {
- tracker.initialize(0)
- val callback = TestCallback()
+ fun testManagedProfileUnavailable() =
+ testScope.runTest {
+ tracker.initialize(0)
+ val profileID = tracker.userId + 10
- tracker.addCallback(callback, executor)
+ whenever(userManager.getProfiles(anyInt())).thenAnswer { invocation ->
+ val id = invocation.getArgument<Int>(0)
+ val info = UserInfo(id, "", UserInfo.FLAG_FULL)
+ val infoProfile =
+ UserInfo(
+ id + 10,
+ "",
+ "",
+ UserInfo.FLAG_MANAGED_PROFILE or UserInfo.FLAG_QUIET_MODE,
+ UserManager.USER_TYPE_PROFILE_MANAGED
+ )
+ infoProfile.profileGroupId = id
+ listOf(info, infoProfile)
+ }
- assertThat(callback.calledOnProfilesChanged).isEqualTo(0)
- assertThat(callback.calledOnUserChanged).isEqualTo(0)
- }
+ val intent =
+ Intent(Intent.ACTION_MANAGED_PROFILE_UNAVAILABLE)
+ .putExtra(Intent.EXTRA_USER, UserHandle.of(profileID))
+ tracker.onReceive(context, intent)
- @Test
- fun testCallbackCalledOnUserChanging() = testScope.runTest {
- tracker.initialize(0)
- val callback = TestCallback()
- tracker.addCallback(callback, executor)
-
- val newID = 5
-
- val captor = ArgumentCaptor.forClass(IUserSwitchObserver::class.java)
- verify(iActivityManager).registerUserSwitchObserver(capture(captor), anyString())
- captor.value.onBeforeUserSwitching(newID)
- captor.value.onUserSwitching(newID, userSwitchingReply)
- runCurrent()
-
- verify(userSwitchingReply).sendResult(any())
- assertThat(callback.calledOnUserChanging).isEqualTo(1)
- assertThat(callback.lastUser).isEqualTo(newID)
- assertThat(callback.lastUserContext?.userId).isEqualTo(newID)
- }
-
- @Test
- fun testAsyncCallbackWaitsUserToChange() = testScope.runTest {
- // Skip this test for CountDownLatch variation. The problem is that there would be a
- // deadlock if the callbacks processing runs on the same thread as the callback (which
- // is blocked by the latch). Before the change it works because the callbacks are
- // processed on a binder thread which is always distinct.
- // This is the issue that this feature addresses.
- assume().that(isBackgroundUserTrackerEnabled).isTrue()
-
- tracker.initialize(0)
- val callback = TestCallback()
- val callbackExecutor = FakeExecutor(FakeSystemClock())
- tracker.addCallback(callback, callbackExecutor)
-
- val newID = 5
-
- val captor = ArgumentCaptor.forClass(IUserSwitchObserver::class.java)
- verify(iActivityManager).registerUserSwitchObserver(capture(captor), anyString())
- captor.value.onUserSwitching(newID, userSwitchingReply)
-
- assertThat(callback.calledOnUserChanging).isEqualTo(0)
- verify(userSwitchingReply, never()).sendResult(any())
-
- FakeExecutor.exhaustExecutors(callbackExecutor)
- runCurrent()
- FakeExecutor.exhaustExecutors(callbackExecutor)
- runCurrent()
-
- assertThat(callback.calledOnUserChanging).isEqualTo(1)
- verify(userSwitchingReply).sendResult(any())
- }
-
- @Test
- fun testCallbackCalledOnUserChanged() = testScope.runTest {
- tracker.initialize(0)
- val callback = TestCallback()
- tracker.addCallback(callback, executor)
-
- val newID = 5
-
- val captor = ArgumentCaptor.forClass(IUserSwitchObserver::class.java)
- verify(iActivityManager).registerUserSwitchObserver(capture(captor), anyString())
- captor.value.onBeforeUserSwitching(newID)
- captor.value.onUserSwitchComplete(newID)
- runCurrent()
-
- assertThat(callback.calledOnUserChanged).isEqualTo(1)
- assertThat(callback.lastUser).isEqualTo(newID)
- assertThat(callback.lastUserContext?.userId).isEqualTo(newID)
- assertThat(callback.calledOnProfilesChanged).isEqualTo(1)
- assertThat(callback.lastUserProfiles.map { it.id }).containsExactly(newID)
- }
-
- @Test
- fun testCallbackCalledOnUserInfoChanged() = testScope.runTest {
- tracker.initialize(0)
- val callback = TestCallback()
- tracker.addCallback(callback, executor)
- val profileID = tracker.userId + 10
-
- `when`(userManager.getProfiles(anyInt())).thenAnswer { invocation ->
- val id = invocation.getArgument<Int>(0)
- val info = UserInfo(id, "", UserInfo.FLAG_FULL)
- val infoProfile = UserInfo(
- id + 10,
- "",
- "",
- UserInfo.FLAG_MANAGED_PROFILE,
- UserManager.USER_TYPE_PROFILE_MANAGED
- )
- infoProfile.profileGroupId = id
- listOf(info, infoProfile)
+ assertThat(tracker.userProfiles.map { it.id })
+ .containsExactly(tracker.userId, profileID)
}
- val intent = Intent(Intent.ACTION_USER_INFO_CHANGED)
- .putExtra(Intent.EXTRA_USER, UserHandle.of(profileID))
+ @Test
+ fun testManagedProfileStartedAndRemoved() =
+ testScope.runTest {
+ tracker.initialize(0)
+ val profileID = tracker.userId + 10
- tracker.onReceive(context, intent)
+ whenever(userManager.getProfiles(anyInt())).thenAnswer { invocation ->
+ val id = invocation.getArgument<Int>(0)
+ val info = UserInfo(id, "", UserInfo.FLAG_FULL)
+ val infoProfile =
+ UserInfo(
+ id + 10,
+ "",
+ "",
+ UserInfo.FLAG_MANAGED_PROFILE,
+ UserManager.USER_TYPE_PROFILE_MANAGED
+ )
+ infoProfile.profileGroupId = id
+ listOf(info, infoProfile)
+ }
- assertThat(callback.calledOnUserChanged).isEqualTo(0)
- assertThat(callback.calledOnProfilesChanged).isEqualTo(1)
- assertThat(callback.lastUserProfiles.map { it.id }).containsExactly(0, profileID)
- }
+ // Managed profile started
+ val intent =
+ Intent(Intent.ACTION_MANAGED_PROFILE_UNLOCKED)
+ .putExtra(Intent.EXTRA_USER, UserHandle.of(profileID))
+ tracker.onReceive(context, intent)
+
+ assertThat(tracker.userProfiles.map { it.id })
+ .containsExactly(tracker.userId, profileID)
+
+ whenever(userManager.getProfiles(anyInt())).thenAnswer { invocation ->
+ listOf(UserInfo(invocation.getArgument(0), "", UserInfo.FLAG_FULL))
+ }
+
+ val intent2 =
+ Intent(Intent.ACTION_MANAGED_PROFILE_REMOVED)
+ .putExtra(Intent.EXTRA_USER, UserHandle.of(profileID))
+ tracker.onReceive(context, intent2)
+
+ assertThat(tracker.userProfiles.map { it.id }).containsExactly(tracker.userId)
+ }
@Test
- fun testCallbackRemoved() = testScope.runTest {
- tracker.initialize(0)
- val newID = 5
- val profileID = newID + 10
+ fun testCallbackNotCalledOnAdd() =
+ testScope.runTest {
+ tracker.initialize(0)
+ val callback = TestCallback()
- val callback = TestCallback()
- tracker.addCallback(callback, executor)
- tracker.removeCallback(callback)
+ tracker.addCallback(callback, executor)
- val captor = ArgumentCaptor.forClass(IUserSwitchObserver::class.java)
- verify(iActivityManager).registerUserSwitchObserver(capture(captor), anyString())
- captor.value.onUserSwitching(newID, userSwitchingReply)
- runCurrent()
- verify(userSwitchingReply).sendResult(any())
- captor.value.onUserSwitchComplete(newID)
+ assertThat(callback.calledOnProfilesChanged).isEqualTo(0)
+ assertThat(callback.calledOnUserChanged).isEqualTo(0)
+ }
- val intentProfiles = Intent(Intent.ACTION_MANAGED_PROFILE_AVAILABLE)
- .putExtra(Intent.EXTRA_USER, UserHandle.of(profileID))
+ @Test
+ fun testCallbackCalledOnUserChanging() =
+ testScope.runTest {
+ tracker.initialize(0)
+ val callback = TestCallback()
+ tracker.addCallback(callback, executor)
- tracker.onReceive(context, intentProfiles)
+ val newID = 5
- assertThat(callback.calledOnUserChanging).isEqualTo(0)
- assertThat(callback.calledOnUserChanged).isEqualTo(0)
- assertThat(callback.calledOnProfilesChanged).isEqualTo(0)
- }
+ val captor = ArgumentCaptor.forClass(IUserSwitchObserver::class.java)
+ verify(iActivityManager).registerUserSwitchObserver(capture(captor), anyString())
+ captor.value.onBeforeUserSwitching(newID)
+ captor.value.onUserSwitching(newID, userSwitchingReply)
+ runCurrent()
+
+ verify(userSwitchingReply).sendResult(any())
+ assertThat(callback.calledOnUserChanging).isEqualTo(1)
+ assertThat(callback.lastUser).isEqualTo(newID)
+ assertThat(callback.lastUserContext?.userId).isEqualTo(newID)
+ }
+
+ @Test
+ fun testAsyncCallbackWaitsUserToChange() =
+ testScope.runTest {
+ // Skip this test for CountDownLatch variation. The problem is that there would be a
+ // deadlock if the callbacks processing runs on the same thread as the callback (which
+ // is blocked by the latch). Before the change it works because the callbacks are
+ // processed on a binder thread which is always distinct.
+ // This is the issue that this feature addresses.
+ assume().that(isBackgroundUserTrackerEnabled).isTrue()
+
+ tracker.initialize(0)
+ val callback = TestCallback()
+ val callbackExecutor = FakeExecutor(FakeSystemClock())
+ tracker.addCallback(callback, callbackExecutor)
+
+ val newID = 5
+
+ val captor = ArgumentCaptor.forClass(IUserSwitchObserver::class.java)
+ verify(iActivityManager).registerUserSwitchObserver(capture(captor), anyString())
+ captor.value.onUserSwitching(newID, userSwitchingReply)
+
+ assertThat(callback.calledOnUserChanging).isEqualTo(0)
+ verify(userSwitchingReply, never()).sendResult(any())
+
+ FakeExecutor.exhaustExecutors(callbackExecutor)
+ runCurrent()
+ FakeExecutor.exhaustExecutors(callbackExecutor)
+ runCurrent()
+
+ assertThat(callback.calledOnUserChanging).isEqualTo(1)
+ verify(userSwitchingReply).sendResult(any())
+ }
+
+ @Test
+ fun testCallbackCalledOnUserChanged() =
+ testScope.runTest {
+ tracker.initialize(0)
+ val callback = TestCallback()
+ tracker.addCallback(callback, executor)
+
+ val newID = 5
+
+ val captor = ArgumentCaptor.forClass(IUserSwitchObserver::class.java)
+ verify(iActivityManager).registerUserSwitchObserver(capture(captor), anyString())
+ captor.value.onBeforeUserSwitching(newID)
+ captor.value.onUserSwitchComplete(newID)
+ runCurrent()
+
+ assertThat(callback.calledOnUserChanged).isEqualTo(1)
+ assertThat(callback.lastUser).isEqualTo(newID)
+ assertThat(callback.lastUserContext?.userId).isEqualTo(newID)
+ assertThat(callback.calledOnProfilesChanged).isEqualTo(1)
+ assertThat(callback.lastUserProfiles.map { it.id }).containsExactly(newID)
+ }
+
+ @Test
+ fun testCallbackCalledOnUserInfoChanged() =
+ testScope.runTest {
+ tracker.initialize(0)
+ val callback = TestCallback()
+ tracker.addCallback(callback, executor)
+ val profileID = tracker.userId + 10
+
+ whenever(userManager.getProfiles(anyInt())).thenAnswer { invocation ->
+ val id = invocation.getArgument<Int>(0)
+ val info = UserInfo(id, "", UserInfo.FLAG_FULL)
+ val infoProfile =
+ UserInfo(
+ id + 10,
+ "",
+ "",
+ UserInfo.FLAG_MANAGED_PROFILE,
+ UserManager.USER_TYPE_PROFILE_MANAGED
+ )
+ infoProfile.profileGroupId = id
+ listOf(info, infoProfile)
+ }
+
+ val intent =
+ Intent(Intent.ACTION_USER_INFO_CHANGED)
+ .putExtra(Intent.EXTRA_USER, UserHandle.of(profileID))
+
+ tracker.onReceive(context, intent)
+
+ assertThat(callback.calledOnUserChanged).isEqualTo(0)
+ assertThat(callback.calledOnProfilesChanged).isEqualTo(1)
+ assertThat(callback.lastUserProfiles.map { it.id }).containsExactly(0, profileID)
+ }
+
+ @Test
+ fun testCallbackRemoved() =
+ testScope.runTest {
+ tracker.initialize(0)
+ val newID = 5
+ val profileID = newID + 10
+
+ val callback = TestCallback()
+ tracker.addCallback(callback, executor)
+ tracker.removeCallback(callback)
+
+ val captor = ArgumentCaptor.forClass(IUserSwitchObserver::class.java)
+ verify(iActivityManager).registerUserSwitchObserver(capture(captor), anyString())
+ captor.value.onUserSwitching(newID, userSwitchingReply)
+ runCurrent()
+ verify(userSwitchingReply).sendResult(any())
+ captor.value.onUserSwitchComplete(newID)
+
+ val intentProfiles =
+ Intent(Intent.ACTION_MANAGED_PROFILE_AVAILABLE)
+ .putExtra(Intent.EXTRA_USER, UserHandle.of(profileID))
+
+ tracker.onReceive(context, intentProfiles)
+
+ assertThat(callback.calledOnUserChanging).isEqualTo(0)
+ assertThat(callback.calledOnUserChanged).isEqualTo(0)
+ assertThat(callback.calledOnProfilesChanged).isEqualTo(0)
+ }
private class TestCallback : UserTracker.Callback {
var calledOnUserChanging = 0