Merge "[DO NOT MERGE] Support multiple smartspace views" into sc-v2-dev
This commit is contained in:
committed by
Android (Google) Code Review
commit
5088c49088
@@ -234,16 +234,6 @@ public class KeyguardClockSwitchController extends ViewController<KeyguardClockS
|
|||||||
mView.setClockPlugin(null, mStatusBarStateController.getState());
|
mView.setClockPlugin(null, mStatusBarStateController.getState());
|
||||||
|
|
||||||
mSmartspaceController.disconnect();
|
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;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -74,15 +74,27 @@ class LockscreenSmartspaceController @Inject constructor(
|
|||||||
) {
|
) {
|
||||||
private var session: SmartspaceSession? = null
|
private var session: SmartspaceSession? = null
|
||||||
private val plugin: BcSmartspaceDataPlugin? = optionalPlugin.orElse(null)
|
private val plugin: BcSmartspaceDataPlugin? = optionalPlugin.orElse(null)
|
||||||
private lateinit var smartspaceView: SmartspaceView
|
|
||||||
|
|
||||||
lateinit var view: View
|
// Smartspace can be used on multiple displays, such as when the user casts their screen
|
||||||
private set
|
private var smartspaceViews = mutableSetOf<SmartspaceView>()
|
||||||
|
|
||||||
private var showSensitiveContentForCurrentUser = false
|
private var showSensitiveContentForCurrentUser = false
|
||||||
private var showSensitiveContentForManagedUser = false
|
private var showSensitiveContentForManagedUser = false
|
||||||
private var managedUserHandle: UserHandle? = null
|
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 {
|
fun isEnabled(): Boolean {
|
||||||
execution.assertIsMainThread()
|
execution.assertIsMainThread()
|
||||||
|
|
||||||
@@ -90,17 +102,16 @@ class LockscreenSmartspaceController @Inject constructor(
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Constructs the smartspace view and connects it to the smartspace service. Subsequent calls
|
* Constructs the smartspace view and connects it to the smartspace service.
|
||||||
* are idempotent until [disconnect] is called.
|
|
||||||
*/
|
*/
|
||||||
fun buildAndConnectView(parent: ViewGroup): View {
|
fun buildAndConnectView(parent: ViewGroup): View? {
|
||||||
execution.assertIsMainThread()
|
execution.assertIsMainThread()
|
||||||
|
|
||||||
if (!isEnabled()) {
|
if (!isEnabled()) {
|
||||||
throw RuntimeException("Cannot build view when not enabled")
|
throw RuntimeException("Cannot build view when not enabled")
|
||||||
}
|
}
|
||||||
|
|
||||||
buildView(parent)
|
val view = buildView(parent)
|
||||||
connectSession()
|
connectSession()
|
||||||
|
|
||||||
return view
|
return view
|
||||||
@@ -110,14 +121,9 @@ class LockscreenSmartspaceController @Inject constructor(
|
|||||||
session?.requestSmartspaceUpdate()
|
session?.requestSmartspaceUpdate()
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun buildView(parent: ViewGroup) {
|
private fun buildView(parent: ViewGroup): View? {
|
||||||
if (plugin == null) {
|
if (plugin == null) {
|
||||||
return
|
return null
|
||||||
}
|
|
||||||
if (this::view.isInitialized) {
|
|
||||||
// Due to some oddities with a singleton smartspace view, allow reparenting
|
|
||||||
(view.getParent() as ViewGroup?)?.removeView(view)
|
|
||||||
return
|
|
||||||
}
|
}
|
||||||
|
|
||||||
val ssView = plugin.getView(parent)
|
val ssView = plugin.getView(parent)
|
||||||
@@ -132,12 +138,7 @@ class LockscreenSmartspaceController @Inject constructor(
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
ssView.setFalsingManager(falsingManager)
|
ssView.setFalsingManager(falsingManager)
|
||||||
|
return (ssView as View).apply { addOnAttachStateChangeListener(stateChangeListener) }
|
||||||
this.smartspaceView = ssView
|
|
||||||
this.view = ssView as View
|
|
||||||
|
|
||||||
updateTextColorFromWallpaper()
|
|
||||||
statusBarStateListener.onDozeAmountChanged(0f, statusBarStateController.dozeAmount)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun connectSession() {
|
private fun connectSession() {
|
||||||
@@ -165,8 +166,6 @@ class LockscreenSmartspaceController @Inject constructor(
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Disconnects the smartspace view from the smartspace service and cleans up any resources.
|
* 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() {
|
fun disconnect() {
|
||||||
execution.assertIsMainThread()
|
execution.assertIsMainThread()
|
||||||
@@ -231,7 +230,7 @@ class LockscreenSmartspaceController @Inject constructor(
|
|||||||
private val statusBarStateListener = object : StatusBarStateController.StateListener {
|
private val statusBarStateListener = object : StatusBarStateController.StateListener {
|
||||||
override fun onDozeAmountChanged(linear: Float, eased: Float) {
|
override fun onDozeAmountChanged(linear: Float, eased: Float) {
|
||||||
execution.assertIsMainThread()
|
execution.assertIsMainThread()
|
||||||
smartspaceView.setDozeAmount(eased)
|
smartspaceViews.forEach { it.setDozeAmount(eased) }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -256,7 +255,7 @@ class LockscreenSmartspaceController @Inject constructor(
|
|||||||
|
|
||||||
private fun updateTextColorFromWallpaper() {
|
private fun updateTextColorFromWallpaper() {
|
||||||
val wallpaperTextColor = Utils.getColorAttrDefaultColor(context, R.attr.wallpaperTextColor)
|
val wallpaperTextColor = Utils.getColorAttrDefaultColor(context, R.attr.wallpaperTextColor)
|
||||||
smartspaceView.setPrimaryTextColor(wallpaperTextColor)
|
smartspaceViews.forEach { it.setPrimaryTextColor(wallpaperTextColor) }
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun reloadSmartspace() {
|
private fun reloadSmartspace() {
|
||||||
|
|||||||
@@ -51,7 +51,6 @@ import com.android.systemui.util.mockito.capture
|
|||||||
import com.android.systemui.util.mockito.eq
|
import com.android.systemui.util.mockito.eq
|
||||||
import com.android.systemui.util.settings.SecureSettings
|
import com.android.systemui.util.settings.SecureSettings
|
||||||
import com.android.systemui.util.time.FakeSystemClock
|
import com.android.systemui.util.time.FakeSystemClock
|
||||||
import org.junit.Assert.assertEquals
|
|
||||||
import org.junit.Before
|
import org.junit.Before
|
||||||
import org.junit.Test
|
import org.junit.Test
|
||||||
import org.mockito.ArgumentCaptor
|
import org.mockito.ArgumentCaptor
|
||||||
@@ -114,6 +113,8 @@ class LockscreenSmartspaceControllerTest : SysuiTestCase() {
|
|||||||
private lateinit var configChangeListener: ConfigurationListener
|
private lateinit var configChangeListener: ConfigurationListener
|
||||||
private lateinit var statusBarStateListener: StateListener
|
private lateinit var statusBarStateListener: StateListener
|
||||||
|
|
||||||
|
private lateinit var smartspaceView: SmartspaceView
|
||||||
|
|
||||||
private val clock = FakeSystemClock()
|
private val clock = FakeSystemClock()
|
||||||
private val executor = FakeExecutor(clock)
|
private val executor = FakeExecutor(clock)
|
||||||
private val execution = FakeExecution()
|
private val execution = FakeExecution()
|
||||||
@@ -141,7 +142,7 @@ class LockscreenSmartspaceControllerTest : SysuiTestCase() {
|
|||||||
`when`(secureSettings.getUriFor(PRIVATE_LOCKSCREEN_SETTING))
|
`when`(secureSettings.getUriFor(PRIVATE_LOCKSCREEN_SETTING))
|
||||||
.thenReturn(fakePrivateLockscreenSettingUri)
|
.thenReturn(fakePrivateLockscreenSettingUri)
|
||||||
`when`(smartspaceManager.createSmartspaceSession(any())).thenReturn(smartspaceSession)
|
`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`(userTracker.userProfiles).thenReturn(userList)
|
||||||
`when`(statusBarStateController.dozeAmount).thenReturn(0.5f)
|
`when`(statusBarStateController.dozeAmount).thenReturn(0.5f)
|
||||||
|
|
||||||
@@ -249,7 +250,7 @@ class LockscreenSmartspaceControllerTest : SysuiTestCase() {
|
|||||||
configChangeListener.onThemeChanged()
|
configChangeListener.onThemeChanged()
|
||||||
|
|
||||||
// We update the new text color to match the wallpaper color
|
// We update the new text color to match the wallpaper color
|
||||||
verify(fakeSmartspaceView).setPrimaryTextColor(anyInt())
|
verify(smartspaceView).setPrimaryTextColor(anyInt())
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@@ -261,7 +262,7 @@ class LockscreenSmartspaceControllerTest : SysuiTestCase() {
|
|||||||
statusBarStateListener.onDozeAmountChanged(0.1f, 0.7f)
|
statusBarStateListener.onDozeAmountChanged(0.1f, 0.7f)
|
||||||
|
|
||||||
// We pass that along to the view
|
// We pass that along to the view
|
||||||
verify(fakeSmartspaceView).setDozeAmount(0.7f)
|
verify(smartspaceView).setDozeAmount(0.7f)
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@@ -393,40 +394,30 @@ class LockscreenSmartspaceControllerTest : SysuiTestCase() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun testBuildViewIsIdempotent() {
|
fun testMultipleViewsUseSameSession() {
|
||||||
// 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() {
|
|
||||||
// GIVEN a connected session
|
// GIVEN a connected session
|
||||||
connectSession()
|
connectSession()
|
||||||
clearInvocations(smartspaceManager)
|
clearInvocations(smartspaceManager)
|
||||||
clearInvocations(plugin)
|
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)
|
val view = controller.buildAndConnectView(fakeParent)
|
||||||
fakeParent.addView(view)
|
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(smartspaceManager, never()).createSmartspaceSession(any())
|
||||||
verify(plugin, never()).getView(any())
|
verify(smartspaceView2).registerDataProvider(plugin)
|
||||||
assertEquals(fakeSmartspaceView, controller.view)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun connectSession() {
|
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)
|
verify(smartspaceSession)
|
||||||
.addOnTargetsAvailableListener(any(), capture(sessionListenerCaptor))
|
.addOnTargetsAvailableListener(any(), capture(sessionListenerCaptor))
|
||||||
sessionListener = sessionListenerCaptor.value
|
sessionListener = sessionListenerCaptor.value
|
||||||
@@ -450,11 +441,11 @@ class LockscreenSmartspaceControllerTest : SysuiTestCase() {
|
|||||||
verify(smartspaceSession).requestSmartspaceUpdate()
|
verify(smartspaceSession).requestSmartspaceUpdate()
|
||||||
clearInvocations(smartspaceSession)
|
clearInvocations(smartspaceSession)
|
||||||
|
|
||||||
verify(fakeSmartspaceView).setPrimaryTextColor(anyInt())
|
verify(smartspaceView).setPrimaryTextColor(anyInt())
|
||||||
verify(fakeSmartspaceView).setDozeAmount(0.5f)
|
verify(smartspaceView).setDozeAmount(0.5f)
|
||||||
clearInvocations(fakeSmartspaceView)
|
clearInvocations(view)
|
||||||
|
|
||||||
fakeParent.addView(fakeSmartspaceView)
|
fakeParent.addView(view)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun setActiveUser(userHandle: UserHandle) {
|
private fun setActiveUser(userHandle: UserHandle) {
|
||||||
@@ -490,31 +481,33 @@ class LockscreenSmartspaceControllerTest : SysuiTestCase() {
|
|||||||
).thenReturn(if (value) 1 else 0)
|
).thenReturn(if (value) 1 else 0)
|
||||||
}
|
}
|
||||||
|
|
||||||
private val fakeSmartspaceView = spy(object : View(context), SmartspaceView {
|
private fun createSmartspaceView(): SmartspaceView {
|
||||||
override fun registerDataProvider(plugin: BcSmartspaceDataPlugin?) {
|
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 =
|
private const val PRIVATE_LOCKSCREEN_SETTING =
|
||||||
|
|||||||
Reference in New Issue
Block a user