Loading packages/SystemUI/multivalentTests/src/com/android/systemui/ambientcue/data/repository/AmbientCueRepositoryTest.kt +77 −0 Original line number Diff line number Diff line Loading @@ -17,22 +17,32 @@ package com.android.systemui.ambientcue.data.repository import android.app.ActivityManager.RunningTaskInfo import android.app.assist.ActivityId import android.app.smartspace.SmartspaceAction import android.app.smartspace.SmartspaceManager import android.app.smartspace.SmartspaceSession import android.app.smartspace.SmartspaceSession.OnTargetsAvailableListener import android.app.smartspace.SmartspaceTarget import android.content.Intent import android.content.testableContext import android.os.Binder import android.os.Bundle import android.view.autofill.AutofillId import android.view.autofill.AutofillManager import androidx.test.ext.junit.runners.AndroidJUnit4 import androidx.test.filters.SmallTest import com.android.systemui.SysuiTestCase import com.android.systemui.ambientcue.data.repository.AmbientCueRepositoryImpl.Companion.AMBIENT_CUE_SURFACE import com.android.systemui.ambientcue.data.repository.AmbientCueRepositoryImpl.Companion.EXTRA_ACTIVITY_ID import com.android.systemui.ambientcue.data.repository.AmbientCueRepositoryImpl.Companion.EXTRA_AUTOFILL_ID import com.android.systemui.ambientcue.shared.model.ActionModel import com.android.systemui.concurrency.fakeExecutor import com.android.systemui.kosmos.advanceUntilIdle import com.android.systemui.kosmos.backgroundScope import com.android.systemui.kosmos.collectLastValue import com.android.systemui.kosmos.runCurrent import com.android.systemui.kosmos.runTest import com.android.systemui.plugins.ActivityStarter import com.android.systemui.shade.data.repository.fakeFocusedDisplayRepository import com.android.systemui.testKosmos import com.google.common.truth.Truth.assertThat Loading @@ -49,6 +59,8 @@ import org.mockito.kotlin.verify class AmbientCueRepositoryTest : SysuiTestCase() { private val kosmos = testKosmos() private val smartSpaceSession = mock<SmartspaceSession>() private val autofillManager = mock<AutofillManager>() private val activityStarter = mock<ActivityStarter>() private val smartSpaceManager = mock<SmartspaceManager>() { on { createSmartspaceSession(any()) } doReturn smartSpaceSession Loading @@ -58,6 +70,8 @@ class AmbientCueRepositoryTest : SysuiTestCase() { AmbientCueRepositoryImpl( backgroundScope = kosmos.backgroundScope, smartSpaceManager = smartSpaceManager, autofillManager = autofillManager, activityStarter = activityStarter, executor = kosmos.fakeExecutor, applicationContext = kosmos.testableContext, focusdDisplayRepository = kosmos.fakeFocusedDisplayRepository, Loading Loading @@ -124,6 +138,37 @@ class AmbientCueRepositoryTest : SysuiTestCase() { assertThat(globallyFocusedTaskId).isEqualTo(TASK_ID) } @Test fun action_performAutofill() = kosmos.runTest { val actions by collectLastValue(underTest.actions) runCurrent() verify(smartSpaceSession) .addOnTargetsAvailableListener(any(), onTargetsAvailableListenerCaptor.capture()) onTargetsAvailableListenerCaptor.firstValue.onTargetsAvailable(listOf(autofillTarget)) val action: ActionModel = actions!!.first() action.onPerformAction() runCurrent() verify(autofillManager) .autofillRemoteApp(autofillId, action.label, activityId.token!!, activityId.taskId) } @Test fun action_performStartActivity() = kosmos.runTest { val actions by collectLastValue(underTest.actions) runCurrent() verify(smartSpaceSession) .addOnTargetsAvailableListener(any(), onTargetsAvailableListenerCaptor.capture()) onTargetsAvailableListenerCaptor.firstValue.onTargetsAvailable(listOf(intentTarget)) val action: ActionModel = actions!!.first() action.onPerformAction() runCurrent() verify(activityStarter).startActivity(launchIntent, false) } companion object { private const val TITLE_1 = "title 1" Loading @@ -144,6 +189,38 @@ class AmbientCueRepositoryTest : SysuiTestCase() { ) } private val autofillId = AutofillId(2) private val activityId = ActivityId(1, Binder()) private val autofillTarget = mock<SmartspaceTarget> { on { smartspaceTargetId } doReturn AMBIENT_CUE_SURFACE on { actionChips } doReturn listOf( SmartspaceAction.Builder("action1-id", "title 1") .setSubtitle("subtitle 1") .setExtras( Bundle().apply { putParcelable(EXTRA_ACTIVITY_ID, activityId) putParcelable(EXTRA_AUTOFILL_ID, autofillId) } ) .build() ) } private val launchIntent = Intent() private val intentTarget = mock<SmartspaceTarget> { on { smartspaceTargetId } doReturn AMBIENT_CUE_SURFACE on { actionChips } doReturn listOf( SmartspaceAction.Builder("action1-id", "title 1") .setSubtitle("subtitle 1") .setIntent(launchIntent) .build() ) } private val invalidTarget1 = mock<SmartspaceTarget> { on { smartspaceTargetId } doReturn "home" Loading packages/SystemUI/multivalentTests/src/com/android/systemui/ambientcue/domain/interactor/AmbientCueInteractorTest.kt +1 −2 Original line number Diff line number Diff line Loading @@ -16,7 +16,6 @@ package com.android.systemui.ambientcue.domain.interactor import android.content.Intent import android.content.applicationContext import androidx.test.ext.junit.runners.AndroidJUnit4 import androidx.test.filters.SmallTest Loading Loading @@ -67,7 +66,7 @@ class AmbientCueInteractorTest : SysuiTestCase() { ), label = "Sunday Morning", attribution = null, intent = Intent(), onPerformAction = {}, ) ) ambientCueRepository.fake.setActions(testActions) Loading packages/SystemUI/multivalentTests/src/com/android/systemui/ambientcue/ui/viewmodel/AmbientCueViewModelTest.kt +34 −0 Original line number Diff line number Diff line Loading @@ -16,15 +16,20 @@ package com.android.systemui.ambientcue.ui.viewmodel import android.content.applicationContext import androidx.test.ext.junit.runners.AndroidJUnit4 import androidx.test.filters.SmallTest import com.android.systemui.SysuiTestCase import com.android.systemui.ambientcue.data.repository.ambientCueRepository import com.android.systemui.ambientcue.data.repository.fake import com.android.systemui.ambientcue.domain.interactor.ambientCueInteractor import com.android.systemui.ambientcue.shared.model.ActionModel import com.android.systemui.kosmos.advanceTimeBy import com.android.systemui.kosmos.runCurrent import com.android.systemui.kosmos.runTest import com.android.systemui.kosmos.testScope import com.android.systemui.lifecycle.activateIn import com.android.systemui.res.R import com.android.systemui.testKosmos import com.google.common.truth.Truth.assertThat import org.junit.Before Loading Loading @@ -68,4 +73,33 @@ class AmbientCueViewModelTest : SysuiTestCase() { runCurrent() assertThat(viewModel.isVisible).isTrue() } @Test fun onClick_collapses() = kosmos.runTest { val testActions = listOf( ActionModel( icon = applicationContext.resources.getDrawable( R.drawable.ic_content_paste_spark, applicationContext.theme, ), label = "Sunday Morning", attribution = null, onPerformAction = {}, ) ) ambientCueRepository.fake.setActions(testActions) ambientCueInteractor.setIsVisible(true) viewModel.expand() runCurrent() assertThat(viewModel.isExpanded).isTrue() val action: ActionViewModel = viewModel.actions.first() // UI Collapses upon clicking on an action action.onClick() assertThat(viewModel.isExpanded).isFalse() } } packages/SystemUI/src/com/android/systemui/ambientcue/data/repository/AmbientCueRepository.kt +36 −2 Original line number Diff line number Diff line Loading @@ -17,17 +17,21 @@ package com.android.systemui.ambientcue.data.repository import android.app.ActivityTaskManager import android.app.assist.ActivityId import android.app.smartspace.SmartspaceConfig import android.app.smartspace.SmartspaceManager import android.app.smartspace.SmartspaceSession.OnTargetsAvailableListener import android.content.Context import android.util.Log import android.view.autofill.AutofillId import android.view.autofill.AutofillManager import androidx.annotation.VisibleForTesting import com.android.systemui.ambientcue.shared.model.ActionModel import com.android.systemui.dagger.SysUISingleton import com.android.systemui.dagger.qualifiers.Application import com.android.systemui.dagger.qualifiers.Background import com.android.systemui.display.data.repository.FocusedDisplayRepository import com.android.systemui.plugins.ActivityStarter import com.android.systemui.res.R import com.android.systemui.utils.coroutines.flow.conflatedCallbackFlow import java.util.concurrent.Executor Loading Loading @@ -63,6 +67,8 @@ class AmbientCueRepositoryImpl constructor( @Background private val backgroundScope: CoroutineScope, private val smartSpaceManager: SmartspaceManager?, private val autofillManager: AutofillManager?, private val activityStarter: ActivityStarter, @Background executor: Executor, @Application applicationContext: Context, focusdDisplayRepository: FocusedDisplayRepository, Loading @@ -86,15 +92,41 @@ constructor( .filter { it.smartspaceTargetId == AMBIENT_CUE_SURFACE } .flatMap { target -> target.actionChips } .map { chip -> val title = chip.title.toString() ActionModel( icon = chip.icon?.loadDrawable(applicationContext) ?: applicationContext.getDrawable( R.drawable.ic_content_paste_spark )!!, intent = chip.intent, label = chip.title.toString(), label = title, attribution = chip.subtitle.toString(), onPerformAction = { val intent = chip.intent val activityId = chip.extras?.getParcelable<ActivityId>( EXTRA_ACTIVITY_ID ) val autofillId = chip.extras?.getParcelable<AutofillId>( EXTRA_AUTOFILL_ID ) val token = activityId?.token Log.v( TAG, "Performing action: $activityId, $autofillId, $intent", ) if (token != null && autofillId != null) { autofillManager?.autofillRemoteApp( autofillId, title, token, activityId.taskId, ) } else if (intent != null) { activityStarter.startActivity(intent, false) } }, ) } if (DEBUG) { Loading Loading @@ -133,6 +165,8 @@ constructor( companion object { // Surface that PCC wants to push cards into @VisibleForTesting const val AMBIENT_CUE_SURFACE = "ambientcue" @VisibleForTesting const val EXTRA_ACTIVITY_ID = "activityId" @VisibleForTesting const val EXTRA_AUTOFILL_ID = "autofillId" // Timeout to hide cuebar if it wasn't interacted with private const val TAG = "AmbientCueRepository" private const val DEBUG = false Loading packages/SystemUI/src/com/android/systemui/ambientcue/shared/model/ActionModel.kt +1 −2 Original line number Diff line number Diff line Loading @@ -16,12 +16,11 @@ package com.android.systemui.ambientcue.shared.model import android.content.Intent import android.graphics.drawable.Drawable data class ActionModel( val icon: Drawable, val label: String, val attribution: String?, val intent: Intent?, val onPerformAction: () -> Unit, ) Loading
packages/SystemUI/multivalentTests/src/com/android/systemui/ambientcue/data/repository/AmbientCueRepositoryTest.kt +77 −0 Original line number Diff line number Diff line Loading @@ -17,22 +17,32 @@ package com.android.systemui.ambientcue.data.repository import android.app.ActivityManager.RunningTaskInfo import android.app.assist.ActivityId import android.app.smartspace.SmartspaceAction import android.app.smartspace.SmartspaceManager import android.app.smartspace.SmartspaceSession import android.app.smartspace.SmartspaceSession.OnTargetsAvailableListener import android.app.smartspace.SmartspaceTarget import android.content.Intent import android.content.testableContext import android.os.Binder import android.os.Bundle import android.view.autofill.AutofillId import android.view.autofill.AutofillManager import androidx.test.ext.junit.runners.AndroidJUnit4 import androidx.test.filters.SmallTest import com.android.systemui.SysuiTestCase import com.android.systemui.ambientcue.data.repository.AmbientCueRepositoryImpl.Companion.AMBIENT_CUE_SURFACE import com.android.systemui.ambientcue.data.repository.AmbientCueRepositoryImpl.Companion.EXTRA_ACTIVITY_ID import com.android.systemui.ambientcue.data.repository.AmbientCueRepositoryImpl.Companion.EXTRA_AUTOFILL_ID import com.android.systemui.ambientcue.shared.model.ActionModel import com.android.systemui.concurrency.fakeExecutor import com.android.systemui.kosmos.advanceUntilIdle import com.android.systemui.kosmos.backgroundScope import com.android.systemui.kosmos.collectLastValue import com.android.systemui.kosmos.runCurrent import com.android.systemui.kosmos.runTest import com.android.systemui.plugins.ActivityStarter import com.android.systemui.shade.data.repository.fakeFocusedDisplayRepository import com.android.systemui.testKosmos import com.google.common.truth.Truth.assertThat Loading @@ -49,6 +59,8 @@ import org.mockito.kotlin.verify class AmbientCueRepositoryTest : SysuiTestCase() { private val kosmos = testKosmos() private val smartSpaceSession = mock<SmartspaceSession>() private val autofillManager = mock<AutofillManager>() private val activityStarter = mock<ActivityStarter>() private val smartSpaceManager = mock<SmartspaceManager>() { on { createSmartspaceSession(any()) } doReturn smartSpaceSession Loading @@ -58,6 +70,8 @@ class AmbientCueRepositoryTest : SysuiTestCase() { AmbientCueRepositoryImpl( backgroundScope = kosmos.backgroundScope, smartSpaceManager = smartSpaceManager, autofillManager = autofillManager, activityStarter = activityStarter, executor = kosmos.fakeExecutor, applicationContext = kosmos.testableContext, focusdDisplayRepository = kosmos.fakeFocusedDisplayRepository, Loading Loading @@ -124,6 +138,37 @@ class AmbientCueRepositoryTest : SysuiTestCase() { assertThat(globallyFocusedTaskId).isEqualTo(TASK_ID) } @Test fun action_performAutofill() = kosmos.runTest { val actions by collectLastValue(underTest.actions) runCurrent() verify(smartSpaceSession) .addOnTargetsAvailableListener(any(), onTargetsAvailableListenerCaptor.capture()) onTargetsAvailableListenerCaptor.firstValue.onTargetsAvailable(listOf(autofillTarget)) val action: ActionModel = actions!!.first() action.onPerformAction() runCurrent() verify(autofillManager) .autofillRemoteApp(autofillId, action.label, activityId.token!!, activityId.taskId) } @Test fun action_performStartActivity() = kosmos.runTest { val actions by collectLastValue(underTest.actions) runCurrent() verify(smartSpaceSession) .addOnTargetsAvailableListener(any(), onTargetsAvailableListenerCaptor.capture()) onTargetsAvailableListenerCaptor.firstValue.onTargetsAvailable(listOf(intentTarget)) val action: ActionModel = actions!!.first() action.onPerformAction() runCurrent() verify(activityStarter).startActivity(launchIntent, false) } companion object { private const val TITLE_1 = "title 1" Loading @@ -144,6 +189,38 @@ class AmbientCueRepositoryTest : SysuiTestCase() { ) } private val autofillId = AutofillId(2) private val activityId = ActivityId(1, Binder()) private val autofillTarget = mock<SmartspaceTarget> { on { smartspaceTargetId } doReturn AMBIENT_CUE_SURFACE on { actionChips } doReturn listOf( SmartspaceAction.Builder("action1-id", "title 1") .setSubtitle("subtitle 1") .setExtras( Bundle().apply { putParcelable(EXTRA_ACTIVITY_ID, activityId) putParcelable(EXTRA_AUTOFILL_ID, autofillId) } ) .build() ) } private val launchIntent = Intent() private val intentTarget = mock<SmartspaceTarget> { on { smartspaceTargetId } doReturn AMBIENT_CUE_SURFACE on { actionChips } doReturn listOf( SmartspaceAction.Builder("action1-id", "title 1") .setSubtitle("subtitle 1") .setIntent(launchIntent) .build() ) } private val invalidTarget1 = mock<SmartspaceTarget> { on { smartspaceTargetId } doReturn "home" Loading
packages/SystemUI/multivalentTests/src/com/android/systemui/ambientcue/domain/interactor/AmbientCueInteractorTest.kt +1 −2 Original line number Diff line number Diff line Loading @@ -16,7 +16,6 @@ package com.android.systemui.ambientcue.domain.interactor import android.content.Intent import android.content.applicationContext import androidx.test.ext.junit.runners.AndroidJUnit4 import androidx.test.filters.SmallTest Loading Loading @@ -67,7 +66,7 @@ class AmbientCueInteractorTest : SysuiTestCase() { ), label = "Sunday Morning", attribution = null, intent = Intent(), onPerformAction = {}, ) ) ambientCueRepository.fake.setActions(testActions) Loading
packages/SystemUI/multivalentTests/src/com/android/systemui/ambientcue/ui/viewmodel/AmbientCueViewModelTest.kt +34 −0 Original line number Diff line number Diff line Loading @@ -16,15 +16,20 @@ package com.android.systemui.ambientcue.ui.viewmodel import android.content.applicationContext import androidx.test.ext.junit.runners.AndroidJUnit4 import androidx.test.filters.SmallTest import com.android.systemui.SysuiTestCase import com.android.systemui.ambientcue.data.repository.ambientCueRepository import com.android.systemui.ambientcue.data.repository.fake import com.android.systemui.ambientcue.domain.interactor.ambientCueInteractor import com.android.systemui.ambientcue.shared.model.ActionModel import com.android.systemui.kosmos.advanceTimeBy import com.android.systemui.kosmos.runCurrent import com.android.systemui.kosmos.runTest import com.android.systemui.kosmos.testScope import com.android.systemui.lifecycle.activateIn import com.android.systemui.res.R import com.android.systemui.testKosmos import com.google.common.truth.Truth.assertThat import org.junit.Before Loading Loading @@ -68,4 +73,33 @@ class AmbientCueViewModelTest : SysuiTestCase() { runCurrent() assertThat(viewModel.isVisible).isTrue() } @Test fun onClick_collapses() = kosmos.runTest { val testActions = listOf( ActionModel( icon = applicationContext.resources.getDrawable( R.drawable.ic_content_paste_spark, applicationContext.theme, ), label = "Sunday Morning", attribution = null, onPerformAction = {}, ) ) ambientCueRepository.fake.setActions(testActions) ambientCueInteractor.setIsVisible(true) viewModel.expand() runCurrent() assertThat(viewModel.isExpanded).isTrue() val action: ActionViewModel = viewModel.actions.first() // UI Collapses upon clicking on an action action.onClick() assertThat(viewModel.isExpanded).isFalse() } }
packages/SystemUI/src/com/android/systemui/ambientcue/data/repository/AmbientCueRepository.kt +36 −2 Original line number Diff line number Diff line Loading @@ -17,17 +17,21 @@ package com.android.systemui.ambientcue.data.repository import android.app.ActivityTaskManager import android.app.assist.ActivityId import android.app.smartspace.SmartspaceConfig import android.app.smartspace.SmartspaceManager import android.app.smartspace.SmartspaceSession.OnTargetsAvailableListener import android.content.Context import android.util.Log import android.view.autofill.AutofillId import android.view.autofill.AutofillManager import androidx.annotation.VisibleForTesting import com.android.systemui.ambientcue.shared.model.ActionModel import com.android.systemui.dagger.SysUISingleton import com.android.systemui.dagger.qualifiers.Application import com.android.systemui.dagger.qualifiers.Background import com.android.systemui.display.data.repository.FocusedDisplayRepository import com.android.systemui.plugins.ActivityStarter import com.android.systemui.res.R import com.android.systemui.utils.coroutines.flow.conflatedCallbackFlow import java.util.concurrent.Executor Loading Loading @@ -63,6 +67,8 @@ class AmbientCueRepositoryImpl constructor( @Background private val backgroundScope: CoroutineScope, private val smartSpaceManager: SmartspaceManager?, private val autofillManager: AutofillManager?, private val activityStarter: ActivityStarter, @Background executor: Executor, @Application applicationContext: Context, focusdDisplayRepository: FocusedDisplayRepository, Loading @@ -86,15 +92,41 @@ constructor( .filter { it.smartspaceTargetId == AMBIENT_CUE_SURFACE } .flatMap { target -> target.actionChips } .map { chip -> val title = chip.title.toString() ActionModel( icon = chip.icon?.loadDrawable(applicationContext) ?: applicationContext.getDrawable( R.drawable.ic_content_paste_spark )!!, intent = chip.intent, label = chip.title.toString(), label = title, attribution = chip.subtitle.toString(), onPerformAction = { val intent = chip.intent val activityId = chip.extras?.getParcelable<ActivityId>( EXTRA_ACTIVITY_ID ) val autofillId = chip.extras?.getParcelable<AutofillId>( EXTRA_AUTOFILL_ID ) val token = activityId?.token Log.v( TAG, "Performing action: $activityId, $autofillId, $intent", ) if (token != null && autofillId != null) { autofillManager?.autofillRemoteApp( autofillId, title, token, activityId.taskId, ) } else if (intent != null) { activityStarter.startActivity(intent, false) } }, ) } if (DEBUG) { Loading Loading @@ -133,6 +165,8 @@ constructor( companion object { // Surface that PCC wants to push cards into @VisibleForTesting const val AMBIENT_CUE_SURFACE = "ambientcue" @VisibleForTesting const val EXTRA_ACTIVITY_ID = "activityId" @VisibleForTesting const val EXTRA_AUTOFILL_ID = "autofillId" // Timeout to hide cuebar if it wasn't interacted with private const val TAG = "AmbientCueRepository" private const val DEBUG = false Loading
packages/SystemUI/src/com/android/systemui/ambientcue/shared/model/ActionModel.kt +1 −2 Original line number Diff line number Diff line Loading @@ -16,12 +16,11 @@ package com.android.systemui.ambientcue.shared.model import android.content.Intent import android.graphics.drawable.Drawable data class ActionModel( val icon: Drawable, val label: String, val attribution: String?, val intent: Intent?, val onPerformAction: () -> Unit, )