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

Commit 066984e7 authored by Ajinkya Chalke's avatar Ajinkya Chalke
Browse files

Cleanup App Clips ViewModel unit tests

Bug: 365911318
Flag: EXEMPT test only changes
Test: atest AppClipsViewModelTest
Change-Id: I1ecb506443f18dbfdd76279c1673162841a919a3
parent 923c3942
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();