Home | History | Annotate | Download | only in app
      1 /*
      2  * Copyright (C) 2016 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 package com.android.internal.app;
     18 
     19 import com.android.internal.R;
     20 import com.android.internal.app.ResolverActivity.ResolvedComponentInfo;
     21 
     22 import org.junit.Before;
     23 import org.junit.Rule;
     24 import org.junit.Test;
     25 import org.junit.runner.RunWith;
     26 import org.mockito.Mockito;
     27 
     28 import android.app.usage.UsageStats;
     29 import android.app.usage.UsageStatsManager;
     30 import android.content.Intent;
     31 import android.content.pm.ResolveInfo;
     32 import android.os.UserHandle;
     33 import android.support.test.InstrumentationRegistry;
     34 import android.support.test.rule.ActivityTestRule;
     35 import android.support.test.runner.AndroidJUnit4;
     36 
     37 import java.util.ArrayList;
     38 import java.util.List;
     39 import java.util.Map;
     40 
     41 import static android.support.test.espresso.Espresso.onView;
     42 import static android.support.test.espresso.action.ViewActions.click;
     43 import static android.support.test.espresso.assertion.ViewAssertions.matches;
     44 import static android.support.test.espresso.matcher.ViewMatchers.isDisplayed;
     45 import static android.support.test.espresso.matcher.ViewMatchers.withId;
     46 import static android.support.test.espresso.matcher.ViewMatchers.withText;
     47 import static com.android.internal.app.ChooserWrapperActivity.sOverrides;
     48 import static org.hamcrest.CoreMatchers.is;
     49 import static org.hamcrest.CoreMatchers.not;
     50 import static org.hamcrest.MatcherAssert.assertThat;
     51 import static org.mockito.Mockito.when;
     52 import static org.mockito.Mockito.verify;
     53 import static org.mockito.Mockito.times;
     54 
     55 /**
     56  * Chooser activity instrumentation tests
     57  */
     58 @RunWith(AndroidJUnit4.class)
     59 public class ChooserActivityTest {
     60     @Rule
     61     public ActivityTestRule<ChooserWrapperActivity> mActivityRule =
     62             new ActivityTestRule<>(ChooserWrapperActivity.class, false,
     63                     false);
     64 
     65     @Before
     66     public void cleanOverrideData() {
     67         sOverrides.reset();
     68     }
     69 
     70     @Test
     71     public void customTitle() throws InterruptedException {
     72         Intent sendIntent = createSendImageIntent();
     73         List<ResolvedComponentInfo> resolvedComponentInfos = createResolvedComponentsForTest(2);
     74 
     75         when(sOverrides.resolverListController.getResolversForIntent(Mockito.anyBoolean(),
     76                 Mockito.anyBoolean(),
     77                 Mockito.isA(List.class))).thenReturn(resolvedComponentInfos);
     78         mActivityRule.launchActivity(Intent.createChooser(sendIntent, "chooser test"));
     79         waitForIdle();
     80         onView(withId(R.id.title)).check(matches(withText("chooser test")));
     81     }
     82 
     83     @Test
     84     public void emptyTitle() throws InterruptedException {
     85         Intent sendIntent = createSendImageIntent();
     86         List<ResolvedComponentInfo> resolvedComponentInfos = createResolvedComponentsForTest(2);
     87 
     88         when(sOverrides.resolverListController.getResolversForIntent(Mockito.anyBoolean(),
     89                 Mockito.anyBoolean(),
     90                 Mockito.isA(List.class))).thenReturn(resolvedComponentInfos);
     91         mActivityRule.launchActivity(Intent.createChooser(sendIntent, null));
     92         waitForIdle();
     93         onView(withId(R.id.title))
     94                 .check(matches(withText(R.string.whichSendApplication)));
     95     }
     96 
     97     @Test
     98     public void twoOptionsAndUserSelectsOne() throws InterruptedException {
     99         Intent sendIntent = createSendImageIntent();
    100         List<ResolvedComponentInfo> resolvedComponentInfos = createResolvedComponentsForTest(2);
    101 
    102         when(sOverrides.resolverListController.getResolversForIntent(Mockito.anyBoolean(),
    103                 Mockito.anyBoolean(),
    104                 Mockito.isA(List.class))).thenReturn(resolvedComponentInfos);
    105 
    106         final ChooserWrapperActivity activity = mActivityRule
    107                 .launchActivity(Intent.createChooser(sendIntent, null));
    108         waitForIdle();
    109 
    110         assertThat(activity.getAdapter().getCount(), is(2));
    111         onView(withId(R.id.profile_button)).check(matches(not(isDisplayed())));
    112 
    113         ResolveInfo[] chosen = new ResolveInfo[1];
    114         sOverrides.onSafelyStartCallback = targetInfo -> {
    115             chosen[0] = targetInfo.getResolveInfo();
    116             return true;
    117         };
    118 
    119         ResolveInfo toChoose = resolvedComponentInfos.get(0).getResolveInfoAt(0);
    120         onView(withText(toChoose.activityInfo.name))
    121                 .perform(click());
    122         waitForIdle();
    123         assertThat(chosen[0], is(toChoose));
    124     }
    125 
    126     @Test
    127     public void updateChooserCountsAndModelAfterUserSelection() throws InterruptedException {
    128         Intent sendIntent = createSendImageIntent();
    129         List<ResolvedComponentInfo> resolvedComponentInfos = createResolvedComponentsForTest(2);
    130 
    131         when(sOverrides.resolverListController.getResolversForIntent(Mockito.anyBoolean(),
    132                 Mockito.anyBoolean(),
    133                 Mockito.isA(List.class))).thenReturn(resolvedComponentInfos);
    134 
    135         final ChooserWrapperActivity activity = mActivityRule
    136                 .launchActivity(Intent.createChooser(sendIntent, null));
    137         waitForIdle();
    138         UsageStatsManager usm = activity.getUsageStatsManager();
    139         verify(sOverrides.resolverListController, times(1))
    140                 .sort(Mockito.any(List.class));
    141         assertThat(activity.getIsSelected(), is(false));
    142         sOverrides.onSafelyStartCallback = targetInfo -> {
    143             return true;
    144         };
    145         ResolveInfo toChoose = resolvedComponentInfos.get(0).getResolveInfoAt(0);
    146         onView(withText(toChoose.activityInfo.name))
    147                 .perform(click());
    148         waitForIdle();
    149         verify(sOverrides.resolverListController, times(1))
    150                 .updateChooserCounts(Mockito.anyString(), Mockito.anyInt(), Mockito.anyString());
    151         verify(sOverrides.resolverListController, times(1))
    152                 .updateModel(toChoose.activityInfo.getComponentName());
    153         assertThat(activity.getIsSelected(), is(true));
    154     }
    155 
    156     @Test
    157     public void noResultsFromPackageManager() {
    158         when(sOverrides.resolverListController.getResolversForIntent(Mockito.anyBoolean(),
    159                 Mockito.anyBoolean(),
    160                 Mockito.isA(List.class))).thenReturn(null);
    161         Intent sendIntent = createSendImageIntent();
    162         final ChooserWrapperActivity activity = mActivityRule
    163                 .launchActivity(Intent.createChooser(sendIntent, null));
    164         waitForIdle();
    165         assertThat(activity.isFinishing(), is(false));
    166 
    167         onView(withId(R.id.empty)).check(matches(isDisplayed()));
    168         onView(withId(R.id.resolver_list)).check(matches(not(isDisplayed())));
    169         InstrumentationRegistry.getInstrumentation().runOnMainSync(
    170                 () -> activity.getAdapter().handlePackagesChanged()
    171         );
    172         // backward compatibility. looks like we finish when data is empty after package change
    173         assertThat(activity.isFinishing(), is(true));
    174     }
    175 
    176     @Test
    177     public void autoLaunchSingleResult() throws InterruptedException {
    178         ResolveInfo[] chosen = new ResolveInfo[1];
    179         sOverrides.onSafelyStartCallback = targetInfo -> {
    180             chosen[0] = targetInfo.getResolveInfo();
    181             return true;
    182         };
    183 
    184         List<ResolvedComponentInfo> resolvedComponentInfos = createResolvedComponentsForTest(1);
    185         when(sOverrides.resolverListController.getResolversForIntent(Mockito.anyBoolean(),
    186                 Mockito.anyBoolean(),
    187                 Mockito.isA(List.class))).thenReturn(resolvedComponentInfos);
    188 
    189         Intent sendIntent = createSendImageIntent();
    190         final ChooserWrapperActivity activity = mActivityRule
    191                 .launchActivity(Intent.createChooser(sendIntent, null));
    192         waitForIdle();
    193 
    194         assertThat(chosen[0], is(resolvedComponentInfos.get(0).getResolveInfoAt(0)));
    195         assertThat(activity.isFinishing(), is(true));
    196     }
    197 
    198     @Test
    199     public void hasOtherProfileOneOption() throws Exception {
    200         Intent sendIntent = createSendImageIntent();
    201         List<ResolvedComponentInfo> resolvedComponentInfos =
    202                 createResolvedComponentsForTestWithOtherProfile(2);
    203         ResolveInfo toChoose = resolvedComponentInfos.get(1).getResolveInfoAt(0);
    204 
    205         when(ChooserWrapperActivity.sOverrides.resolverListController.getResolversForIntent(
    206                 Mockito.anyBoolean(),
    207                 Mockito.anyBoolean(),
    208                 Mockito.isA(List.class))).thenReturn(resolvedComponentInfos);
    209 
    210         final ChooserWrapperActivity activity = mActivityRule
    211                 .launchActivity(Intent.createChooser(sendIntent, null));
    212         waitForIdle();
    213 
    214         // The other entry is filtered to the other profile slot
    215         assertThat(activity.getAdapter().getCount(), is(1));
    216 
    217         ResolveInfo[] chosen = new ResolveInfo[1];
    218         ChooserWrapperActivity.sOverrides.onSafelyStartCallback = targetInfo -> {
    219             chosen[0] = targetInfo.getResolveInfo();
    220             return true;
    221         };
    222 
    223         // Make a stable copy of the components as the original list may be modified
    224         List<ResolvedComponentInfo> stableCopy =
    225                 createResolvedComponentsForTestWithOtherProfile(2);
    226         // Check that the "Other Profile" activity is put in the right spot
    227         onView(withId(R.id.profile_button)).check(matches(
    228                 withText(stableCopy.get(0).getResolveInfoAt(0).activityInfo.name)));
    229         onView(withText(stableCopy.get(1).getResolveInfoAt(0).activityInfo.name))
    230                 .perform(click());
    231         waitForIdle();
    232         assertThat(chosen[0], is(toChoose));
    233     }
    234 
    235     @Test
    236     public void hasOtherProfileTwoOptionsAndUserSelectsOne() throws Exception {
    237         Intent sendIntent = createSendImageIntent();
    238         List<ResolvedComponentInfo> resolvedComponentInfos =
    239                 createResolvedComponentsForTestWithOtherProfile(3);
    240         ResolveInfo toChoose = resolvedComponentInfos.get(1).getResolveInfoAt(0);
    241 
    242         when(ChooserWrapperActivity.sOverrides.resolverListController.getResolversForIntent(
    243                 Mockito.anyBoolean(),
    244                 Mockito.anyBoolean(),
    245                 Mockito.isA(List.class))).thenReturn(resolvedComponentInfos);
    246         when(ChooserWrapperActivity.sOverrides.resolverListController.getLastChosen())
    247                 .thenReturn(resolvedComponentInfos.get(0).getResolveInfoAt(0));
    248 
    249         final ChooserWrapperActivity activity = mActivityRule
    250                 .launchActivity(Intent.createChooser(sendIntent, null));
    251         waitForIdle();
    252 
    253         // The other entry is filtered to the other profile slot
    254         assertThat(activity.getAdapter().getCount(), is(2));
    255 
    256         ResolveInfo[] chosen = new ResolveInfo[1];
    257         ChooserWrapperActivity.sOverrides.onSafelyStartCallback = targetInfo -> {
    258             chosen[0] = targetInfo.getResolveInfo();
    259             return true;
    260         };
    261 
    262         // Make a stable copy of the components as the original list may be modified
    263         List<ResolvedComponentInfo> stableCopy =
    264                 createResolvedComponentsForTestWithOtherProfile(3);
    265         // Check that the "Other Profile" activity is put in the right spot
    266         onView(withId(R.id.profile_button)).check(matches(
    267                 withText(stableCopy.get(0).getResolveInfoAt(0).activityInfo.name)));
    268         onView(withText(stableCopy.get(1).getResolveInfoAt(0).activityInfo.name))
    269                 .perform(click());
    270         waitForIdle();
    271         assertThat(chosen[0], is(toChoose));
    272     }
    273 
    274     @Test
    275     public void hasLastChosenActivityAndOtherProfile() throws Exception {
    276         Intent sendIntent = createSendImageIntent();
    277         List<ResolvedComponentInfo> resolvedComponentInfos =
    278                 createResolvedComponentsForTestWithOtherProfile(3);
    279         ResolveInfo toChoose = resolvedComponentInfos.get(1).getResolveInfoAt(0);
    280 
    281         when(ChooserWrapperActivity.sOverrides.resolverListController.getResolversForIntent(
    282                 Mockito.anyBoolean(),
    283                 Mockito.anyBoolean(),
    284                 Mockito.isA(List.class))).thenReturn(resolvedComponentInfos);
    285 
    286         final ChooserWrapperActivity activity = mActivityRule
    287                 .launchActivity(Intent.createChooser(sendIntent, null));
    288         waitForIdle();
    289 
    290         // The other entry is filtered to the last used slot
    291         assertThat(activity.getAdapter().getCount(), is(2));
    292 
    293         ResolveInfo[] chosen = new ResolveInfo[1];
    294         ChooserWrapperActivity.sOverrides.onSafelyStartCallback = targetInfo -> {
    295             chosen[0] = targetInfo.getResolveInfo();
    296             return true;
    297         };
    298 
    299         // Make a stable copy of the components as the original list may be modified
    300         List<ResolvedComponentInfo> stableCopy =
    301                 createResolvedComponentsForTestWithOtherProfile(3);
    302         // Check that the "Other Profile" activity is put in the right spot
    303         onView(withId(R.id.profile_button)).check(matches(
    304                 withText(stableCopy.get(0).getResolveInfoAt(0).activityInfo.name)));
    305         onView(withText(stableCopy.get(1).getResolveInfoAt(0).activityInfo.name))
    306                 .perform(click());
    307         waitForIdle();
    308         assertThat(chosen[0], is(toChoose));
    309     }
    310 
    311     private Intent createSendImageIntent() {
    312         Intent sendIntent = new Intent();
    313         sendIntent.setAction(Intent.ACTION_SEND);
    314         sendIntent.putExtra(Intent.EXTRA_TEXT, "testing intent sending");
    315         sendIntent.setType("image/jpeg");
    316         return sendIntent;
    317     }
    318 
    319     private List<ResolvedComponentInfo> createResolvedComponentsForTest(int numberOfResults) {
    320         List<ResolvedComponentInfo> infoList = new ArrayList<>(numberOfResults);
    321         for (int i = 0; i < numberOfResults; i++) {
    322             infoList.add(ResolverDataProvider.createResolvedComponentInfo(i));
    323         }
    324         return infoList;
    325     }
    326 
    327     private List<ResolvedComponentInfo> createResolvedComponentsForTestWithOtherProfile(
    328             int numberOfResults) {
    329         List<ResolvedComponentInfo> infoList = new ArrayList<>(numberOfResults);
    330         for (int i = 0; i < numberOfResults; i++) {
    331             if (i == 0) {
    332                 infoList.add(ResolverDataProvider.createResolvedComponentInfoWithOtherId(i));
    333             } else {
    334                 infoList.add(ResolverDataProvider.createResolvedComponentInfo(i));
    335             }
    336         }
    337         return infoList;
    338     }
    339 
    340     private void waitForIdle() {
    341         InstrumentationRegistry.getInstrumentation().waitForIdleSync();
    342     }
    343 }