Loading packages/SystemUI/multivalentTests/src/com/android/systemui/growth/GrowthInteractorTest.kt +78 −26 Original line number Diff line number Diff line Loading @@ -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 Loading @@ -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 Loading @@ -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 Loading @@ -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() { Loading @@ -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() { Loading Loading @@ -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 } } packages/SystemUI/res/values/config.xml +2 −2 Original line number Diff line number Diff line Loading @@ -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> packages/SystemUI/src/com/android/systemui/growth/domain/interactor/GrowthInteractor.kt +30 −16 Original line number Diff line number Diff line Loading @@ -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 Loading @@ -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 Loading Loading
packages/SystemUI/multivalentTests/src/com/android/systemui/growth/GrowthInteractorTest.kt +78 −26 Original line number Diff line number Diff line Loading @@ -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 Loading @@ -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 Loading @@ -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 Loading @@ -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() { Loading @@ -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() { Loading Loading @@ -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 } }
packages/SystemUI/res/values/config.xml +2 −2 Original line number Diff line number Diff line Loading @@ -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>
packages/SystemUI/src/com/android/systemui/growth/domain/interactor/GrowthInteractor.kt +30 −16 Original line number Diff line number Diff line Loading @@ -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 Loading @@ -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 Loading