summaryrefslogtreecommitdiff
path: root/tests
diff options
context:
space:
mode:
Diffstat (limited to 'tests')
-rw-r--r--tests/unit/src/com/android/intentresolver/interactive/domain/interactor/InteractiveSessionInteractorTest.kt420
-rw-r--r--tests/unit/src/com/android/intentresolver/ui/model/ActivityModelTest.kt13
-rw-r--r--tests/unit/src/com/android/intentresolver/ui/viewmodel/ChooserRequestTest.kt1
-rw-r--r--tests/unit/src/com/android/intentresolver/ui/viewmodel/ResolverRequestTest.kt1
4 files changed, 433 insertions, 2 deletions
diff --git a/tests/unit/src/com/android/intentresolver/interactive/domain/interactor/InteractiveSessionInteractorTest.kt b/tests/unit/src/com/android/intentresolver/interactive/domain/interactor/InteractiveSessionInteractorTest.kt
new file mode 100644
index 00000000..75d4ec0d
--- /dev/null
+++ b/tests/unit/src/com/android/intentresolver/interactive/domain/interactor/InteractiveSessionInteractorTest.kt
@@ -0,0 +1,420 @@
+/*
+ * Copyright 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.intentresolver.interactive.domain.interactor
+
+import android.content.ComponentName
+import android.content.Intent
+import android.content.Intent.ACTION_QUICK_VIEW
+import android.content.Intent.ACTION_RUN
+import android.content.Intent.ACTION_SEND
+import android.content.Intent.ACTION_VIEW
+import android.content.Intent.EXTRA_ALTERNATE_INTENTS
+import android.content.Intent.EXTRA_CHOOSER_REFINEMENT_INTENT_SENDER
+import android.content.Intent.EXTRA_CHOOSER_RESULT_INTENT_SENDER
+import android.content.Intent.EXTRA_CHOOSER_TARGETS
+import android.content.Intent.EXTRA_EXCLUDE_COMPONENTS
+import android.content.Intent.EXTRA_INITIAL_INTENTS
+import android.content.Intent.EXTRA_REPLACEMENT_EXTRAS
+import android.content.IntentSender
+import android.os.Binder
+import android.os.IBinder
+import android.os.IBinder.DeathRecipient
+import android.os.IInterface
+import android.os.Parcel
+import android.os.ResultReceiver
+import android.os.ShellCallback
+import android.service.chooser.ChooserTarget
+import androidx.core.os.bundleOf
+import androidx.lifecycle.SavedStateHandle
+import com.android.intentresolver.IChooserController
+import com.android.intentresolver.IChooserInteractiveSessionCallback
+import com.android.intentresolver.contentpreview.payloadtoggle.data.repository.PendingSelectionCallbackRepository
+import com.android.intentresolver.data.model.ChooserRequest
+import com.android.intentresolver.data.repository.ActivityModelRepository
+import com.android.intentresolver.data.repository.ChooserRequestRepository
+import com.android.intentresolver.interactive.data.repository.InteractiveSessionCallbackRepository
+import com.android.intentresolver.shared.model.ActivityModel
+import com.google.common.truth.Correspondence
+import com.google.common.truth.Truth.assertThat
+import java.io.FileDescriptor
+import kotlinx.coroutines.launch
+import kotlinx.coroutines.test.runTest
+import org.junit.Test
+
+class InteractiveSessionInteractorTest {
+ private val activityModelRepo =
+ ActivityModelRepository().apply {
+ initialize {
+ ActivityModel(
+ intent = Intent(),
+ launchedFromUid = 12345,
+ launchedFromPackage = "org.client.package",
+ referrer = null,
+ isTaskRoot = false,
+ )
+ }
+ }
+ private val interactiveSessionCallback = FakeChooserInteractiveSessionCallback()
+ private val pendingSelectionCallbackRepo = PendingSelectionCallbackRepository()
+ private val savedStateHandle = SavedStateHandle()
+ private val interactiveCallbackRepo = InteractiveSessionCallbackRepository(savedStateHandle)
+
+ @Test
+ fun testChooserLaunchedInNewTask_sessionClosed() = runTest {
+ val activityModelRepo =
+ ActivityModelRepository().apply {
+ initialize {
+ ActivityModel(
+ intent = Intent(),
+ launchedFromUid = 12345,
+ launchedFromPackage = "org.client.package",
+ referrer = null,
+ isTaskRoot = true,
+ )
+ }
+ }
+ val chooserRequestRepository =
+ ChooserRequestRepository(
+ initialRequest =
+ ChooserRequest(
+ targetIntent = Intent(ACTION_SEND),
+ interactiveSessionCallback = interactiveSessionCallback,
+ launchedFromPackage = activityModelRepo.value.launchedFromPackage,
+ ),
+ initialActions = emptyList(),
+ )
+ val testSubject =
+ InteractiveSessionInteractor(
+ activityModelRepo = activityModelRepo,
+ chooserRequestRepository = chooserRequestRepository,
+ pendingSelectionCallbackRepo,
+ interactiveCallbackRepo,
+ )
+
+ testSubject.activate()
+
+ assertThat(interactiveSessionCallback.registeredIntentUpdaters).containsExactly(null)
+ }
+
+ @Test
+ fun testDeadBinder_sessionEnd() = runTest {
+ interactiveSessionCallback.isAlive = false
+ val chooserRequestRepository =
+ ChooserRequestRepository(
+ initialRequest =
+ ChooserRequest(
+ targetIntent = Intent(ACTION_SEND),
+ interactiveSessionCallback = interactiveSessionCallback,
+ launchedFromPackage = activityModelRepo.value.launchedFromPackage,
+ ),
+ initialActions = emptyList(),
+ )
+ val testSubject =
+ InteractiveSessionInteractor(
+ activityModelRepo = activityModelRepo,
+ chooserRequestRepository = chooserRequestRepository,
+ pendingSelectionCallbackRepo,
+ interactiveCallbackRepo,
+ )
+
+ backgroundScope.launch { testSubject.activate() }
+ this.testScheduler.runCurrent()
+
+ assertThat(testSubject.isSessionActive.value).isFalse()
+ }
+
+ @Test
+ fun testBinderDies_sessionEnd() = runTest {
+ val chooserRequestRepository =
+ ChooserRequestRepository(
+ initialRequest =
+ ChooserRequest(
+ targetIntent = Intent(ACTION_SEND),
+ interactiveSessionCallback = interactiveSessionCallback,
+ launchedFromPackage = activityModelRepo.value.launchedFromPackage,
+ ),
+ initialActions = emptyList(),
+ )
+ val testSubject =
+ InteractiveSessionInteractor(
+ activityModelRepo = activityModelRepo,
+ chooserRequestRepository = chooserRequestRepository,
+ pendingSelectionCallbackRepo,
+ interactiveCallbackRepo,
+ )
+
+ backgroundScope.launch { testSubject.activate() }
+ this.testScheduler.runCurrent()
+
+ assertThat(testSubject.isSessionActive.value).isTrue()
+ assertThat(interactiveSessionCallback.linkedDeathRecipients).hasSize(1)
+
+ interactiveSessionCallback.linkedDeathRecipients[0].binderDied()
+
+ assertThat(testSubject.isSessionActive.value).isFalse()
+ }
+
+ @Test
+ fun testScopeCancelled_unsubscribeFromBinder() = runTest {
+ val chooserRequestRepository =
+ ChooserRequestRepository(
+ initialRequest =
+ ChooserRequest(
+ targetIntent = Intent(ACTION_SEND),
+ interactiveSessionCallback = interactiveSessionCallback,
+ launchedFromPackage = activityModelRepo.value.launchedFromPackage,
+ ),
+ initialActions = emptyList(),
+ )
+ val testSubject =
+ InteractiveSessionInteractor(
+ activityModelRepo = activityModelRepo,
+ chooserRequestRepository = chooserRequestRepository,
+ pendingSelectionCallbackRepo,
+ interactiveCallbackRepo,
+ )
+
+ val job = backgroundScope.launch { testSubject.activate() }
+ testScheduler.runCurrent()
+
+ assertThat(interactiveSessionCallback.linkedDeathRecipients).hasSize(1)
+ assertThat(interactiveSessionCallback.unlinkedDeathRecipients).hasSize(0)
+
+ job.cancel()
+ testScheduler.runCurrent()
+
+ assertThat(interactiveSessionCallback.unlinkedDeathRecipients).hasSize(1)
+ }
+
+ @Test
+ fun endSession_intentUpdaterCallbackReset() = runTest {
+ val chooserRequestRepository =
+ ChooserRequestRepository(
+ initialRequest =
+ ChooserRequest(
+ targetIntent = Intent(ACTION_SEND),
+ interactiveSessionCallback = interactiveSessionCallback,
+ launchedFromPackage = activityModelRepo.value.launchedFromPackage,
+ ),
+ initialActions = emptyList(),
+ )
+ val testSubject =
+ InteractiveSessionInteractor(
+ activityModelRepo = activityModelRepo,
+ chooserRequestRepository = chooserRequestRepository,
+ pendingSelectionCallbackRepo,
+ interactiveCallbackRepo,
+ )
+
+ backgroundScope.launch { testSubject.activate() }
+ testScheduler.runCurrent()
+
+ assertThat(interactiveSessionCallback.registeredIntentUpdaters).hasSize(1)
+
+ testSubject.endSession()
+
+ assertThat(interactiveSessionCallback.registeredIntentUpdaters).hasSize(2)
+ assertThat(interactiveSessionCallback.registeredIntentUpdaters[1]).isNull()
+ }
+
+ @Test
+ fun nullChooserIntentReceived_sessionEnds() = runTest {
+ val chooserRequestRepository =
+ ChooserRequestRepository(
+ initialRequest =
+ ChooserRequest(
+ targetIntent = Intent(ACTION_SEND),
+ interactiveSessionCallback = interactiveSessionCallback,
+ launchedFromPackage = activityModelRepo.value.launchedFromPackage,
+ ),
+ initialActions = emptyList(),
+ )
+ val testSubject =
+ InteractiveSessionInteractor(
+ activityModelRepo = activityModelRepo,
+ chooserRequestRepository = chooserRequestRepository,
+ pendingSelectionCallbackRepo,
+ interactiveCallbackRepo,
+ )
+
+ backgroundScope.launch { testSubject.activate() }
+ testScheduler.runCurrent()
+
+ assertThat(interactiveSessionCallback.registeredIntentUpdaters).hasSize(1)
+ interactiveSessionCallback.registeredIntentUpdaters[0]!!.updateIntent(null)
+ testScheduler.runCurrent()
+
+ assertThat(testSubject.isSessionActive.value).isFalse()
+ }
+
+ @Test
+ fun invalidChooserIntentReceived_intentIgnored() = runTest {
+ val chooserRequestRepository =
+ ChooserRequestRepository(
+ initialRequest =
+ ChooserRequest(
+ targetIntent = Intent(ACTION_SEND),
+ interactiveSessionCallback = interactiveSessionCallback,
+ launchedFromPackage = activityModelRepo.value.launchedFromPackage,
+ ),
+ initialActions = emptyList(),
+ )
+ val testSubject =
+ InteractiveSessionInteractor(
+ activityModelRepo = activityModelRepo,
+ chooserRequestRepository = chooserRequestRepository,
+ pendingSelectionCallbackRepo,
+ interactiveCallbackRepo,
+ )
+
+ backgroundScope.launch { testSubject.activate() }
+ testScheduler.runCurrent()
+
+ assertThat(interactiveSessionCallback.registeredIntentUpdaters).hasSize(1)
+ interactiveSessionCallback.registeredIntentUpdaters[0]!!.updateIntent(Intent())
+ testScheduler.runCurrent()
+
+ assertThat(testSubject.isSessionActive.value).isTrue()
+ assertThat(chooserRequestRepository.chooserRequest.value)
+ .isEqualTo(chooserRequestRepository.initialRequest)
+ }
+
+ @Test
+ fun validChooserIntentReceived_chooserRequestUpdated() = runTest {
+ val chooserRequestRepository =
+ ChooserRequestRepository(
+ initialRequest =
+ ChooserRequest(
+ targetIntent = Intent(ACTION_SEND),
+ interactiveSessionCallback = interactiveSessionCallback,
+ launchedFromPackage = activityModelRepo.value.launchedFromPackage,
+ ),
+ initialActions = emptyList(),
+ )
+ val testSubject =
+ InteractiveSessionInteractor(
+ activityModelRepo = activityModelRepo,
+ chooserRequestRepository = chooserRequestRepository,
+ pendingSelectionCallbackRepo,
+ interactiveCallbackRepo,
+ )
+
+ backgroundScope.launch { testSubject.activate() }
+ testScheduler.runCurrent()
+
+ assertThat(interactiveSessionCallback.registeredIntentUpdaters).hasSize(1)
+ val newTargetIntent = Intent(ACTION_VIEW).apply { type = "image/png" }
+ val newFilteredComponents = arrayOf(ComponentName.unflattenFromString("com.app/.MainA"))
+ val newCallerTargets =
+ arrayOf(
+ ChooserTarget(
+ "A",
+ null,
+ 0.5f,
+ ComponentName.unflattenFromString("org.pkg/.Activity"),
+ null,
+ )
+ )
+ val newAdditionalIntents = arrayOf(Intent(ACTION_RUN))
+ val newReplacementExtras = bundleOf("ONE" to 1, "TWO" to 2)
+ val newInitialIntents = arrayOf(Intent(ACTION_QUICK_VIEW))
+ val newResultSender = IntentSender(Binder())
+ val newRefinementSender = IntentSender(Binder())
+ interactiveSessionCallback.registeredIntentUpdaters[0]!!.updateIntent(
+ Intent.createChooser(newTargetIntent, "").apply {
+ putExtra(EXTRA_EXCLUDE_COMPONENTS, newFilteredComponents)
+ putExtra(EXTRA_CHOOSER_TARGETS, newCallerTargets)
+ putExtra(EXTRA_ALTERNATE_INTENTS, newAdditionalIntents)
+ putExtra(EXTRA_REPLACEMENT_EXTRAS, newReplacementExtras)
+ putExtra(EXTRA_INITIAL_INTENTS, newInitialIntents)
+ putExtra(EXTRA_CHOOSER_RESULT_INTENT_SENDER, newResultSender)
+ putExtra(EXTRA_CHOOSER_REFINEMENT_INTENT_SENDER, newRefinementSender)
+ }
+ )
+ testScheduler.runCurrent()
+
+ assertThat(testSubject.isSessionActive.value).isTrue()
+ val updatedRequest = chooserRequestRepository.chooserRequest.value
+ assertThat(updatedRequest.targetAction).isEqualTo(newTargetIntent.action)
+ assertThat(updatedRequest.targetType).isEqualTo(newTargetIntent.type)
+ assertThat(updatedRequest.filteredComponentNames).containsExactly(newFilteredComponents[0])
+ assertThat(updatedRequest.callerChooserTargets).containsExactly(newCallerTargets[0])
+ assertThat(updatedRequest.additionalTargets)
+ .comparingElementsUsing<Intent, String>(
+ Correspondence.transforming({ it.action }, "action")
+ )
+ .containsExactly(newAdditionalIntents[0].action)
+ assertThat(updatedRequest.replacementExtras!!.keySet())
+ .containsExactlyElementsIn(newReplacementExtras.keySet())
+ assertThat(updatedRequest.initialIntents)
+ .comparingElementsUsing<Intent, String>(
+ Correspondence.transforming({ it.action }, "action")
+ )
+ .containsExactly(newInitialIntents[0].action)
+ assertThat(updatedRequest.chosenComponentSender).isEqualTo(newResultSender)
+ assertThat(updatedRequest.refinementIntentSender).isEqualTo(newRefinementSender)
+ }
+}
+
+private class FakeChooserInteractiveSessionCallback :
+ IChooserInteractiveSessionCallback, IBinder, IInterface {
+ var isAlive = true
+ val registeredIntentUpdaters = ArrayList<IChooserController?>()
+ val linkedDeathRecipients = ArrayList<DeathRecipient>()
+ val unlinkedDeathRecipients = ArrayList<DeathRecipient>()
+
+ override fun registerChooserController(intentUpdater: IChooserController?) {
+ registeredIntentUpdaters.add(intentUpdater)
+ }
+
+ override fun onDrawerVerticalOffsetChanged(offset: Int) {}
+
+ override fun asBinder() = this
+
+ override fun getInterfaceDescriptor() = ""
+
+ override fun pingBinder() = true
+
+ override fun isBinderAlive() = isAlive
+
+ override fun queryLocalInterface(descriptor: String): IInterface =
+ this@FakeChooserInteractiveSessionCallback
+
+ override fun dump(fd: FileDescriptor, args: Array<out String>?) = Unit
+
+ override fun dumpAsync(fd: FileDescriptor, args: Array<out String>?) = Unit
+
+ override fun shellCommand(
+ `in`: FileDescriptor?,
+ out: FileDescriptor?,
+ err: FileDescriptor?,
+ args: Array<out String>,
+ shellCallback: ShellCallback?,
+ resultReceiver: ResultReceiver,
+ ) = Unit
+
+ override fun transact(code: Int, data: Parcel, reply: Parcel?, flags: Int) = true
+
+ override fun linkToDeath(recipient: DeathRecipient, flags: Int) {
+ linkedDeathRecipients.add(recipient)
+ }
+
+ override fun unlinkToDeath(recipient: DeathRecipient, flags: Int): Boolean {
+ unlinkedDeathRecipients.add(recipient)
+ return true
+ }
+}
diff --git a/tests/unit/src/com/android/intentresolver/ui/model/ActivityModelTest.kt b/tests/unit/src/com/android/intentresolver/ui/model/ActivityModelTest.kt
index 5f86159c..b48a6422 100644
--- a/tests/unit/src/com/android/intentresolver/ui/model/ActivityModelTest.kt
+++ b/tests/unit/src/com/android/intentresolver/ui/model/ActivityModelTest.kt
@@ -30,7 +30,7 @@ class ActivityModelTest {
@Test
fun testDefaultValues() {
- val input = ActivityModel(Intent(ACTION_CHOOSER), 0, "example.com", null)
+ val input = ActivityModel(Intent(ACTION_CHOOSER), 0, "example.com", null, false)
val output = input.toParcelAndBack()
@@ -41,7 +41,13 @@ class ActivityModelTest {
fun testCommonValues() {
val intent = Intent(ACTION_CHOOSER).apply { putExtra(EXTRA_TEXT, "Test") }
val input =
- ActivityModel(intent, 1234, "com.example", Uri.parse("android-app://example.com"))
+ ActivityModel(
+ intent,
+ 1234,
+ "com.example",
+ Uri.parse("android-app://example.com"),
+ false,
+ )
val output = input.toParcelAndBack()
@@ -56,6 +62,7 @@ class ActivityModelTest {
launchedFromUid = 1000,
launchedFromPackage = "other.example.com",
referrer = Uri.parse("android-app://app.example.com"),
+ false,
)
assertThat(launch1.referrerPackage).isEqualTo("app.example.com")
@@ -69,6 +76,7 @@ class ActivityModelTest {
launchedFromUid = 1000,
launchedFromPackage = "example.com",
referrer = Uri.parse("http://some.other.value"),
+ false,
)
assertThat(launch.referrerPackage).isNull()
@@ -82,6 +90,7 @@ class ActivityModelTest {
launchedFromUid = 1000,
launchedFromPackage = "example.com",
referrer = null,
+ false,
)
assertThat(launch.referrerPackage).isNull()
diff --git a/tests/unit/src/com/android/intentresolver/ui/viewmodel/ChooserRequestTest.kt b/tests/unit/src/com/android/intentresolver/ui/viewmodel/ChooserRequestTest.kt
index 71f28950..facfe151 100644
--- a/tests/unit/src/com/android/intentresolver/ui/viewmodel/ChooserRequestTest.kt
+++ b/tests/unit/src/com/android/intentresolver/ui/viewmodel/ChooserRequestTest.kt
@@ -53,6 +53,7 @@ private fun createActivityModel(
launchedFromUid = 10000,
launchedFromPackage = "com.android.example",
referrer = referrer ?: "android-app://com.android.example".toUri(),
+ false,
)
class ChooserRequestTest {
diff --git a/tests/unit/src/com/android/intentresolver/ui/viewmodel/ResolverRequestTest.kt b/tests/unit/src/com/android/intentresolver/ui/viewmodel/ResolverRequestTest.kt
index 70512021..be6560c2 100644
--- a/tests/unit/src/com/android/intentresolver/ui/viewmodel/ResolverRequestTest.kt
+++ b/tests/unit/src/com/android/intentresolver/ui/viewmodel/ResolverRequestTest.kt
@@ -40,6 +40,7 @@ private fun createActivityModel(targetIntent: Intent, referrer: Uri? = null) =
launchedFromUid = 10000,
launchedFromPackage = "com.android.example",
referrer = referrer ?: "android-app://com.android.example".toUri(),
+ false,
)
class ResolverRequestTest {