diff options
| author | 2017-01-17 12:20:01 -0800 | |
|---|---|---|
| committer | 2017-01-23 10:43:03 -0800 | |
| commit | 9149dcaf414ebdac231af93d44abd5951a514a7e (patch) | |
| tree | 7f4c13e6ef1d01ba07c1bdd2c6dea9c5ab8dbc35 | |
| parent | 1eb7161f4573243d3ee38f40b5d4e664d6ac640d (diff) | |
Add ResolverActivity testing
Still very basic, but will be adding as we find more issues pop up.
Test: Ran the tests
Change-Id: Ib9863509d140ff425ce446ecc876f53494d4fd0e
| -rw-r--r-- | core/java/com/android/internal/app/ResolverActivity.java | 10 | ||||
| -rw-r--r-- | core/java/com/android/internal/app/ResolverListController.java | 19 | ||||
| -rw-r--r-- | core/tests/coretests/AndroidManifest.xml | 1 | ||||
| -rw-r--r-- | core/tests/coretests/src/com/android/internal/app/ChooserActivityTest.java | 2 | ||||
| -rw-r--r-- | core/tests/coretests/src/com/android/internal/app/ChooserWrapperActivity.java | 9 | ||||
| -rw-r--r-- | core/tests/coretests/src/com/android/internal/app/ResolverActivityTest.java | 151 | ||||
| -rw-r--r-- | core/tests/coretests/src/com/android/internal/app/ResolverDataProvider.java (renamed from core/tests/coretests/src/com/android/internal/app/ChooserDataProvider.java) | 5 | ||||
| -rw-r--r-- | core/tests/coretests/src/com/android/internal/app/ResolverWrapperActivity.java | 91 | 
8 files changed, 271 insertions, 17 deletions
| diff --git a/core/java/com/android/internal/app/ResolverActivity.java b/core/java/com/android/internal/app/ResolverActivity.java index d734d17b2dc9..ab1d9b9c6f6e 100644 --- a/core/java/com/android/internal/app/ResolverActivity.java +++ b/core/java/com/android/internal/app/ResolverActivity.java @@ -749,10 +749,7 @@ public class ResolverActivity extends Activity {                      }                  } else {                      try { -                        AppGlobals.getPackageManager().setLastChosenActivity(intent, -                                intent.resolveType(getContentResolver()), -                                PackageManager.MATCH_DEFAULT_ONLY, -                                filter, bestMatch, intent.getComponent()); +                        mAdapter.mResolverListController.setLastChosen(intent, filter, bestMatch);                      } catch (RemoteException re) {                          Log.d(TAG, "Error calling setLastChosenActivity\n" + re);                      } @@ -1312,10 +1309,7 @@ public class ResolverActivity extends Activity {          protected boolean rebuildList() {              List<ResolvedComponentInfo> currentResolveList = null;              try { -                final Intent primaryIntent = getTargetIntent(); -                mLastChosen = AppGlobals.getPackageManager().getLastChosenActivity( -                        primaryIntent, primaryIntent.resolveTypeIfNeeded(getContentResolver()), -                        PackageManager.MATCH_DEFAULT_ONLY); +                mLastChosen = mResolverListController.getLastChosen();              } catch (RemoteException re) {                  Log.d(TAG, "Error calling getLastChosenActivity\n" + re);              } diff --git a/core/java/com/android/internal/app/ResolverListController.java b/core/java/com/android/internal/app/ResolverListController.java index f88f6f9a07e0..00faf65d004c 100644 --- a/core/java/com/android/internal/app/ResolverListController.java +++ b/core/java/com/android/internal/app/ResolverListController.java @@ -19,13 +19,16 @@ package com.android.internal.app;  import android.annotation.WorkerThread;  import android.app.ActivityManager; +import android.app.AppGlobals;  import android.content.ComponentName;  import android.content.Context;  import android.content.Intent; +import android.content.IntentFilter;  import android.content.pm.ActivityInfo;  import android.content.pm.ApplicationInfo;  import android.content.pm.PackageManager;  import android.content.pm.ResolveInfo; +import android.os.RemoteException;  import android.util.Log;  import com.android.internal.annotations.VisibleForTesting; @@ -66,6 +69,22 @@ public class ResolverListController {      }      @VisibleForTesting +    ResolveInfo getLastChosen() throws RemoteException { +        return AppGlobals.getPackageManager().getLastChosenActivity( +                mTargetIntent, mTargetIntent.resolveTypeIfNeeded(mContext.getContentResolver()), +                PackageManager.MATCH_DEFAULT_ONLY); +    } + +    @VisibleForTesting +    void setLastChosen(Intent intent, IntentFilter filter, int match) +            throws RemoteException { +        AppGlobals.getPackageManager().setLastChosenActivity(intent, +                intent.resolveType(mContext.getContentResolver()), +                PackageManager.MATCH_DEFAULT_ONLY, +                filter, match, intent.getComponent()); +    } + +    @VisibleForTesting      public List<ResolverActivity.ResolvedComponentInfo> getResolversForIntent(              boolean shouldGetResolvedFilter,              boolean shouldGetActivityMetadata, diff --git a/core/tests/coretests/AndroidManifest.xml b/core/tests/coretests/AndroidManifest.xml index cba485a606cc..91ce7a468484 100644 --- a/core/tests/coretests/AndroidManifest.xml +++ b/core/tests/coretests/AndroidManifest.xml @@ -1168,6 +1168,7 @@          <activity android:name="android.app.EmptyActivity">          </activity>          <activity android:name="com.android.internal.app.ChooserWrapperActivity"/> +        <activity android:name="com.android.internal.app.ResolverWrapperActivity"/>          <receiver android:name="android.app.activity.AbortReceiver">              <intent-filter android:priority="1"> diff --git a/core/tests/coretests/src/com/android/internal/app/ChooserActivityTest.java b/core/tests/coretests/src/com/android/internal/app/ChooserActivityTest.java index aab4698fc49a..daebf888f715 100644 --- a/core/tests/coretests/src/com/android/internal/app/ChooserActivityTest.java +++ b/core/tests/coretests/src/com/android/internal/app/ChooserActivityTest.java @@ -222,7 +222,7 @@ public class ChooserActivityTest {      private List<ResolvedComponentInfo> createResolvedComponentsForTest(int numberOfResults) {          List<ResolvedComponentInfo> infoList = new ArrayList<>(numberOfResults);          for (int i = 0; i < numberOfResults; i++) { -            infoList.add(ChooserDataProvider.createResolvedComponentInfo(i)); +            infoList.add(ResolverDataProvider.createResolvedComponentInfo(i));          }          return infoList;      } diff --git a/core/tests/coretests/src/com/android/internal/app/ChooserWrapperActivity.java b/core/tests/coretests/src/com/android/internal/app/ChooserWrapperActivity.java index 41016e12bbf9..c446f3c79ea8 100644 --- a/core/tests/coretests/src/com/android/internal/app/ChooserWrapperActivity.java +++ b/core/tests/coretests/src/com/android/internal/app/ChooserWrapperActivity.java @@ -24,11 +24,10 @@ import java.util.function.Function;  import static org.mockito.Mockito.mock; - -/** - * Simple wrapper around chooser activity to be able to initiate it under test - */  public class ChooserWrapperActivity extends ChooserActivity { +    /* +     * Simple wrapper around chooser activity to be able to initiate it under test +     */      static final OverrideData sOverrides = new OverrideData();      private UsageStatsManager mUsm; @@ -94,4 +93,4 @@ public class ChooserWrapperActivity extends ChooserActivity {              resolverListController = mock(ResolverListController.class);          }      } -}
\ No newline at end of file +} diff --git a/core/tests/coretests/src/com/android/internal/app/ResolverActivityTest.java b/core/tests/coretests/src/com/android/internal/app/ResolverActivityTest.java new file mode 100644 index 000000000000..84b844a5b4b6 --- /dev/null +++ b/core/tests/coretests/src/com/android/internal/app/ResolverActivityTest.java @@ -0,0 +1,151 @@ +/* + * Copyright (C) 2016 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.internal.app; + +import com.android.internal.R; +import com.android.internal.app.ResolverActivity.ResolvedComponentInfo; + +import org.junit.Before; +import org.junit.Rule; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mockito; + +import android.app.usage.UsageStats; +import android.app.usage.UsageStatsManager; +import android.content.Intent; +import android.content.pm.ResolveInfo; +import android.os.UserHandle; +import android.support.test.InstrumentationRegistry; +import android.support.test.rule.ActivityTestRule; +import android.support.test.runner.AndroidJUnit4; + +import java.util.ArrayList; +import java.util.List; +import java.util.Map; + +import static android.os.SystemClock.sleep; +import static android.support.test.espresso.Espresso.onView; +import static android.support.test.espresso.action.ViewActions.click; +import static android.support.test.espresso.assertion.ViewAssertions.matches; +import static android.support.test.espresso.matcher.ViewMatchers.isDisplayed; +import static android.support.test.espresso.matcher.ViewMatchers.withId; +import static android.support.test.espresso.matcher.ViewMatchers.withText; +import static com.android.internal.app.ResolverWrapperActivity.sOverrides; +import static org.hamcrest.CoreMatchers.is; +import static org.hamcrest.CoreMatchers.not; +import static org.hamcrest.MatcherAssert.assertThat; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +/** + * Resolver activity instrumentation tests + */ +@RunWith(AndroidJUnit4.class) +public class ResolverActivityTest { +    @Rule +    public ActivityTestRule<ResolverWrapperActivity> mActivityRule = +            new ActivityTestRule<>(ResolverWrapperActivity.class, false, +                    false); + +    @Before +    public void cleanOverrideData() { +        sOverrides.reset(); +    } + +    @Test +    public void twoOptionsAndUserSelectsOne() throws InterruptedException { +        Intent sendIntent = createSendImageIntent(); +        List<ResolvedComponentInfo> resolvedComponentInfos = createResolvedComponentsForTest(2); + +        when(sOverrides.resolverListController.getResolversForIntent(Mockito.anyBoolean(), +                Mockito.anyBoolean(), +                Mockito.isA(List.class))).thenReturn(resolvedComponentInfos); + +        final ResolverWrapperActivity activity = mActivityRule.launchActivity(sendIntent); +        waitForIdle(); + +        assertThat(activity.getAdapter().getCount(), is(2)); + +        ResolveInfo[] chosen = new ResolveInfo[1]; +        sOverrides.onSafelyStartCallback = targetInfo -> { +            chosen[0] = targetInfo.getResolveInfo(); +            return true; +        }; + +        ResolveInfo toChoose = resolvedComponentInfos.get(0).getResolveInfoAt(0); +        onView(withText(toChoose.activityInfo.name)) +                .perform(click()); +        onView(withId(R.id.button_once)) +                .perform(click()); +        waitForIdle(); +        assertThat(chosen[0], is(toChoose)); +    } + +    @Test +    public void hasLastChosenActivity() throws Exception { +        Intent sendIntent = createSendImageIntent(); +        List<ResolvedComponentInfo> resolvedComponentInfos = createResolvedComponentsForTest(2); + +        when(sOverrides.resolverListController.getResolversForIntent(Mockito.anyBoolean(), +                Mockito.anyBoolean(), +                Mockito.isA(List.class))).thenReturn(resolvedComponentInfos); +        when(sOverrides.resolverListController.getLastChosen()) +                .thenReturn(resolvedComponentInfos.get(0).getResolveInfoAt(0)); + +        final ResolverWrapperActivity activity = mActivityRule.launchActivity(sendIntent); +        waitForIdle(); + +        // The other entry is filtered to the last used slot +        assertThat(activity.getAdapter().getCount(), is(1)); + +        ResolveInfo[] chosen = new ResolveInfo[1]; +        sOverrides.onSafelyStartCallback = targetInfo -> { +            chosen[0] = targetInfo.getResolveInfo(); +            return true; +        }; + +        ResolveInfo toChoose = resolvedComponentInfos.get(0).getResolveInfoAt(0); +        onView(withId(R.id.title)).perform(click()); +        onView(withId(R.id.button_once)) +                .perform(click()); +        waitForIdle(); +        assertThat(chosen[0], is(toChoose)); +    } + +    private Intent createSendImageIntent() { +        Intent sendIntent = new Intent(); +        sendIntent.setAction(Intent.ACTION_SEND); +        sendIntent.putExtra(Intent.EXTRA_TEXT, "testing intent sending"); +        sendIntent.setType("image/jpeg"); +        return sendIntent; +    } + +    private List<ResolvedComponentInfo> createResolvedComponentsForTest(int numberOfResults) { +        List<ResolvedComponentInfo> infoList = new ArrayList<>(numberOfResults); +        for (int i = 0; i < numberOfResults; i++) { +            infoList.add(ResolverDataProvider.createResolvedComponentInfo(i)); +        } +        return infoList; +    } + +    private void waitForIdle() { +        InstrumentationRegistry.getInstrumentation().waitForIdleSync(); +    } +}
\ No newline at end of file diff --git a/core/tests/coretests/src/com/android/internal/app/ChooserDataProvider.java b/core/tests/coretests/src/com/android/internal/app/ResolverDataProvider.java index f6f63f1de81e..ae063065afad 100644 --- a/core/tests/coretests/src/com/android/internal/app/ChooserDataProvider.java +++ b/core/tests/coretests/src/com/android/internal/app/ResolverDataProvider.java @@ -22,16 +22,15 @@ import android.content.pm.ActivityInfo;  import android.content.pm.ApplicationInfo;  import android.content.pm.ResolveInfo;  import android.os.UserHandle; -import android.service.chooser.ChooserTarget;  import java.util.HashMap;  import java.util.Map;  import java.util.concurrent.atomic.AtomicInteger;  /** - * Utility class used by chooser tests to create mock data + * Utility class used by resolver tests to create mock data   */ -class ChooserDataProvider { +class ResolverDataProvider {      static ResolverActivity.ResolvedComponentInfo createResolvedComponentInfo(int i) {          return new ResolverActivity.ResolvedComponentInfo(createComponentName(i), diff --git a/core/tests/coretests/src/com/android/internal/app/ResolverWrapperActivity.java b/core/tests/coretests/src/com/android/internal/app/ResolverWrapperActivity.java new file mode 100644 index 000000000000..163211e10e6a --- /dev/null +++ b/core/tests/coretests/src/com/android/internal/app/ResolverWrapperActivity.java @@ -0,0 +1,91 @@ +/* + * Copyright (C) 2017 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.internal.app; + +import android.app.usage.UsageStatsManager; +import android.content.Context; +import android.content.Intent; +import android.content.IntentFilter; +import android.content.pm.PackageManager; +import android.os.RemoteException; + +import java.util.function.Function; + +import static org.mockito.Mockito.mock; + + +/* + * Simple wrapper around chooser activity to be able to initiate it under test + */ +public class ResolverWrapperActivity extends ResolverActivity { +    static final OverrideData sOverrides = new OverrideData(); +    private UsageStatsManager mUsm; + +    ResolveListAdapter getAdapter() { +        return mAdapter; +    } + +    @Override +    public boolean isVoiceInteraction() { +        if (sOverrides.isVoiceInteraction != null) { +            return sOverrides.isVoiceInteraction; +        } +        return super.isVoiceInteraction(); +    } + +    @Override +    public void safelyStartActivity(TargetInfo cti) { +        if (sOverrides.onSafelyStartCallback != null && +                sOverrides.onSafelyStartCallback.apply(cti)) { +            return; +        } +        super.safelyStartActivity(cti); +    } + +    @Override +    protected ResolverListController createListController() { +        return sOverrides.resolverListController; +    } + +    @Override +    public PackageManager getPackageManager() { +        if (sOverrides.createPackageManager != null) { +            return sOverrides.createPackageManager.apply(super.getPackageManager()); +        } +        return super.getPackageManager(); +    } + +    /** +     * We cannot directly mock the activity created since instrumentation creates it. +     * <p> +     * Instead, we use static instances of this object to modify behavior. +     */ +    static class OverrideData { +        @SuppressWarnings("Since15") +        public Function<PackageManager, PackageManager> createPackageManager; +        public Function<TargetInfo, Boolean> onSafelyStartCallback; +        public ResolverListController resolverListController; +        public Boolean isVoiceInteraction; + +        public void reset() { +            onSafelyStartCallback = null; +            isVoiceInteraction = null; +            createPackageManager = null; +            resolverListController = mock(ResolverListController.class); +        } +    } +}
\ No newline at end of file |