Loading packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitchController.java +0 −10 Original line number Diff line number Diff line Loading @@ -234,16 +234,6 @@ public class KeyguardClockSwitchController extends ViewController<KeyguardClockS mView.setClockPlugin(null, mStatusBarStateController.getState()); mSmartspaceController.disconnect(); // TODO: This is an unfortunate necessity since smartspace plugin retains a single instance // of the smartspace view -- if we don't remove the view, it can't be reused by a later // instance of this class. In order to fix this, we need to modify the plugin so that // (a) we get a new view each time and (b) we can properly clean up an old view by making // it unregister itself as a plugin listener. if (mSmartspaceView != null) { mView.removeView(mSmartspaceView); mSmartspaceView = null; } } /** Loading packages/SystemUI/src/com/android/systemui/statusbar/lockscreen/LockscreenSmartspaceController.kt +23 −24 Original line number Diff line number Diff line Loading @@ -74,15 +74,27 @@ class LockscreenSmartspaceController @Inject constructor( ) { private var session: SmartspaceSession? = null private val plugin: BcSmartspaceDataPlugin? = optionalPlugin.orElse(null) private lateinit var smartspaceView: SmartspaceView lateinit var view: View private set // Smartspace can be used on multiple displays, such as when the user casts their screen private var smartspaceViews = mutableSetOf<SmartspaceView>() 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() Loading @@ -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 Loading @@ -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) Loading @@ -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() { Loading Loading @@ -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() Loading Loading @@ -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) } } } Loading @@ -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() { Loading packages/SystemUI/tests/src/com/android/systemui/statusbar/lockscreen/LockscreenSmartspaceControllerTest.kt +40 −47 Original line number Diff line number Diff line Loading @@ -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 Loading Loading @@ -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() Loading Loading @@ -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) Loading Loading @@ -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 Loading @@ -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 Loading Loading @@ -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 Loading @@ -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) { Loading Loading @@ -490,7 +481,8 @@ class LockscreenSmartspaceControllerTest : SysuiTestCase() { ).thenReturn(if (value) 1 else 0) } private val fakeSmartspaceView = spy(object : View(context), SmartspaceView { private fun createSmartspaceView(): SmartspaceView { return spy(object : View(context), SmartspaceView { override fun registerDataProvider(plugin: BcSmartspaceDataPlugin?) { } Loading @@ -516,6 +508,7 @@ class LockscreenSmartspaceControllerTest : SysuiTestCase() { } }) } } private const val PRIVATE_LOCKSCREEN_SETTING = Settings.Secure.LOCK_SCREEN_ALLOW_PRIVATE_NOTIFICATIONS Loading
packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitchController.java +0 −10 Original line number Diff line number Diff line Loading @@ -234,16 +234,6 @@ public class KeyguardClockSwitchController extends ViewController<KeyguardClockS mView.setClockPlugin(null, mStatusBarStateController.getState()); mSmartspaceController.disconnect(); // TODO: This is an unfortunate necessity since smartspace plugin retains a single instance // of the smartspace view -- if we don't remove the view, it can't be reused by a later // instance of this class. In order to fix this, we need to modify the plugin so that // (a) we get a new view each time and (b) we can properly clean up an old view by making // it unregister itself as a plugin listener. if (mSmartspaceView != null) { mView.removeView(mSmartspaceView); mSmartspaceView = null; } } /** Loading
packages/SystemUI/src/com/android/systemui/statusbar/lockscreen/LockscreenSmartspaceController.kt +23 −24 Original line number Diff line number Diff line Loading @@ -74,15 +74,27 @@ class LockscreenSmartspaceController @Inject constructor( ) { private var session: SmartspaceSession? = null private val plugin: BcSmartspaceDataPlugin? = optionalPlugin.orElse(null) private lateinit var smartspaceView: SmartspaceView lateinit var view: View private set // Smartspace can be used on multiple displays, such as when the user casts their screen private var smartspaceViews = mutableSetOf<SmartspaceView>() 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() Loading @@ -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 Loading @@ -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) Loading @@ -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() { Loading Loading @@ -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() Loading Loading @@ -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) } } } Loading @@ -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() { Loading
packages/SystemUI/tests/src/com/android/systemui/statusbar/lockscreen/LockscreenSmartspaceControllerTest.kt +40 −47 Original line number Diff line number Diff line Loading @@ -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 Loading Loading @@ -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() Loading Loading @@ -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) Loading Loading @@ -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 Loading @@ -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 Loading Loading @@ -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 Loading @@ -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) { Loading Loading @@ -490,7 +481,8 @@ class LockscreenSmartspaceControllerTest : SysuiTestCase() { ).thenReturn(if (value) 1 else 0) } private val fakeSmartspaceView = spy(object : View(context), SmartspaceView { private fun createSmartspaceView(): SmartspaceView { return spy(object : View(context), SmartspaceView { override fun registerDataProvider(plugin: BcSmartspaceDataPlugin?) { } Loading @@ -516,6 +508,7 @@ class LockscreenSmartspaceControllerTest : SysuiTestCase() { } }) } } private const val PRIVATE_LOCKSCREEN_SETTING = Settings.Secure.LOCK_SCREEN_ALLOW_PRIVATE_NOTIFICATIONS