Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 5088c490 authored by Android Build Prod User's avatar Android Build Prod User Committed by Android (Google) Code Review
Browse files

Merge "[DO NOT MERGE] Support multiple smartspace views" into sc-v2-dev

parents 3921366d b9b97ec9
Loading
Loading
Loading
Loading
+0 −10
Original line number Diff line number Diff line
@@ -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;
        }
    }

    /**
+23 −24
Original line number Diff line number Diff line
@@ -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()

@@ -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() {
+40 −47
Original line number Diff line number Diff line
@@ -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,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?) {
            }

@@ -516,6 +508,7 @@ class LockscreenSmartspaceControllerTest : SysuiTestCase() {
            }
        })
    }
}

private const val PRIVATE_LOCKSCREEN_SETTING =
        Settings.Secure.LOCK_SCREEN_ALLOW_PRIVATE_NOTIFICATIONS