summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
author Govinda Wasserman <gwasserman@google.com> 2023-11-03 18:17:04 +0000
committer Android (Google) Code Review <android-gerrit@google.com> 2023-11-03 18:17:04 +0000
commit80118c7a461a6111829ddbc5c44931044d00e9fd (patch)
treeb60fec852b9e1396304b9ae6a1cbb4fe346acb30
parentff782b33b49466a2816cbf73abbe05a69483eec1 (diff)
parent0842d845019153cc7138b0208a9eca0b5ac73784 (diff)
Merge changes If064e760,Idb7a269c into main
* changes: Moves AnnotatedUserHandles to ActivityLogic Moves theme and profile switch message to ActivityLogic
-rw-r--r--java/src/com/android/intentresolver/v2/ActivityLogic.kt79
-rw-r--r--java/src/com/android/intentresolver/v2/ChooserActivity.java125
-rw-r--r--java/src/com/android/intentresolver/v2/ChooserActivityLogic.kt27
-rw-r--r--java/src/com/android/intentresolver/v2/ResolverActivity.java171
-rw-r--r--java/src/com/android/intentresolver/v2/ResolverActivityLogic.kt14
-rw-r--r--java/src/com/android/intentresolver/v2/util/MutableLazy.kt36
-rw-r--r--java/tests/src/com/android/intentresolver/v2/ChooserWrapperActivity.java17
-rw-r--r--java/tests/src/com/android/intentresolver/v2/ResolverWrapperActivity.java12
-rw-r--r--java/tests/src/com/android/intentresolver/v2/TestChooserActivityLogic.kt25
-rw-r--r--java/tests/src/com/android/intentresolver/v2/TestResolverActivityLogic.kt16
10 files changed, 337 insertions, 185 deletions
diff --git a/java/src/com/android/intentresolver/v2/ActivityLogic.kt b/java/src/com/android/intentresolver/v2/ActivityLogic.kt
index 0613882e..e5b89dfa 100644
--- a/java/src/com/android/intentresolver/v2/ActivityLogic.kt
+++ b/java/src/com/android/intentresolver/v2/ActivityLogic.kt
@@ -1,10 +1,18 @@
package com.android.intentresolver.v2
import android.app.Activity
+import android.app.admin.DevicePolicyManager
+import android.app.admin.DevicePolicyResources.Strings.Core.FORWARD_INTENT_TO_PERSONAL
+import android.app.admin.DevicePolicyResources.Strings.Core.FORWARD_INTENT_TO_WORK
import android.content.Context
import android.content.Intent
import android.net.Uri
+import android.os.UserHandle
+import android.os.UserManager
+import android.util.Log
import androidx.activity.ComponentActivity
+import com.android.intentresolver.AnnotatedUserHandles
+import com.android.intentresolver.R
import com.android.intentresolver.icons.TargetDataLoader
/**
@@ -30,11 +38,20 @@ interface ActivityLogic : CommonActivityLogic {
val supportsAlwaysUseOption: Boolean
/** Fetches display info for processed candidates. */
val targetDataLoader: TargetDataLoader
+ /** The theme to use. */
+ val themeResId: Int
+ /**
+ * Message showing that intent is forwarded from managed profile to owner or other way around.
+ */
+ val profileSwitchMessage: String?
/**
* Called after Activity superclass creation, but before any other onCreate logic is performed.
*/
fun preInitialization()
+
+ /** Sets [profileSwitchMessage] to null */
+ fun clearProfileSwitchMessage()
}
/**
@@ -42,10 +59,21 @@ interface ActivityLogic : CommonActivityLogic {
* activities (including test activities), should live here.
*/
interface CommonActivityLogic {
+ /** The tag to use when logging. */
+ val tag: String
/** A reference to the activity owning, and used by, this logic. */
val activity: ComponentActivity
/** The name of the referring package. */
val referrerPackageName: String?
+ /** User manager system service. */
+ val userManager: UserManager
+ /** Device policy manager system service. */
+ val devicePolicyManager: DevicePolicyManager
+ /** Current [UserHandle]s retrievable by type. */
+ val annotatedUserHandles: AnnotatedUserHandles?
+
+ /** Returns display message indicating intent forwarding or null if not intent forwarding. */
+ fun forwardMessageFor(intent: Intent): String?
// TODO: For some reason the IDE complains about getting Activity fields from a
// ComponentActivity. These are a band-aid until the bug is fixed and should be removed when
@@ -60,7 +88,10 @@ interface CommonActivityLogic {
* [ActivityLogic] implementations. Test implementations of [ActivityLogic] may need to create their
* own [CommonActivityLogic] implementation.
*/
-class CommonActivityLogicImpl(activityProvider: () -> ComponentActivity) : CommonActivityLogic {
+class CommonActivityLogicImpl(
+ override val tag: String,
+ activityProvider: () -> ComponentActivity,
+) : CommonActivityLogic {
override val activity: ComponentActivity by lazy { activityProvider() }
@@ -74,6 +105,52 @@ class CommonActivityLogicImpl(activityProvider: () -> ComponentActivity) : Commo
}
}
+ override val userManager: UserManager by lazy {
+ activity.context.getSystemService(Context.USER_SERVICE) as UserManager
+ }
+
+ override val devicePolicyManager: DevicePolicyManager by lazy {
+ activity.context.getSystemService(DevicePolicyManager::class.java)!!
+ }
+
+ override val annotatedUserHandles: AnnotatedUserHandles? by lazy {
+ try {
+ AnnotatedUserHandles.forShareActivity(activity)
+ } catch (e: SecurityException) {
+ Log.e(tag, "Request from UID without necessary permissions", e)
+ null
+ }
+ }
+
+ private val forwardToPersonalMessage: String? by lazy {
+ devicePolicyManager.resources.getString(FORWARD_INTENT_TO_PERSONAL) {
+ activity.context.getString(R.string.forward_intent_to_owner)
+ }
+ }
+
+ private val forwardToWorkMessage: String? by lazy {
+ devicePolicyManager.resources.getString(FORWARD_INTENT_TO_WORK) {
+ activity.context.getString(R.string.forward_intent_to_work)
+ }
+ }
+
+ override fun forwardMessageFor(intent: Intent): String? {
+ val contentUserHint = intent.contentUserHint
+ if (
+ contentUserHint != UserHandle.USER_CURRENT && contentUserHint != UserHandle.myUserId()
+ ) {
+ val originUserInfo = userManager.getUserInfo(contentUserHint)
+ val originIsManaged = originUserInfo?.isManagedProfile ?: false
+ val targetIsManaged = userManager.isManagedProfile
+ return when {
+ originIsManaged && !targetIsManaged -> forwardToPersonalMessage
+ !originIsManaged && targetIsManaged -> forwardToWorkMessage
+ else -> null
+ }
+ }
+ return null
+ }
+
companion object {
private const val ANDROID_APP_URI_SCHEME = "android-app"
}
diff --git a/java/src/com/android/intentresolver/v2/ChooserActivity.java b/java/src/com/android/intentresolver/v2/ChooserActivity.java
index d2dabfb3..36e0cad1 100644
--- a/java/src/com/android/intentresolver/v2/ChooserActivity.java
+++ b/java/src/com/android/intentresolver/v2/ChooserActivity.java
@@ -76,6 +76,7 @@ import androidx.recyclerview.widget.GridLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
import androidx.viewpager.widget.ViewPager;
+import com.android.intentresolver.AnnotatedUserHandles;
import com.android.intentresolver.ChooserGridLayoutManager;
import com.android.intentresolver.ChooserListAdapter;
import com.android.intentresolver.ChooserRefinementManager;
@@ -244,43 +245,21 @@ public class ChooserActivity extends Hilt_ChooserActivity implements
*/
private boolean mFinishWhenStopped = false;
- @Override
- protected void onCreate(Bundle savedInstanceState) {
- Tracer.INSTANCE.markLaunched();
- AtomicLong intentReceivedTime = new AtomicLong(-1);
+ private final AtomicLong mIntentReceivedTime = new AtomicLong(-1);
+
+ ChooserActivity() {
+ super();
mLogic = new ChooserActivityLogic(
TAG,
() -> this,
() -> mTargetDataLoader,
- () -> {
- intentReceivedTime.set(System.currentTimeMillis());
- mLatencyTracker.onActionStart(ACTION_LOAD_SHARE_SHEET);
-
- mPinnedSharedPrefs = getPinnedSharedPrefs(this);
- mMaxTargetsPerRow =
- getResources().getInteger(R.integer.config_chooser_max_targets_per_row);
- mShouldDisplayLandscape =
- shouldDisplayLandscape(getResources().getConfiguration().orientation);
-
-
- ChooserRequestParameters chooserRequest =
- ((ChooserActivityLogic) mLogic).getChooserRequestParameters();
- if (chooserRequest == null) {
- return Unit.INSTANCE;
- }
- setRetainInOnStop(chooserRequest.shouldRetainInOnStop());
-
- createProfileRecords(
- new AppPredictorFactory(
- this,
- chooserRequest.getSharedText(),
- chooserRequest.getTargetIntentFilter()
- ),
- chooserRequest.getTargetIntentFilter()
- );
- return Unit.INSTANCE;
- }
+ this::onPreinitialization
);
+ }
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ Tracer.INSTANCE.markLaunched();
super.onCreate(savedInstanceState);
if (getChooserRequest() == null) {
finish();
@@ -291,6 +270,7 @@ public class ChooserActivity extends Hilt_ChooserActivity implements
// Skip initializing any additional resources.
return;
}
+ setTheme(mLogic.getThemeResId());
getEventLog().logSharesheetTriggered();
@@ -336,7 +316,7 @@ public class ChooserActivity extends Hilt_ChooserActivity implements
}
mChooserShownTime = System.currentTimeMillis();
- final long systemCost = mChooserShownTime - intentReceivedTime.get();
+ final long systemCost = mChooserShownTime - mIntentReceivedTime.get();
getEventLog().logChooserActivityShown(
isWorkProfile(), chooserRequest.getTargetType(), systemCost);
@@ -370,6 +350,34 @@ public class ChooserActivity extends Hilt_ChooserActivity implements
mEnterTransitionAnimationDelegate.postponeTransition();
}
+ protected final Unit onPreinitialization() {
+ mIntentReceivedTime.set(System.currentTimeMillis());
+ mLatencyTracker.onActionStart(ACTION_LOAD_SHARE_SHEET);
+
+ mPinnedSharedPrefs = getPinnedSharedPrefs(this);
+ mMaxTargetsPerRow =
+ getResources().getInteger(R.integer.config_chooser_max_targets_per_row);
+ mShouldDisplayLandscape =
+ shouldDisplayLandscape(getResources().getConfiguration().orientation);
+
+
+ ChooserRequestParameters chooserRequest = getChooserRequest();
+ if (chooserRequest == null) {
+ return Unit.INSTANCE;
+ }
+ setRetainInOnStop(chooserRequest.shouldRetainInOnStop());
+
+ createProfileRecords(
+ new AppPredictorFactory(
+ this,
+ chooserRequest.getSharedText(),
+ chooserRequest.getTargetIntentFilter()
+ ),
+ chooserRequest.getTargetIntentFilter()
+ );
+ return Unit.INSTANCE;
+ }
+
@Nullable
private ChooserRequestParameters getChooserRequest() {
return ((ChooserActivityLogic) mLogic).getChooserRequestParameters();
@@ -379,20 +387,19 @@ public class ChooserActivity extends Hilt_ChooserActivity implements
return requireNonNull(getChooserRequest());
}
- @Override
- protected int appliedThemeResId() {
- return R.style.Theme_DeviceDefault_Chooser;
+ private AnnotatedUserHandles requireAnnotatedUserHandles() {
+ return requireNonNull(mLogic.getAnnotatedUserHandles());
}
private void createProfileRecords(
AppPredictorFactory factory, IntentFilter targetIntentFilter) {
- UserHandle mainUserHandle = getAnnotatedUserHandles().personalProfileUserHandle;
+ UserHandle mainUserHandle = requireAnnotatedUserHandles().personalProfileUserHandle;
ProfileRecord record = createProfileRecord(mainUserHandle, targetIntentFilter, factory);
if (record.shortcutLoader == null) {
Tracer.INSTANCE.endLaunchToShortcutTrace();
}
- UserHandle workUserHandle = getAnnotatedUserHandles().workProfileUserHandle;
+ UserHandle workUserHandle = requireAnnotatedUserHandles().workProfileUserHandle;
if (workUserHandle != null) {
createProfileRecord(workUserHandle, targetIntentFilter, factory);
}
@@ -486,11 +493,11 @@ public class ChooserActivity extends Hilt_ChooserActivity implements
/* devicePolicyEventCategory= */ ResolverActivity.METRICS_CATEGORY_CHOOSER);
return new NoCrossProfileEmptyStateProvider(
- getAnnotatedUserHandles().personalProfileUserHandle,
+ requireAnnotatedUserHandles().personalProfileUserHandle,
noWorkToPersonalEmptyState,
noPersonalToWorkEmptyState,
createCrossProfileIntentsChecker(),
- getAnnotatedUserHandles().tabOwnerUserHandleForLaunch);
+ requireAnnotatedUserHandles().tabOwnerUserHandleForLaunch);
}
private ChooserMultiProfilePagerAdapter createChooserMultiProfilePagerAdapterForOneProfile(
@@ -504,7 +511,7 @@ public class ChooserActivity extends Hilt_ChooserActivity implements
initialIntents,
rList,
filterLastUsed,
- /* userHandle */ getAnnotatedUserHandles().personalProfileUserHandle,
+ /* userHandle */ requireAnnotatedUserHandles().personalProfileUserHandle,
targetDataLoader);
return new ChooserMultiProfilePagerAdapter(
/* context */ this,
@@ -512,7 +519,7 @@ public class ChooserActivity extends Hilt_ChooserActivity implements
createEmptyStateProvider(/* workProfileUserHandle= */ null),
/* workProfileQuietModeChecker= */ () -> false,
/* workProfileUserHandle= */ null,
- getAnnotatedUserHandles().cloneProfileUserHandle,
+ requireAnnotatedUserHandles().cloneProfileUserHandle,
mMaxTargetsPerRow,
mFeatureFlags);
}
@@ -529,7 +536,7 @@ public class ChooserActivity extends Hilt_ChooserActivity implements
selectedProfile == PROFILE_PERSONAL ? initialIntents : null,
rList,
filterLastUsed,
- /* userHandle */ getAnnotatedUserHandles().personalProfileUserHandle,
+ /* userHandle */ requireAnnotatedUserHandles().personalProfileUserHandle,
targetDataLoader);
ChooserGridAdapter workAdapter = createChooserGridAdapter(
/* context */ this,
@@ -537,17 +544,17 @@ public class ChooserActivity extends Hilt_ChooserActivity implements
selectedProfile == PROFILE_WORK ? initialIntents : null,
rList,
filterLastUsed,
- /* userHandle */ getAnnotatedUserHandles().workProfileUserHandle,
+ /* userHandle */ requireAnnotatedUserHandles().workProfileUserHandle,
targetDataLoader);
return new ChooserMultiProfilePagerAdapter(
/* context */ this,
personalAdapter,
workAdapter,
- createEmptyStateProvider(getAnnotatedUserHandles().workProfileUserHandle),
+ createEmptyStateProvider(requireAnnotatedUserHandles().workProfileUserHandle),
() -> mWorkProfileAvailability.isQuietModeEnabled(),
selectedProfile,
- getAnnotatedUserHandles().workProfileUserHandle,
- getAnnotatedUserHandles().cloneProfileUserHandle,
+ requireAnnotatedUserHandles().workProfileUserHandle,
+ requireAnnotatedUserHandles().cloneProfileUserHandle,
mMaxTargetsPerRow,
mFeatureFlags);
}
@@ -556,7 +563,7 @@ public class ChooserActivity extends Hilt_ChooserActivity implements
int selectedProfile = getSelectedProfileExtra();
if (selectedProfile == -1) {
selectedProfile = getProfileForUser(
- getAnnotatedUserHandles().tabOwnerUserHandleForLaunch);
+ requireAnnotatedUserHandles().tabOwnerUserHandleForLaunch);
}
return selectedProfile;
}
@@ -802,8 +809,8 @@ public class ChooserActivity extends Hilt_ChooserActivity implements
if (!chooserRequest.getCallerChooserTargets().isEmpty()) {
// Send the caller's chooser targets only to the default profile.
UserHandle defaultUser = (findSelectedProfile() == PROFILE_WORK)
- ? getAnnotatedUserHandles().workProfileUserHandle
- : getAnnotatedUserHandles().personalProfileUserHandle;
+ ? requireAnnotatedUserHandles().workProfileUserHandle
+ : requireAnnotatedUserHandles().personalProfileUserHandle;
if (mChooserMultiProfilePagerAdapter.getCurrentUserHandle() == defaultUser) {
mChooserMultiProfilePagerAdapter.getActiveListAdapter().addServiceResults(
/* origTarget */ null,
@@ -1117,7 +1124,7 @@ public class ChooserActivity extends Hilt_ChooserActivity implements
ProfileRecord record = getProfileRecord(userHandle);
// We cannot use APS service when clone profile is present as APS service cannot sort
// cross profile targets as of now.
- return ((record == null) || (getAnnotatedUserHandles().cloneProfileUserHandle != null))
+ return ((record == null) || (requireAnnotatedUserHandles().cloneProfileUserHandle != null))
? null : record.appPredictor;
}
@@ -1257,8 +1264,8 @@ public class ChooserActivity extends Hilt_ChooserActivity implements
int maxTargetsPerRow,
TargetDataLoader targetDataLoader) {
UserHandle initialIntentsUserSpace = isLaunchedAsCloneProfile()
- && userHandle.equals(getAnnotatedUserHandles().personalProfileUserHandle)
- ? getAnnotatedUserHandles().cloneProfileUserHandle : userHandle;
+ && userHandle.equals(requireAnnotatedUserHandles().personalProfileUserHandle)
+ ? requireAnnotatedUserHandles().cloneProfileUserHandle : userHandle;
return new ChooserListAdapter(
context,
payloadIntents,
@@ -1279,7 +1286,7 @@ public class ChooserActivity extends Hilt_ChooserActivity implements
@Override
protected void onWorkProfileStatusUpdated() {
- UserHandle workUser = getAnnotatedUserHandles().workProfileUserHandle;
+ UserHandle workUser = requireAnnotatedUserHandles().workProfileUserHandle;
ProfileRecord record = workUser == null ? null : getProfileRecord(workUser);
if (record != null && record.shortcutLoader != null) {
record.shortcutLoader.reset();
@@ -1313,7 +1320,7 @@ public class ChooserActivity extends Hilt_ChooserActivity implements
mPm,
getTargetIntent(),
mLogic.getReferrerPackageName(),
- getAnnotatedUserHandles().userIdOfCallingApp,
+ requireAnnotatedUserHandles().userIdOfCallingApp,
resolverComparator,
getQueryIntentsUser(userHandle));
}
@@ -1335,7 +1342,9 @@ public class ChooserActivity extends Hilt_ChooserActivity implements
@Override
public void safelyStartActivityAsPersonalProfileUser(TargetInfo targetInfo) {
safelyStartActivityAsUser(
- targetInfo, getAnnotatedUserHandles().personalProfileUserHandle);
+ targetInfo,
+ requireAnnotatedUserHandles().personalProfileUserHandle
+ );
finish();
}
@@ -1346,7 +1355,7 @@ public class ChooserActivity extends Hilt_ChooserActivity implements
ChooserActivity.this, sharedElement, sharedElementName);
safelyStartActivityAsUser(
targetInfo,
- getAnnotatedUserHandles().personalProfileUserHandle,
+ requireAnnotatedUserHandles().personalProfileUserHandle,
options.toBundle());
// Can't finish right away because the shared element transition may not
// be ready to start.
@@ -1504,7 +1513,7 @@ public class ChooserActivity extends Hilt_ChooserActivity implements
* Returns {@link #PROFILE_PERSONAL}, otherwise.
**/
private int getProfileForUser(UserHandle currentUserHandle) {
- if (currentUserHandle.equals(getAnnotatedUserHandles().workProfileUserHandle)) {
+ if (currentUserHandle.equals(requireAnnotatedUserHandles().workProfileUserHandle)) {
return PROFILE_WORK;
}
// We return personal profile, as it is the default when there is no work profile, personal
diff --git a/java/src/com/android/intentresolver/v2/ChooserActivityLogic.kt b/java/src/com/android/intentresolver/v2/ChooserActivityLogic.kt
index 1db3f407..838c39e2 100644
--- a/java/src/com/android/intentresolver/v2/ChooserActivityLogic.kt
+++ b/java/src/com/android/intentresolver/v2/ChooserActivityLogic.kt
@@ -4,16 +4,26 @@ import android.app.Activity
import android.content.Intent
import android.util.Log
import androidx.activity.ComponentActivity
+import androidx.annotation.OpenForTesting
import com.android.intentresolver.ChooserRequestParameters
+import com.android.intentresolver.R
import com.android.intentresolver.icons.TargetDataLoader
+import com.android.intentresolver.v2.util.mutableLazy
-/** Activity logic for [ChooserActivity]. */
-class ChooserActivityLogic(
- private val tag: String,
+/**
+ * Activity logic for [ChooserActivity].
+ *
+ * TODO: Make this class no longer open once [ChooserActivity] no longer needs to cast to access
+ * [chooserRequestParameters]. For now, this class being open is better than using reflection
+ * there.
+ */
+@OpenForTesting
+open class ChooserActivityLogic(
+ tag: String,
activityProvider: () -> ComponentActivity,
targetDataLoaderProvider: () -> TargetDataLoader,
private val onPreInitialization: () -> Unit,
-) : ActivityLogic, CommonActivityLogic by CommonActivityLogicImpl(activityProvider) {
+) : ActivityLogic, CommonActivityLogic by CommonActivityLogicImpl(tag, activityProvider) {
override val targetIntent: Intent by lazy { chooserRequestParameters?.targetIntent ?: Intent() }
@@ -37,6 +47,11 @@ class ChooserActivityLogic(
override val targetDataLoader: TargetDataLoader by lazy { targetDataLoaderProvider() }
+ override val themeResId: Int = R.style.Theme_DeviceDefault_Chooser
+
+ private val _profileSwitchMessage = mutableLazy { forwardMessageFor(targetIntent) }
+ override val profileSwitchMessage: String? by _profileSwitchMessage
+
val chooserRequestParameters: ChooserRequestParameters? by lazy {
try {
ChooserRequestParameters(
@@ -53,4 +68,8 @@ class ChooserActivityLogic(
override fun preInitialization() {
onPreInitialization()
}
+
+ override fun clearProfileSwitchMessage() {
+ _profileSwitchMessage.setLazy(null)
+ }
}
diff --git a/java/src/com/android/intentresolver/v2/ResolverActivity.java b/java/src/com/android/intentresolver/v2/ResolverActivity.java
index 1c9ee99d..b34ce16d 100644
--- a/java/src/com/android/intentresolver/v2/ResolverActivity.java
+++ b/java/src/com/android/intentresolver/v2/ResolverActivity.java
@@ -17,8 +17,6 @@
package com.android.intentresolver.v2;
import static android.Manifest.permission.INTERACT_ACROSS_PROFILES;
-import static android.app.admin.DevicePolicyResources.Strings.Core.FORWARD_INTENT_TO_PERSONAL;
-import static android.app.admin.DevicePolicyResources.Strings.Core.FORWARD_INTENT_TO_WORK;
import static android.app.admin.DevicePolicyResources.Strings.Core.RESOLVER_CANT_ACCESS_PERSONAL;
import static android.app.admin.DevicePolicyResources.Strings.Core.RESOLVER_CANT_ACCESS_WORK;
import static android.app.admin.DevicePolicyResources.Strings.Core.RESOLVER_CROSS_PROFILE_BLOCKED_TITLE;
@@ -35,6 +33,8 @@ import static android.view.WindowManager.LayoutParams.SYSTEM_FLAG_HIDE_NON_SYSTE
import static com.android.internal.annotations.VisibleForTesting.Visibility.PROTECTED;
+import static java.util.Objects.requireNonNull;
+
import android.annotation.Nullable;
import android.annotation.StringRes;
import android.annotation.UiThread;
@@ -131,7 +131,6 @@ import java.util.Iterator;
import java.util.List;
import java.util.Objects;
import java.util.Set;
-import java.util.function.Supplier;
/**
* This is a copy of ResolverActivity to support IntentResolver's ChooserActivity. This code is
@@ -143,7 +142,7 @@ import java.util.function.Supplier;
public class ResolverActivity extends FragmentActivity implements
ResolverListAdapter.ResolverListCommunicator {
- protected ActivityLogic mLogic = new ResolverActivityLogic(() -> this);
+ protected ActivityLogic mLogic = new ResolverActivityLogic(TAG, () -> this);
public ResolverActivity() {
mIsIntentPicker = getClass().equals(ResolverActivity.class);
@@ -157,7 +156,6 @@ public class ResolverActivity extends FragmentActivity implements
private Button mOnceButton;
protected View mProfileView;
private int mLastSelected = AbsListView.INVALID_POSITION;
- private String mProfileSwitchMessage;
private int mLayoutId;
@VisibleForTesting
protected final ArrayList<Intent> mIntents = new ArrayList<>();
@@ -224,27 +222,6 @@ public class ResolverActivity extends FragmentActivity implements
private UserHandle mHeaderCreatorUser;
- // User handle annotations are lazy-initialized to ensure that they're computed exactly once
- // (even though they can't be computed prior to activity creation).
- // TODO: use a less ad-hoc pattern for lazy initialization (by switching to Dagger or
- // introducing a common `LazySingletonSupplier` API, etc), and/or migrate all dependents to a
- // new component whose lifecycle is limited to the "created" Activity (so that we can just hold
- // the annotations as a `final` ivar, which is a better way to show immutability).
- private Supplier<AnnotatedUserHandles> mLazyAnnotatedUserHandles = () -> {
- final AnnotatedUserHandles result = computeAnnotatedUserHandles();
- mLazyAnnotatedUserHandles = () -> result;
- return result;
- };
-
- // This method is called exactly once during creation to compute the immutable annotations
- // accessible through the lazy supplier {@link mLazyAnnotatedUserHandles}.
- // TODO: this is only defined so that tests can provide an override that injects fake
- // annotations. Dagger could provide a cleaner model for our testing/injection requirements.
- @VisibleForTesting(visibility = VisibleForTesting.Visibility.PRIVATE)
- protected AnnotatedUserHandles computeAnnotatedUserHandles() {
- return AnnotatedUserHandles.forShareActivity(this);
- }
-
@Nullable
private OnSwitchOnWorkSelectedListener mOnSwitchOnWorkSelectedListener;
@@ -337,6 +314,7 @@ public class ResolverActivity extends FragmentActivity implements
// Skip initializing any additional resources.
return;
}
+ setTheme(mLogic.getThemeResId());
mLogic.preInitialization();
init(
mLogic.getTargetIntent(),
@@ -354,15 +332,11 @@ public class ResolverActivity extends FragmentActivity implements
Intent[] initialIntents,
TargetDataLoader targetDataLoader
) {
- setTheme(appliedThemeResId());
-
- // Determine whether we should show that intent is forwarded
- // from managed profile to owner or other way around.
- setProfileSwitchMessage(intent.getContentUserHint());
-
- // Force computation of user handle annotations in order to validate the caller ID. (See the
- // associated TODO comment to explain why this is structured as a lazy computation.)
- AnnotatedUserHandles unusedReferenceToHandles = mLazyAnnotatedUserHandles.get();
+ // Calling UID did not have valid permissions
+ if (mLogic.getAnnotatedUserHandles() == null) {
+ finish();
+ return;
+ }
mWorkProfileAvailability = createWorkProfileAvailabilityManager();
@@ -397,12 +371,20 @@ public class ResolverActivity extends FragmentActivity implements
mPersonalPackageMonitor = createPackageMonitor(
mMultiProfilePagerAdapter.getPersonalListAdapter());
mPersonalPackageMonitor.register(
- this, getMainLooper(), getAnnotatedUserHandles().personalProfileUserHandle, false);
+ this,
+ getMainLooper(),
+ requireAnnotatedUserHandles().personalProfileUserHandle,
+ false
+ );
if (shouldShowTabs()) {
mWorkPackageMonitor = createPackageMonitor(
mMultiProfilePagerAdapter.getWorkListAdapter());
mWorkPackageMonitor.register(
- this, getMainLooper(), getAnnotatedUserHandles().workProfileUserHandle, false);
+ this,
+ getMainLooper(),
+ requireAnnotatedUserHandles().workProfileUserHandle,
+ false
+ );
}
mRegistered = true;
@@ -494,15 +476,11 @@ public class ResolverActivity extends FragmentActivity implements
ResolverActivity.METRICS_CATEGORY_RESOLVER);
return new NoCrossProfileEmptyStateProvider(
- getAnnotatedUserHandles().personalProfileUserHandle,
+ requireAnnotatedUserHandles().personalProfileUserHandle,
noWorkToPersonalEmptyState,
noPersonalToWorkEmptyState,
createCrossProfileIntentsChecker(),
- getAnnotatedUserHandles().tabOwnerUserHandleForLaunch);
- }
-
- protected int appliedThemeResId() {
- return R.style.Theme_DeviceDefault_Resolver;
+ requireAnnotatedUserHandles().tabOwnerUserHandleForLaunch);
}
/**
@@ -890,7 +868,7 @@ public class ResolverActivity extends FragmentActivity implements
mPm,
getTargetIntent(),
mLogic.getReferrerPackageName(),
- getAnnotatedUserHandles().userIdOfCallingApp,
+ requireAnnotatedUserHandles().userIdOfCallingApp,
resolverComparator,
getQueryIntentsUser(userHandle));
}
@@ -978,7 +956,8 @@ public class ResolverActivity extends FragmentActivity implements
@Override // ResolverListCommunicator
public void onHandlePackagesChanged(ResolverListAdapter listAdapter) {
if (listAdapter == mMultiProfilePagerAdapter.getActiveListAdapter()) {
- if (listAdapter.getUserHandle().equals(getAnnotatedUserHandles().workProfileUserHandle)
+ if (listAdapter.getUserHandle().equals(
+ requireAnnotatedUserHandles().workProfileUserHandle)
&& mWorkProfileAvailability.isWaitingToEnableWorkProfile()) {
// We have just turned on the work profile and entered the pass code to start it,
// now we are waiting to receive the ACTION_USER_UNLOCKED broadcast. There is no
@@ -1018,13 +997,13 @@ public class ResolverActivity extends FragmentActivity implements
protected WorkProfileAvailabilityManager createWorkProfileAvailabilityManager() {
return new WorkProfileAvailabilityManager(
getSystemService(UserManager.class),
- getAnnotatedUserHandles().workProfileUserHandle,
+ requireAnnotatedUserHandles().workProfileUserHandle,
this::onWorkProfileStatusUpdated);
}
protected void onWorkProfileStatusUpdated() {
if (mMultiProfilePagerAdapter.getCurrentUserHandle().equals(
- getAnnotatedUserHandles().workProfileUserHandle)) {
+ requireAnnotatedUserHandles().workProfileUserHandle)) {
mMultiProfilePagerAdapter.rebuildActiveTab(true);
} else {
mMultiProfilePagerAdapter.clearInactiveProfileCache();
@@ -1042,8 +1021,8 @@ public class ResolverActivity extends FragmentActivity implements
UserHandle userHandle,
TargetDataLoader targetDataLoader) {
UserHandle initialIntentsUserSpace = isLaunchedAsCloneProfile()
- && userHandle.equals(getAnnotatedUserHandles().personalProfileUserHandle)
- ? getAnnotatedUserHandles().cloneProfileUserHandle : userHandle;
+ && userHandle.equals(requireAnnotatedUserHandles().personalProfileUserHandle)
+ ? requireAnnotatedUserHandles().cloneProfileUserHandle : userHandle;
return new ResolverListAdapter(
context,
payloadIntents,
@@ -1092,9 +1071,9 @@ public class ResolverActivity extends FragmentActivity implements
final EmptyStateProvider noAppsEmptyStateProvider = new NoAppsAvailableEmptyStateProvider(
this,
workProfileUserHandle,
- getAnnotatedUserHandles().personalProfileUserHandle,
+ requireAnnotatedUserHandles().personalProfileUserHandle,
getMetricsCategory(),
- getAnnotatedUserHandles().tabOwnerUserHandleForLaunch
+ requireAnnotatedUserHandles().tabOwnerUserHandleForLaunch
);
// Return composite provider, the order matters (the higher, the more priority)
@@ -1117,7 +1096,7 @@ public class ResolverActivity extends FragmentActivity implements
initialIntents,
resolutionList,
filterLastUsed,
- /* userHandle */ getAnnotatedUserHandles().personalProfileUserHandle,
+ /* userHandle */ requireAnnotatedUserHandles().personalProfileUserHandle,
targetDataLoader);
return new ResolverMultiProfilePagerAdapter(
/* context */ this,
@@ -1125,13 +1104,13 @@ public class ResolverActivity extends FragmentActivity implements
createEmptyStateProvider(/* workProfileUserHandle= */ null),
/* workProfileQuietModeChecker= */ () -> false,
/* workProfileUserHandle= */ null,
- getAnnotatedUserHandles().cloneProfileUserHandle);
+ requireAnnotatedUserHandles().cloneProfileUserHandle);
}
private UserHandle getIntentUser() {
return getIntent().hasExtra(EXTRA_CALLING_USER)
? getIntent().getParcelableExtra(EXTRA_CALLING_USER)
- : getAnnotatedUserHandles().tabOwnerUserHandleForLaunch;
+ : requireAnnotatedUserHandles().tabOwnerUserHandleForLaunch;
}
private ResolverMultiProfilePagerAdapter createResolverMultiProfilePagerAdapterForTwoProfiles(
@@ -1144,10 +1123,10 @@ public class ResolverActivity extends FragmentActivity implements
// this happens, we check for it here and set the current profile's tab.
int selectedProfile = getCurrentProfile();
UserHandle intentUser = getIntentUser();
- if (!getAnnotatedUserHandles().tabOwnerUserHandleForLaunch.equals(intentUser)) {
- if (getAnnotatedUserHandles().personalProfileUserHandle.equals(intentUser)) {
+ if (!requireAnnotatedUserHandles().tabOwnerUserHandleForLaunch.equals(intentUser)) {
+ if (requireAnnotatedUserHandles().personalProfileUserHandle.equals(intentUser)) {
selectedProfile = PROFILE_PERSONAL;
- } else if (getAnnotatedUserHandles().workProfileUserHandle.equals(intentUser)) {
+ } else if (requireAnnotatedUserHandles().workProfileUserHandle.equals(intentUser)) {
selectedProfile = PROFILE_WORK;
}
} else {
@@ -1165,10 +1144,10 @@ public class ResolverActivity extends FragmentActivity implements
selectedProfile == PROFILE_PERSONAL ? initialIntents : null,
resolutionList,
(filterLastUsed && UserHandle.myUserId()
- == getAnnotatedUserHandles().personalProfileUserHandle.getIdentifier()),
- /* userHandle */ getAnnotatedUserHandles().personalProfileUserHandle,
+ == requireAnnotatedUserHandles().personalProfileUserHandle.getIdentifier()),
+ /* userHandle */ requireAnnotatedUserHandles().personalProfileUserHandle,
targetDataLoader);
- UserHandle workProfileUserHandle = getAnnotatedUserHandles().workProfileUserHandle;
+ UserHandle workProfileUserHandle = requireAnnotatedUserHandles().workProfileUserHandle;
ResolverListAdapter workAdapter = createResolverListAdapter(
/* context */ this,
/* payloadIntents */ mIntents,
@@ -1186,7 +1165,7 @@ public class ResolverActivity extends FragmentActivity implements
() -> mWorkProfileAvailability.isQuietModeEnabled(),
selectedProfile,
workProfileUserHandle,
- getAnnotatedUserHandles().cloneProfileUserHandle);
+ requireAnnotatedUserHandles().cloneProfileUserHandle);
}
/**
@@ -1209,26 +1188,26 @@ public class ResolverActivity extends FragmentActivity implements
}
protected final @Profile int getCurrentProfile() {
- UserHandle launchUser = getAnnotatedUserHandles().tabOwnerUserHandleForLaunch;
- UserHandle personalUser = getAnnotatedUserHandles().personalProfileUserHandle;
+ UserHandle launchUser = requireAnnotatedUserHandles().tabOwnerUserHandleForLaunch;
+ UserHandle personalUser = requireAnnotatedUserHandles().personalProfileUserHandle;
return launchUser.equals(personalUser) ? PROFILE_PERSONAL : PROFILE_WORK;
}
- protected final AnnotatedUserHandles getAnnotatedUserHandles() {
- return mLazyAnnotatedUserHandles.get();
+ private AnnotatedUserHandles requireAnnotatedUserHandles() {
+ return requireNonNull(mLogic.getAnnotatedUserHandles());
}
private boolean hasWorkProfile() {
- return getAnnotatedUserHandles().workProfileUserHandle != null;
+ return requireAnnotatedUserHandles().workProfileUserHandle != null;
}
private boolean hasCloneProfile() {
- return getAnnotatedUserHandles().cloneProfileUserHandle != null;
+ return requireAnnotatedUserHandles().cloneProfileUserHandle != null;
}
protected final boolean isLaunchedAsCloneProfile() {
- UserHandle launchUser = getAnnotatedUserHandles().userHandleSharesheetLaunchedAs;
- UserHandle cloneUser = getAnnotatedUserHandles().cloneProfileUserHandle;
+ UserHandle launchUser = requireAnnotatedUserHandles().userHandleSharesheetLaunchedAs;
+ UserHandle cloneUser = requireAnnotatedUserHandles().cloneProfileUserHandle;
return hasCloneProfile() && launchUser.equals(cloneUser);
}
@@ -1244,7 +1223,7 @@ public class ResolverActivity extends FragmentActivity implements
}
// Do not show the profile switch message anymore.
- mProfileSwitchMessage = null;
+ mLogic.clearProfileSwitchMessage();
onTargetSelected(dri, false);
finish();
@@ -1273,7 +1252,7 @@ public class ResolverActivity extends FragmentActivity implements
.createEvent(DevicePolicyEnums.RESOLVER_CROSS_PROFILE_TARGET_OPENED)
.setBoolean(
currentUserHandle.equals(
- getAnnotatedUserHandles().personalProfileUserHandle))
+ requireAnnotatedUserHandles().personalProfileUserHandle))
.setStrings(getMetricsCategory(),
cti.isInDirectShareMetricsCategory() ? "direct_share" : "other_target")
.write();
@@ -1331,34 +1310,6 @@ public class ResolverActivity extends FragmentActivity implements
}
}
- private void setProfileSwitchMessage(int contentUserHint) {
- if ((contentUserHint != UserHandle.USER_CURRENT)
- && (contentUserHint != UserHandle.myUserId())) {
- UserManager userManager = (UserManager) getSystemService(Context.USER_SERVICE);
- UserInfo originUserInfo = userManager.getUserInfo(contentUserHint);
- boolean originIsManaged = originUserInfo != null ? originUserInfo.isManagedProfile()
- : false;
- boolean targetIsManaged = userManager.isManagedProfile();
- if (originIsManaged && !targetIsManaged) {
- mProfileSwitchMessage = getForwardToPersonalMsg();
- } else if (!originIsManaged && targetIsManaged) {
- mProfileSwitchMessage = getForwardToWorkMsg();
- }
- }
- }
-
- private String getForwardToPersonalMsg() {
- return getSystemService(DevicePolicyManager.class).getResources().getString(
- FORWARD_INTENT_TO_PERSONAL,
- () -> getString(R.string.forward_intent_to_owner));
- }
-
- private String getForwardToWorkMsg() {
- return getSystemService(DevicePolicyManager.class).getResources().getString(
- FORWARD_INTENT_TO_WORK,
- () -> getString(R.string.forward_intent_to_work));
- }
-
protected final CharSequence getTitleForAction(Intent intent, int defaultTitleRes) {
final ActionTitle title = mLogic.getResolvingHome()
? ActionTitle.HOME
@@ -1394,7 +1345,7 @@ public class ResolverActivity extends FragmentActivity implements
mPersonalPackageMonitor.register(
this,
getMainLooper(),
- getAnnotatedUserHandles().personalProfileUserHandle,
+ requireAnnotatedUserHandles().personalProfileUserHandle,
false);
if (shouldShowTabs()) {
if (mWorkPackageMonitor == null) {
@@ -1404,7 +1355,7 @@ public class ResolverActivity extends FragmentActivity implements
mWorkPackageMonitor.register(
this,
getMainLooper(),
- getAnnotatedUserHandles().workProfileUserHandle,
+ requireAnnotatedUserHandles().workProfileUserHandle,
false);
}
mRegistered = true;
@@ -1612,8 +1563,9 @@ public class ResolverActivity extends FragmentActivity implements
}
// If needed, show that intent is forwarded
// from managed profile to owner or other way around.
- if (mProfileSwitchMessage != null) {
- Toast.makeText(this, mProfileSwitchMessage, Toast.LENGTH_LONG).show();
+ String profileSwitchMessage = mLogic.getProfileSwitchMessage();
+ if (profileSwitchMessage != null) {
+ Toast.makeText(this, profileSwitchMessage, Toast.LENGTH_LONG).show();
}
try {
if (cti.startAsCaller(this, options, user.getIdentifier())) {
@@ -1622,7 +1574,7 @@ public class ResolverActivity extends FragmentActivity implements
}
} catch (RuntimeException e) {
Slog.wtf(TAG,
- "Unable to launch as uid " + getAnnotatedUserHandles().userIdOfCallingApp
+ "Unable to launch as uid " + requireAnnotatedUserHandles().userIdOfCallingApp
+ " package " + getLaunchedFromPackage() + ", while running in "
+ ActivityThread.currentProcessName(), e);
}
@@ -1873,7 +1825,7 @@ public class ResolverActivity extends FragmentActivity implements
DevicePolicyEventLogger
.createEvent(DevicePolicyEnums.RESOLVER_AUTOLAUNCH_CROSS_PROFILE_TARGET)
.setBoolean(activeListAdapter.getUserHandle()
- .equals(getAnnotatedUserHandles().personalProfileUserHandle))
+ .equals(requireAnnotatedUserHandles().personalProfileUserHandle))
.setStrings(getMetricsCategory())
.write();
safelyStartActivity(activeProfileTarget);
@@ -2157,7 +2109,8 @@ public class ResolverActivity extends FragmentActivity implements
// filtered item. We always show the same default app even in the inactive user profile.
boolean adapterForCurrentUserHasFilteredItem =
mMultiProfilePagerAdapter.getListAdapterForUserHandle(
- getAnnotatedUserHandles().tabOwnerUserHandleForLaunch).hasFilteredItem();
+ requireAnnotatedUserHandles().tabOwnerUserHandleForLaunch
+ ).hasFilteredItem();
return mLogic.getSupportsAlwaysUseOption() && adapterForCurrentUserHasFilteredItem;
}
@@ -2278,7 +2231,7 @@ public class ResolverActivity extends FragmentActivity implements
* {@link ResolverListController} configured for the provided {@code userHandle}.
*/
protected final UserHandle getQueryIntentsUser(UserHandle userHandle) {
- return getAnnotatedUserHandles().getQueryIntentsUser(userHandle);
+ return requireAnnotatedUserHandles().getQueryIntentsUser(userHandle);
}
/**
@@ -2298,9 +2251,9 @@ public class ResolverActivity extends FragmentActivity implements
// Add clonedProfileUserHandle to the list only if we are:
// a. Building the Personal Tab.
// b. CloneProfile exists on the device.
- if (userHandle.equals(getAnnotatedUserHandles().personalProfileUserHandle)
+ if (userHandle.equals(requireAnnotatedUserHandles().personalProfileUserHandle)
&& hasCloneProfile()) {
- userList.add(getAnnotatedUserHandles().cloneProfileUserHandle);
+ userList.add(requireAnnotatedUserHandles().cloneProfileUserHandle);
}
return userList;
}
diff --git a/java/src/com/android/intentresolver/v2/ResolverActivityLogic.kt b/java/src/com/android/intentresolver/v2/ResolverActivityLogic.kt
index 1d02e6c2..1b936159 100644
--- a/java/src/com/android/intentresolver/v2/ResolverActivityLogic.kt
+++ b/java/src/com/android/intentresolver/v2/ResolverActivityLogic.kt
@@ -2,13 +2,16 @@ package com.android.intentresolver.v2
import android.content.Intent
import androidx.activity.ComponentActivity
+import com.android.intentresolver.R
import com.android.intentresolver.icons.DefaultTargetDataLoader
import com.android.intentresolver.icons.TargetDataLoader
+import com.android.intentresolver.v2.util.mutableLazy
/** Activity logic for [ResolverActivity]. */
class ResolverActivityLogic(
+ tag: String,
activityProvider: () -> ComponentActivity,
-) : ActivityLogic, CommonActivityLogic by CommonActivityLogicImpl(activityProvider) {
+) : ActivityLogic, CommonActivityLogic by CommonActivityLogicImpl(tag, activityProvider) {
override val targetIntent: Intent by lazy {
val intent = Intent(activity.intent)
@@ -55,7 +58,16 @@ class ResolverActivityLogic(
)
}
+ override val themeResId: Int = R.style.Theme_DeviceDefault_Resolver
+
+ private val _profileSwitchMessage = mutableLazy { forwardMessageFor(targetIntent) }
+ override val profileSwitchMessage: String? by _profileSwitchMessage
+
override fun preInitialization() {
// Do nothing
}
+
+ override fun clearProfileSwitchMessage() {
+ _profileSwitchMessage.setLazy(null)
+ }
}
diff --git a/java/src/com/android/intentresolver/v2/util/MutableLazy.kt b/java/src/com/android/intentresolver/v2/util/MutableLazy.kt
new file mode 100644
index 00000000..4ce9b7fd
--- /dev/null
+++ b/java/src/com/android/intentresolver/v2/util/MutableLazy.kt
@@ -0,0 +1,36 @@
+package com.android.intentresolver.v2.util
+
+import java.util.concurrent.atomic.AtomicReference
+import kotlin.reflect.KProperty
+
+/** A lazy delegate that can be changed to a new lazy or null at any time. */
+class MutableLazy<T>(initializer: () -> T?) : Lazy<T?> {
+
+ override val value: T?
+ get() = lazy.get()?.value
+
+ private var lazy: AtomicReference<Lazy<T?>?> = AtomicReference(lazy(initializer))
+
+ override fun isInitialized(): Boolean = lazy.get()?.isInitialized() != false
+
+ operator fun getValue(thisRef: Any?, property: KProperty<*>): T? =
+ lazy.get()?.getValue(thisRef, property)
+
+ /** Replace the existing lazy logic with the [newLazy] */
+ fun setLazy(newLazy: Lazy<T?>?) {
+ lazy.set(newLazy)
+ }
+
+ /** Replace the existing lazy logic with a [Lazy] created from the [newInitializer]. */
+ fun setLazy(newInitializer: () -> T?) {
+ lazy.set(lazy(newInitializer))
+ }
+
+ /** Set the lazy logic to null. */
+ fun clear() {
+ lazy.set(null)
+ }
+}
+
+/** Constructs a [MutableLazy] using the given [initializer] */
+fun <T> mutableLazy(initializer: () -> T?) = MutableLazy(initializer)
diff --git a/java/tests/src/com/android/intentresolver/v2/ChooserWrapperActivity.java b/java/tests/src/com/android/intentresolver/v2/ChooserWrapperActivity.java
index 65d33485..6fdba4c2 100644
--- a/java/tests/src/com/android/intentresolver/v2/ChooserWrapperActivity.java
+++ b/java/tests/src/com/android/intentresolver/v2/ChooserWrapperActivity.java
@@ -33,7 +33,6 @@ import android.os.UserHandle;
import androidx.lifecycle.ViewModelProvider;
-import com.android.intentresolver.AnnotatedUserHandles;
import com.android.intentresolver.ChooserListAdapter;
import com.android.intentresolver.ChooserRequestParameters;
import com.android.intentresolver.IChooserWrapper;
@@ -59,6 +58,17 @@ public class ChooserWrapperActivity extends ChooserActivity implements IChooserW
static final ChooserActivityOverrideData sOverrides = ChooserActivityOverrideData.getInstance();
private UsageStatsManager mUsm;
+ public ChooserWrapperActivity() {
+ super();
+ mLogic = new TestChooserActivityLogic(
+ "ChooserWrapper",
+ () -> this,
+ () -> mTargetDataLoader,
+ super::onPreinitialization,
+ sOverrides
+ );
+ }
+
// 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
@@ -235,11 +245,6 @@ public class ChooserWrapperActivity extends ChooserActivity implements IChooserW
}
@Override
- protected AnnotatedUserHandles computeAnnotatedUserHandles() {
- return sOverrides.annotatedUserHandles;
- }
-
- @Override
public UserHandle getCurrentUserHandle() {
return mMultiProfilePagerAdapter.getCurrentUserHandle();
}
diff --git a/java/tests/src/com/android/intentresolver/v2/ResolverWrapperActivity.java b/java/tests/src/com/android/intentresolver/v2/ResolverWrapperActivity.java
index 0fb77457..e5617090 100644
--- a/java/tests/src/com/android/intentresolver/v2/ResolverWrapperActivity.java
+++ b/java/tests/src/com/android/intentresolver/v2/ResolverWrapperActivity.java
@@ -60,6 +60,11 @@ public class ResolverWrapperActivity extends ResolverActivity {
public ResolverWrapperActivity() {
super(/* isIntentPicker= */ true);
+ mLogic = new TestResolverActivityLogic(
+ "ResolverWrapper",
+ () -> this,
+ sOverrides
+ );
}
public CountingIdlingResource getLabelIdlingResource() {
@@ -159,11 +164,6 @@ public class ResolverWrapperActivity extends ResolverActivity {
}
@Override
- protected AnnotatedUserHandles computeAnnotatedUserHandles() {
- return sOverrides.annotatedUserHandles;
- }
-
- @Override
public void startActivityAsUser(Intent intent, Bundle options, UserHandle user) {
super.startActivityAsUser(intent, options, user);
}
@@ -179,7 +179,7 @@ public class ResolverWrapperActivity extends ResolverActivity {
* <p>
* Instead, we use static instances of this object to modify behavior.
*/
- static class OverrideData {
+ public static class OverrideData {
@SuppressWarnings("Since15")
public Function<PackageManager, PackageManager> createPackageManager;
public Function<Pair<TargetInfo, UserHandle>, Boolean> onSafelyStartInternalCallback;
diff --git a/java/tests/src/com/android/intentresolver/v2/TestChooserActivityLogic.kt b/java/tests/src/com/android/intentresolver/v2/TestChooserActivityLogic.kt
new file mode 100644
index 00000000..fb1eab6c
--- /dev/null
+++ b/java/tests/src/com/android/intentresolver/v2/TestChooserActivityLogic.kt
@@ -0,0 +1,25 @@
+package com.android.intentresolver.v2
+
+import androidx.activity.ComponentActivity
+import com.android.intentresolver.AnnotatedUserHandles
+import com.android.intentresolver.icons.TargetDataLoader
+
+/** Activity logic for use when testing [ChooserActivity]. */
+class TestChooserActivityLogic(
+ tag: String,
+ activityProvider: () -> ComponentActivity,
+ targetDataLoaderProvider: () -> TargetDataLoader,
+ onPreinitialization: () -> Unit,
+ overrideData: ChooserActivityOverrideData,
+) :
+ ChooserActivityLogic(
+ tag,
+ activityProvider,
+ targetDataLoaderProvider,
+ onPreinitialization,
+ ) {
+
+ override val annotatedUserHandles: AnnotatedUserHandles? by lazy {
+ overrideData.annotatedUserHandles
+ }
+}
diff --git a/java/tests/src/com/android/intentresolver/v2/TestResolverActivityLogic.kt b/java/tests/src/com/android/intentresolver/v2/TestResolverActivityLogic.kt
new file mode 100644
index 00000000..7f8e6f70
--- /dev/null
+++ b/java/tests/src/com/android/intentresolver/v2/TestResolverActivityLogic.kt
@@ -0,0 +1,16 @@
+package com.android.intentresolver.v2
+
+import androidx.activity.ComponentActivity
+import com.android.intentresolver.AnnotatedUserHandles
+
+/** Activity logic for use when testing [ResolverActivity]. */
+class TestResolverActivityLogic(
+ tag: String,
+ activityProvider: () -> ComponentActivity,
+ overrideData: ResolverWrapperActivity.OverrideData,
+) : ActivityLogic by ResolverActivityLogic(tag, activityProvider) {
+
+ override val annotatedUserHandles: AnnotatedUserHandles? by lazy {
+ overrideData.annotatedUserHandles
+ }
+}