summaryrefslogtreecommitdiff
path: root/java/tests
diff options
context:
space:
mode:
author Treehugger Robot <android-test-infra-autosubmit@system.gserviceaccount.com> 2023-09-27 20:06:53 +0000
committer Android (Google) Code Review <android-gerrit@google.com> 2023-09-27 20:06:53 +0000
commit9f7b4d19b7a3668091b81ef4fcc752e66f713202 (patch)
tree396d62ac0f13537f35fc88ba17f189812e176750 /java/tests
parentfaac60a597aa8f23f03a86feab76ad0f86854219 (diff)
parent607f13d48aec6fdd8030273ae4a6cf7a712f4258 (diff)
Merge "Add unit tests for initial intents in Resolver and Chooser adapters" into main
Diffstat (limited to 'java/tests')
-rw-r--r--java/tests/src/com/android/intentresolver/ChooserListAdapterDataTest.kt179
-rw-r--r--java/tests/src/com/android/intentresolver/FakeResolverListCommunicator.kt56
-rw-r--r--java/tests/src/com/android/intentresolver/ResolverListAdapterTest.kt204
-rw-r--r--java/tests/src/com/android/intentresolver/util/TestImmediateHandler.kt42
4 files changed, 392 insertions, 89 deletions
diff --git a/java/tests/src/com/android/intentresolver/ChooserListAdapterDataTest.kt b/java/tests/src/com/android/intentresolver/ChooserListAdapterDataTest.kt
new file mode 100644
index 00000000..e5927e36
--- /dev/null
+++ b/java/tests/src/com/android/intentresolver/ChooserListAdapterDataTest.kt
@@ -0,0 +1,179 @@
+package com.android.intentresolver
+
+import android.content.Context
+import android.content.Intent
+import android.content.pm.PackageManager
+import android.content.pm.PackageManager.ComponentInfoFlags
+import android.os.UserHandle
+import android.os.UserManager
+import android.view.LayoutInflater
+import com.android.intentresolver.ResolverDataProvider.createActivityInfo
+import com.android.intentresolver.ResolverDataProvider.createResolvedComponentInfo
+import com.android.intentresolver.icons.TargetDataLoader
+import com.android.intentresolver.logging.FakeEventLog
+import com.android.intentresolver.util.TestExecutor
+import com.android.internal.logging.InstanceId
+import com.google.common.truth.Truth.assertThat
+import org.junit.Test
+import org.mockito.Mockito
+
+class ChooserListAdapterDataTest {
+ private val layoutInflater = mock<LayoutInflater>()
+ private val packageManager = mock<PackageManager>()
+ private val userManager = mock<UserManager> { whenever(isManagedProfile).thenReturn(false) }
+ private val resources =
+ mock<android.content.res.Resources> {
+ whenever(getInteger(R.integer.config_maxShortcutTargetsPerApp)).thenReturn(2)
+ }
+ private val context =
+ mock<Context> {
+ whenever(getSystemService(Context.LAYOUT_INFLATER_SERVICE)).thenReturn(layoutInflater)
+ whenever(getSystemService(Context.USER_SERVICE)).thenReturn(userManager)
+ whenever(packageManager).thenReturn(this@ChooserListAdapterDataTest.packageManager)
+ whenever(resources).thenReturn(this@ChooserListAdapterDataTest.resources)
+ }
+ private val targetIntent = Intent(Intent.ACTION_SEND)
+ private val payloadIntents = listOf(targetIntent)
+ private val resolverListController =
+ mock<ResolverListController> {
+ whenever(filterIneligibleActivities(any(), Mockito.anyBoolean())).thenReturn(null)
+ whenever(filterLowPriority(any(), Mockito.anyBoolean())).thenReturn(null)
+ }
+ private val resolverListCommunicator = FakeResolverListCommunicator()
+ private val userHandle = UserHandle.of(UserHandle.USER_CURRENT)
+ private val targetDataLoader = mock<TargetDataLoader>()
+ private val backgroundExecutor = TestExecutor()
+ private val immediateExecutor = TestExecutor(immediate = true)
+ private val chooserRequestParams =
+ ChooserRequestParameters(
+ Intent.createChooser(targetIntent, ""),
+ "org.referrer.package",
+ null
+ )
+
+ @Test
+ fun test_twoTargetsWithNonOverlappingInitialIntent_threeTargetsInResolverAdapter() {
+ val resolvedTargets =
+ listOf(
+ createResolvedComponentInfo(1),
+ createResolvedComponentInfo(2),
+ )
+ val targetIntent = Intent(Intent.ACTION_SEND)
+ whenever(
+ resolverListController.getResolversForIntentAsUser(
+ true,
+ resolverListCommunicator.shouldGetActivityMetadata(),
+ resolverListCommunicator.shouldGetOnlyDefaultActivities(),
+ payloadIntents,
+ userHandle
+ )
+ )
+ .thenReturn(resolvedTargets)
+ val initialActivityInfo = createActivityInfo(3)
+ val initialIntents =
+ arrayOf(
+ Intent(Intent.ACTION_SEND).apply { component = initialActivityInfo.componentName }
+ )
+ whenever(
+ packageManager.getActivityInfo(
+ eq(initialActivityInfo.componentName),
+ any<ComponentInfoFlags>()
+ )
+ )
+ .thenReturn(initialActivityInfo)
+ val testSubject =
+ ChooserListAdapter(
+ context,
+ payloadIntents,
+ initialIntents,
+ /*rList=*/ null,
+ /*filterLastUsed=*/ false,
+ resolverListController,
+ userHandle,
+ targetIntent,
+ resolverListCommunicator,
+ packageManager,
+ FakeEventLog(InstanceId.fakeInstanceId(1)),
+ chooserRequestParams,
+ /*maxRankedTargets=*/ 2,
+ /*initialIntentsUserSpace=*/ userHandle,
+ targetDataLoader,
+ backgroundExecutor,
+ immediateExecutor,
+ )
+ val doPostProcessing = true
+
+ val isLoaded = testSubject.rebuildList(doPostProcessing)
+
+ assertThat(isLoaded).isFalse()
+ assertThat(testSubject.displayResolveInfoCount).isEqualTo(0)
+ assertThat(backgroundExecutor.pendingCommandCount).isEqualTo(1)
+
+ backgroundExecutor.runUntilIdle()
+
+ // we don't reset placeholder count (legacy logic, likely an oversight?)
+ assertThat(testSubject.displayResolveInfoCount).isEqualTo(resolvedTargets.size)
+ }
+
+ @Test
+ fun test_twoTargetsWithOverlappingInitialIntent_oneTargetsInResolverAdapter() {
+ val resolvedTargets =
+ listOf(
+ createResolvedComponentInfo(1),
+ createResolvedComponentInfo(2),
+ )
+ val targetIntent = Intent(Intent.ACTION_SEND)
+ whenever(
+ resolverListController.getResolversForIntentAsUser(
+ true,
+ resolverListCommunicator.shouldGetActivityMetadata(),
+ resolverListCommunicator.shouldGetOnlyDefaultActivities(),
+ payloadIntents,
+ userHandle
+ )
+ )
+ .thenReturn(resolvedTargets)
+ val activityInfo = resolvedTargets[1].getResolveInfoAt(0).activityInfo
+ val initialIntents =
+ arrayOf(Intent(Intent.ACTION_SEND).apply { component = activityInfo.componentName })
+ whenever(
+ packageManager.getActivityInfo(
+ eq(activityInfo.componentName),
+ any<ComponentInfoFlags>()
+ )
+ )
+ .thenReturn(activityInfo)
+ val testSubject =
+ ChooserListAdapter(
+ context,
+ payloadIntents,
+ initialIntents,
+ /*rList=*/ null,
+ /*filterLastUsed=*/ false,
+ resolverListController,
+ userHandle,
+ targetIntent,
+ resolverListCommunicator,
+ packageManager,
+ FakeEventLog(InstanceId.fakeInstanceId(1)),
+ chooserRequestParams,
+ /*maxRankedTargets=*/ 2,
+ /*initialIntentsUserSpace=*/ userHandle,
+ targetDataLoader,
+ backgroundExecutor,
+ immediateExecutor,
+ )
+ val doPostProcessing = true
+
+ val isLoaded = testSubject.rebuildList(doPostProcessing)
+
+ assertThat(isLoaded).isFalse()
+ assertThat(testSubject.displayResolveInfoCount).isEqualTo(0)
+ assertThat(backgroundExecutor.pendingCommandCount).isEqualTo(1)
+
+ backgroundExecutor.runUntilIdle()
+
+ // we don't reset placeholder count (legacy logic, likely an oversight?)
+ assertThat(testSubject.displayResolveInfoCount).isEqualTo(resolvedTargets.size - 1)
+ }
+}
diff --git a/java/tests/src/com/android/intentresolver/FakeResolverListCommunicator.kt b/java/tests/src/com/android/intentresolver/FakeResolverListCommunicator.kt
new file mode 100644
index 00000000..5e9cd98f
--- /dev/null
+++ b/java/tests/src/com/android/intentresolver/FakeResolverListCommunicator.kt
@@ -0,0 +1,56 @@
+/*
+ * Copyright (C) 2023 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
+ *
+ * http://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
+
+import android.content.Intent
+import android.content.pm.ActivityInfo
+import java.util.concurrent.atomic.AtomicInteger
+
+class FakeResolverListCommunicator(private val layoutWithDefaults: Boolean = true) :
+ ResolverListAdapter.ResolverListCommunicator {
+ private val sendVoiceCounter = AtomicInteger()
+ private val updateProfileViewButtonCounter = AtomicInteger()
+
+ val sendVoiceCommandCount
+ get() = sendVoiceCounter.get()
+ val updateProfileViewButtonCount
+ get() = updateProfileViewButtonCounter.get()
+
+ override fun getReplacementIntent(activityInfo: ActivityInfo?, defIntent: Intent): Intent {
+ return defIntent
+ }
+
+ override fun onPostListReady(
+ listAdapter: ResolverListAdapter?,
+ updateUi: Boolean,
+ rebuildCompleted: Boolean,
+ ) = Unit
+
+ override fun sendVoiceChoicesIfNeeded() {
+ sendVoiceCounter.incrementAndGet()
+ }
+
+ override fun updateProfileViewButton() {
+ updateProfileViewButtonCounter.incrementAndGet()
+ }
+
+ override fun useLayoutWithDefault(): Boolean = layoutWithDefaults
+
+ override fun shouldGetActivityMetadata(): Boolean = true
+
+ override fun onHandlePackagesChanged(listAdapter: ResolverListAdapter?) {}
+}
diff --git a/java/tests/src/com/android/intentresolver/ResolverListAdapterTest.kt b/java/tests/src/com/android/intentresolver/ResolverListAdapterTest.kt
index 53c90199..61b9fd9c 100644
--- a/java/tests/src/com/android/intentresolver/ResolverListAdapterTest.kt
+++ b/java/tests/src/com/android/intentresolver/ResolverListAdapterTest.kt
@@ -19,16 +19,16 @@ package com.android.intentresolver
import android.content.ComponentName
import android.content.Context
import android.content.Intent
-import android.content.pm.ActivityInfo
-import android.content.pm.ApplicationInfo
+import android.content.pm.PackageManager
import android.content.pm.ResolveInfo
import android.os.UserHandle
+import android.os.UserManager
import android.view.LayoutInflater
+import com.android.intentresolver.ResolverDataProvider.createActivityInfo
import com.android.intentresolver.ResolverListAdapter.ResolverListCommunicator
import com.android.intentresolver.icons.TargetDataLoader
import com.android.intentresolver.util.TestExecutor
import com.google.common.truth.Truth.assertThat
-import java.util.concurrent.atomic.AtomicInteger
import org.junit.Test
import org.mockito.Mockito.anyBoolean
import org.mockito.Mockito.inOrder
@@ -36,14 +36,19 @@ import org.mockito.Mockito.never
import org.mockito.Mockito.verify
private const val PKG_NAME = "org.pkg.app"
-private const val PKG_NAME_TWO = "org.pkgtwo.app"
+private const val PKG_NAME_TWO = "org.pkg.two.app"
+private const val PKG_NAME_THREE = "org.pkg.three.app"
private const val CLASS_NAME = "org.pkg.app.TheClass"
class ResolverListAdapterTest {
private val layoutInflater = mock<LayoutInflater>()
+ private val packageManager = mock<PackageManager>()
+ private val userManager = mock<UserManager> { whenever(isManagedProfile).thenReturn(false) }
private val context =
mock<Context> {
whenever(getSystemService(Context.LAYOUT_INFLATER_SERVICE)).thenReturn(layoutInflater)
+ whenever(getSystemService(Context.USER_SERVICE)).thenReturn(userManager)
+ whenever(packageManager).thenReturn(this@ResolverListAdapterTest.packageManager)
}
private val targetIntent = Intent(Intent.ACTION_SEND)
private val payloadIntents = listOf(targetIntent)
@@ -53,7 +58,7 @@ class ResolverListAdapterTest {
whenever(filterLowPriority(any(), anyBoolean())).thenReturn(null)
}
private val resolverListCommunicator = FakeResolverListCommunicator()
- private val userHandle = UserHandle.of(0)
+ private val userHandle = UserHandle.of(UserHandle.USER_CURRENT)
private val targetDataLoader = mock<TargetDataLoader>()
private val backgroundExecutor = TestExecutor()
private val immediateExecutor = TestExecutor(immediate = true)
@@ -666,6 +671,150 @@ class ResolverListAdapterTest {
}
@Test
+ fun test_twoTargetsWithNonOverlappingInitialIntent_threeTargetsInAdapter() {
+ val resolvedTargets =
+ createResolvedComponents(
+ ComponentName(PKG_NAME, CLASS_NAME),
+ ComponentName(PKG_NAME_TWO, CLASS_NAME),
+ )
+ whenever(
+ resolverListController.getResolversForIntentAsUser(
+ true,
+ resolverListCommunicator.shouldGetActivityMetadata(),
+ resolverListCommunicator.shouldGetOnlyDefaultActivities(),
+ payloadIntents,
+ userHandle
+ )
+ )
+ .thenReturn(resolvedTargets)
+ val initialComponent = ComponentName(PKG_NAME_THREE, CLASS_NAME)
+ val initialIntents =
+ arrayOf(Intent(Intent.ACTION_SEND).apply { component = initialComponent })
+ whenever(packageManager.getActivityInfo(eq(initialComponent), eq(0)))
+ .thenReturn(createActivityInfo(initialComponent))
+ val testSubject =
+ ResolverListAdapter(
+ context,
+ payloadIntents,
+ initialIntents,
+ /*rList=*/ null,
+ /*filterLastUsed=*/ true,
+ resolverListController,
+ userHandle,
+ targetIntent,
+ resolverListCommunicator,
+ /*initialIntentsUserSpace=*/ userHandle,
+ targetDataLoader,
+ backgroundExecutor,
+ immediateExecutor,
+ )
+ val doPostProcessing = true
+
+ val isLoaded = testSubject.rebuildList(doPostProcessing)
+
+ assertThat(isLoaded).isFalse()
+ val placeholderCount = resolvedTargets.size - 1
+ assertThat(testSubject.count).isEqualTo(placeholderCount)
+ assertThat(testSubject.placeholderCount).isEqualTo(placeholderCount)
+ assertThat(testSubject.hasFilteredItem()).isFalse()
+ assertThat(testSubject.filteredItem).isNull()
+ assertThat(testSubject.filteredPosition).isLessThan(0)
+ assertThat(testSubject.unfilteredResolveList).containsExactlyElementsIn(resolvedTargets)
+ assertThat(testSubject.isTabLoaded).isFalse()
+ assertThat(backgroundExecutor.pendingCommandCount).isEqualTo(1)
+ assertThat(resolverListCommunicator.updateProfileViewButtonCount).isEqualTo(0)
+ assertThat(resolverListCommunicator.sendVoiceCommandCount).isEqualTo(0)
+
+ backgroundExecutor.runUntilIdle()
+
+ // we don't reset placeholder count (legacy logic, likely an oversight?)
+ assertThat(testSubject.placeholderCount).isEqualTo(placeholderCount)
+ assertThat(testSubject.hasFilteredItem()).isFalse()
+ assertThat(testSubject.count).isEqualTo(resolvedTargets.size + initialIntents.size)
+ assertThat(testSubject.getItem(0)?.targetIntent?.component)
+ .isEqualTo(initialIntents[0].component)
+ assertThat(testSubject.filteredItem).isNull()
+ assertThat(testSubject.filteredPosition).isLessThan(0)
+ assertThat(testSubject.unfilteredResolveList).containsExactlyElementsIn(resolvedTargets)
+ assertThat(testSubject.isTabLoaded).isTrue()
+ assertThat(resolverListCommunicator.updateProfileViewButtonCount).isEqualTo(1)
+ assertThat(resolverListCommunicator.sendVoiceCommandCount).isEqualTo(1)
+ assertThat(backgroundExecutor.pendingCommandCount).isEqualTo(0)
+ }
+
+ @Test
+ fun test_twoTargetsWithOverlappingInitialIntent_twoTargetsInAdapter() {
+ val resolvedTargets =
+ createResolvedComponents(
+ ComponentName(PKG_NAME, CLASS_NAME),
+ ComponentName(PKG_NAME_TWO, CLASS_NAME),
+ )
+ whenever(
+ resolverListController.getResolversForIntentAsUser(
+ true,
+ resolverListCommunicator.shouldGetActivityMetadata(),
+ resolverListCommunicator.shouldGetOnlyDefaultActivities(),
+ payloadIntents,
+ userHandle
+ )
+ )
+ .thenReturn(resolvedTargets)
+ val initialComponent = ComponentName(PKG_NAME_TWO, CLASS_NAME)
+ val initialIntents =
+ arrayOf(Intent(Intent.ACTION_SEND).apply { component = initialComponent })
+ whenever(packageManager.getActivityInfo(eq(initialComponent), eq(0)))
+ .thenReturn(createActivityInfo(initialComponent))
+ val testSubject =
+ ResolverListAdapter(
+ context,
+ payloadIntents,
+ initialIntents,
+ /*rList=*/ null,
+ /*filterLastUsed=*/ true,
+ resolverListController,
+ userHandle,
+ targetIntent,
+ resolverListCommunicator,
+ /*initialIntentsUserSpace=*/ userHandle,
+ targetDataLoader,
+ backgroundExecutor,
+ immediateExecutor,
+ )
+ val doPostProcessing = true
+
+ val isLoaded = testSubject.rebuildList(doPostProcessing)
+
+ assertThat(isLoaded).isFalse()
+ val placeholderCount = resolvedTargets.size - 1
+ assertThat(testSubject.count).isEqualTo(placeholderCount)
+ assertThat(testSubject.placeholderCount).isEqualTo(placeholderCount)
+ assertThat(testSubject.hasFilteredItem()).isFalse()
+ assertThat(testSubject.filteredItem).isNull()
+ assertThat(testSubject.filteredPosition).isLessThan(0)
+ assertThat(testSubject.unfilteredResolveList).containsExactlyElementsIn(resolvedTargets)
+ assertThat(testSubject.isTabLoaded).isFalse()
+ assertThat(backgroundExecutor.pendingCommandCount).isEqualTo(1)
+ assertThat(resolverListCommunicator.updateProfileViewButtonCount).isEqualTo(0)
+ assertThat(resolverListCommunicator.sendVoiceCommandCount).isEqualTo(0)
+
+ backgroundExecutor.runUntilIdle()
+
+ // we don't reset placeholder count (legacy logic, likely an oversight?)
+ assertThat(testSubject.placeholderCount).isEqualTo(placeholderCount)
+ assertThat(testSubject.hasFilteredItem()).isFalse()
+ assertThat(testSubject.count).isEqualTo(resolvedTargets.size)
+ assertThat(testSubject.getItem(0)?.targetIntent?.component)
+ .isEqualTo(initialIntents[0].component)
+ assertThat(testSubject.filteredItem).isNull()
+ assertThat(testSubject.filteredPosition).isLessThan(0)
+ assertThat(testSubject.unfilteredResolveList).containsExactlyElementsIn(resolvedTargets)
+ assertThat(testSubject.isTabLoaded).isTrue()
+ assertThat(resolverListCommunicator.updateProfileViewButtonCount).isEqualTo(1)
+ assertThat(resolverListCommunicator.sendVoiceCommandCount).isEqualTo(1)
+ assertThat(backgroundExecutor.pendingCommandCount).isEqualTo(0)
+ }
+
+ @Test
fun testPostListReadyAtEndOfRebuild_synchronous() {
val communicator = mock<ResolverListCommunicator> {}
val testSubject =
@@ -892,47 +1041,8 @@ class ResolverListAdapterTest {
private fun createResolveInfo(packageName: String, className: String): ResolveInfo =
mock<ResolveInfo> {
- activityInfo =
- ActivityInfo().apply {
- name = className
- this.packageName = packageName
- applicationInfo = ApplicationInfo().apply { this.packageName = packageName }
- }
- targetUserId = UserHandle.USER_CURRENT
+ activityInfo = createActivityInfo(ComponentName(packageName, className))
+ targetUserId = this@ResolverListAdapterTest.userHandle.identifier
+ userHandle = this@ResolverListAdapterTest.userHandle
}
}
-
-private class FakeResolverListCommunicator(private val layoutWithDefaults: Boolean = true) :
- ResolverListAdapter.ResolverListCommunicator {
- private val sendVoiceCounter = AtomicInteger()
- private val updateProfileViewButtonCounter = AtomicInteger()
-
- val sendVoiceCommandCount
- get() = sendVoiceCounter.get()
- val updateProfileViewButtonCount
- get() = updateProfileViewButtonCounter.get()
-
- override fun getReplacementIntent(activityInfo: ActivityInfo?, defIntent: Intent): Intent {
- return defIntent
- }
-
- override fun onPostListReady(
- listAdapter: ResolverListAdapter?,
- updateUi: Boolean,
- rebuildCompleted: Boolean,
- ) = Unit
-
- override fun sendVoiceChoicesIfNeeded() {
- sendVoiceCounter.incrementAndGet()
- }
-
- override fun updateProfileViewButton() {
- updateProfileViewButtonCounter.incrementAndGet()
- }
-
- override fun useLayoutWithDefault(): Boolean = layoutWithDefaults
-
- override fun shouldGetActivityMetadata(): Boolean = true
-
- override fun onHandlePackagesChanged(listAdapter: ResolverListAdapter?) {}
-}
diff --git a/java/tests/src/com/android/intentresolver/util/TestImmediateHandler.kt b/java/tests/src/com/android/intentresolver/util/TestImmediateHandler.kt
deleted file mode 100644
index 9e6fc989..00000000
--- a/java/tests/src/com/android/intentresolver/util/TestImmediateHandler.kt
+++ /dev/null
@@ -1,42 +0,0 @@
-/*
- * Copyright (C) 2023 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
- *
- * http://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.util
-
-import android.os.Handler
-import android.os.Looper
-import android.os.Message
-
-/**
- * A test Handler that executes posted [Runnable] immediately regardless of the target time (delay).
- * Does not support messages.
- */
-class TestImmediateHandler : Handler(createTestLooper()) {
- override fun sendMessageAtTime(msg: Message, uptimeMillis: Long): Boolean {
- msg.callback.run()
- return true
- }
-
- companion object {
- private val looperConstructor by lazy {
- Looper::class.java.getDeclaredConstructor(java.lang.Boolean.TYPE).apply {
- isAccessible = true
- }
- }
-
- private fun createTestLooper(): Looper = looperConstructor.newInstance(true)
- }
-}