Merge "Decompose ChooserActivityTest for reuse."

This commit is contained in:
Joshua Trask
2021-12-20 20:20:42 +00:00
committed by Android (Google) Code Review
5 changed files with 884 additions and 397 deletions

View File

@@ -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",
],
}

View File

@@ -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() {}
}

View File

@@ -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;
}
};
}
}
}

View File

@@ -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();
}