diff options
| author | 2023-09-19 21:58:02 -0700 | |
|---|---|---|
| committer | 2023-09-27 11:58:20 -0700 | |
| commit | 607f13d48aec6fdd8030273ae4a6cf7a712f4258 (patch) | |
| tree | 3c790a5414249069657581eb0cc69d87722265aa /java | |
| parent | c9e8f1116e2ad1ce3f9aa60efe4be0a1c94eec02 (diff) | |
Add unit tests for initial intents in Resolver and Chooser adapters
Plus some trivial changes to improve code readability
Test: atest IntentResolverUnitTests:ResolverListAdapterTest
Test: atest IntentResolverUnitTests:ChooserListAdapterDataTest
Change-Id: Id32460fb3ea1d8a706e48361c9baa8cce67fd46f
Diffstat (limited to 'java')
6 files changed, 453 insertions, 101 deletions
diff --git a/java/src/com/android/intentresolver/ChooserActivity.java b/java/src/com/android/intentresolver/ChooserActivity.java index 7b4f4827..a6612216 100644 --- a/java/src/com/android/intentresolver/ChooserActivity.java +++ b/java/src/com/android/intentresolver/ChooserActivity.java @@ -68,6 +68,7 @@ import android.view.WindowInsets; import android.widget.TextView; import androidx.annotation.MainThread; +import androidx.annotation.NonNull; import androidx.lifecycle.ViewModelProvider; import androidx.recyclerview.widget.GridLayoutManager; import androidx.recyclerview.widget.RecyclerView; @@ -1017,7 +1018,7 @@ public class ChooserActivity extends Hilt_ChooserActivity implements mIsSuccessfullySelected = true; } - private void maybeRemoveSharedText(@androidx.annotation.NonNull TargetInfo targetInfo) { + private void maybeRemoveSharedText(@NonNull TargetInfo targetInfo) { Intent targetIntent = targetInfo.getTargetIntent(); if (targetIntent == null) { return; @@ -1498,19 +1499,21 @@ public class ChooserActivity extends Hilt_ChooserActivity implements } @Override - public void onListRebuilt(ResolverListAdapter listAdapter, boolean rebuildComplete) { + protected void onListRebuilt(ResolverListAdapter listAdapter, boolean rebuildComplete) { setupScrollListener(); maybeSetupGlobalLayoutListener(); ChooserListAdapter chooserListAdapter = (ChooserListAdapter) listAdapter; - if (chooserListAdapter.getUserHandle() - .equals(mChooserMultiProfilePagerAdapter.getCurrentUserHandle())) { + UserHandle listProfileUserHandle = chooserListAdapter.getUserHandle(); + if (listProfileUserHandle.equals(mChooserMultiProfilePagerAdapter.getCurrentUserHandle())) { mChooserMultiProfilePagerAdapter.getActiveAdapterView() .setAdapter(mChooserMultiProfilePagerAdapter.getCurrentRootAdapter()); mChooserMultiProfilePagerAdapter .setupListAdapter(mChooserMultiProfilePagerAdapter.getCurrentPage()); } + //TODO: move this block inside ChooserListAdapter (should be called when + // ResolverListAdapter#mPostListReadyRunnable is executed. if (chooserListAdapter.getDisplayResolveInfoCount() == 0) { chooserListAdapter.notifyDataSetChanged(); } else { @@ -1518,25 +1521,28 @@ public class ChooserActivity extends Hilt_ChooserActivity implements } if (rebuildComplete) { - long duration = Tracer.INSTANCE.endAppTargetLoadingSection(listAdapter.getUserHandle()); + long duration = Tracer.INSTANCE.endAppTargetLoadingSection(listProfileUserHandle); if (duration >= 0) { Log.d(TAG, "app target loading time " + duration + " ms"); } addCallerChooserTargets(); getEventLog().logSharesheetAppLoadComplete(); - maybeQueryAdditionalPostProcessingTargets(chooserListAdapter); + maybeQueryAdditionalPostProcessingTargets( + listProfileUserHandle, + chooserListAdapter.getDisplayResolveInfos()); mLatencyTracker.onActionEnd(ACTION_LOAD_SHARE_SHEET); } } - private void maybeQueryAdditionalPostProcessingTargets(ChooserListAdapter chooserListAdapter) { - UserHandle userHandle = chooserListAdapter.getUserHandle(); + private void maybeQueryAdditionalPostProcessingTargets( + UserHandle userHandle, + DisplayResolveInfo[] displayResolveInfos) { ProfileRecord record = getProfileRecord(userHandle); if (record == null || record.shortcutLoader == null) { return; } record.loadingStartTime = SystemClock.elapsedRealtime(); - record.shortcutLoader.updateAppTargets(chooserListAdapter.getDisplayResolveInfos()); + record.shortcutLoader.updateAppTargets(displayResolveInfos); } @MainThread diff --git a/java/src/com/android/intentresolver/ChooserListAdapter.java b/java/src/com/android/intentresolver/ChooserListAdapter.java index 2e1476d8..230c18b2 100644 --- a/java/src/com/android/intentresolver/ChooserListAdapter.java +++ b/java/src/com/android/intentresolver/ChooserListAdapter.java @@ -63,6 +63,7 @@ import java.util.List; import java.util.Map; import java.util.Objects; import java.util.Set; +import java.util.concurrent.Executor; import java.util.stream.Collectors; public class ChooserListAdapter extends ResolverListAdapter { @@ -99,7 +100,7 @@ public class ChooserListAdapter extends ResolverListAdapter { private final ShortcutSelectionLogic mShortcutSelectionLogic; // Sorted list of DisplayResolveInfos for the alphabetical app section. - private List<DisplayResolveInfo> mSortedList = new ArrayList<>(); + private final List<DisplayResolveInfo> mSortedList = new ArrayList<>(); private final ItemRevealAnimationTracker mAnimationTracker = new ItemRevealAnimationTracker(); @@ -150,6 +151,45 @@ public class ChooserListAdapter extends ResolverListAdapter { int maxRankedTargets, UserHandle initialIntentsUserSpace, TargetDataLoader targetDataLoader) { + this( + context, + payloadIntents, + initialIntents, + rList, + filterLastUsed, + resolverListController, + userHandle, + targetIntent, + resolverListCommunicator, + packageManager, + eventLog, + chooserRequest, + maxRankedTargets, + initialIntentsUserSpace, + targetDataLoader, + AsyncTask.SERIAL_EXECUTOR, + context.getMainExecutor()); + } + + @VisibleForTesting + public ChooserListAdapter( + Context context, + List<Intent> payloadIntents, + Intent[] initialIntents, + List<ResolveInfo> rList, + boolean filterLastUsed, + ResolverListController resolverListController, + UserHandle userHandle, + Intent targetIntent, + ResolverListCommunicator resolverListCommunicator, + PackageManager packageManager, + EventLog eventLog, + ChooserRequestParameters chooserRequest, + int maxRankedTargets, + UserHandle initialIntentsUserSpace, + TargetDataLoader targetDataLoader, + Executor bgExecutor, + Executor mainExecutor) { // Don't send the initial intents through the shared ResolverActivity path, // we want to separate them into a different section. super( @@ -163,7 +203,9 @@ public class ChooserListAdapter extends ResolverListAdapter { targetIntent, resolverListCommunicator, initialIntentsUserSpace, - targetDataLoader); + targetDataLoader, + bgExecutor, + mainExecutor); mChooserRequest = chooserRequest; mMaxRankedTargets = maxRankedTargets; @@ -413,7 +455,8 @@ public class ChooserListAdapter extends ResolverListAdapter { @Override protected void onPostExecute(List<DisplayResolveInfo> newList) { - mSortedList = newList; + mSortedList.clear(); + mSortedList.addAll(newList); notifyDataSetChanged(); } 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) - } -} |