summaryrefslogtreecommitdiff
path: root/java/tests
diff options
context:
space:
mode:
author Joshua Trask <joshtrask@google.com> 2021-12-21 16:40:22 -0500
committer Matt Casey <mrcasey@google.com> 2022-01-19 17:20:53 -0500
commit5312de584408f56ede119bfbc094b39a090969be (patch)
tree6412b220fe4c389155c82a19d988bf2e0a7ab03b /java/tests
parentbd05901f4029112b525732215c430f2bcc3ddfe4 (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.bp9
-rw-r--r--java/tests/AndroidManifest.xml9
-rw-r--r--java/tests/src/com/android/intentresolver/ChooserWrapperActivity.java273
-rw-r--r--java/tests/src/com/android/intentresolver/UnbundledChooserActivityTest.java120
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();
+ }
+}