[DO NOT MERGE] Smartspace - Don't connect until setup
SmartspaceService attempts to cache connections until the proper
remote service comes online. However, this cache can be cleared,
dropping any prior connections without informing them. This leaves
smartspace in a state where it will never be updated until after
reboot, and happens after SUW most prominently.
Delay connecting until the device is provisioned and the user is
completely setup to avoid this early connection issue.
Fixes: 190462561
Test: atest LockscreenSmartspaceControllerTest
Change-Id: I4081136c76488874cb50de58dfb8484bb19b23bb
(cherry picked from commit bb0f290077)
This commit is contained in:
@@ -45,6 +45,7 @@ import com.android.systemui.plugins.statusbar.StatusBarStateController
|
|||||||
import com.android.systemui.settings.UserTracker
|
import com.android.systemui.settings.UserTracker
|
||||||
import com.android.systemui.flags.FeatureFlags
|
import com.android.systemui.flags.FeatureFlags
|
||||||
import com.android.systemui.statusbar.policy.ConfigurationController
|
import com.android.systemui.statusbar.policy.ConfigurationController
|
||||||
|
import com.android.systemui.statusbar.policy.DeviceProvisionedController
|
||||||
import com.android.systemui.util.concurrency.Execution
|
import com.android.systemui.util.concurrency.Execution
|
||||||
import com.android.systemui.util.settings.SecureSettings
|
import com.android.systemui.util.settings.SecureSettings
|
||||||
import java.lang.RuntimeException
|
import java.lang.RuntimeException
|
||||||
@@ -67,6 +68,7 @@ class LockscreenSmartspaceController @Inject constructor(
|
|||||||
private val contentResolver: ContentResolver,
|
private val contentResolver: ContentResolver,
|
||||||
private val configurationController: ConfigurationController,
|
private val configurationController: ConfigurationController,
|
||||||
private val statusBarStateController: StatusBarStateController,
|
private val statusBarStateController: StatusBarStateController,
|
||||||
|
private val deviceProvisionedController: DeviceProvisionedController,
|
||||||
private val execution: Execution,
|
private val execution: Execution,
|
||||||
@Main private val uiExecutor: Executor,
|
@Main private val uiExecutor: Executor,
|
||||||
@Main private val handler: Handler,
|
@Main private val handler: Handler,
|
||||||
@@ -95,6 +97,55 @@ class LockscreenSmartspaceController @Inject constructor(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private val sessionListener = SmartspaceSession.OnTargetsAvailableListener { targets ->
|
||||||
|
execution.assertIsMainThread()
|
||||||
|
val filteredTargets = targets.filter(::filterSmartspaceTarget)
|
||||||
|
plugin?.onTargetsAvailable(filteredTargets)
|
||||||
|
}
|
||||||
|
|
||||||
|
private val userTrackerCallback = object : UserTracker.Callback {
|
||||||
|
override fun onUserChanged(newUser: Int, userContext: Context) {
|
||||||
|
execution.assertIsMainThread()
|
||||||
|
reloadSmartspace()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private val settingsObserver = object : ContentObserver(handler) {
|
||||||
|
override fun onChange(selfChange: Boolean, uri: Uri?) {
|
||||||
|
execution.assertIsMainThread()
|
||||||
|
reloadSmartspace()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private val configChangeListener = object : ConfigurationController.ConfigurationListener {
|
||||||
|
override fun onThemeChanged() {
|
||||||
|
execution.assertIsMainThread()
|
||||||
|
updateTextColorFromWallpaper()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private val statusBarStateListener = object : StatusBarStateController.StateListener {
|
||||||
|
override fun onDozeAmountChanged(linear: Float, eased: Float) {
|
||||||
|
execution.assertIsMainThread()
|
||||||
|
smartspaceViews.forEach { it.setDozeAmount(eased) }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private val deviceProvisionedListener =
|
||||||
|
object : DeviceProvisionedController.DeviceProvisionedListener {
|
||||||
|
override fun onDeviceProvisionedChanged() {
|
||||||
|
connectSession()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onUserSetupChanged() {
|
||||||
|
connectSession()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
init {
|
||||||
|
deviceProvisionedController.addCallback(deviceProvisionedListener)
|
||||||
|
}
|
||||||
|
|
||||||
fun isEnabled(): Boolean {
|
fun isEnabled(): Boolean {
|
||||||
execution.assertIsMainThread()
|
execution.assertIsMainThread()
|
||||||
|
|
||||||
@@ -145,10 +196,20 @@ class LockscreenSmartspaceController @Inject constructor(
|
|||||||
if (plugin == null || session != null) {
|
if (plugin == null || session != null) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
val session = smartspaceManager.createSmartspaceSession(
|
|
||||||
SmartspaceConfig.Builder(context, "lockscreen").build())
|
|
||||||
session.addOnTargetsAvailableListener(uiExecutor, sessionListener)
|
|
||||||
|
|
||||||
|
// Only connect after the device is fully provisioned to avoid connection caching
|
||||||
|
// issues
|
||||||
|
if (!deviceProvisionedController.isDeviceProvisioned() ||
|
||||||
|
!deviceProvisionedController.isCurrentUserSetup()) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
val newSession = smartspaceManager.createSmartspaceSession(
|
||||||
|
SmartspaceConfig.Builder(context, "lockscreen").build())
|
||||||
|
newSession.addOnTargetsAvailableListener(uiExecutor, sessionListener)
|
||||||
|
this.session = newSession
|
||||||
|
|
||||||
|
deviceProvisionedController.removeCallback(deviceProvisionedListener)
|
||||||
userTracker.addCallback(userTrackerCallback, uiExecutor)
|
userTracker.addCallback(userTrackerCallback, uiExecutor)
|
||||||
contentResolver.registerContentObserver(
|
contentResolver.registerContentObserver(
|
||||||
secureSettings.getUriFor(Settings.Secure.LOCK_SCREEN_ALLOW_PRIVATE_NOTIFICATIONS),
|
secureSettings.getUriFor(Settings.Secure.LOCK_SCREEN_ALLOW_PRIVATE_NOTIFICATIONS),
|
||||||
@@ -159,8 +220,6 @@ class LockscreenSmartspaceController @Inject constructor(
|
|||||||
configurationController.addCallback(configChangeListener)
|
configurationController.addCallback(configChangeListener)
|
||||||
statusBarStateController.addCallback(statusBarStateListener)
|
statusBarStateController.addCallback(statusBarStateListener)
|
||||||
|
|
||||||
this.session = session
|
|
||||||
|
|
||||||
reloadSmartspace()
|
reloadSmartspace()
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -197,43 +256,6 @@ class LockscreenSmartspaceController @Inject constructor(
|
|||||||
plugin?.unregisterListener(listener)
|
plugin?.unregisterListener(listener)
|
||||||
}
|
}
|
||||||
|
|
||||||
private val sessionListener = SmartspaceSession.OnTargetsAvailableListener { targets ->
|
|
||||||
execution.assertIsMainThread()
|
|
||||||
val filteredTargets = targets.filter(::filterSmartspaceTarget)
|
|
||||||
plugin?.onTargetsAvailable(filteredTargets)
|
|
||||||
}
|
|
||||||
|
|
||||||
private val userTrackerCallback = object : UserTracker.Callback {
|
|
||||||
override fun onUserChanged(newUser: Int, userContext: Context) {
|
|
||||||
execution.assertIsMainThread()
|
|
||||||
reloadSmartspace()
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onProfilesChanged(profiles: List<UserInfo>) {
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private val settingsObserver = object : ContentObserver(handler) {
|
|
||||||
override fun onChange(selfChange: Boolean, uri: Uri?) {
|
|
||||||
execution.assertIsMainThread()
|
|
||||||
reloadSmartspace()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private val configChangeListener = object : ConfigurationController.ConfigurationListener {
|
|
||||||
override fun onThemeChanged() {
|
|
||||||
execution.assertIsMainThread()
|
|
||||||
updateTextColorFromWallpaper()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private val statusBarStateListener = object : StatusBarStateController.StateListener {
|
|
||||||
override fun onDozeAmountChanged(linear: Float, eased: Float) {
|
|
||||||
execution.assertIsMainThread()
|
|
||||||
smartspaceViews.forEach { it.setDozeAmount(eased) }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun filterSmartspaceTarget(t: SmartspaceTarget): Boolean {
|
private fun filterSmartspaceTarget(t: SmartspaceTarget): Boolean {
|
||||||
return when (t.userHandle) {
|
return when (t.userHandle) {
|
||||||
userTracker.userHandle -> {
|
userTracker.userHandle -> {
|
||||||
|
|||||||
@@ -44,6 +44,8 @@ import com.android.systemui.settings.UserTracker
|
|||||||
import com.android.systemui.flags.FeatureFlags
|
import com.android.systemui.flags.FeatureFlags
|
||||||
import com.android.systemui.statusbar.policy.ConfigurationController
|
import com.android.systemui.statusbar.policy.ConfigurationController
|
||||||
import com.android.systemui.statusbar.policy.ConfigurationController.ConfigurationListener
|
import com.android.systemui.statusbar.policy.ConfigurationController.ConfigurationListener
|
||||||
|
import com.android.systemui.statusbar.policy.DeviceProvisionedController
|
||||||
|
import com.android.systemui.statusbar.policy.DeviceProvisionedController.DeviceProvisionedListener
|
||||||
import com.android.systemui.util.concurrency.FakeExecution
|
import com.android.systemui.util.concurrency.FakeExecution
|
||||||
import com.android.systemui.util.concurrency.FakeExecutor
|
import com.android.systemui.util.concurrency.FakeExecutor
|
||||||
import com.android.systemui.util.mockito.any
|
import com.android.systemui.util.mockito.any
|
||||||
@@ -89,6 +91,8 @@ class LockscreenSmartspaceControllerTest : SysuiTestCase() {
|
|||||||
@Mock
|
@Mock
|
||||||
private lateinit var statusBarStateController: StatusBarStateController
|
private lateinit var statusBarStateController: StatusBarStateController
|
||||||
@Mock
|
@Mock
|
||||||
|
private lateinit var deviceProvisionedController: DeviceProvisionedController
|
||||||
|
@Mock
|
||||||
private lateinit var handler: Handler
|
private lateinit var handler: Handler
|
||||||
|
|
||||||
@Mock
|
@Mock
|
||||||
@@ -106,12 +110,15 @@ class LockscreenSmartspaceControllerTest : SysuiTestCase() {
|
|||||||
private lateinit var configChangeListenerCaptor: ArgumentCaptor<ConfigurationListener>
|
private lateinit var configChangeListenerCaptor: ArgumentCaptor<ConfigurationListener>
|
||||||
@Captor
|
@Captor
|
||||||
private lateinit var statusBarStateListenerCaptor: ArgumentCaptor<StateListener>
|
private lateinit var statusBarStateListenerCaptor: ArgumentCaptor<StateListener>
|
||||||
|
@Captor
|
||||||
|
private lateinit var deviceProvisionedCaptor: ArgumentCaptor<DeviceProvisionedListener>
|
||||||
|
|
||||||
private lateinit var sessionListener: OnTargetsAvailableListener
|
private lateinit var sessionListener: OnTargetsAvailableListener
|
||||||
private lateinit var userListener: UserTracker.Callback
|
private lateinit var userListener: UserTracker.Callback
|
||||||
private lateinit var settingsObserver: ContentObserver
|
private lateinit var settingsObserver: ContentObserver
|
||||||
private lateinit var configChangeListener: ConfigurationListener
|
private lateinit var configChangeListener: ConfigurationListener
|
||||||
private lateinit var statusBarStateListener: StateListener
|
private lateinit var statusBarStateListener: StateListener
|
||||||
|
private lateinit var deviceProvisionedListener: DeviceProvisionedListener
|
||||||
|
|
||||||
private lateinit var smartspaceView: SmartspaceView
|
private lateinit var smartspaceView: SmartspaceView
|
||||||
|
|
||||||
@@ -145,6 +152,8 @@ class LockscreenSmartspaceControllerTest : SysuiTestCase() {
|
|||||||
`when`(plugin.getView(any())).thenReturn(createSmartspaceView(), createSmartspaceView())
|
`when`(plugin.getView(any())).thenReturn(createSmartspaceView(), createSmartspaceView())
|
||||||
`when`(userTracker.userProfiles).thenReturn(userList)
|
`when`(userTracker.userProfiles).thenReturn(userList)
|
||||||
`when`(statusBarStateController.dozeAmount).thenReturn(0.5f)
|
`when`(statusBarStateController.dozeAmount).thenReturn(0.5f)
|
||||||
|
`when`(deviceProvisionedController.isDeviceProvisioned()).thenReturn(true)
|
||||||
|
`when`(deviceProvisionedController.isCurrentUserSetup()).thenReturn(true)
|
||||||
|
|
||||||
setActiveUser(userHandlePrimary)
|
setActiveUser(userHandlePrimary)
|
||||||
setAllowPrivateNotifications(userHandlePrimary, true)
|
setAllowPrivateNotifications(userHandlePrimary, true)
|
||||||
@@ -162,11 +171,15 @@ class LockscreenSmartspaceControllerTest : SysuiTestCase() {
|
|||||||
contentResolver,
|
contentResolver,
|
||||||
configurationController,
|
configurationController,
|
||||||
statusBarStateController,
|
statusBarStateController,
|
||||||
|
deviceProvisionedController,
|
||||||
execution,
|
execution,
|
||||||
executor,
|
executor,
|
||||||
handler,
|
handler,
|
||||||
Optional.of(plugin)
|
Optional.of(plugin)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
verify(deviceProvisionedController).addCallback(capture(deviceProvisionedCaptor))
|
||||||
|
deviceProvisionedListener = deviceProvisionedCaptor.value
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test(expected = RuntimeException::class)
|
@Test(expected = RuntimeException::class)
|
||||||
@@ -180,6 +193,27 @@ class LockscreenSmartspaceControllerTest : SysuiTestCase() {
|
|||||||
// THEN an exception is thrown
|
// THEN an exception is thrown
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun connectOnlyAfterDeviceIsProvisioned() {
|
||||||
|
// GIVEN an unprovisioned device and an attempt to connect
|
||||||
|
`when`(deviceProvisionedController.isDeviceProvisioned()).thenReturn(false)
|
||||||
|
`when`(deviceProvisionedController.isCurrentUserSetup()).thenReturn(false)
|
||||||
|
|
||||||
|
// WHEN a connection attempt is made
|
||||||
|
controller.buildAndConnectView(fakeParent)
|
||||||
|
|
||||||
|
// THEN no session is created
|
||||||
|
verify(smartspaceManager, never()).createSmartspaceSession(any())
|
||||||
|
|
||||||
|
// WHEN it does become provisioned
|
||||||
|
`when`(deviceProvisionedController.isDeviceProvisioned()).thenReturn(true)
|
||||||
|
`when`(deviceProvisionedController.isCurrentUserSetup()).thenReturn(true)
|
||||||
|
deviceProvisionedListener.onUserSetupChanged()
|
||||||
|
|
||||||
|
// THEN the session is created
|
||||||
|
verify(smartspaceManager).createSmartspaceSession(any())
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun testListenersAreRegistered() {
|
fun testListenersAreRegistered() {
|
||||||
// GIVEN a listener is added after a session is created
|
// GIVEN a listener is added after a session is created
|
||||||
|
|||||||
Reference in New Issue
Block a user