Decompose ChooserActivityTest for reuse.
Prepare build targets and set up design to share test suite across different ChooserActivity subclasses. (This was somewhat tricky because the tests need to use wrapped activities for instrumentation; those activities need to have the same inheritance relationship with ChooserActivity as the chooser-under-test would normally have; and shared test code needs to use a common type to refer to the wrapped activities.) Test: `atest ChooserActivityTest` (modulo standing flakes); also tested a proof-of-concept unbundled version locally (CL to follow). Bug: 202166045 Change-Id: I8dc317ed9fac7195e525d62fdd386dcf11ef7dba
This commit is contained in:
@@ -138,3 +138,39 @@ java_genrule {
|
||||
"done && " +
|
||||
"$(location soong_zip) -o $(out) -C $(genDir)/res -D $(genDir)/res",
|
||||
}
|
||||
|
||||
// In addition to running as part of FrameworksCoreTests, we run (a subclass of)
|
||||
// ChooserActivityTest against the unbundled ChooserActivity implementation in
|
||||
// //packages/modules/IntentResolver/. The following library provides the
|
||||
// minimum dependencies required to build that test in the unbundled package.
|
||||
android_library {
|
||||
name: "ChooserActivityTestsLib",
|
||||
visibility: ["//packages/modules/IntentResolver/java/tests:__pkg__"],
|
||||
|
||||
srcs: [
|
||||
"src/com/android/internal/app/ChooserActivityLoggerFake.java",
|
||||
"src/com/android/internal/app/ChooserActivityOverrideData.java",
|
||||
"src/com/android/internal/app/ChooserActivityTest.java",
|
||||
"src/com/android/internal/app/ChooserWrapperActivity.java",
|
||||
"src/com/android/internal/app/IChooserWrapper.java",
|
||||
"src/com/android/internal/app/MatcherUtils.java",
|
||||
"src/com/android/internal/app/ResolverDataProvider.java",
|
||||
],
|
||||
|
||||
static_libs: [
|
||||
"androidx.test.espresso.core",
|
||||
"androidx.test.ext.junit",
|
||||
"androidx.test.runner",
|
||||
"androidx.test.rules",
|
||||
"mockito-target-minus-junit4",
|
||||
"truth-prebuilt",
|
||||
],
|
||||
|
||||
libs: [
|
||||
"android.test.runner",
|
||||
"android.test.base",
|
||||
"android.test.mock",
|
||||
"framework",
|
||||
"framework-res",
|
||||
],
|
||||
}
|
||||
@@ -0,0 +1,115 @@
|
||||
/*
|
||||
* 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.internal.app;
|
||||
|
||||
import static org.mockito.Mockito.mock;
|
||||
|
||||
import android.content.Intent;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.content.res.Resources;
|
||||
import android.database.Cursor;
|
||||
import android.graphics.Bitmap;
|
||||
import android.os.UserHandle;
|
||||
|
||||
import com.android.internal.app.chooser.TargetInfo;
|
||||
import com.android.internal.logging.MetricsLogger;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.function.Function;
|
||||
|
||||
/**
|
||||
* Singleton providing overrides to be applied by any {@code IChooserWrapper} used in testing.
|
||||
* We cannot directly mock the activity created since instrumentation creates it, so instead we use
|
||||
* this singleton to modify behavior.
|
||||
*/
|
||||
public class ChooserActivityOverrideData {
|
||||
private static ChooserActivityOverrideData sInstance = null;
|
||||
|
||||
public static ChooserActivityOverrideData getInstance() {
|
||||
if (sInstance == null) {
|
||||
sInstance = new ChooserActivityOverrideData();
|
||||
}
|
||||
return sInstance;
|
||||
}
|
||||
|
||||
@SuppressWarnings("Since15")
|
||||
public Function<PackageManager, PackageManager> createPackageManager;
|
||||
public Function<TargetInfo, Boolean> onSafelyStartCallback;
|
||||
public Function<ChooserListAdapter, Void> onQueryDirectShareTargets;
|
||||
public ResolverListController resolverListController;
|
||||
public ResolverListController workResolverListController;
|
||||
public Boolean isVoiceInteraction;
|
||||
public boolean isImageType;
|
||||
public Cursor resolverCursor;
|
||||
public boolean resolverForceException;
|
||||
public Bitmap previewThumbnail;
|
||||
public MetricsLogger metricsLogger;
|
||||
public ChooserActivityLogger chooserActivityLogger;
|
||||
public int alternateProfileSetting;
|
||||
public Resources resources;
|
||||
public UserHandle workProfileUserHandle;
|
||||
public boolean hasCrossProfileIntents;
|
||||
public boolean isQuietModeEnabled;
|
||||
public boolean isWorkProfileUserRunning;
|
||||
public boolean isWorkProfileUserUnlocked;
|
||||
public AbstractMultiProfilePagerAdapter.Injector multiPagerAdapterInjector;
|
||||
public PackageManager packageManager;
|
||||
|
||||
public void reset() {
|
||||
onSafelyStartCallback = null;
|
||||
onQueryDirectShareTargets = null;
|
||||
isVoiceInteraction = null;
|
||||
createPackageManager = null;
|
||||
previewThumbnail = null;
|
||||
isImageType = false;
|
||||
resolverCursor = null;
|
||||
resolverForceException = false;
|
||||
resolverListController = mock(ResolverListController.class);
|
||||
workResolverListController = mock(ResolverListController.class);
|
||||
metricsLogger = mock(MetricsLogger.class);
|
||||
chooserActivityLogger = new ChooserActivityLoggerFake();
|
||||
alternateProfileSetting = 0;
|
||||
resources = null;
|
||||
workProfileUserHandle = null;
|
||||
hasCrossProfileIntents = true;
|
||||
isQuietModeEnabled = false;
|
||||
isWorkProfileUserRunning = true;
|
||||
isWorkProfileUserUnlocked = true;
|
||||
packageManager = null;
|
||||
multiPagerAdapterInjector = new AbstractMultiProfilePagerAdapter.Injector() {
|
||||
@Override
|
||||
public boolean hasCrossProfileIntents(List<Intent> intents, int sourceUserId,
|
||||
int targetUserId) {
|
||||
return hasCrossProfileIntents;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isQuietModeEnabled(UserHandle workProfileUserHandle) {
|
||||
return isQuietModeEnabled;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void requestQuietModeEnabled(boolean enabled,
|
||||
UserHandle workProfileUserHandle) {
|
||||
isQuietModeEnabled = enabled;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
private ChooserActivityOverrideData() {}
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -16,7 +16,6 @@
|
||||
|
||||
package com.android.internal.app;
|
||||
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
import android.annotation.Nullable;
|
||||
@@ -41,13 +40,15 @@ import com.android.internal.logging.MetricsLogger;
|
||||
import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.function.Function;
|
||||
|
||||
public class ChooserWrapperActivity extends ChooserActivity {
|
||||
/*
|
||||
* Simple wrapper around chooser activity to be able to initiate it under test
|
||||
*/
|
||||
static final OverrideData sOverrides = new OverrideData();
|
||||
/**
|
||||
* Simple wrapper around chooser activity to be able to initiate it under test with overrides
|
||||
* specified in the {@code ChooserActivityOverrideData} singleton. This should be copy-and-pasted
|
||||
* verbatim to test other {@code ChooserActivity} subclasses (updating only the `extends` to match
|
||||
* the concrete activity under test).
|
||||
*/
|
||||
public class ChooserWrapperActivity extends ChooserActivity implements IChooserWrapper {
|
||||
static final ChooserActivityOverrideData sOverrides = ChooserActivityOverrideData.getInstance();
|
||||
private UsageStatsManager mUsm;
|
||||
|
||||
@Override
|
||||
@@ -72,16 +73,19 @@ public class ChooserWrapperActivity extends ChooserActivity {
|
||||
getChooserActivityLogger());
|
||||
}
|
||||
|
||||
ChooserListAdapter getAdapter() {
|
||||
@Override
|
||||
public ChooserListAdapter getAdapter() {
|
||||
return mChooserMultiProfilePagerAdapter.getActiveListAdapter();
|
||||
}
|
||||
|
||||
ChooserListAdapter getPersonalListAdapter() {
|
||||
@Override
|
||||
public ChooserListAdapter getPersonalListAdapter() {
|
||||
return ((ChooserGridAdapter) mMultiProfilePagerAdapter.getAdapterForIndex(0))
|
||||
.getListAdapter();
|
||||
}
|
||||
|
||||
ChooserListAdapter getWorkListAdapter() {
|
||||
@Override
|
||||
public ChooserListAdapter getWorkListAdapter() {
|
||||
if (mMultiProfilePagerAdapter.getInactiveListAdapter() == null) {
|
||||
return null;
|
||||
}
|
||||
@@ -89,7 +93,10 @@ public class ChooserWrapperActivity extends ChooserActivity {
|
||||
.getListAdapter();
|
||||
}
|
||||
|
||||
boolean getIsSelected() { return mIsSuccessfullySelected; }
|
||||
@Override
|
||||
public boolean getIsSelected() {
|
||||
return mIsSuccessfullySelected;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected ComponentName getNearbySharingComponent() {
|
||||
@@ -103,7 +110,8 @@ public class ChooserWrapperActivity extends ChooserActivity {
|
||||
return new ChooserWrapperActivity.EmptyTargetInfo();
|
||||
}
|
||||
|
||||
UsageStatsManager getUsageStatsManager() {
|
||||
@Override
|
||||
public UsageStatsManager getUsageStatsManager() {
|
||||
if (mUsm == null) {
|
||||
mUsm = (UsageStatsManager) getSystemService(Context.USAGE_STATS_SERVICE);
|
||||
}
|
||||
@@ -172,7 +180,7 @@ public class ChooserWrapperActivity extends ChooserActivity {
|
||||
}
|
||||
|
||||
@Override
|
||||
protected ChooserActivityLogger getChooserActivityLogger() {
|
||||
public ChooserActivityLogger getChooserActivityLogger() {
|
||||
return sOverrides.chooserActivityLogger;
|
||||
}
|
||||
|
||||
@@ -197,6 +205,7 @@ public class ChooserWrapperActivity extends ChooserActivity {
|
||||
return super.isWorkProfile();
|
||||
}
|
||||
|
||||
@Override
|
||||
public DisplayResolveInfo createTestDisplayResolveInfo(Intent originalIntent, ResolveInfo pri,
|
||||
CharSequence pLabel, CharSequence pInfo, Intent replacementIntent,
|
||||
@Nullable ResolveInfoPresentationGetter resolveInfoPresentationGetter) {
|
||||
@@ -209,7 +218,8 @@ public class ChooserWrapperActivity extends ChooserActivity {
|
||||
return sOverrides.workProfileUserHandle;
|
||||
}
|
||||
|
||||
protected UserHandle getCurrentUserHandle() {
|
||||
@Override
|
||||
public UserHandle getCurrentUserHandle() {
|
||||
return mMultiProfilePagerAdapter.getCurrentUserHandle();
|
||||
}
|
||||
|
||||
@@ -248,75 +258,4 @@ public class ChooserWrapperActivity extends ChooserActivity {
|
||||
}
|
||||
return sOverrides.isWorkProfileUserUnlocked;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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 Function<ChooserListAdapter, Void> onQueryDirectShareTargets;
|
||||
public ResolverListController resolverListController;
|
||||
public ResolverListController workResolverListController;
|
||||
public Boolean isVoiceInteraction;
|
||||
public boolean isImageType;
|
||||
public Cursor resolverCursor;
|
||||
public boolean resolverForceException;
|
||||
public Bitmap previewThumbnail;
|
||||
public MetricsLogger metricsLogger;
|
||||
public ChooserActivityLogger chooserActivityLogger;
|
||||
public int alternateProfileSetting;
|
||||
public Resources resources;
|
||||
public UserHandle workProfileUserHandle;
|
||||
public boolean hasCrossProfileIntents;
|
||||
public boolean isQuietModeEnabled;
|
||||
public boolean isWorkProfileUserRunning;
|
||||
public boolean isWorkProfileUserUnlocked;
|
||||
public AbstractMultiProfilePagerAdapter.Injector multiPagerAdapterInjector;
|
||||
public PackageManager packageManager;
|
||||
|
||||
public void reset() {
|
||||
onSafelyStartCallback = null;
|
||||
onQueryDirectShareTargets = null;
|
||||
isVoiceInteraction = null;
|
||||
createPackageManager = null;
|
||||
previewThumbnail = null;
|
||||
isImageType = false;
|
||||
resolverCursor = null;
|
||||
resolverForceException = false;
|
||||
resolverListController = mock(ResolverListController.class);
|
||||
workResolverListController = mock(ResolverListController.class);
|
||||
metricsLogger = mock(MetricsLogger.class);
|
||||
chooserActivityLogger = new ChooserActivityLoggerFake();
|
||||
alternateProfileSetting = 0;
|
||||
resources = null;
|
||||
workProfileUserHandle = null;
|
||||
hasCrossProfileIntents = true;
|
||||
isQuietModeEnabled = false;
|
||||
isWorkProfileUserRunning = true;
|
||||
isWorkProfileUserUnlocked = true;
|
||||
packageManager = null;
|
||||
multiPagerAdapterInjector = new AbstractMultiProfilePagerAdapter.Injector() {
|
||||
@Override
|
||||
public boolean hasCrossProfileIntents(List<Intent> intents, int sourceUserId,
|
||||
int targetUserId) {
|
||||
return hasCrossProfileIntents;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isQuietModeEnabled(UserHandle workProfileUserHandle) {
|
||||
return isQuietModeEnabled;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void requestQuietModeEnabled(boolean enabled,
|
||||
UserHandle workProfileUserHandle) {
|
||||
isQuietModeEnabled = enabled;
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,44 @@
|
||||
/*
|
||||
* 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.internal.app;
|
||||
|
||||
import android.annotation.Nullable;
|
||||
import android.app.usage.UsageStatsManager;
|
||||
import android.content.Intent;
|
||||
import android.content.pm.ResolveInfo;
|
||||
import android.os.UserHandle;
|
||||
|
||||
import com.android.internal.app.ResolverListAdapter.ResolveInfoPresentationGetter;
|
||||
import com.android.internal.app.chooser.DisplayResolveInfo;
|
||||
|
||||
/**
|
||||
* Test-only extended API capabilities that an instrumented ChooserActivity subclass provides in
|
||||
* order to expose the internals for override/inspection. Implementations should apply the overrides
|
||||
* specified by the {@code ChooserActivityOverrideData} singleton.
|
||||
*/
|
||||
public interface IChooserWrapper {
|
||||
ChooserListAdapter getAdapter();
|
||||
ChooserListAdapter getPersonalListAdapter();
|
||||
ChooserListAdapter getWorkListAdapter();
|
||||
boolean getIsSelected();
|
||||
UsageStatsManager getUsageStatsManager();
|
||||
DisplayResolveInfo createTestDisplayResolveInfo(Intent originalIntent, ResolveInfo pri,
|
||||
CharSequence pLabel, CharSequence pInfo, Intent replacementIntent,
|
||||
@Nullable ResolveInfoPresentationGetter resolveInfoPresentationGetter);
|
||||
UserHandle getCurrentUserHandle();
|
||||
ChooserActivityLogger getChooserActivityLogger();
|
||||
}
|
||||
Reference in New Issue
Block a user