diff options
| author | 2021-12-21 16:40:22 -0500 | |
|---|---|---|
| committer | 2022-01-19 17:20:53 -0500 | |
| commit | 5312de584408f56ede119bfbc094b39a090969be (patch) | |
| tree | 6412b220fe4c389155c82a19d988bf2e0a7ab03b /java/tests | |
| parent | bd05901f4029112b525732215c430f2bcc3ddfe4 (diff) | |
Initial (inherited) tests for unbundled chooser.
This required disabling the #testEditImageLogs method in the base
class (ag/16520095) due to what could be a legitimate failure in the
unbundled implementation; we should investigate imminently.
Note this only brings the tests up to parity with the system
implementation - existing issues in the system ChooserActivityTest (e.g.
b/211669337) will presumably still occur in the unbundled version.
No test flakes are known to be specific to unbundling (among those that
are enabled after ag/16520095).
Bug: 202165481,211669337
Test: `atest UnbundledChooserActivityTest`
Change-Id: If8e2b896627661e59fa4a85aa3dd1eedb8eb91bc
Diffstat (limited to 'java/tests')
| -rw-r--r-- | java/tests/Android.bp | 9 | ||||
| -rw-r--r-- | java/tests/AndroidManifest.xml | 9 | ||||
| -rw-r--r-- | java/tests/src/com/android/intentresolver/ChooserWrapperActivity.java | 273 | ||||
| -rw-r--r-- | java/tests/src/com/android/intentresolver/UnbundledChooserActivityTest.java | 120 |
4 files changed, 406 insertions, 5 deletions
diff --git a/java/tests/Android.bp b/java/tests/Android.bp index fc78a604..fdabc4e0 100644 --- a/java/tests/Android.bp +++ b/java/tests/Android.bp @@ -13,10 +13,13 @@ android_test { "android.test.runner", "android.test.base", "android.test.mock", + "framework", + "framework-res", ], static_libs: [ "IntentResolver-core", + "ChooserActivityTestsLib", "androidx.test.rules", "mockito-target-minus-junit4", "androidx.test.espresso.core", @@ -24,10 +27,10 @@ android_test { "testables", "testng", ], - jni_libs: [ - ], test_suites: ["general-tests"], - min_sdk_version: "30", + sdk_version: "core_platform", platform_apis: true, compile_multilib: "both", + + dont_merge_manifests: true, } diff --git a/java/tests/AndroidManifest.xml b/java/tests/AndroidManifest.xml index faf55ecf..1c7506b6 100644 --- a/java/tests/AndroidManifest.xml +++ b/java/tests/AndroidManifest.xml @@ -17,12 +17,17 @@ <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.android.intentresolver.tests"> - <uses-sdk android:minSdkVersion="21" android:targetSdkVersion="21" /> + <uses-sdk android:minSdkVersion="21" android:targetSdkVersion="30" /> - <uses-permission android:name="android.permission.START_ACTIVITY_AS_CALLER"/> + <uses-permission android:name="android.permission.INTERACT_ACROSS_USERS_FULL"/> + <uses-permission android:name="android.permission.QUERY_USERS"/> + <uses-permission android:name="android.permission.READ_CLIPBOARD_IN_BACKGROUND"/> + <uses-permission android:name="android.permission.WRITE_DEVICE_CONFIG"/> <application> <uses-library android:name="android.test.runner" /> + <activity android:name="com.android.intentresolver.ChooserWrapperActivity" /> + <activity android:name="com.android.internal.app.ChooserWrapperActivity" /> </application> <instrumentation android:name="android.testing.TestableInstrumentation" diff --git a/java/tests/src/com/android/intentresolver/ChooserWrapperActivity.java b/java/tests/src/com/android/intentresolver/ChooserWrapperActivity.java new file mode 100644 index 00000000..552b4e0d --- /dev/null +++ b/java/tests/src/com/android/intentresolver/ChooserWrapperActivity.java @@ -0,0 +1,273 @@ +/* + * Copyright (C) 2008 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 static org.mockito.Mockito.when; + +import android.annotation.Nullable; +import android.app.usage.UsageStatsManager; +import android.content.ComponentName; +import android.content.ContentResolver; +import android.content.Context; +import android.content.Intent; +import android.content.pm.PackageManager; +import android.content.pm.ResolveInfo; +import android.content.res.Resources; +import android.database.Cursor; +import android.graphics.Bitmap; +import android.net.Uri; +import android.os.UserHandle; +import android.util.Size; + +import com.android.internal.app.AbstractMultiProfilePagerAdapter; +import com.android.internal.app.ChooserActivityLogger; +import com.android.internal.app.ChooserActivityOverrideData; +import com.android.internal.app.ChooserListAdapter; +import com.android.internal.app.IChooserWrapper; +import com.android.internal.app.ResolverListAdapter.ResolveInfoPresentationGetter; +import com.android.internal.app.ResolverListController; +import com.android.internal.app.chooser.DisplayResolveInfo; +import com.android.internal.app.chooser.TargetInfo; +import com.android.internal.logging.MetricsLogger; +import com.android.internal.logging.nano.MetricsProto.MetricsEvent; + +import java.util.List; + +/** + * Simple wrapper around chooser activity to be able to initiate it under test. For more + * information, see {@code com.android.internal.app.ChooserWrapperActivity}. + */ +public class ChooserWrapperActivity + extends com.android.intentresolver.ChooserActivity implements IChooserWrapper { + static final ChooserActivityOverrideData sOverrides = ChooserActivityOverrideData.getInstance(); + private UsageStatsManager mUsm; + + // ResolverActivity (the base class of ChooserActivity) inspects the launched-from UID at + // onCreate and needs to see some non-negative value in the test. + @Override + public int getLaunchedFromUid() { + return 1234; + } + + @Override + protected AbstractMultiProfilePagerAdapter createMultiProfilePagerAdapter( + Intent[] initialIntents, List<ResolveInfo> rList, boolean filterLastUsed) { + AbstractMultiProfilePagerAdapter multiProfilePagerAdapter = + super.createMultiProfilePagerAdapter(initialIntents, rList, filterLastUsed); + multiProfilePagerAdapter.setInjector(sOverrides.multiPagerAdapterInjector); + return multiProfilePagerAdapter; + } + + @Override + public ChooserListAdapter createChooserListAdapter(Context context, List<Intent> payloadIntents, + Intent[] initialIntents, List<ResolveInfo> rList, boolean filterLastUsed, + ResolverListController resolverListController) { + PackageManager packageManager = + sOverrides.packageManager == null ? context.getPackageManager() + : sOverrides.packageManager; + return new ChooserListAdapter(context, payloadIntents, initialIntents, rList, + filterLastUsed, resolverListController, + this, this, packageManager, + getChooserActivityLogger()); + } + + @Override + public ChooserListAdapter getAdapter() { + return mChooserMultiProfilePagerAdapter.getActiveListAdapter(); + } + + @Override + public ChooserListAdapter getPersonalListAdapter() { + return ((ChooserGridAdapter) mMultiProfilePagerAdapter.getAdapterForIndex(0)) + .getListAdapter(); + } + + @Override + public ChooserListAdapter getWorkListAdapter() { + if (mMultiProfilePagerAdapter.getInactiveListAdapter() == null) { + return null; + } + return ((ChooserGridAdapter) mMultiProfilePagerAdapter.getAdapterForIndex(1)) + .getListAdapter(); + } + + @Override + public boolean getIsSelected() { + return mIsSuccessfullySelected; + } + + @Override + protected ComponentName getNearbySharingComponent() { + // an arbitrary pre-installed activity that handles this type of intent + return ComponentName.unflattenFromString("com.google.android.apps.messaging/" + + "com.google.android.apps.messaging.ui.conversationlist.ShareIntentActivity"); + } + + @Override + protected TargetInfo getNearbySharingTarget(Intent originalIntent) { + return new ChooserWrapperActivity.EmptyTargetInfo(); + } + + @Override + public UsageStatsManager getUsageStatsManager() { + if (mUsm == null) { + mUsm = getSystemService(UsageStatsManager.class); + } + return mUsm; + } + + @Override + public boolean isVoiceInteraction() { + if (sOverrides.isVoiceInteraction != null) { + return sOverrides.isVoiceInteraction; + } + return super.isVoiceInteraction(); + } + + @Override + public void safelyStartActivity(com.android.internal.app.chooser.TargetInfo cti) { + if (sOverrides.onSafelyStartCallback != null + && sOverrides.onSafelyStartCallback.apply(cti)) { + return; + } + super.safelyStartActivity(cti); + } + + @Override + protected ResolverListController createListController(UserHandle userHandle) { + if (userHandle == UserHandle.SYSTEM) { + when(sOverrides.resolverListController.getUserHandle()).thenReturn(UserHandle.SYSTEM); + return sOverrides.resolverListController; + } + when(sOverrides.workResolverListController.getUserHandle()).thenReturn(userHandle); + return sOverrides.workResolverListController; + } + + @Override + public PackageManager getPackageManager() { + if (sOverrides.createPackageManager != null) { + return sOverrides.createPackageManager.apply(super.getPackageManager()); + } + return super.getPackageManager(); + } + + @Override + public Resources getResources() { + if (sOverrides.resources != null) { + return sOverrides.resources; + } + return super.getResources(); + } + + @Override + protected Bitmap loadThumbnail(Uri uri, Size size) { + if (sOverrides.previewThumbnail != null) { + return sOverrides.previewThumbnail; + } + return super.loadThumbnail(uri, size); + } + + @Override + protected boolean isImageType(String mimeType) { + return sOverrides.isImageType; + } + + @Override + protected MetricsLogger getMetricsLogger() { + return sOverrides.metricsLogger; + } + + @Override + public ChooserActivityLogger getChooserActivityLogger() { + return sOverrides.chooserActivityLogger; + } + + @Override + public Cursor queryResolver(ContentResolver resolver, Uri uri) { + if (sOverrides.resolverCursor != null) { + return sOverrides.resolverCursor; + } + + if (sOverrides.resolverForceException) { + throw new SecurityException("Test exception handling"); + } + + return super.queryResolver(resolver, uri); + } + + @Override + protected boolean isWorkProfile() { + if (sOverrides.alternateProfileSetting != 0) { + return sOverrides.alternateProfileSetting == MetricsEvent.MANAGED_PROFILE; + } + return super.isWorkProfile(); + } + + @Override + public DisplayResolveInfo createTestDisplayResolveInfo(Intent originalIntent, ResolveInfo pri, + CharSequence pLabel, CharSequence pInfo, Intent replacementIntent, + @Nullable ResolveInfoPresentationGetter resolveInfoPresentationGetter) { + return new DisplayResolveInfo(originalIntent, pri, pLabel, pInfo, replacementIntent, + resolveInfoPresentationGetter); + } + + @Override + protected UserHandle getWorkProfileUserHandle() { + return sOverrides.workProfileUserHandle; + } + + @Override + public UserHandle getCurrentUserHandle() { + return mMultiProfilePagerAdapter.getCurrentUserHandle(); + } + + @Override + public Context createContextAsUser(UserHandle user, int flags) { + // return the current context as a work profile doesn't really exist in these tests + return getApplicationContext(); + } + + @Override + protected void queryDirectShareTargets(ChooserListAdapter adapter, + boolean skipAppPredictionService) { + if (sOverrides.onQueryDirectShareTargets != null) { + sOverrides.onQueryDirectShareTargets.apply(adapter); + } + super.queryDirectShareTargets(adapter, skipAppPredictionService); + } + + @Override + protected boolean isQuietModeEnabled(UserHandle userHandle) { + return sOverrides.isQuietModeEnabled; + } + + @Override + protected boolean isUserRunning(UserHandle userHandle) { + if (userHandle.equals(UserHandle.SYSTEM)) { + return super.isUserRunning(userHandle); + } + return sOverrides.isWorkProfileUserRunning; + } + + @Override + protected boolean isUserUnlocked(UserHandle userHandle) { + if (userHandle.equals(UserHandle.SYSTEM)) { + return super.isUserUnlocked(userHandle); + } + return sOverrides.isWorkProfileUserUnlocked; + } +} diff --git a/java/tests/src/com/android/intentresolver/UnbundledChooserActivityTest.java b/java/tests/src/com/android/intentresolver/UnbundledChooserActivityTest.java new file mode 100644 index 00000000..c88fc53d --- /dev/null +++ b/java/tests/src/com/android/intentresolver/UnbundledChooserActivityTest.java @@ -0,0 +1,120 @@ +/* + * Copyright (C) 2021 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 static com.google.common.truth.Truth.assertThat; + +import static org.mockito.Mockito.when; + +import android.app.ActivityTaskManager; +import android.content.Context; +import android.content.Intent; +import android.content.pm.PackageManager; +import android.os.Binder; + +import androidx.test.platform.app.InstrumentationRegistry; + +import com.android.internal.app.ChooserActivity; +import com.android.internal.app.ChooserActivityOverrideData; +import com.android.internal.app.ChooserActivityTest; + +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.Parameterized; +import org.mockito.Mockito; + +import java.util.Arrays; +import java.util.Collection; +import java.util.function.Function; + +@RunWith(Parameterized.class) +public class UnbundledChooserActivityTest extends ChooserActivityTest { + private static final Function<PackageManager, PackageManager> DEFAULT_PM = pm -> pm; + private static final Function<PackageManager, PackageManager> NO_APP_PREDICTION_SERVICE_PM = + pm -> { + PackageManager mock = Mockito.spy(pm); + when(mock.getAppPredictionServicePackageName()).thenReturn(null); + return mock; + }; + + @Parameterized.Parameters + public static Collection packageManagers() { + return Arrays.asList(new Object[][] { + {0, "Default PackageManager", DEFAULT_PM}, + {1, "No App Prediction Service", NO_APP_PREDICTION_SERVICE_PM} + }); + } + + @Override + protected Intent getConcreteIntentForLaunch(Intent clientIntent) { + Context context = InstrumentationRegistry.getInstrumentation().getTargetContext(); + clientIntent.setClass(context, com.android.intentresolver.ChooserWrapperActivity.class); + + clientIntent.putExtra(ActivityTaskManager.EXTRA_PERMISSION_TOKEN, new Binder()); + + PackageManager pm = ChooserActivityOverrideData.getInstance().createPackageManager + .apply(context.getPackageManager()); + clientIntent.putExtra( + ChooserActivity.EXTRA_IS_APP_PREDICTION_SERVICE_AVAILABLE, + (pm.getAppPredictionServicePackageName() != null)); + return clientIntent; + } + + @Override + protected boolean shouldTestTogglingAppPredictionServiceAvailabilityAtRuntime() { + // Unbundled chooser takes in app prediction availability as a parameter from the system, so + // changing the availability conditions after the fact won't make a difference. + return false; + } + + @Override + protected void setup() { + // TODO: use the other form of `adoptShellPermissionIdentity()` where we explicitly list the + // permissions we require (which we'll read from the manifest at runtime). + InstrumentationRegistry + .getInstrumentation() + .getUiAutomation() + .adoptShellPermissionIdentity(); + + super.setup(); + } + + public UnbundledChooserActivityTest( + int testNum, + String testName, + Function<PackageManager, PackageManager> packageManagerOverride) { + super(testNum, testName, packageManagerOverride); + } + + /* This is a "test of a test" to make sure that our inherited test class + * is successfully configured to operate on the unbundled-equivalent + * ChooserWrapperActivity. + * + * TODO: remove after unbundling is complete. + */ + @Test + public void testWrapperActivityHasExpectedConcreteType() { + final ChooserActivity activity = mActivityRule.launchActivity( + Intent.createChooser(new Intent("ACTION_FOO"), "foo")); + waitForIdle(); + assertThat(activity).isInstanceOf(com.android.intentresolver.ChooserWrapperActivity.class); + } + + private void waitForIdle() { + InstrumentationRegistry.getInstrumentation().waitForIdleSync(); + } +} |