From e9beecfa7e2fce23174fb102139c418e9d5c75f6 Mon Sep 17 00:00:00 2001 From: Shaun Corkran Date: Thu, 10 Mar 2022 23:34:42 +0000 Subject: [PATCH] Add CrossTaskNavigations API to restrict navigation from current task This changes the API to allow virtual device owners to configure allow and deny lists of components to navigate to new tasks while being streamed. The change is only in VirtualDeviceParams, a recent API addition with low touch. Base case has the new lists set to an empty set preventing any change to current behavior. Bug: 223915401 Test: Tests added in ag/17235857 Change-Id: Icb44163acb23736e562ffb4b08f4eb93c8b01990 --- core/api/system-current.txt | 7 + .../virtual/VirtualDeviceParams.java | 161 +++++++++++++++++- 2 files changed, 165 insertions(+), 3 deletions(-) diff --git a/core/api/system-current.txt b/core/api/system-current.txt index 0a748142d65e9..4cc63fee241cc 100644 --- a/core/api/system-current.txt +++ b/core/api/system-current.txt @@ -2802,8 +2802,11 @@ package android.companion.virtual { public final class VirtualDeviceParams implements android.os.Parcelable { method public int describeContents(); method @NonNull public java.util.Set getAllowedActivities(); + method @NonNull public java.util.Set getAllowedCrossTaskNavigations(); method @NonNull public java.util.Set getBlockedActivities(); + method @NonNull public java.util.Set getBlockedCrossTaskNavigations(); method public int getDefaultActivityPolicy(); + method public int getDefaultNavigationPolicy(); method public int getLockState(); method @NonNull public java.util.Set getUsersWithMatchingAccounts(); method public void writeToParcel(@NonNull android.os.Parcel, int); @@ -2812,13 +2815,17 @@ package android.companion.virtual { field @NonNull public static final android.os.Parcelable.Creator CREATOR; field public static final int LOCK_STATE_ALWAYS_UNLOCKED = 1; // 0x1 field public static final int LOCK_STATE_DEFAULT = 0; // 0x0 + field public static final int NAVIGATION_POLICY_DEFAULT_ALLOWED = 0; // 0x0 + field public static final int NAVIGATION_POLICY_DEFAULT_BLOCKED = 1; // 0x1 } public static final class VirtualDeviceParams.Builder { ctor public VirtualDeviceParams.Builder(); method @NonNull public android.companion.virtual.VirtualDeviceParams build(); method @NonNull public android.companion.virtual.VirtualDeviceParams.Builder setAllowedActivities(@NonNull java.util.Set); + method @NonNull public android.companion.virtual.VirtualDeviceParams.Builder setAllowedCrossTaskNavigations(@NonNull java.util.Set); method @NonNull public android.companion.virtual.VirtualDeviceParams.Builder setBlockedActivities(@NonNull java.util.Set); + method @NonNull public android.companion.virtual.VirtualDeviceParams.Builder setBlockedCrossTaskNavigations(@NonNull java.util.Set); method @NonNull @RequiresPermission(value=android.Manifest.permission.ADD_ALWAYS_UNLOCKED_DISPLAY, conditional=true) public android.companion.virtual.VirtualDeviceParams.Builder setLockState(int); method @NonNull public android.companion.virtual.VirtualDeviceParams.Builder setUsersWithMatchingAccounts(@NonNull java.util.Set); } diff --git a/core/java/android/companion/virtual/VirtualDeviceParams.java b/core/java/android/companion/virtual/VirtualDeviceParams.java index cbb51838507bb..3b1ff3fa65b5a 100644 --- a/core/java/android/companion/virtual/VirtualDeviceParams.java +++ b/core/java/android/companion/virtual/VirtualDeviceParams.java @@ -83,8 +83,31 @@ public final class VirtualDeviceParams implements Parcelable { */ public static final int ACTIVITY_POLICY_DEFAULT_BLOCKED = 1; + /** @hide */ + @IntDef(prefix = "NAVIGATION_POLICY_", + value = {NAVIGATION_POLICY_DEFAULT_ALLOWED, NAVIGATION_POLICY_DEFAULT_BLOCKED}) + @Retention(RetentionPolicy.SOURCE) + @Target({ElementType.TYPE_PARAMETER, ElementType.TYPE_USE}) + public @interface NavigationPolicy {} + + /** + * Indicates that tasks are allowed to navigate to other tasks on this virtual device, + * unless they are explicitly blocked by {@link Builder#setBlockedCrossTaskNavigations}. + */ + public static final int NAVIGATION_POLICY_DEFAULT_ALLOWED = 0; + + /** + * Indicates that tasks are blocked from navigating to other tasks by default on this virtual + * device, unless allowed by {@link Builder#setAllowedCrossTaskNavigations}. + */ + public static final int NAVIGATION_POLICY_DEFAULT_BLOCKED = 1; + private final int mLockState; @NonNull private final ArraySet mUsersWithMatchingAccounts; + @NonNull private final ArraySet mAllowedCrossTaskNavigations; + @NonNull private final ArraySet mBlockedCrossTaskNavigations; + @NavigationPolicy + private final int mDefaultNavigationPolicy; @NonNull private final ArraySet mAllowedActivities; @NonNull private final ArraySet mBlockedActivities; @ActivityPolicy @@ -93,15 +116,23 @@ public final class VirtualDeviceParams implements Parcelable { private VirtualDeviceParams( @LockState int lockState, @NonNull Set usersWithMatchingAccounts, + @NonNull Set allowedCrossTaskNavigations, + @NonNull Set blockedCrossTaskNavigations, + @NavigationPolicy int defaultNavigationPolicy, @NonNull Set allowedActivities, @NonNull Set blockedActivities, @ActivityPolicy int defaultActivityPolicy) { Preconditions.checkNotNull(usersWithMatchingAccounts); + Preconditions.checkNotNull(allowedCrossTaskNavigations); + Preconditions.checkNotNull(blockedCrossTaskNavigations); Preconditions.checkNotNull(allowedActivities); Preconditions.checkNotNull(blockedActivities); mLockState = lockState; mUsersWithMatchingAccounts = new ArraySet<>(usersWithMatchingAccounts); + mAllowedCrossTaskNavigations = new ArraySet<>(allowedCrossTaskNavigations); + mBlockedCrossTaskNavigations = new ArraySet<>(blockedCrossTaskNavigations); + mDefaultNavigationPolicy = defaultNavigationPolicy; mAllowedActivities = new ArraySet<>(allowedActivities); mBlockedActivities = new ArraySet<>(blockedActivities); mDefaultActivityPolicy = defaultActivityPolicy; @@ -111,6 +142,9 @@ public final class VirtualDeviceParams implements Parcelable { private VirtualDeviceParams(Parcel parcel) { mLockState = parcel.readInt(); mUsersWithMatchingAccounts = (ArraySet) parcel.readArraySet(null); + mAllowedCrossTaskNavigations = (ArraySet) parcel.readArraySet(null); + mBlockedCrossTaskNavigations = (ArraySet) parcel.readArraySet(null); + mDefaultNavigationPolicy = parcel.readInt(); mAllowedActivities = (ArraySet) parcel.readArraySet(null); mBlockedActivities = (ArraySet) parcel.readArraySet(null); mDefaultActivityPolicy = parcel.readInt(); @@ -135,6 +169,45 @@ public final class VirtualDeviceParams implements Parcelable { return Collections.unmodifiableSet(mUsersWithMatchingAccounts); } + /** + * Returns the set of tasks that are allowed to navigate from current task, + * or empty set if all tasks are allowed, except the ones explicitly blocked. + * If neither allowed or blocked tasks are provided, all task navigations will + * be be allowed by default. + * + * @see Builder#setAllowedCrossTaskNavigations(Set) + */ + @NonNull + public Set getAllowedCrossTaskNavigations() { + return Collections.unmodifiableSet(mAllowedCrossTaskNavigations); + } + + /** + * Returns the set of tasks that are blocked from navigating from the current task, + * or empty set to indicate that all tasks in {@link #getAllowedCrossTaskNavigations} + * are allowed. If neither allowed or blocked tasks are provided, all task navigations + * will be be allowed by default. + * + * @see Builder#setBlockedCrossTaskNavigations(Set) + */ + @NonNull + public Set getBlockedCrossTaskNavigations() { + return Collections.unmodifiableSet(mBlockedCrossTaskNavigations); + } + + /** + * Returns {@link #NAVIGATION_POLICY_DEFAULT_ALLOWED} if tasks are allowed to navigate on + * this virtual device by default, or {@link #NAVIGATION_POLICY_DEFAULT_BLOCKED} if tasks + * must be allowed by {@link Builder#setAllowedCrossTaskNavigations} to navigate here. + * + * @see Builder#setAllowedCrossTaskNavigations + * @see Builder#setBlockedCrossTaskNavigations + */ + @NavigationPolicy + public int getDefaultNavigationPolicy() { + return mDefaultNavigationPolicy; + } + /** * Returns the set of activities allowed to be streamed, or empty set if all activities are * allowed, except the ones explicitly blocked. @@ -179,6 +252,9 @@ public final class VirtualDeviceParams implements Parcelable { public void writeToParcel(@NonNull Parcel dest, int flags) { dest.writeInt(mLockState); dest.writeArraySet(mUsersWithMatchingAccounts); + dest.writeArraySet(mAllowedCrossTaskNavigations); + dest.writeArraySet(mBlockedCrossTaskNavigations); + dest.writeInt(mDefaultNavigationPolicy); dest.writeArraySet(mAllowedActivities); dest.writeArraySet(mBlockedActivities); dest.writeInt(mDefaultActivityPolicy); @@ -195,6 +271,9 @@ public final class VirtualDeviceParams implements Parcelable { VirtualDeviceParams that = (VirtualDeviceParams) o; return mLockState == that.mLockState && mUsersWithMatchingAccounts.equals(that.mUsersWithMatchingAccounts) + && Objects.equals(mAllowedCrossTaskNavigations, that.mAllowedCrossTaskNavigations) + && Objects.equals(mBlockedCrossTaskNavigations, that.mBlockedCrossTaskNavigations) + && mDefaultNavigationPolicy == that.mDefaultNavigationPolicy && Objects.equals(mAllowedActivities, that.mAllowedActivities) && Objects.equals(mBlockedActivities, that.mBlockedActivities) && mDefaultActivityPolicy == that.mDefaultActivityPolicy; @@ -203,8 +282,9 @@ public final class VirtualDeviceParams implements Parcelable { @Override public int hashCode() { return Objects.hash( - mLockState, mUsersWithMatchingAccounts, mAllowedActivities, mBlockedActivities, - mDefaultActivityPolicy); + mLockState, mUsersWithMatchingAccounts, mAllowedCrossTaskNavigations, + mBlockedCrossTaskNavigations, mDefaultNavigationPolicy, mAllowedActivities, + mBlockedActivities, mDefaultActivityPolicy); } @Override @@ -213,6 +293,9 @@ public final class VirtualDeviceParams implements Parcelable { return "VirtualDeviceParams(" + " mLockState=" + mLockState + " mUsersWithMatchingAccounts=" + mUsersWithMatchingAccounts + + " mAllowedCrossTaskNavigations=" + mAllowedCrossTaskNavigations + + " mBlockedCrossTaskNavigations=" + mBlockedCrossTaskNavigations + + " mDefaultNavigationPolicy=" + mDefaultNavigationPolicy + " mAllowedActivities=" + mAllowedActivities + " mBlockedActivities=" + mBlockedActivities + " mDefaultActivityPolicy=" + mDefaultActivityPolicy @@ -237,7 +320,12 @@ public final class VirtualDeviceParams implements Parcelable { public static final class Builder { private @LockState int mLockState = LOCK_STATE_DEFAULT; - @NonNull private Set mUsersWithMatchingAccounts = Collections.emptySet();; + @NonNull private Set mUsersWithMatchingAccounts = Collections.emptySet(); + @NonNull private Set mAllowedCrossTaskNavigations = Collections.emptySet(); + @NonNull private Set mBlockedCrossTaskNavigations = Collections.emptySet(); + @NavigationPolicy + private int mDefaultNavigationPolicy = NAVIGATION_POLICY_DEFAULT_ALLOWED; + private boolean mDefaultNavigationPolicyConfigured = false; @NonNull private Set mBlockedActivities = Collections.emptySet(); @NonNull private Set mAllowedActivities = Collections.emptySet(); @ActivityPolicy @@ -287,6 +375,70 @@ public final class VirtualDeviceParams implements Parcelable { return this; } + /** + * Sets the tasks allowed to navigate from current task in the virtual device. Tasks + * not in {@code allowedCrossTaskNavigations} will be blocked from navigating to a new + * task. Calling this method will cause {@link #getDefaultNavigationPolicy()} to be + * {@link #NAVIGATION_POLICY_DEFAULT_BLOCKED}, meaning tasks not in + * {@code allowedCrossTaskNavigations} will be blocked from navigating here. + * + *

This method must not be called if {@link #setBlockedCrossTaskNavigations(Set)} has + * been called. + * + * @throws IllegalArgumentException if {@link #setBlockedCrossTaskNavigations(Set)} has been + * called. + * + * @param allowedCrossTaskNavigations A set of tasks {@link ComponentName} allowed to + * navigate to new tasks in the virtual device. + */ + @NonNull + public Builder setAllowedCrossTaskNavigations( + @NonNull Set allowedCrossTaskNavigations) { + Preconditions.checkNotNull(allowedCrossTaskNavigations); + if (mDefaultNavigationPolicyConfigured + && mDefaultNavigationPolicy != NAVIGATION_POLICY_DEFAULT_BLOCKED) { + throw new IllegalArgumentException( + "Allowed cross task navigation and blocked task navigation cannot " + + " both be set."); + } + mDefaultNavigationPolicy = NAVIGATION_POLICY_DEFAULT_BLOCKED; + mDefaultNavigationPolicyConfigured = true; + mAllowedCrossTaskNavigations = allowedCrossTaskNavigations; + return this; + } + + /** + * Sets the tasks blocked from navigating from current task in the virtual device. + * Tasks are allowed to navigate unless they are in + * {@code blockedCrossTaskNavigations}. Calling this method will cause + * {@link #NAVIGATION_POLICY_DEFAULT_ALLOWED}, meaning activities are allowed to launch + * unless they are in {@code blockedCrossTaskNavigations}. + * + *

This method must not be called if {@link #setAllowedCrossTaskNavigations(Set)} has + * been called. + * + * @throws IllegalArgumentException if {@link #setAllowedCrossTaskNavigations(Set)} has + * been called. + * + * @param blockedCrossTaskNavigations A set of tasks {@link ComponentName} to be + * blocked from navigating to new tasks in the virtual device. + */ + @NonNull + public Builder setBlockedCrossTaskNavigations( + @NonNull Set blockedCrossTaskNavigations) { + Preconditions.checkNotNull(blockedCrossTaskNavigations); + if (mDefaultNavigationPolicyConfigured + && mDefaultNavigationPolicy != NAVIGATION_POLICY_DEFAULT_ALLOWED) { + throw new IllegalArgumentException( + "Allowed cross task navigation and blocked task navigation cannot " + + " be set."); + } + mDefaultNavigationPolicy = NAVIGATION_POLICY_DEFAULT_ALLOWED; + mDefaultNavigationPolicyConfigured = true; + mBlockedCrossTaskNavigations = blockedCrossTaskNavigations; + return this; + } + /** * Sets the activities allowed to be launched in the virtual device. Calling this method * will cause {@link #getDefaultActivityPolicy()} to be @@ -349,6 +501,9 @@ public final class VirtualDeviceParams implements Parcelable { return new VirtualDeviceParams( mLockState, mUsersWithMatchingAccounts, + mAllowedCrossTaskNavigations, + mBlockedCrossTaskNavigations, + mDefaultNavigationPolicy, mAllowedActivities, mBlockedActivities, mDefaultActivityPolicy);