Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit fe1f4bdb authored by Ajinkya Chalke's avatar Ajinkya Chalke Committed by Android (Google) Code Review
Browse files

Merge "Cleanup App Clips ViewModel unit tests" into main

parents d62ea074 066984e7
Loading
Loading
Loading
Loading
+111 −105
Original line number Diff line number Diff line
@@ -31,12 +31,10 @@ import static com.google.common.truth.Truth.assertThat;
import static com.google.common.util.concurrent.MoreExecutors.directExecutor;

import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyBoolean;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.argThat;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.doAnswer;
import static org.mockito.Mockito.reset;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;

@@ -74,7 +72,6 @@ import com.google.common.util.concurrent.Futures;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.ArgumentCaptor;
import org.mockito.ArgumentMatcher;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
@@ -98,6 +95,10 @@ public final class AppClipsViewModelTest extends SysuiTestCase {
    private static final String BACKLINKS_TASK_APP_NAME = "Ultimate question app";
    private static final String BACKLINKS_TASK_PACKAGE_NAME = "backlinksTaskPackageName";
    private static final AssistContent EMPTY_ASSIST_CONTENT = new AssistContent();
    private static final ResolveInfo BACKLINKS_TASK_RESOLVE_INFO =
            createBacklinksTaskResolveInfo();
    private static final RunningTaskInfo BACKLINKS_TASK_RUNNING_TASK_INFO =
            createTaskInfoForBacklinksTask();

    @Mock
    private AppClipsCrossProcessHelper mAppClipsCrossProcessHelper;
@@ -111,26 +112,11 @@ public final class AppClipsViewModelTest extends SysuiTestCase {
    Context mMockedContext;
    @Mock
    private PackageManager mPackageManager;
    private ArgumentCaptor<Intent> mPackageManagerLauncherIntentCaptor;
    private ArgumentCaptor<Intent> mPackageManagerBacklinkIntentCaptor;
    private AppClipsViewModel mViewModel;

    @Before
    public void setUp() throws RemoteException {
        MockitoAnnotations.initMocks(this);
        mPackageManagerLauncherIntentCaptor = ArgumentCaptor.forClass(Intent.class);
        mPackageManagerBacklinkIntentCaptor = ArgumentCaptor.forClass(Intent.class);

        // Set up mocking for backlinks.
        when(mAtmService.getTasks(Integer.MAX_VALUE, false, false, DEFAULT_DISPLAY))
                .thenReturn(List.of(createTaskInfoForBacklinksTask()));
        ResolveInfo expectedResolveInfo = createBacklinksTaskResolveInfo();
        when(mPackageManager.resolveActivity(mPackageManagerLauncherIntentCaptor.capture(),
                anyInt())).thenReturn(expectedResolveInfo);
        when(mPackageManager.queryIntentActivities(mPackageManagerBacklinkIntentCaptor.capture(),
                eq(MATCH_DEFAULT_ONLY))).thenReturn(List.of(expectedResolveInfo));
        when(mPackageManager.loadItemIcon(any(), any())).thenReturn(FAKE_DRAWABLE);
        when(mMockedContext.getPackageManager()).thenReturn(mPackageManager);

        mViewModel = new AppClipsViewModel.Factory(mAppClipsCrossProcessHelper, mImageExporter,
                mAtmService, mAssistContentRequester, mMockedContext,
@@ -208,19 +194,18 @@ public final class AppClipsViewModelTest extends SysuiTestCase {
    }

    @Test
    public void triggerBacklinks_shouldUpdateBacklinks_withUri() {
    public void triggerBacklinks_shouldUpdateBacklinks_withUri() throws RemoteException {
        Uri expectedUri = Uri.parse("https://developers.android.com");
        AssistContent contentWithUri = new AssistContent();
        contentWithUri.setWebUri(expectedUri);
        mockForAssistContent(contentWithUri, BACKLINKS_TASK_ID);
        mockPackageManagerToResolveUri(expectedUri, BACKLINKS_TASK_RESOLVE_INFO);
        mockBacklinksTaskForMainLauncherIntent();
        mockAtmToReturnRunningTaskInfo(BACKLINKS_TASK_RUNNING_TASK_INFO);

        mViewModel.triggerBacklinks(Collections.emptySet(), DEFAULT_DISPLAY);
        waitForIdleSync();

        Intent queriedIntent = mPackageManagerBacklinkIntentCaptor.getValue();
        assertThat(queriedIntent.getData()).isEqualTo(expectedUri);
        assertThat(queriedIntent.getAction()).isEqualTo(ACTION_VIEW);

        BacklinksData result = (BacklinksData) mViewModel.mSelectedBacklinksLiveData.getValue();
        assertThat(result.getAppIcon()).isEqualTo(FAKE_DRAWABLE);
        ClipData clipData = result.getClipData();
@@ -234,14 +219,17 @@ public final class AppClipsViewModelTest extends SysuiTestCase {
    }

    @Test
    public void triggerBacklinks_shouldUpdateBacklinks_withUriForDifferentApp() {
    public void triggerBacklinks_shouldUpdateBacklinks_withUriForDifferentApp()
            throws RemoteException {
        // Mock for the screenshotted app so that it can be used for fallback backlink.
        mockAtmToReturnRunningTaskInfo(BACKLINKS_TASK_RUNNING_TASK_INFO);
        mockBacklinksTaskForMainLauncherIntent();

        Uri expectedUri = Uri.parse("https://android.com");
        AssistContent contentWithUri = new AssistContent();
        contentWithUri.setWebUri(expectedUri);
        mockForAssistContent(contentWithUri, BACKLINKS_TASK_ID);

        // Reset PackageManager mocking done in setup.
        reset(mPackageManager);
        String package2 = BACKLINKS_TASK_PACKAGE_NAME + 2;
        String appName2 = BACKLINKS_TASK_APP_NAME + 2;
        ResolveInfo resolveInfo2 = createBacklinksTaskResolveInfo();
@@ -250,14 +238,9 @@ public final class AppClipsViewModelTest extends SysuiTestCase {
        activityInfo2.packageName = package2;
        activityInfo2.applicationInfo.packageName = package2;

        Intent app2LauncherIntent = new Intent(ACTION_MAIN).addCategory(
                CATEGORY_LAUNCHER).setPackage(package2);
        when(mPackageManager.resolveActivity(intentEquals(app2LauncherIntent), eq(/* flags= */ 0)))
                .thenReturn(resolveInfo2);
        Intent uriIntent = new Intent(ACTION_VIEW).setData(expectedUri);
        when(mPackageManager.queryIntentActivities(intentEquals(uriIntent), eq(MATCH_DEFAULT_ONLY)))
                .thenReturn(List.of(resolveInfo2));
        when(mPackageManager.loadItemIcon(any(), any())).thenReturn(FAKE_DRAWABLE);
        // Mock the different app resolve info so that backlinks resolves to this different app.
        mockPackageManagerToResolveUri(expectedUri, resolveInfo2);
        mockPmToResolveForMainLauncherIntent(resolveInfo2);

        mViewModel.triggerBacklinks(Collections.emptySet(), DEFAULT_DISPLAY);
        waitForIdleSync();
@@ -273,30 +256,15 @@ public final class AppClipsViewModelTest extends SysuiTestCase {
        assertThat(mViewModel.getBacklinksLiveData().getValue().size()).isEqualTo(1);
    }

    private static class IntentMatcher implements ArgumentMatcher<Intent> {
        private final Intent mExpectedIntent;

        IntentMatcher(Intent expectedIntent) {
            mExpectedIntent = expectedIntent;
        }

        @Override
        public boolean matches(Intent actualIntent) {
            return actualIntent != null && mExpectedIntent.filterEquals(actualIntent);
        }
    }

    private static Intent intentEquals(Intent intent) {
        return argThat(new IntentMatcher(intent));
    }

    @Test
    public void triggerBacklinks_withNonResolvableUri_usesMainLauncherIntent() {
    public void triggerBacklinks_withNonResolvableUri_usesMainLauncherIntent()
            throws RemoteException {
        Uri expectedUri = Uri.parse("https://developers.android.com");
        AssistContent contentWithUri = new AssistContent();
        contentWithUri.setWebUri(expectedUri);
        mockForAssistContent(contentWithUri, BACKLINKS_TASK_ID);
        resetPackageManagerMockingForUsingFallbackBacklinks();
        mockBacklinksTaskForMainLauncherIntent();
        mockAtmToReturnRunningTaskInfo(BACKLINKS_TASK_RUNNING_TASK_INFO);

        mViewModel.triggerBacklinks(Collections.emptySet(), DEFAULT_DISPLAY);
        waitForIdleSync();
@@ -305,18 +273,19 @@ public final class AppClipsViewModelTest extends SysuiTestCase {
    }

    @Test
    public void triggerBacklinks_shouldUpdateBacklinks_withAppProvidedIntent() {
    public void triggerBacklinks_shouldUpdateBacklinks_withAppProvidedIntent()
            throws RemoteException {
        Intent expectedIntent = new Intent().setPackage(BACKLINKS_TASK_PACKAGE_NAME);
        AssistContent contentWithAppProvidedIntent = new AssistContent();
        contentWithAppProvidedIntent.setIntent(expectedIntent);
        mockForAssistContent(contentWithAppProvidedIntent, BACKLINKS_TASK_ID);
        mockQueryIntentActivities(expectedIntent, BACKLINKS_TASK_RESOLVE_INFO);
        mockBacklinksTaskForMainLauncherIntent();
        mockAtmToReturnRunningTaskInfo(BACKLINKS_TASK_RUNNING_TASK_INFO);

        mViewModel.triggerBacklinks(Collections.emptySet(), DEFAULT_DISPLAY);
        waitForIdleSync();

        Intent queriedIntent = mPackageManagerBacklinkIntentCaptor.getValue();
        assertThat(queriedIntent.getPackage()).isEqualTo(expectedIntent.getPackage());

        BacklinksData result = (BacklinksData) mViewModel.mSelectedBacklinksLiveData.getValue();
        assertThat(result.getAppIcon()).isEqualTo(FAKE_DRAWABLE);
        ClipData clipData = result.getClipData();
@@ -328,12 +297,14 @@ public final class AppClipsViewModelTest extends SysuiTestCase {
    }

    @Test
    public void triggerBacklinks_withNonResolvableAppProvidedIntent_usesMainLauncherIntent() {
    public void triggerBacklinks_withNonResolvableAppProvidedIntent_usesMainLauncherIntent()
            throws RemoteException {
        Intent expectedIntent = new Intent().setPackage(BACKLINKS_TASK_PACKAGE_NAME);
        AssistContent contentWithAppProvidedIntent = new AssistContent();
        contentWithAppProvidedIntent.setIntent(expectedIntent);
        mockForAssistContent(contentWithAppProvidedIntent, BACKLINKS_TASK_ID);
        resetPackageManagerMockingForUsingFallbackBacklinks();
        mockBacklinksTaskForMainLauncherIntent();
        mockAtmToReturnRunningTaskInfo(BACKLINKS_TASK_RUNNING_TASK_INFO);

        mViewModel.triggerBacklinks(Collections.emptySet(), DEFAULT_DISPLAY);
        waitForIdleSync();
@@ -342,25 +313,28 @@ public final class AppClipsViewModelTest extends SysuiTestCase {
    }

    @Test
    public void triggerBacklinks_shouldUpdateBacklinks_withMainLauncherIntent() {
    public void triggerBacklinks_shouldUpdateBacklinks_withMainLauncherIntent()
            throws RemoteException {
        mockForAssistContent(EMPTY_ASSIST_CONTENT, BACKLINKS_TASK_ID);
        mockBacklinksTaskForMainLauncherIntent();
        mockAtmToReturnRunningTaskInfo(BACKLINKS_TASK_RUNNING_TASK_INFO);

        mViewModel.triggerBacklinks(Collections.emptySet(), DEFAULT_DISPLAY);
        waitForIdleSync();

        Intent queriedIntent = mPackageManagerLauncherIntentCaptor.getValue();
        assertThat(queriedIntent.getPackage()).isEqualTo(BACKLINKS_TASK_PACKAGE_NAME);
        assertThat(queriedIntent.getAction()).isEqualTo(ACTION_MAIN);
        assertThat(queriedIntent.getCategories()).containsExactly(CATEGORY_LAUNCHER);

        verifyMainLauncherBacklinksIntent();
    }

    @Test
    public void triggerBacklinks_withNonResolvableMainLauncherIntent_noBacklinksAvailable() {
        reset(mPackageManager);
    public void triggerBacklinks_withNonResolvableMainLauncherIntent_noBacklinksAvailable()
            throws RemoteException {
        mockForAssistContent(EMPTY_ASSIST_CONTENT, BACKLINKS_TASK_ID);

        // Mock ATM service so we return task info but don't mock PM to resolve the task intent.
        when(mAtmService.getTasks(Integer.MAX_VALUE, /* filterOnlyVisibleRecents= */
                false, /* keepIntentExtras= */ false, DEFAULT_DISPLAY)).thenReturn(
                List.of(BACKLINKS_TASK_RUNNING_TASK_INFO));

        mViewModel.triggerBacklinks(Collections.emptySet(), DEFAULT_DISPLAY);
        waitForIdleSync();

@@ -371,11 +345,9 @@ public final class AppClipsViewModelTest extends SysuiTestCase {
    @Test
    public void triggerBacklinks_nonStandardActivityIgnored_noBacklinkAvailable()
            throws RemoteException {
        reset(mAtmService);
        RunningTaskInfo taskInfo = createTaskInfoForBacklinksTask();
        taskInfo.configuration.windowConfiguration.setActivityType(ACTIVITY_TYPE_HOME);
        when(mAtmService.getTasks(Integer.MAX_VALUE, false, false, DEFAULT_DISPLAY))
                .thenReturn(List.of(taskInfo));
        mockAtmToReturnRunningTaskInfo(taskInfo);

        mViewModel.triggerBacklinks(Collections.emptySet(), DEFAULT_DISPLAY);
        waitForIdleSync();
@@ -399,9 +371,9 @@ public final class AppClipsViewModelTest extends SysuiTestCase {
    public void triggerBacklinks_multipleAppsOnScreen_multipleBacklinksAvailable()
            throws RemoteException {
        // Set up mocking for multiple backlinks.
        reset(mAtmService, mPackageManager);
        RunningTaskInfo runningTaskInfo1 = createTaskInfoForBacklinksTask();
        ResolveInfo resolveInfo1 = createBacklinksTaskResolveInfo();
        RunningTaskInfo runningTaskInfo1 = createTaskInfoForBacklinksTask();
        runningTaskInfo1.topActivityInfo = resolveInfo1.activityInfo;

        int taskId2 = BACKLINKS_TASK_ID + 2;
        String package2 = BACKLINKS_TASK_PACKAGE_NAME + 2;
@@ -418,27 +390,23 @@ public final class AppClipsViewModelTest extends SysuiTestCase {
        runningTaskInfo2.topActivityInfo = resolveInfo2.activityInfo;
        runningTaskInfo2.baseIntent = new Intent().setComponent(runningTaskInfo2.topActivity);

        // For each task, the logic queries PM 3 times, twice for verifying if an app can be
        // launched via launcher and once with the data provided in backlink intent.
        when(mPackageManager.resolveActivity(any(), anyInt())).thenReturn(resolveInfo1,
                resolveInfo1, resolveInfo2, resolveInfo2);
        when(mPackageManager.queryIntentActivities(any(Intent.class), eq(MATCH_DEFAULT_ONLY)))
                .thenReturn(List.of(resolveInfo1)).thenReturn(List.of(resolveInfo2));
        when(mPackageManager.loadItemIcon(any(), any())).thenReturn(FAKE_DRAWABLE);
        when(mAtmService.getTasks(Integer.MAX_VALUE, false, false, DEFAULT_DISPLAY))
                .thenReturn(List.of(runningTaskInfo1, runningTaskInfo2));
        mockAtmToReturnRunningTaskInfo(runningTaskInfo1, runningTaskInfo2);
        mockPmToResolveForMainLauncherIntent(resolveInfo1);
        mockPmToResolveForMainLauncherIntent(resolveInfo2);

        // Using app provided web uri for the first backlink.
        Uri expectedUri = Uri.parse("https://developers.android.com");
        AssistContent contentWithUri = new AssistContent();
        contentWithUri.setWebUri(expectedUri);
        mockForAssistContent(contentWithUri, BACKLINKS_TASK_ID);
        mockPackageManagerToResolveUri(expectedUri, resolveInfo1);

        // Using app provided intent for the second backlink.
        Intent expectedIntent = new Intent().setPackage(package2);
        AssistContent contentWithAppProvidedIntent = new AssistContent();
        contentWithAppProvidedIntent.setIntent(expectedIntent);
        mockForAssistContent(contentWithAppProvidedIntent, taskId2);
        mockQueryIntentActivities(expectedIntent, resolveInfo2);

        // Set up complete, trigger the backlinks action.
        mViewModel.triggerBacklinks(Collections.emptySet(), DEFAULT_DISPLAY);
@@ -460,11 +428,12 @@ public final class AppClipsViewModelTest extends SysuiTestCase {
    @Test
    public void triggerBacklinks_singleCrossProfileApp_shouldIndicateError()
            throws RemoteException {
        reset(mAtmService);
        RunningTaskInfo taskInfo = createTaskInfoForBacklinksTask();
        taskInfo.userId = UserHandle.myUserId() + 1;
        when(mAtmService.getTasks(Integer.MAX_VALUE, false, false, DEFAULT_DISPLAY))
                .thenReturn(List.of(taskInfo));
        when(mAtmService.getTasks(Integer.MAX_VALUE, /* filterOnlyVisibleRecents= */
                false, /* keepIntentExtra */ false, DEFAULT_DISPLAY)).thenReturn(List.of(taskInfo));
        when(mPackageManager.loadItemIcon(taskInfo.topActivityInfo,
                taskInfo.topActivityInfo.applicationInfo)).thenReturn(FAKE_DRAWABLE);

        mViewModel.triggerBacklinks(Collections.emptySet(), DEFAULT_DISPLAY);
        waitForIdleSync();
@@ -478,13 +447,13 @@ public final class AppClipsViewModelTest extends SysuiTestCase {
            throws RemoteException {
        // Set up mocking for multiple backlinks.
        mockForAssistContent(EMPTY_ASSIST_CONTENT, BACKLINKS_TASK_ID);
        reset(mAtmService);
        RunningTaskInfo runningTaskInfo1 = createTaskInfoForBacklinksTask();
        RunningTaskInfo runningTaskInfo2 = createTaskInfoForBacklinksTask();
        runningTaskInfo2.userId = UserHandle.myUserId() + 1;

        when(mAtmService.getTasks(anyInt(), anyBoolean(), anyBoolean(), anyInt()))
                .thenReturn(List.of(runningTaskInfo1, runningTaskInfo2));
        mockAtmToReturnRunningTaskInfo(BACKLINKS_TASK_RUNNING_TASK_INFO, runningTaskInfo2);
        when(mPackageManager.loadItemIcon(runningTaskInfo2.topActivityInfo,
                runningTaskInfo2.topActivityInfo.applicationInfo)).thenReturn(FAKE_DRAWABLE);
        mockBacklinksTaskForMainLauncherIntent();

        // Set up complete, trigger the backlinks action.
        mViewModel.triggerBacklinks(Collections.emptySet(), DEFAULT_DISPLAY);
@@ -497,22 +466,6 @@ public final class AppClipsViewModelTest extends SysuiTestCase {
        assertThat(actualBacklinks.get(1)).isInstanceOf(CrossProfileError.class);
    }

    private void resetPackageManagerMockingForUsingFallbackBacklinks() {
        ResolveInfo backlinksTaskResolveInfo = createBacklinksTaskResolveInfo();
        reset(mPackageManager);
        when(mPackageManager.loadItemIcon(any(), any())).thenReturn(FAKE_DRAWABLE);
        when(mPackageManager.resolveActivity(any(Intent.class), anyInt()))
                // Firstly, the logic queries whether a package has a launcher activity, this should
                // resolve otherwise the logic filters out the task.
                .thenReturn(backlinksTaskResolveInfo)
                // Secondly, the logic builds a fallback main launcher intent, this should also
                // resolve for the fallback intent to build correctly.
                .thenReturn(backlinksTaskResolveInfo)
                // Lastly, logic queries with the backlinks intent, this should not resolve for the
                // logic to use the fallback intent.
                .thenReturn(null);
    }

    private void verifyMainLauncherBacklinksIntent() {
        BacklinksData result = (BacklinksData) mViewModel.mSelectedBacklinksLiveData.getValue();
        assertThat(result.getAppIcon()).isEqualTo(FAKE_DRAWABLE);
@@ -540,6 +493,59 @@ public final class AppClipsViewModelTest extends SysuiTestCase {
        }).when(mAssistContentRequester).requestAssistContent(eq(taskId), any());
    }

    private void mockPackageManagerToResolveUri(Uri uriToResolve, ResolveInfo resolveInfoToReturn) {
        Intent uriIntent = new Intent(ACTION_VIEW).setData(uriToResolve);
        mockQueryIntentActivities(uriIntent, resolveInfoToReturn);
        mockPmToLoadAppIcon(resolveInfoToReturn);
    }

    private void mockQueryIntentActivities(Intent expectedIntent, ResolveInfo resolveInfoToReturn) {
        when(mPackageManager.queryIntentActivities(intentEquals(expectedIntent),
                eq(MATCH_DEFAULT_ONLY)))
                .thenReturn(List.of(resolveInfoToReturn));
    }

    private void mockBacklinksTaskForMainLauncherIntent() {
        mockPmToResolveForMainLauncherIntent(BACKLINKS_TASK_RESOLVE_INFO);
    }

    private void mockPmToResolveForMainLauncherIntent(ResolveInfo resolveInfo) {
        Intent intent = new Intent(ACTION_MAIN).addCategory(CATEGORY_LAUNCHER).setPackage(
                resolveInfo.activityInfo.packageName);
        when(mPackageManager.resolveActivity(intentEquals(intent), eq(/* flags= */ 0))).thenReturn(
                resolveInfo);
        mockPmToLoadAppIcon(resolveInfo);
    }

    private void mockPmToLoadAppIcon(ResolveInfo resolveInfo) {
        when(mPackageManager.loadItemIcon(resolveInfo.activityInfo,
                resolveInfo.activityInfo.applicationInfo)).thenReturn(FAKE_DRAWABLE);
    }

    private void mockAtmToReturnRunningTaskInfo(RunningTaskInfo... taskInfos)
            throws RemoteException {
        when(mAtmService.getTasks(Integer.MAX_VALUE, /* filterOnlyVisibleRecents= */
                false, /* keepIntentExtras= */ false, DEFAULT_DISPLAY)).thenReturn(
                List.of(taskInfos));
    }

    private static Intent intentEquals(Intent intent) {
        return argThat(new IntentMatcher(intent));
    }

    private static class IntentMatcher implements ArgumentMatcher<Intent> {
        private final Intent mExpectedIntent;

        IntentMatcher(Intent expectedIntent) {
            mExpectedIntent = expectedIntent;
        }

        @Override
        public boolean matches(Intent actualIntent) {
            return actualIntent != null && mExpectedIntent.filterEquals(actualIntent);
        }
    }

    private static ResolveInfo createBacklinksTaskResolveInfo() {
        ActivityInfo activityInfo = new ActivityInfo();
        activityInfo.applicationInfo = new ApplicationInfo();
@@ -558,7 +564,7 @@ public final class AppClipsViewModelTest extends SysuiTestCase {
        taskInfo.isRunning = true;
        taskInfo.numActivities = 1;
        taskInfo.topActivity = new ComponentName(BACKLINKS_TASK_PACKAGE_NAME, "backlinksClass");
        taskInfo.topActivityInfo = createBacklinksTaskResolveInfo().activityInfo;
        taskInfo.topActivityInfo = BACKLINKS_TASK_RESOLVE_INFO.activityInfo;
        taskInfo.baseIntent = new Intent().setComponent(taskInfo.topActivity);
        taskInfo.configuration.windowConfiguration.setActivityType(ACTIVITY_TYPE_STANDARD);
        taskInfo.userId = UserHandle.myUserId();