diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitchController.java b/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitchController.java index 539fb656eaa2d..260b39378485c 100644 --- a/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitchController.java +++ b/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitchController.java @@ -239,16 +239,6 @@ public class KeyguardClockSwitchController extends ViewController() private var showSensitiveContentForCurrentUser = false private var showSensitiveContentForManagedUser = false private var managedUserHandle: UserHandle? = null + var stateChangeListener = object : View.OnAttachStateChangeListener { + override fun onViewAttachedToWindow(v: View) { + smartspaceViews.add(v as SmartspaceView) + + updateTextColorFromWallpaper() + statusBarStateListener.onDozeAmountChanged(0f, statusBarStateController.dozeAmount) + } + + override fun onViewDetachedFromWindow(v: View) { + smartspaceViews.remove(v as SmartspaceView) + } + } + fun isEnabled(): Boolean { execution.assertIsMainThread() @@ -90,17 +102,16 @@ class LockscreenSmartspaceController @Inject constructor( } /** - * Constructs the smartspace view and connects it to the smartspace service. Subsequent calls - * are idempotent until [disconnect] is called. + * Constructs the smartspace view and connects it to the smartspace service. */ - fun buildAndConnectView(parent: ViewGroup): View { + fun buildAndConnectView(parent: ViewGroup): View? { execution.assertIsMainThread() if (!isEnabled()) { throw RuntimeException("Cannot build view when not enabled") } - buildView(parent) + val view = buildView(parent) connectSession() return view @@ -110,14 +121,9 @@ class LockscreenSmartspaceController @Inject constructor( session?.requestSmartspaceUpdate() } - private fun buildView(parent: ViewGroup) { + private fun buildView(parent: ViewGroup): View? { if (plugin == null) { - return - } - if (this::view.isInitialized) { - // Due to some oddities with a singleton smartspace view, allow reparenting - (view.getParent() as ViewGroup?)?.removeView(view) - return + return null } val ssView = plugin.getView(parent) @@ -132,12 +138,7 @@ class LockscreenSmartspaceController @Inject constructor( } }) ssView.setFalsingManager(falsingManager) - - this.smartspaceView = ssView - this.view = ssView as View - - updateTextColorFromWallpaper() - statusBarStateListener.onDozeAmountChanged(0f, statusBarStateController.dozeAmount) + return (ssView as View).apply { addOnAttachStateChangeListener(stateChangeListener) } } private fun connectSession() { @@ -165,8 +166,6 @@ class LockscreenSmartspaceController @Inject constructor( /** * Disconnects the smartspace view from the smartspace service and cleans up any resources. - * Calling [buildAndConnectView] again will cause the same view to be reconnected to the - * service. */ fun disconnect() { execution.assertIsMainThread() @@ -231,7 +230,7 @@ class LockscreenSmartspaceController @Inject constructor( private val statusBarStateListener = object : StatusBarStateController.StateListener { override fun onDozeAmountChanged(linear: Float, eased: Float) { execution.assertIsMainThread() - smartspaceView.setDozeAmount(eased) + smartspaceViews.forEach { it.setDozeAmount(eased) } } } @@ -256,7 +255,7 @@ class LockscreenSmartspaceController @Inject constructor( private fun updateTextColorFromWallpaper() { val wallpaperTextColor = Utils.getColorAttrDefaultColor(context, R.attr.wallpaperTextColor) - smartspaceView.setPrimaryTextColor(wallpaperTextColor) + smartspaceViews.forEach { it.setPrimaryTextColor(wallpaperTextColor) } } private fun reloadSmartspace() { diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/lockscreen/LockscreenSmartspaceControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/lockscreen/LockscreenSmartspaceControllerTest.kt index a2bb0aff48e36..575e01cf6e0f7 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/lockscreen/LockscreenSmartspaceControllerTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/lockscreen/LockscreenSmartspaceControllerTest.kt @@ -51,7 +51,6 @@ import com.android.systemui.util.mockito.capture import com.android.systemui.util.mockito.eq import com.android.systemui.util.settings.SecureSettings import com.android.systemui.util.time.FakeSystemClock -import org.junit.Assert.assertEquals import org.junit.Before import org.junit.Test import org.mockito.ArgumentCaptor @@ -114,6 +113,8 @@ class LockscreenSmartspaceControllerTest : SysuiTestCase() { private lateinit var configChangeListener: ConfigurationListener private lateinit var statusBarStateListener: StateListener + private lateinit var smartspaceView: SmartspaceView + private val clock = FakeSystemClock() private val executor = FakeExecutor(clock) private val execution = FakeExecution() @@ -141,7 +142,7 @@ class LockscreenSmartspaceControllerTest : SysuiTestCase() { `when`(secureSettings.getUriFor(PRIVATE_LOCKSCREEN_SETTING)) .thenReturn(fakePrivateLockscreenSettingUri) `when`(smartspaceManager.createSmartspaceSession(any())).thenReturn(smartspaceSession) - `when`(plugin.getView(any())).thenReturn(fakeSmartspaceView) + `when`(plugin.getView(any())).thenReturn(createSmartspaceView(), createSmartspaceView()) `when`(userTracker.userProfiles).thenReturn(userList) `when`(statusBarStateController.dozeAmount).thenReturn(0.5f) @@ -249,7 +250,7 @@ class LockscreenSmartspaceControllerTest : SysuiTestCase() { configChangeListener.onThemeChanged() // We update the new text color to match the wallpaper color - verify(fakeSmartspaceView).setPrimaryTextColor(anyInt()) + verify(smartspaceView).setPrimaryTextColor(anyInt()) } @Test @@ -261,7 +262,7 @@ class LockscreenSmartspaceControllerTest : SysuiTestCase() { statusBarStateListener.onDozeAmountChanged(0.1f, 0.7f) // We pass that along to the view - verify(fakeSmartspaceView).setDozeAmount(0.7f) + verify(smartspaceView).setDozeAmount(0.7f) } @Test @@ -393,40 +394,30 @@ class LockscreenSmartspaceControllerTest : SysuiTestCase() { } @Test - fun testBuildViewIsIdempotent() { - // GIVEN a connected session - connectSession() - clearInvocations(plugin) - - // WHEN we disconnect and then reconnect - controller.disconnect() - controller.buildAndConnectView(fakeParent) - - // THEN the view is not rebuilt - verify(plugin, never()).getView(any()) - assertEquals(fakeSmartspaceView, controller.view) - } - - @Test - fun testDoubleConnectIsIgnored() { + fun testMultipleViewsUseSameSession() { // GIVEN a connected session connectSession() clearInvocations(smartspaceManager) clearInvocations(plugin) - // WHEN we're asked to connect a second time and add to a parent + // WHEN we're asked to connect a second time and add to a parent. If the same view + // was created the ViewGroup will throw an exception val view = controller.buildAndConnectView(fakeParent) fakeParent.addView(view) + val smartspaceView2 = view as SmartspaceView - // THEN the existing view and session are reused + // THEN the existing session is reused and views are registered verify(smartspaceManager, never()).createSmartspaceSession(any()) - verify(plugin, never()).getView(any()) - assertEquals(fakeSmartspaceView, controller.view) + verify(smartspaceView2).registerDataProvider(plugin) } private fun connectSession() { - controller.buildAndConnectView(fakeParent) + val view = controller.buildAndConnectView(fakeParent) + smartspaceView = view as SmartspaceView + controller.stateChangeListener.onViewAttachedToWindow(view) + + verify(smartspaceView).registerDataProvider(plugin) verify(smartspaceSession) .addOnTargetsAvailableListener(any(), capture(sessionListenerCaptor)) sessionListener = sessionListenerCaptor.value @@ -450,11 +441,11 @@ class LockscreenSmartspaceControllerTest : SysuiTestCase() { verify(smartspaceSession).requestSmartspaceUpdate() clearInvocations(smartspaceSession) - verify(fakeSmartspaceView).setPrimaryTextColor(anyInt()) - verify(fakeSmartspaceView).setDozeAmount(0.5f) - clearInvocations(fakeSmartspaceView) + verify(smartspaceView).setPrimaryTextColor(anyInt()) + verify(smartspaceView).setDozeAmount(0.5f) + clearInvocations(view) - fakeParent.addView(fakeSmartspaceView) + fakeParent.addView(view) } private fun setActiveUser(userHandle: UserHandle) { @@ -490,31 +481,33 @@ class LockscreenSmartspaceControllerTest : SysuiTestCase() { ).thenReturn(if (value) 1 else 0) } - private val fakeSmartspaceView = spy(object : View(context), SmartspaceView { - override fun registerDataProvider(plugin: BcSmartspaceDataPlugin?) { - } + private fun createSmartspaceView(): SmartspaceView { + return spy(object : View(context), SmartspaceView { + override fun registerDataProvider(plugin: BcSmartspaceDataPlugin?) { + } - override fun setPrimaryTextColor(color: Int) { - } + override fun setPrimaryTextColor(color: Int) { + } - override fun setDozeAmount(amount: Float) { - } + override fun setDozeAmount(amount: Float) { + } - override fun setIntentStarter(intentStarter: BcSmartspaceDataPlugin.IntentStarter?) { - } + override fun setIntentStarter(intentStarter: BcSmartspaceDataPlugin.IntentStarter?) { + } - override fun setFalsingManager(falsingManager: FalsingManager?) { - } + override fun setFalsingManager(falsingManager: FalsingManager?) { + } - override fun setDnd(image: Drawable?, description: String?) { - } + override fun setDnd(image: Drawable?, description: String?) { + } - override fun setNextAlarm(image: Drawable?, description: String?) { - } + override fun setNextAlarm(image: Drawable?, description: String?) { + } - override fun setMediaTarget(target: SmartspaceTarget?) { - } - }) + override fun setMediaTarget(target: SmartspaceTarget?) { + } + }) + } } private const val PRIVATE_LOCKSCREEN_SETTING =