Merge "Make UserTrackerImpl use UserSwitchObserver instead of broadcast." into tm-qpr-dev
This commit is contained in:
committed by
Android (Google) Code Review
commit
8fd6cb70f0
@@ -62,12 +62,24 @@ interface UserTracker : UserContentResolverProvider, UserContextProvider {
|
||||
fun removeCallback(callback: Callback)
|
||||
|
||||
/**
|
||||
* Ćallback for notifying of changes.
|
||||
* Callback for notifying of changes.
|
||||
*/
|
||||
interface Callback {
|
||||
|
||||
/**
|
||||
* Notifies that the current user is being changed.
|
||||
* Override this method to run things while the screen is frozen for the user switch.
|
||||
* Please use {@link #onUserChanged} if the task doesn't need to push the unfreezing of the
|
||||
* screen further. Please be aware that code executed in this callback will lengthen the
|
||||
* user switch duration.
|
||||
*/
|
||||
@JvmDefault
|
||||
fun onUserChanging(newUser: Int, userContext: Context) {}
|
||||
|
||||
/**
|
||||
* Notifies that the current user has changed.
|
||||
* Override this method to run things after the screen is unfrozen for the user switch.
|
||||
* Please see {@link #onUserChanging} if you need to hide jank.
|
||||
*/
|
||||
@JvmDefault
|
||||
fun onUserChanged(newUser: Int, userContext: Context) {}
|
||||
@@ -78,4 +90,4 @@ interface UserTracker : UserContentResolverProvider, UserContextProvider {
|
||||
@JvmDefault
|
||||
fun onProfilesChanged(profiles: List<@JvmSuppressWildcards UserInfo>) {}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,6 +16,8 @@
|
||||
|
||||
package com.android.systemui.settings
|
||||
|
||||
import android.app.IActivityManager
|
||||
import android.app.UserSwitchObserver
|
||||
import android.content.BroadcastReceiver
|
||||
import android.content.ContentResolver
|
||||
import android.content.Context
|
||||
@@ -23,6 +25,7 @@ import android.content.Intent
|
||||
import android.content.IntentFilter
|
||||
import android.content.pm.UserInfo
|
||||
import android.os.Handler
|
||||
import android.os.IRemoteCallback
|
||||
import android.os.UserHandle
|
||||
import android.os.UserManager
|
||||
import android.util.Log
|
||||
@@ -34,6 +37,7 @@ import com.android.systemui.util.Assert
|
||||
import java.io.PrintWriter
|
||||
import java.lang.IllegalStateException
|
||||
import java.lang.ref.WeakReference
|
||||
import java.util.concurrent.CountDownLatch
|
||||
import java.util.concurrent.Executor
|
||||
import kotlin.properties.ReadWriteProperty
|
||||
import kotlin.reflect.KProperty
|
||||
@@ -56,6 +60,7 @@ import kotlin.reflect.KProperty
|
||||
class UserTrackerImpl internal constructor(
|
||||
private val context: Context,
|
||||
private val userManager: UserManager,
|
||||
private val iActivityManager: IActivityManager,
|
||||
private val dumpManager: DumpManager,
|
||||
private val backgroundHandler: Handler
|
||||
) : UserTracker, Dumpable, BroadcastReceiver() {
|
||||
@@ -107,7 +112,6 @@ class UserTrackerImpl internal constructor(
|
||||
setUserIdInternal(startingUser)
|
||||
|
||||
val filter = IntentFilter().apply {
|
||||
addAction(Intent.ACTION_USER_SWITCHED)
|
||||
addAction(Intent.ACTION_USER_INFO_CHANGED)
|
||||
// These get called when a managed profile goes in or out of quiet mode.
|
||||
addAction(Intent.ACTION_MANAGED_PROFILE_AVAILABLE)
|
||||
@@ -118,14 +122,13 @@ class UserTrackerImpl internal constructor(
|
||||
}
|
||||
context.registerReceiverForAllUsers(this, filter, null /* permission */, backgroundHandler)
|
||||
|
||||
registerUserSwitchObserver()
|
||||
|
||||
dumpManager.registerDumpable(TAG, this)
|
||||
}
|
||||
|
||||
override fun onReceive(context: Context, intent: Intent) {
|
||||
when (intent.action) {
|
||||
Intent.ACTION_USER_SWITCHED -> {
|
||||
handleSwitchUser(intent.getIntExtra(Intent.EXTRA_USER_HANDLE, UserHandle.USER_NULL))
|
||||
}
|
||||
Intent.ACTION_USER_INFO_CHANGED,
|
||||
Intent.ACTION_MANAGED_PROFILE_AVAILABLE,
|
||||
Intent.ACTION_MANAGED_PROFILE_UNAVAILABLE,
|
||||
@@ -157,22 +160,43 @@ class UserTrackerImpl internal constructor(
|
||||
return ctx to profiles
|
||||
}
|
||||
|
||||
private fun registerUserSwitchObserver() {
|
||||
iActivityManager.registerUserSwitchObserver(object : UserSwitchObserver() {
|
||||
override fun onUserSwitching(newUserId: Int, reply: IRemoteCallback?) {
|
||||
backgroundHandler.run {
|
||||
handleUserSwitching(newUserId)
|
||||
reply?.sendResult(null)
|
||||
}
|
||||
}
|
||||
|
||||
override fun onUserSwitchComplete(newUserId: Int) {
|
||||
backgroundHandler.run {
|
||||
handleUserSwitchComplete(newUserId)
|
||||
}
|
||||
}
|
||||
}, TAG)
|
||||
}
|
||||
|
||||
@WorkerThread
|
||||
private fun handleSwitchUser(newUser: Int) {
|
||||
private fun handleUserSwitching(newUserId: Int) {
|
||||
Assert.isNotMainThread()
|
||||
if (newUser == UserHandle.USER_NULL) {
|
||||
Log.w(TAG, "handleSwitchUser - Couldn't get new id from intent")
|
||||
return
|
||||
}
|
||||
|
||||
if (newUser == userId) return
|
||||
Log.i(TAG, "Switching to user $newUser")
|
||||
|
||||
val (ctx, profiles) = setUserIdInternal(newUser)
|
||||
Log.i(TAG, "Switching to user $newUserId")
|
||||
|
||||
setUserIdInternal(newUserId)
|
||||
notifySubscribers {
|
||||
onUserChanged(newUser, ctx)
|
||||
onProfilesChanged(profiles)
|
||||
onUserChanging(newUserId, userContext)
|
||||
}.await()
|
||||
}
|
||||
|
||||
@WorkerThread
|
||||
private fun handleUserSwitchComplete(newUserId: Int) {
|
||||
Assert.isNotMainThread()
|
||||
Log.i(TAG, "Switched to user $newUserId")
|
||||
|
||||
setUserIdInternal(newUserId)
|
||||
notifySubscribers {
|
||||
onUserChanged(newUserId, userContext)
|
||||
onProfilesChanged(userProfiles)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -201,17 +225,25 @@ class UserTrackerImpl internal constructor(
|
||||
}
|
||||
}
|
||||
|
||||
private inline fun notifySubscribers(crossinline action: UserTracker.Callback.() -> Unit) {
|
||||
private inline fun notifySubscribers(
|
||||
crossinline action: UserTracker.Callback.() -> Unit
|
||||
): CountDownLatch {
|
||||
val list = synchronized(callbacks) {
|
||||
callbacks.toList()
|
||||
}
|
||||
val latch = CountDownLatch(list.size)
|
||||
|
||||
list.forEach {
|
||||
if (it.callback.get() != null) {
|
||||
it.executor.execute {
|
||||
it.callback.get()?.action()
|
||||
latch.countDown()
|
||||
}
|
||||
} else {
|
||||
latch.countDown()
|
||||
}
|
||||
}
|
||||
return latch
|
||||
}
|
||||
|
||||
override fun dump(pw: PrintWriter, args: Array<out String>) {
|
||||
@@ -258,4 +290,4 @@ private data class DataItem(
|
||||
fun sameOrEmpty(other: UserTracker.Callback): Boolean {
|
||||
return callback.get()?.equals(other) ?: true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
package com.android.systemui.settings.dagger;
|
||||
|
||||
import android.app.ActivityManager;
|
||||
import android.app.IActivityManager;
|
||||
import android.content.Context;
|
||||
import android.os.Handler;
|
||||
import android.os.UserManager;
|
||||
@@ -57,11 +58,13 @@ public abstract class MultiUserUtilsModule {
|
||||
static UserTracker provideUserTracker(
|
||||
Context context,
|
||||
UserManager userManager,
|
||||
IActivityManager iActivityManager,
|
||||
DumpManager dumpManager,
|
||||
@Background Handler handler
|
||||
) {
|
||||
int startingUser = ActivityManager.getCurrentUser();
|
||||
UserTrackerImpl tracker = new UserTrackerImpl(context, userManager, dumpManager, handler);
|
||||
UserTrackerImpl tracker = new UserTrackerImpl(context, userManager, iActivityManager,
|
||||
dumpManager, handler);
|
||||
tracker.initialize(startingUser);
|
||||
return tracker;
|
||||
}
|
||||
|
||||
@@ -174,7 +174,7 @@ constructor(
|
||||
|
||||
val callback =
|
||||
object : UserTracker.Callback {
|
||||
override fun onUserChanged(newUser: Int, userContext: Context) {
|
||||
override fun onUserChanging(newUser: Int, userContext: Context) {
|
||||
send()
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
package com.android.systemui.settings
|
||||
|
||||
import android.app.IActivityManager
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.content.pm.UserInfo
|
||||
@@ -51,6 +52,7 @@ class UserTrackerImplReceiveTest : SysuiTestCase() {
|
||||
|
||||
@Mock private lateinit var context: Context
|
||||
@Mock private lateinit var userManager: UserManager
|
||||
@Mock private lateinit var iActivityManager: IActivityManager
|
||||
@Mock(stubOnly = true) private lateinit var dumpManager: DumpManager
|
||||
@Mock(stubOnly = true) private lateinit var handler: Handler
|
||||
|
||||
@@ -67,7 +69,7 @@ class UserTrackerImplReceiveTest : SysuiTestCase() {
|
||||
`when`(context.user).thenReturn(UserHandle.SYSTEM)
|
||||
`when`(context.createContextAsUser(ArgumentMatchers.any(), anyInt())).thenReturn(context)
|
||||
|
||||
tracker = UserTrackerImpl(context, userManager, dumpManager, handler)
|
||||
tracker = UserTrackerImpl(context, userManager, iActivityManager, dumpManager, handler)
|
||||
}
|
||||
|
||||
@Test
|
||||
|
||||
@@ -16,11 +16,14 @@
|
||||
|
||||
package com.android.systemui.settings
|
||||
|
||||
import android.app.IActivityManager
|
||||
import android.app.IUserSwitchObserver
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.content.IntentFilter
|
||||
import android.content.pm.UserInfo
|
||||
import android.os.Handler
|
||||
import android.os.IRemoteCallback
|
||||
import android.os.UserHandle
|
||||
import android.os.UserManager
|
||||
import android.testing.AndroidTestingRunner
|
||||
@@ -29,19 +32,20 @@ import com.android.systemui.SysuiTestCase
|
||||
import com.android.systemui.dump.DumpManager
|
||||
import com.android.systemui.util.mockito.capture
|
||||
import com.google.common.truth.Truth.assertThat
|
||||
import java.util.concurrent.Executor
|
||||
import org.junit.Before
|
||||
import org.junit.Test
|
||||
import org.junit.runner.RunWith
|
||||
import org.mockito.ArgumentCaptor
|
||||
import org.mockito.ArgumentMatchers.any
|
||||
import org.mockito.ArgumentMatchers.anyInt
|
||||
import org.mockito.ArgumentMatchers.anyString
|
||||
import org.mockito.ArgumentMatchers.eq
|
||||
import org.mockito.ArgumentMatchers.isNull
|
||||
import org.mockito.Mock
|
||||
import org.mockito.Mockito.`when`
|
||||
import org.mockito.Mockito.verify
|
||||
import org.mockito.Mockito.`when`
|
||||
import org.mockito.MockitoAnnotations
|
||||
import java.util.concurrent.Executor
|
||||
|
||||
@SmallTest
|
||||
@RunWith(AndroidTestingRunner::class)
|
||||
@@ -51,6 +55,10 @@ class UserTrackerImplTest : SysuiTestCase() {
|
||||
private lateinit var context: Context
|
||||
@Mock
|
||||
private lateinit var userManager: UserManager
|
||||
@Mock
|
||||
private lateinit var iActivityManager: IActivityManager
|
||||
@Mock
|
||||
private lateinit var userSwitchingReply: IRemoteCallback
|
||||
@Mock(stubOnly = true)
|
||||
private lateinit var dumpManager: DumpManager
|
||||
@Mock(stubOnly = true)
|
||||
@@ -76,7 +84,7 @@ class UserTrackerImplTest : SysuiTestCase() {
|
||||
listOf(info)
|
||||
}
|
||||
|
||||
tracker = UserTrackerImpl(context, userManager, dumpManager, handler)
|
||||
tracker = UserTrackerImpl(context, userManager, iActivityManager, dumpManager, handler)
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -125,8 +133,7 @@ class UserTrackerImplTest : SysuiTestCase() {
|
||||
verify(context).registerReceiverForAllUsers(
|
||||
eq(tracker), capture(captor), isNull(), eq(handler))
|
||||
with(captor.value) {
|
||||
assertThat(countActions()).isEqualTo(7)
|
||||
assertThat(hasAction(Intent.ACTION_USER_SWITCHED)).isTrue()
|
||||
assertThat(countActions()).isEqualTo(6)
|
||||
assertThat(hasAction(Intent.ACTION_USER_INFO_CHANGED)).isTrue()
|
||||
assertThat(hasAction(Intent.ACTION_MANAGED_PROFILE_AVAILABLE)).isTrue()
|
||||
assertThat(hasAction(Intent.ACTION_MANAGED_PROFILE_UNAVAILABLE)).isTrue()
|
||||
@@ -158,8 +165,10 @@ class UserTrackerImplTest : SysuiTestCase() {
|
||||
tracker.initialize(0)
|
||||
val newID = 5
|
||||
|
||||
val intent = Intent(Intent.ACTION_USER_SWITCHED).putExtra(Intent.EXTRA_USER_HANDLE, newID)
|
||||
tracker.onReceive(context, intent)
|
||||
val captor = ArgumentCaptor.forClass(IUserSwitchObserver::class.java)
|
||||
verify(iActivityManager).registerUserSwitchObserver(capture(captor), anyString())
|
||||
captor.value.onUserSwitching(newID, userSwitchingReply)
|
||||
verify(userSwitchingReply).sendResult(any())
|
||||
|
||||
verify(userManager).getProfiles(newID)
|
||||
|
||||
@@ -271,6 +280,24 @@ class UserTrackerImplTest : SysuiTestCase() {
|
||||
assertThat(callback.calledOnUserChanged).isEqualTo(0)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testCallbackCalledOnUserChanging() {
|
||||
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.onUserSwitching(newID, userSwitchingReply)
|
||||
verify(userSwitchingReply).sendResult(any())
|
||||
|
||||
assertThat(callback.calledOnUserChanging).isEqualTo(1)
|
||||
assertThat(callback.lastUser).isEqualTo(newID)
|
||||
assertThat(callback.lastUserContext?.userId).isEqualTo(newID)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testCallbackCalledOnUserChanged() {
|
||||
tracker.initialize(0)
|
||||
@@ -279,8 +306,9 @@ class UserTrackerImplTest : SysuiTestCase() {
|
||||
|
||||
val newID = 5
|
||||
|
||||
val intent = Intent(Intent.ACTION_USER_SWITCHED).putExtra(Intent.EXTRA_USER_HANDLE, newID)
|
||||
tracker.onReceive(context, intent)
|
||||
val captor = ArgumentCaptor.forClass(IUserSwitchObserver::class.java)
|
||||
verify(iActivityManager).registerUserSwitchObserver(capture(captor), anyString())
|
||||
captor.value.onUserSwitchComplete(newID)
|
||||
|
||||
assertThat(callback.calledOnUserChanged).isEqualTo(1)
|
||||
assertThat(callback.lastUser).isEqualTo(newID)
|
||||
@@ -330,25 +358,36 @@ class UserTrackerImplTest : SysuiTestCase() {
|
||||
tracker.addCallback(callback, executor)
|
||||
tracker.removeCallback(callback)
|
||||
|
||||
val intent = Intent(Intent.ACTION_USER_SWITCHED).putExtra(Intent.EXTRA_USER_HANDLE, 5)
|
||||
tracker.onReceive(context, intent)
|
||||
val captor = ArgumentCaptor.forClass(IUserSwitchObserver::class.java)
|
||||
verify(iActivityManager).registerUserSwitchObserver(capture(captor), anyString())
|
||||
captor.value.onUserSwitching(newID, userSwitchingReply)
|
||||
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
|
||||
var calledOnUserChanged = 0
|
||||
var calledOnProfilesChanged = 0
|
||||
var lastUser: Int? = null
|
||||
var lastUserContext: Context? = null
|
||||
var lastUserProfiles = emptyList<UserInfo>()
|
||||
|
||||
override fun onUserChanging(newUser: Int, userContext: Context) {
|
||||
calledOnUserChanging++
|
||||
lastUser = newUser
|
||||
lastUserContext = userContext
|
||||
}
|
||||
|
||||
override fun onUserChanged(newUser: Int, userContext: Context) {
|
||||
calledOnUserChanged++
|
||||
lastUser = newUser
|
||||
@@ -360,4 +399,4 @@ class UserTrackerImplTest : SysuiTestCase() {
|
||||
lastUserProfiles = profiles
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -67,7 +67,10 @@ class FakeUserTracker(
|
||||
_userHandle = UserHandle.of(_userId)
|
||||
|
||||
val copy = callbacks.toList()
|
||||
copy.forEach { it.onUserChanged(_userId, userContext) }
|
||||
copy.forEach {
|
||||
it.onUserChanging(_userId, userContext)
|
||||
it.onUserChanged(_userId, userContext)
|
||||
}
|
||||
}
|
||||
|
||||
fun onProfileChanged() {
|
||||
|
||||
Reference in New Issue
Block a user