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

Commit 733493bf authored by Tao Wu's avatar Tao Wu
Browse files

Growth : add delay before broadcasting device entered event.

The main goal is to mitigate the initial performance impact.

Also remove the growth app receiver permission, which is added in the AndroidManifest.xml.

Bug: 410857267
Flag: com.android.systemui.enable_desktop_growth
Change-Id: Iea8c9e1c35aa8a31172a720df4163ef234f48615
parent d2503c2d
Loading
Loading
Loading
Loading
+78 −26
Original line number Diff line number Diff line
@@ -28,6 +28,7 @@ import com.android.systemui.broadcast.mockBroadcastSender
import com.android.systemui.deviceentry.domain.interactor.deviceEntryInteractor
import com.android.systemui.flags.EnableSceneContainer
import com.android.systemui.kosmos.Kosmos
import com.android.systemui.kosmos.advanceTimeBy
import com.android.systemui.kosmos.collectLastValue
import com.android.systemui.kosmos.runCurrent
import com.android.systemui.kosmos.runTest
@@ -40,6 +41,7 @@ import com.android.systemui.scene.domain.startable.sceneContainerStartable
import com.android.systemui.scene.shared.model.Scenes
import com.android.systemui.testKosmos
import com.google.common.truth.Truth.assertThat
import kotlin.time.Duration.Companion.milliseconds
import kotlinx.coroutines.flow.flowOf
import org.junit.Before
import org.junit.Test
@@ -51,7 +53,6 @@ import org.mockito.Mockito.verify
import org.mockito.MockitoAnnotations
import org.mockito.kotlin.any
import org.mockito.kotlin.capture
import org.mockito.kotlin.eq
import org.mockito.kotlin.never
import org.mockito.kotlin.times

