diff options
| author | 2022-10-04 21:36:28 +0000 | |
|---|---|---|
| committer | 2022-10-04 21:36:28 +0000 | |
| commit | e2c09d4de735846ff81c86c573dd4ea5d606b498 (patch) | |
| tree | 91f5184e792cc061ce0f56380c1d612d7fda8be5 /java/tests | |
| parent | e95a98abd7d7f7333e48d011176429842d7c398b (diff) | |
| parent | 539dad4c7b79249c44ae826d72d119a97291f45e (diff) | |
Merge "Move shortcut processing logic into separate components." into tm-qpr-dev am: e4b8aee927 am: 539dad4c7b
Original change: https://googleplex-android-review.googlesource.com/c/platform/packages/modules/IntentResolver/+/20076592
Change-Id: I38e8b999b29632f0ad28005979e70486119c6f34
Signed-off-by: Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>
Diffstat (limited to 'java/tests')
6 files changed, 664 insertions, 102 deletions
diff --git a/java/tests/Android.bp b/java/tests/Android.bp index 70c497f5..d19661e8 100644 --- a/java/tests/Android.bp +++ b/java/tests/Android.bp @@ -7,7 +7,7 @@ android_test { name: "IntentResolverUnitTests", // Include all test java files. - srcs: ["src/**/*.java"], + srcs: ["src/**/*.java", "src/**/*.kt"], libs: [ "android.test.runner", diff --git a/java/tests/src/com/android/intentresolver/MockitoKotlinHelpers.kt b/java/tests/src/com/android/intentresolver/MockitoKotlinHelpers.kt new file mode 100644 index 00000000..159c6d6a --- /dev/null +++ b/java/tests/src/com/android/intentresolver/MockitoKotlinHelpers.kt @@ -0,0 +1,146 @@ +/* + * Copyright (C) 2022 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 + +/** + * Kotlin versions of popular mockito methods that can return null in situations when Kotlin expects + * a non-null value. Kotlin will throw an IllegalStateException when this takes place ("x must not + * be null"). To fix this, we can use methods that modify the return type to be nullable. This + * causes Kotlin to skip the null checks. + * Cloned from frameworks/base/packages/SystemUI/tests/utils/src/com/android/systemui/util/mockito/KotlinMockitoHelpers.kt + */ + +import org.mockito.ArgumentCaptor +import org.mockito.ArgumentMatcher +import org.mockito.Mockito +import org.mockito.stubbing.OngoingStubbing + +/** + * Returns Mockito.eq() as nullable type to avoid java.lang.IllegalStateException when + * null is returned. + * + * Generic T is nullable because implicitly bounded by Any?. + */ +fun <T> eq(obj: T): T = Mockito.eq<T>(obj) + +/** + * Returns Mockito.any() as nullable type to avoid java.lang.IllegalStateException when + * null is returned. + * + * Generic T is nullable because implicitly bounded by Any?. + */ +fun <T> any(type: Class<T>): T = Mockito.any<T>(type) +inline fun <reified T> any(): T = any(T::class.java) + +/** + * Returns Mockito.argThat() as nullable type to avoid java.lang.IllegalStateException when + * null is returned. + * + * Generic T is nullable because implicitly bounded by Any?. + */ +fun <T> argThat(matcher: ArgumentMatcher<T>): T = Mockito.argThat(matcher) + +/** + * Kotlin type-inferred version of Mockito.nullable() + */ +inline fun <reified T> nullable(): T? = Mockito.nullable(T::class.java) + +/** + * Returns ArgumentCaptor.capture() as nullable type to avoid java.lang.IllegalStateException + * when null is returned. + * + * Generic T is nullable because implicitly bounded by Any?. + */ +fun <T> capture(argumentCaptor: ArgumentCaptor<T>): T = argumentCaptor.capture() + +/** + * Helper function for creating an argumentCaptor in kotlin. + * + * Generic T is nullable because implicitly bounded by Any?. + */ +inline fun <reified T : Any> argumentCaptor(): ArgumentCaptor<T> = + ArgumentCaptor.forClass(T::class.java) + +/** + * Helper function for creating new mocks, without the need to pass in a [Class] instance. + * + * Generic T is nullable because implicitly bounded by Any?. + * + * @param apply builder function to simplify stub configuration by improving type inference. + */ +inline fun <reified T : Any> mock(apply: T.() -> Unit = {}): T = Mockito.mock(T::class.java) + .apply(apply) + +/** + * Helper function for stubbing methods without the need to use backticks. + * + * @see Mockito.when + */ +fun <T> whenever(methodCall: T): OngoingStubbing<T> = Mockito.`when`(methodCall) + +/** + * A kotlin implemented wrapper of [ArgumentCaptor] which prevents the following exception when + * kotlin tests are mocking kotlin objects and the methods take non-null parameters: + * + * java.lang.NullPointerException: capture() must not be null + */ +class KotlinArgumentCaptor<T> constructor(clazz: Class<T>) { + private val wrapped: ArgumentCaptor<T> = ArgumentCaptor.forClass(clazz) + fun capture(): T = wrapped.capture() + val value: T + get() = wrapped.value + val allValues: List<T> + get() = wrapped.allValues +} + +/** + * Helper function for creating an argumentCaptor in kotlin. + * + * Generic T is nullable because implicitly bounded by Any?. + */ +inline fun <reified T : Any> kotlinArgumentCaptor(): KotlinArgumentCaptor<T> = + KotlinArgumentCaptor(T::class.java) + +/** + * Helper function for creating and using a single-use ArgumentCaptor in kotlin. + * + * val captor = argumentCaptor<Foo>() + * verify(...).someMethod(captor.capture()) + * val captured = captor.value + * + * becomes: + * + * val captured = withArgCaptor<Foo> { verify(...).someMethod(capture()) } + * + * NOTE: this uses the KotlinArgumentCaptor to avoid the NullPointerException. + */ +inline fun <reified T : Any> withArgCaptor(block: KotlinArgumentCaptor<T>.() -> Unit): T = + kotlinArgumentCaptor<T>().apply { block() }.value + +/** + * Variant of [withArgCaptor] for capturing multiple arguments. + * + * val captor = argumentCaptor<Foo>() + * verify(...).someMethod(captor.capture()) + * val captured: List<Foo> = captor.allValues + * + * becomes: + * + * val capturedList = captureMany<Foo> { verify(...).someMethod(capture()) } + */ +inline fun <reified T : Any> captureMany(block: KotlinArgumentCaptor<T>.() -> Unit): List<T> = + kotlinArgumentCaptor<T>().apply{ block() }.allValues diff --git a/java/tests/src/com/android/intentresolver/ShortcutSelectionLogicTest.kt b/java/tests/src/com/android/intentresolver/ShortcutSelectionLogicTest.kt new file mode 100644 index 00000000..052ad446 --- /dev/null +++ b/java/tests/src/com/android/intentresolver/ShortcutSelectionLogicTest.kt @@ -0,0 +1,271 @@ +/* + * Copyright (C) 2022 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.ComponentName +import android.content.Context +import android.content.Intent +import android.content.pm.ShortcutInfo +import android.service.chooser.ChooserTarget +import com.android.intentresolver.chooser.ChooserTargetInfo +import com.android.intentresolver.chooser.SelectableTargetInfo.SelectableTargetInfoCommunicator +import org.junit.Assert.assertEquals +import org.junit.Assert.assertTrue +import org.junit.Test + +private const val PACKAGE_A = "package.a" +private const val PACKAGE_B = "package.b" +private const val CLASS_NAME = "./MainActivity" + +class ShortcutSelectionLogicTest { + private val packageTargets = HashMap<String, Array<ChooserTarget>>().apply { + arrayOf(PACKAGE_A, PACKAGE_B).forEach { pkg -> + // shortcuts in reverse priority order + val targets = Array(3) { i -> + createChooserTarget( + "Shortcut $i", + (i + 1).toFloat() / 10f, + ComponentName(pkg, CLASS_NAME), + pkg.shortcutId(i), + ) + } + this[pkg] = targets + } + } + + private operator fun Map<String, Array<ChooserTarget>>.get(pkg: String, idx: Int) = + this[pkg]?.get(idx) ?: error("missing package $pkg") + + @Test + fun testAddShortcuts_no_limits() { + val serviceResults = ArrayList<ChooserTargetInfo>() + val sc1 = packageTargets[PACKAGE_A, 0] + val sc2 = packageTargets[PACKAGE_A, 1] + val testSubject = ShortcutSelectionLogic( + /* maxShortcutTargetsPerApp = */ 1, + /* applySharingAppLimits = */ false + ) + + val isUpdated = testSubject.addServiceResults( + /* origTarget = */ mock(), + /* origTargetScore = */ 0.1f, + /* targets = */ listOf(sc1, sc2), + /* isShortcutResult = */ true, + /* directShareToShortcutInfos = */ emptyMap(), + /* userContext = */ mock(), + /* mSelectableTargetInfoCommunicator = */ mock(), + /* maxRankedTargets = */ 4, + /* serviceTargets = */ serviceResults + ) + + assertTrue("Updates are expected", isUpdated) + assertShortcutsInOrder( + listOf(sc2, sc1), + serviceResults, + "Two shortcuts are expected as we do not apply per-app shortcut limit" + ) + } + + @Test + fun testAddShortcuts_same_package_with_per_package_limit() { + val serviceResults = ArrayList<ChooserTargetInfo>() + val sc1 = packageTargets[PACKAGE_A, 0] + val sc2 = packageTargets[PACKAGE_A, 1] + val testSubject = ShortcutSelectionLogic( + /* maxShortcutTargetsPerApp = */ 1, + /* applySharingAppLimits = */ true + ) + + val isUpdated = testSubject.addServiceResults( + /* origTarget = */ mock(), + /* origTargetScore = */ 0.1f, + /* targets = */ listOf(sc1, sc2), + /* isShortcutResult = */ true, + /* directShareToShortcutInfos = */ emptyMap(), + /* userContext = */ mock(), + /* mSelectableTargetInfoCommunicator = */ mock(), + /* maxRankedTargets = */ 4, + /* serviceTargets = */ serviceResults + ) + + assertTrue("Updates are expected", isUpdated) + assertShortcutsInOrder( + listOf(sc2), + serviceResults, + "One shortcut is expected as we apply per-app shortcut limit" + ) + } + + @Test + fun testAddShortcuts_same_package_no_per_app_limit_with_target_limit() { + val serviceResults = ArrayList<ChooserTargetInfo>() + val sc1 = packageTargets[PACKAGE_A, 0] + val sc2 = packageTargets[PACKAGE_A, 1] + val testSubject = ShortcutSelectionLogic( + /* maxShortcutTargetsPerApp = */ 1, + /* applySharingAppLimits = */ false + ) + + val isUpdated = testSubject.addServiceResults( + /* origTarget = */ mock(), + /* origTargetScore = */ 0.1f, + /* targets = */ listOf(sc1, sc2), + /* isShortcutResult = */ true, + /* directShareToShortcutInfos = */ emptyMap(), + /* userContext = */ mock(), + /* mSelectableTargetInfoCommunicator = */ mock(), + /* maxRankedTargets = */ 1, + /* serviceTargets = */ serviceResults + ) + + assertTrue("Updates are expected", isUpdated) + assertShortcutsInOrder( + listOf(sc2), + serviceResults, + "One shortcut is expected as we apply overall shortcut limit" + ) + } + + @Test + fun testAddShortcuts_different_packages_with_per_package_limit() { + val serviceResults = ArrayList<ChooserTargetInfo>() + val pkgAsc1 = packageTargets[PACKAGE_A, 0] + val pkgAsc2 = packageTargets[PACKAGE_A, 1] + val pkgBsc1 = packageTargets[PACKAGE_B, 0] + val pkgBsc2 = packageTargets[PACKAGE_B, 1] + val testSubject = ShortcutSelectionLogic( + /* maxShortcutTargetsPerApp = */ 1, + /* applySharingAppLimits = */ true + ) + + testSubject.addServiceResults( + /* origTarget = */ mock(), + /* origTargetScore = */ 0.1f, + /* targets = */ listOf(pkgAsc1, pkgAsc2), + /* isShortcutResult = */ true, + /* directShareToShortcutInfos = */ emptyMap(), + /* userContext = */ mock(), + /* mSelectableTargetInfoCommunicator = */ mock(), + /* maxRankedTargets = */ 4, + /* serviceTargets = */ serviceResults + ) + testSubject.addServiceResults( + /* origTarget = */ mock(), + /* origTargetScore = */ 0.2f, + /* targets = */ listOf(pkgBsc1, pkgBsc2), + /* isShortcutResult = */ true, + /* directShareToShortcutInfos = */ emptyMap(), + /* userContext = */ mock(), + /* mSelectableTargetInfoCommunicator = */ mock(), + /* maxRankedTargets = */ 4, + /* serviceTargets = */ serviceResults + ) + + assertShortcutsInOrder( + listOf(pkgBsc2, pkgAsc2), + serviceResults, + "Two shortcuts are expected as we apply per-app shortcut limit" + ) + } + + @Test + fun testAddShortcuts_pinned_shortcut() { + val serviceResults = ArrayList<ChooserTargetInfo>() + val sc1 = packageTargets[PACKAGE_A, 0] + val sc2 = packageTargets[PACKAGE_A, 1] + val testSubject = ShortcutSelectionLogic( + /* maxShortcutTargetsPerApp = */ 1, + /* applySharingAppLimits = */ false + ) + + val isUpdated = testSubject.addServiceResults( + /* origTarget = */ mock(), + /* origTargetScore = */ 0.1f, + /* targets = */ listOf(sc1, sc2), + /* isShortcutResult = */ true, + /* directShareToShortcutInfos = */ mapOf( + sc1 to createShortcutInfo( + PACKAGE_A.shortcutId(1), + sc1.componentName, 1).apply { + addFlags(ShortcutInfo.FLAG_PINNED) + } + ), + /* userContext = */ mock(), + /* mSelectableTargetInfoCommunicator = */ mock(), + /* maxRankedTargets = */ 4, + /* serviceTargets = */ serviceResults + ) + + assertTrue("Updates are expected", isUpdated) + assertShortcutsInOrder( + listOf(sc1, sc2), + serviceResults, + "Two shortcuts are expected as we do not apply per-app shortcut limit" + ) + } + + @Test + fun test_available_caller_shortcuts_count_is_limited() { + val serviceResults = ArrayList<ChooserTargetInfo>() + val sc1 = packageTargets[PACKAGE_A, 0] + val sc2 = packageTargets[PACKAGE_A, 1] + val sc3 = packageTargets[PACKAGE_A, 2] + val testSubject = ShortcutSelectionLogic( + /* maxShortcutTargetsPerApp = */ 1, + /* applySharingAppLimits = */ true + ) + val targetInfoCommunicator = mock<SelectableTargetInfoCommunicator> { + whenever(targetIntent).thenReturn(Intent()) + } + val context = mock<Context> { + whenever(packageManager).thenReturn(mock()) + } + + testSubject.addServiceResults( + /* origTarget = */ null, + /* origTargetScore = */ 0f, + /* targets = */ listOf(sc1, sc2, sc3), + /* isShortcutResult = */ false /*isShortcutResult*/, + /* directShareToShortcutInfos = */ emptyMap(), + /* userContext = */ context, + /* mSelectableTargetInfoCommunicator = */ targetInfoCommunicator, + /* maxRankedTargets = */ 4, + /* serviceTargets = */ serviceResults + ) + + assertShortcutsInOrder( + listOf(sc3, sc2), + serviceResults, + "At most two caller-provided shortcuts are allowed" + ) + } + + private fun assertShortcutsInOrder( + expected: List<ChooserTarget>, actual: List<ChooserTargetInfo>, msg: String? = "" + ) { + assertEquals(msg, expected.size, actual.size) + for (i in expected.indices) { + assertEquals( + "Unexpected item at position $i", + expected[i], + actual[i].chooserTarget + ) + } + } + + private fun String.shortcutId(id: Int) = "$this.$id" +}
\ No newline at end of file diff --git a/java/tests/src/com/android/intentresolver/ShortcutToChooserTargetConverterTest.kt b/java/tests/src/com/android/intentresolver/ShortcutToChooserTargetConverterTest.kt new file mode 100644 index 00000000..5529e714 --- /dev/null +++ b/java/tests/src/com/android/intentresolver/ShortcutToChooserTargetConverterTest.kt @@ -0,0 +1,175 @@ +/* + * Copyright (C) 2022 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.app.prediction.AppTarget +import android.content.ComponentName +import android.content.Intent +import android.content.pm.ShortcutInfo +import android.content.pm.ShortcutManager.ShareShortcutInfo +import android.service.chooser.ChooserTarget +import org.junit.Assert.assertEquals +import org.junit.Assert.assertNotNull +import org.junit.Test + +private const val PACKAGE = "org.package" + +class ShortcutToChooserTargetConverterTest { + private val testSubject = ShortcutToChooserTargetConverter() + private val ranks = arrayOf(3 ,7, 1 ,3) + private val shortcuts = ranks + .foldIndexed(ArrayList<ShareShortcutInfo>(ranks.size)) { i, acc, rank -> + val id = i + 1 + acc.add( + createShareShortcutInfo( + id = "id-$i", + componentName = ComponentName(PACKAGE, "Class$id"), + rank, + ) + ) + acc + } + + @Test + fun testConvertToChooserTarget_predictionService() { + val appTargets = shortcuts.map { createAppTarget(it.shortcutInfo) } + val expectedOrderAllShortcuts = intArrayOf(0, 1, 2, 3) + val expectedScoreAllShortcuts = floatArrayOf(1.0f, 0.99f, 0.98f, 0.97f) + val appTargetCache = HashMap<ChooserTarget, AppTarget>() + val shortcutInfoCache = HashMap<ChooserTarget, ShortcutInfo>() + + var chooserTargets = testSubject.convertToChooserTarget( + shortcuts, + shortcuts, + appTargets, + appTargetCache, + shortcutInfoCache, + ) + + assertCorrectShortcutToChooserTargetConversion( + shortcuts, + chooserTargets, + expectedOrderAllShortcuts, + expectedScoreAllShortcuts, + ) + assertAppTargetCache(chooserTargets, appTargetCache) + assertShortcutInfoCache(chooserTargets, shortcutInfoCache) + + val subset = shortcuts.subList(1, shortcuts.size) + val expectedOrderSubset = intArrayOf(1, 2, 3) + val expectedScoreSubset = floatArrayOf(0.99f, 0.98f, 0.97f) + appTargetCache.clear() + shortcutInfoCache.clear() + + chooserTargets = testSubject.convertToChooserTarget( + subset, + shortcuts, + appTargets, + appTargetCache, + shortcutInfoCache, + ) + + assertCorrectShortcutToChooserTargetConversion( + shortcuts, + chooserTargets, + expectedOrderSubset, + expectedScoreSubset, + ) + assertAppTargetCache(chooserTargets, appTargetCache) + assertShortcutInfoCache(chooserTargets, shortcutInfoCache) + } + + @Test + fun testConvertToChooserTarget_shortcutManager() { + val testSubject = ShortcutToChooserTargetConverter() + val expectedOrderAllShortcuts = intArrayOf(2, 0, 3, 1) + val expectedScoreAllShortcuts = floatArrayOf(1.0f, 0.99f, 0.99f, 0.98f) + val shortcutInfoCache = HashMap<ChooserTarget, ShortcutInfo>() + + var chooserTargets = testSubject.convertToChooserTarget( + shortcuts, + shortcuts, + null, + null, + shortcutInfoCache, + ) + + assertCorrectShortcutToChooserTargetConversion( + shortcuts, chooserTargets, + expectedOrderAllShortcuts, expectedScoreAllShortcuts + ) + assertShortcutInfoCache(chooserTargets, shortcutInfoCache) + + val subset: MutableList<ShareShortcutInfo> = java.util.ArrayList() + subset.add(shortcuts[1]) + subset.add(shortcuts[2]) + subset.add(shortcuts[3]) + val expectedOrderSubset = intArrayOf(2, 3, 1) + val expectedScoreSubset = floatArrayOf(1.0f, 0.99f, 0.98f) + shortcutInfoCache.clear() + + chooserTargets = testSubject.convertToChooserTarget( + subset, + shortcuts, + null, + null, + shortcutInfoCache, + ) + + assertCorrectShortcutToChooserTargetConversion( + shortcuts, chooserTargets, + expectedOrderSubset, expectedScoreSubset + ) + assertShortcutInfoCache(chooserTargets, shortcutInfoCache) + } + + private fun assertCorrectShortcutToChooserTargetConversion( + shortcuts: List<ShareShortcutInfo>, + chooserTargets: List<ChooserTarget>, + expectedOrder: IntArray, + expectedScores: FloatArray, + ) { + assertEquals("Unexpected ChooserTarget count", expectedOrder.size, chooserTargets.size) + for (i in chooserTargets.indices) { + val ct = chooserTargets[i] + val si = shortcuts[expectedOrder[i]].shortcutInfo + val cn = shortcuts[expectedOrder[i]].targetComponent + assertEquals(si.id, ct.intentExtras.getString(Intent.EXTRA_SHORTCUT_ID)) + assertEquals(si.label, ct.title) + assertEquals(expectedScores[i], ct.score) + assertEquals(cn, ct.componentName) + } + } + + private fun assertAppTargetCache( + chooserTargets: List<ChooserTarget>, cache: Map<ChooserTarget, AppTarget> + ) { + for (ct in chooserTargets) { + val target = cache[ct] + assertNotNull("AppTarget is missing", target) + } + } + + private fun assertShortcutInfoCache( + chooserTargets: List<ChooserTarget>, cache: Map<ChooserTarget, ShortcutInfo> + ) { + for (ct in chooserTargets) { + val si = cache[ct] + assertNotNull("AppTarget is missing", si) + } + } +} diff --git a/java/tests/src/com/android/intentresolver/TestHelpers.kt b/java/tests/src/com/android/intentresolver/TestHelpers.kt new file mode 100644 index 00000000..f4b83249 --- /dev/null +++ b/java/tests/src/com/android/intentresolver/TestHelpers.kt @@ -0,0 +1,71 @@ +/* + * Copyright (C) 2022 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.app.prediction.AppTarget +import android.app.prediction.AppTargetId +import android.content.ComponentName +import android.content.Context +import android.content.Intent +import android.content.pm.ShortcutInfo +import android.content.pm.ShortcutManager.ShareShortcutInfo +import android.os.Bundle +import android.service.chooser.ChooserTarget +import org.mockito.Mockito.`when` as whenever + +internal fun createShareShortcutInfo( + id: String, + componentName: ComponentName, + rank: Int +): ShareShortcutInfo = + ShareShortcutInfo( + createShortcutInfo(id, componentName, rank), + componentName + ) + +internal fun createShortcutInfo( + id: String, + componentName: ComponentName, + rank: Int +): ShortcutInfo { + val context = mock<Context>() + whenever(context.packageName).thenReturn(componentName.packageName) + return ShortcutInfo.Builder(context, id) + .setShortLabel("Short Label $id") + .setLongLabel("Long Label $id") + .setActivity(componentName) + .setRank(rank) + .build() +} + +internal fun createAppTarget(shortcutInfo: ShortcutInfo) = + AppTarget( + AppTargetId(shortcutInfo.id), + shortcutInfo, + shortcutInfo.activity?.className ?: error("missing activity info") + ) + +internal fun createChooserTarget( + title: String, score: Float, componentName: ComponentName, shortcutId: String +): ChooserTarget = + ChooserTarget( + title, + null, + score, + componentName, + Bundle().apply { putString(Intent.EXTRA_SHORTCUT_ID, shortcutId) } + ) diff --git a/java/tests/src/com/android/intentresolver/UnbundledChooserActivityTest.java b/java/tests/src/com/android/intentresolver/UnbundledChooserActivityTest.java index e9baf893..7a590584 100644 --- a/java/tests/src/com/android/intentresolver/UnbundledChooserActivityTest.java +++ b/java/tests/src/com/android/intentresolver/UnbundledChooserActivityTest.java @@ -1370,92 +1370,6 @@ public class UnbundledChooserActivityTest { is(testBaseScore * SHORTCUT_TARGET_SCORE_BOOST)); } - @Test - public void testConvertToChooserTarget_predictionService() { - Intent sendIntent = createSendTextIntent(); - List<ResolvedComponentInfo> resolvedComponentInfos = createResolvedComponentsForTest(2); - when( - ChooserActivityOverrideData - .getInstance() - .resolverListController - .getResolversForIntent( - Mockito.anyBoolean(), - Mockito.anyBoolean(), - Mockito.anyBoolean(), - Mockito.isA(List.class))) - .thenReturn(resolvedComponentInfos); - - final ChooserActivity activity = - mActivityRule.launchActivity(Intent.createChooser(sendIntent, null)); - waitForIdle(); - - List<ShareShortcutInfo> shortcuts = createShortcuts(activity); - - int[] expectedOrderAllShortcuts = {0, 1, 2, 3}; - float[] expectedScoreAllShortcuts = {1.0f, 0.99f, 0.98f, 0.97f}; - - List<ChooserTarget> chooserTargets = activity.convertToChooserTarget(shortcuts, shortcuts, - null, TARGET_TYPE_SHORTCUTS_FROM_PREDICTION_SERVICE); - assertCorrectShortcutToChooserTargetConversion(shortcuts, chooserTargets, - expectedOrderAllShortcuts, expectedScoreAllShortcuts); - - List<ShareShortcutInfo> subset = new ArrayList<>(); - subset.add(shortcuts.get(1)); - subset.add(shortcuts.get(2)); - subset.add(shortcuts.get(3)); - - int[] expectedOrderSubset = {1, 2, 3}; - float[] expectedScoreSubset = {0.99f, 0.98f, 0.97f}; - - chooserTargets = activity.convertToChooserTarget(subset, shortcuts, null, - TARGET_TYPE_SHORTCUTS_FROM_PREDICTION_SERVICE); - assertCorrectShortcutToChooserTargetConversion(shortcuts, chooserTargets, - expectedOrderSubset, expectedScoreSubset); - } - - @Test - public void testConvertToChooserTarget_shortcutManager() { - Intent sendIntent = createSendTextIntent(); - List<ResolvedComponentInfo> resolvedComponentInfos = createResolvedComponentsForTest(2); - when( - ChooserActivityOverrideData - .getInstance() - .resolverListController - .getResolversForIntent( - Mockito.anyBoolean(), - Mockito.anyBoolean(), - Mockito.anyBoolean(), - Mockito.isA(List.class))) - .thenReturn(resolvedComponentInfos); - - final ChooserActivity activity = - mActivityRule.launchActivity(Intent.createChooser(sendIntent, null)); - waitForIdle(); - - List<ShareShortcutInfo> shortcuts = createShortcuts(activity); - - int[] expectedOrderAllShortcuts = {2, 0, 3, 1}; - float[] expectedScoreAllShortcuts = {1.0f, 0.99f, 0.99f, 0.98f}; - - List<ChooserTarget> chooserTargets = activity.convertToChooserTarget(shortcuts, shortcuts, - null, TARGET_TYPE_SHORTCUTS_FROM_SHORTCUT_MANAGER); - assertCorrectShortcutToChooserTargetConversion(shortcuts, chooserTargets, - expectedOrderAllShortcuts, expectedScoreAllShortcuts); - - List<ShareShortcutInfo> subset = new ArrayList<>(); - subset.add(shortcuts.get(1)); - subset.add(shortcuts.get(2)); - subset.add(shortcuts.get(3)); - - int[] expectedOrderSubset = {2, 3, 1}; - float[] expectedScoreSubset = {1.0f, 0.99f, 0.98f}; - - chooserTargets = activity.convertToChooserTarget(subset, shortcuts, null, - TARGET_TYPE_SHORTCUTS_FROM_SHORTCUT_MANAGER); - assertCorrectShortcutToChooserTargetConversion(shortcuts, chooserTargets, - expectedOrderSubset, expectedScoreSubset); - } - // This test is too long and too slow and should not be taken as an example for future tests. @Test @Ignore public void testDirectTargetSelectionLogging() throws InterruptedException { @@ -3112,21 +3026,6 @@ public class UnbundledChooserActivityTest { return shortcuts; } - private void assertCorrectShortcutToChooserTargetConversion(List<ShareShortcutInfo> shortcuts, - List<ChooserTarget> chooserTargets, int[] expectedOrder, float[] expectedScores) { - assertEquals(expectedOrder.length, chooserTargets.size()); - for (int i = 0; i < chooserTargets.size(); i++) { - ChooserTarget ct = chooserTargets.get(i); - ShortcutInfo si = shortcuts.get(expectedOrder[i]).getShortcutInfo(); - ComponentName cn = shortcuts.get(expectedOrder[i]).getTargetComponent(); - - assertEquals(si.getId(), ct.getIntentExtras().getString(Intent.EXTRA_SHORTCUT_ID)); - assertEquals(si.getShortLabel(), ct.getTitle()); - assertThat(Math.abs(expectedScores[i] - ct.getScore()) < 0.000001, is(true)); - assertEquals(cn.flattenToString(), ct.getComponentName().flattenToString()); - } - } - private void markWorkProfileUserAvailable() { ChooserActivityOverrideData.getInstance().workProfileUserHandle = UserHandle.of(10); } |