@@ -64,8 +65,7 @@ class GrowthInteractorTest : SysuiTestCase() {
    private val broadcastSender by lazy { kosmos.mockBroadcastSender }
    private lateinit var underTest: GrowthInteractor

    @Captor
    private lateinit var intentArgumentCaptor: ArgumentCaptor<Intent>
    @Captor private lateinit var intentArgumentCaptor: ArgumentCaptor<Intent>

    @Before
    fun setUp() {
@@ -76,57 +76,108 @@ class GrowthInteractorTest : SysuiTestCase() {
    @Test
    fun onDeviceEnteredDirectly_sendBroadcast_withAllConfigs() =
        kosmos.runTest {
            overrideResources()
            overrideResources(GROWTH_APP_PACKAGE_NAME, GROWTH_RECEIVER_CLASS_NAME)
            underTest = kosmos.growthInteractor
            underTest.activateIn(kosmos.testScope)
            setDeviceEntered()
            advanceTimeBy(GROWTH_BROADCAST_DELAY.plus(DURATION_50_MILLIS))
            runCurrent()

            verify(broadcastSender, times(1))
                .sendBroadcast(capture(intentArgumentCaptor), eq(GROWTH_RECEIVER_PERMISSION))
            verify(broadcastSender, times(1)).sendBroadcast(capture(intentArgumentCaptor))
            assertThat(intentArgumentCaptor.value.action)
                .isEqualTo(GrowthInteractor.ACTION_DEVICE_ENTERED_DIRECTLY)
            assertThat(intentArgumentCaptor.value.`package`).isEqualTo(GROWTH_APP_PACKAGE_NAME)
            assertThat(intentArgumentCaptor.value.`package`).isNull()
            assertThat(intentArgumentCaptor.value.component?.packageName)
                .isEqualTo(GROWTH_APP_PACKAGE_NAME)
            assertThat(intentArgumentCaptor.value.component?.className)
                .isEqualTo(GROWTH_RECEIVER_CLASS_NAME)
        }

    @Test
    fun onDeviceEnteredDirectly_sendBroadcast_withEmptyPackageName() =
        kosmos.runTest {
            overrideResources("", GROWTH_RECEIVER_CLASS_NAME)
            underTest = kosmos.growthInteractor
            underTest.activateIn(kosmos.testScope)
            setDeviceEntered()
            advanceTimeBy(GROWTH_BROADCAST_DELAY.plus(DURATION_50_MILLIS))
            runCurrent()

            verify(broadcastSender, times(1)).sendBroadcast(capture(intentArgumentCaptor))
            assertThat(intentArgumentCaptor.value.action)
                .isEqualTo(GrowthInteractor.ACTION_DEVICE_ENTERED_DIRECTLY)
            assertThat(intentArgumentCaptor.value.`package`).isNull()
            assertThat(intentArgumentCaptor.value.component).isNull()
        }

    @Test
    fun onDeviceEnteredDirectly_sendBroadcast_withEmptyReceiverClassName() =
        kosmos.runTest {
            overrideResources(GROWTH_APP_PACKAGE_NAME, "")
            underTest = kosmos.growthInteractor
            underTest.activateIn(kosmos.testScope)
            setDeviceEntered()
            advanceTimeBy(GROWTH_BROADCAST_DELAY.plus(DURATION_50_MILLIS))
            runCurrent()

            verify(broadcastSender, times(1)).sendBroadcast(capture(intentArgumentCaptor))
            assertThat(intentArgumentCaptor.value.action)
                .isEqualTo(GrowthInteractor.ACTION_DEVICE_ENTERED_DIRECTLY)
            assertThat(intentArgumentCaptor.value.`package`).isNull()
            assertThat(intentArgumentCaptor.value.component).isNull()
        }

    @Test
    fun onDeviceEnteredDirectly_sendBroadcast_withEmptyConfigs() =
        kosmos.runTest {
            overrideResourcesWithEmptyValues()
            overrideResources("", "")
            underTest = kosmos.growthInteractor
            underTest.activateIn(kosmos.testScope)
            setDeviceEntered()
            advanceTimeBy(GROWTH_BROADCAST_DELAY.plus(DURATION_50_MILLIS))
            runCurrent()

            verify(broadcastSender, times(1))
                .sendBroadcast(capture(intentArgumentCaptor))
            verify(broadcastSender, times(1)).sendBroadcast(capture(intentArgumentCaptor))
            assertThat(intentArgumentCaptor.value.action)
                .isEqualTo(GrowthInteractor.ACTION_DEVICE_ENTERED_DIRECTLY)
            assertThat(intentArgumentCaptor.value.`package`).isNull()
            assertThat(intentArgumentCaptor.value.component)
                .isNull()
            assertThat(intentArgumentCaptor.value.component).isNull()
        }

    @Test
    fun onDeviceNotEnteredDirectly_doNotSendBroadcast() =
    fun onDeviceNotEnteredDirectly_doNotSendBroadcast_onLockscreen() =
        kosmos.runTest {
            overrideResources(GROWTH_APP_PACKAGE_NAME, GROWTH_RECEIVER_CLASS_NAME)
            setDeviceEntered()
            advanceTimeBy(GROWTH_BROADCAST_DELAY.plus(DURATION_50_MILLIS))
            clearInvocations(broadcastSender)

            setScene(Scenes.Lockscreen)
            advanceTimeBy(GROWTH_BROADCAST_DELAY.plus(DURATION_50_MILLIS))
            verify(broadcastSender, never()).sendBroadcast(any(), any())
        }

    private fun overrideResources() {
        overrideResource(R.string.config_growthAppPackageName, GROWTH_APP_PACKAGE_NAME)
        overrideResource(R.string.config_growthReceiverClassName, GROWTH_RECEIVER_CLASS_NAME)
        overrideResource(R.string.config_growthReceiverPermission, GROWTH_RECEIVER_PERMISSION)
    @Test
    fun onDeviceEnteredDirectly_doNotSendBroadcast_lockedBeforeDelay() =
        kosmos.runTest {
            overrideResources(GROWTH_APP_PACKAGE_NAME, GROWTH_RECEIVER_CLASS_NAME)
            underTest = kosmos.growthInteractor
            underTest.activateIn(kosmos.testScope)
            setDeviceEntered()
            advanceTimeBy(DURATION_50_MILLIS)
            runCurrent()
            verify(broadcastSender, never()).sendBroadcast(any(), any())

            setScene(Scenes.Lockscreen)
            advanceTimeBy(GROWTH_BROADCAST_DELAY.plus(DURATION_50_MILLIS))
            runCurrent()
            verify(broadcastSender, never()).sendBroadcast(any(), any())
        }

    private fun overrideResourcesWithEmptyValues() {
        overrideResource(R.string.config_growthAppPackageName, "")
        overrideResource(R.string.config_growthReceiverClassName, "")
        overrideResource(R.string.config_growthReceiverPermission, "")
    private fun overrideResources(packageName: String, receiverClassName: String) {
        overrideResource(R.string.config_growthAppPackageName, packageName)
        overrideResource(R.string.config_growthReceiverClassName, receiverClassName)
        overrideResource(R.integer.config_growthBroadcastDelayMillis, DELAY_200_MILLIS)
    }

    private suspend fun Kosmos.setDeviceEntered() {
@@ -155,7 +206,8 @@ class GrowthInteractorTest : SysuiTestCase() {
    companion object {
        private const val GROWTH_APP_PACKAGE_NAME = "com.android.systemui.growth"
        private const val GROWTH_RECEIVER_CLASS_NAME = "com.android.systemui.growth.GrowthReceiver"
        private const val GROWTH_RECEIVER_PERMISSION =
            "com.android.systemui.growth.permission.SEND_BROADCAST"
        private const val DELAY_200_MILLIS = 200
        private val GROWTH_BROADCAST_DELAY = DELAY_200_MILLIS.milliseconds
        private val DURATION_50_MILLIS = 50.milliseconds
    }
}
+2 −2
Original line number Diff line number Diff line
@@ -1145,6 +1145,6 @@
    <string name="config_growthAppPackageName" translatable="false" />
    <!-- Class name for the growth app's receiver. -->
    <string name="config_growthReceiverClassName" translatable="false" />
    <!-- Permission to send a broadcast to the growth app receiver. -->
    <string name="config_growthReceiverPermission" translatable="false" />
    <!-- Delay in milliseconds before sending the broadcast to the growth app. -->
    <integer name="config_growthBroadcastDelayMillis">10000</integer>
</resources>
+30 −16
Original line number Diff line number Diff line
@@ -28,6 +28,11 @@ import com.android.systemui.lifecycle.ExclusiveActivatable
import com.android.systemui.res.R
import dagger.Lazy
import javax.inject.Inject
import kotlinx.coroutines.Job
import kotlinx.coroutines.cancel
import kotlinx.coroutines.coroutineScope
import kotlinx.coroutines.delay
import kotlinx.coroutines.launch

/** Interactor to communicate with the growth app. */
@SysUISingleton
@@ -38,31 +43,40 @@ constructor(
    private val deviceEntryInteractor: Lazy<DeviceEntryInteractor>,
    private val broadcastSender: BroadcastSender,
) : ExclusiveActivatable() {
    private val growthAppPackageName =
        resources.getString(R.string.config_growthAppPackageName)
    private val growthAppPackageName = resources.getString(R.string.config_growthAppPackageName)
    private val growthReceiverClassName =
        resources.getString(R.string.config_growthReceiverClassName)
    private val growthReceiverPermission =
        resources.getString(R.string.config_growthReceiverPermission)
    private val growthBroadcastDelayMillis =
        resources.getInteger(R.integer.config_growthBroadcastDelayMillis)

    private var sendBroadcastJob: Job? = null

    override suspend fun onActivated(): Nothing {
        deviceEntryInteractor.get().isDeviceEnteredDirectly.collect {
            // Cancel any existing job before launching a new one.
            sendBroadcastJob?.cancel()
            sendBroadcastJob = null

            if (it) {
                // Broadcast the device entered event to the growth app.
                // Launch the delayed task.
                sendBroadcastJob = coroutineScope {
                    launch {
                        delay(growthBroadcastDelayMillis.toLong())
                        sendBroadcast()
                    }
                }
            }
        }
    }

    private suspend fun sendBroadcast() {
        // Broadcast the device entered event.
        val intent = Intent().apply { setAction(ACTION_DEVICE_ENTERED_DIRECTLY) }
        if (growthAppPackageName.isNotEmpty() && growthReceiverClassName.isNotEmpty()) {
                    intent.setPackage(growthAppPackageName)
            intent.setComponent(ComponentName(growthAppPackageName, growthReceiverClassName))
        }

                if (growthReceiverPermission.isNotEmpty()) {
                    broadcastSender.sendBroadcast(intent, growthReceiverPermission)
                } else {
        broadcastSender.sendBroadcast(intent)
    }
            }
        }
    }

    companion object {
        @VisibleForTesting