diff options
| author | 2022-02-17 00:09:08 -0800 | |
|---|---|---|
| committer | 2022-02-22 20:37:20 +0000 | |
| commit | 804b69925ea08d80f14c367e5fed819dc6fd1cfe (patch) | |
| tree | 86b53dca7bdb013c1e6ccd80e014941c920d0701 | |
| parent | 60224bcea6ea3b8b31825cf8afdf90300a98a0ff (diff) | |
Specify default activity policy
Instead of using null values to indicate whether to use the allow list
or deny list for activity launching, add an intdef value to specify that
explicitly.
Bug: 219985243
Test: atest CtsVirtualDevicesTestCases
Change-Id: Ie6039262c95270f8886da7146999f30844f69a3c
5 files changed, 121 insertions, 59 deletions
diff --git a/core/api/system-current.txt b/core/api/system-current.txt index 2c0e6416b455..7d814d60063e 100644 --- a/core/api/system-current.txt +++ b/core/api/system-current.txt @@ -2804,11 +2804,14 @@ package android.companion.virtual { public final class VirtualDeviceParams implements android.os.Parcelable { method public int describeContents(); - method @Nullable public java.util.Set<android.content.ComponentName> getAllowedActivities(); - method @Nullable public java.util.Set<android.content.ComponentName> getBlockedActivities(); + method @NonNull public java.util.Set<android.content.ComponentName> getAllowedActivities(); + method @NonNull public java.util.Set<android.content.ComponentName> getBlockedActivities(); + method public int getDefaultActivityPolicy(); method public int getLockState(); method @NonNull public java.util.Set<android.os.UserHandle> getUsersWithMatchingAccounts(); method public void writeToParcel(@NonNull android.os.Parcel, int); + field public static final int ACTIVITY_POLICY_DEFAULT_ALLOWED = 0; // 0x0 + field public static final int ACTIVITY_POLICY_DEFAULT_BLOCKED = 1; // 0x1 field @NonNull public static final android.os.Parcelable.Creator<android.companion.virtual.VirtualDeviceParams> CREATOR; field public static final int LOCK_STATE_ALWAYS_UNLOCKED = 1; // 0x1 field public static final int LOCK_STATE_DEFAULT = 0; // 0x0 @@ -2817,8 +2820,8 @@ package android.companion.virtual { 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(@Nullable java.util.Set<android.content.ComponentName>); - method @NonNull public android.companion.virtual.VirtualDeviceParams.Builder setBlockedActivities(@Nullable java.util.Set<android.content.ComponentName>); + method @NonNull public android.companion.virtual.VirtualDeviceParams.Builder setAllowedActivities(@NonNull java.util.Set<android.content.ComponentName>); + method @NonNull public android.companion.virtual.VirtualDeviceParams.Builder setBlockedActivities(@NonNull java.util.Set<android.content.ComponentName>); 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<android.os.UserHandle>); } diff --git a/core/java/android/companion/virtual/VirtualDeviceParams.java b/core/java/android/companion/virtual/VirtualDeviceParams.java index 45d0ad51da04..41b1a1feae80 100644 --- a/core/java/android/companion/virtual/VirtualDeviceParams.java +++ b/core/java/android/companion/virtual/VirtualDeviceParams.java @@ -20,9 +20,7 @@ import static android.Manifest.permission.ADD_ALWAYS_UNLOCKED_DISPLAY; import android.annotation.IntDef; import android.annotation.NonNull; -import android.annotation.Nullable; import android.annotation.RequiresPermission; -import android.annotation.SuppressLint; import android.annotation.SystemApi; import android.content.ComponentName; import android.os.Parcel; @@ -64,20 +62,43 @@ public final class VirtualDeviceParams implements Parcelable { */ public static final int LOCK_STATE_ALWAYS_UNLOCKED = 1; + /** @hide */ + @IntDef(prefix = "ACTIVITY_POLICY_", + value = {ACTIVITY_POLICY_DEFAULT_ALLOWED, ACTIVITY_POLICY_DEFAULT_BLOCKED}) + @Retention(RetentionPolicy.SOURCE) + @Target({ElementType.TYPE_PARAMETER, ElementType.TYPE_USE}) + public @interface ActivityPolicy {} + + /** + * Indicates that activities are allowed by default on this virtual device, unless they are + * explicitly blocked by {@link Builder#setBlockedActivities}. + */ + public static final int ACTIVITY_POLICY_DEFAULT_ALLOWED = 0; + + /** + * Indicates that activities are blocked by default on this virtual device, unless they are + * allowed by {@link Builder#setAllowedActivities}. + */ + public static final int ACTIVITY_POLICY_DEFAULT_BLOCKED = 1; + private final int mLockState; private final ArraySet<UserHandle> mUsersWithMatchingAccounts; - @Nullable private final ArraySet<ComponentName> mAllowedActivities; - @Nullable private final ArraySet<ComponentName> mBlockedActivities; + @NonNull private final ArraySet<ComponentName> mAllowedActivities; + @NonNull private final ArraySet<ComponentName> mBlockedActivities; + @ActivityPolicy + private final int mDefaultActivityPolicy; private VirtualDeviceParams( @LockState int lockState, @NonNull Set<UserHandle> usersWithMatchingAccounts, - @Nullable Set<ComponentName> allowedActivities, - @Nullable Set<ComponentName> blockedActivities) { + @NonNull Set<ComponentName> allowedActivities, + @NonNull Set<ComponentName> blockedActivities, + @ActivityPolicy int defaultActivityPolicy) { mLockState = lockState; mUsersWithMatchingAccounts = new ArraySet<>(usersWithMatchingAccounts); mAllowedActivities = allowedActivities == null ? null : new ArraySet<>(allowedActivities); mBlockedActivities = blockedActivities == null ? null : new ArraySet<>(blockedActivities); + mDefaultActivityPolicy = defaultActivityPolicy; } @SuppressWarnings("unchecked") @@ -86,6 +107,7 @@ public final class VirtualDeviceParams implements Parcelable { mUsersWithMatchingAccounts = (ArraySet<UserHandle>) parcel.readArraySet(null); mAllowedActivities = (ArraySet<ComponentName>) parcel.readArraySet(null); mBlockedActivities = (ArraySet<ComponentName>) parcel.readArraySet(null); + mDefaultActivityPolicy = parcel.readInt(); } /** @@ -113,12 +135,10 @@ public final class VirtualDeviceParams implements Parcelable { * * @see Builder#setAllowedActivities(Set) */ - // Null and empty have different semantics - Null allows all activities to be streamed - @SuppressLint("NullableCollection") - @Nullable + @NonNull public Set<ComponentName> getAllowedActivities() { if (mAllowedActivities == null) { - return null; + return Collections.emptySet(); } return Collections.unmodifiableSet(mAllowedActivities); } @@ -129,16 +149,27 @@ public final class VirtualDeviceParams implements Parcelable { * * @see Builder#setBlockedActivities(Set) */ - // Allowing null to enforce that at most one of allowed / blocked activities can be non-null - @SuppressLint("NullableCollection") - @Nullable + @NonNull public Set<ComponentName> getBlockedActivities() { if (mBlockedActivities == null) { - return null; + return Collections.emptySet(); } return Collections.unmodifiableSet(mBlockedActivities); } + /** + * Returns {@link #ACTIVITY_POLICY_DEFAULT_ALLOWED} if activities are allowed to launch on this + * virtual device by default, or {@link #ACTIVITY_POLICY_DEFAULT_BLOCKED} if activities must be + * allowed by {@link Builder#setAllowedActivities} to launch here. + * + * @see Builder#setBlockedActivities + * @see Builder#setAllowedActivities + */ + @ActivityPolicy + public int getDefaultActivityPolicy() { + return mDefaultActivityPolicy; + } + @Override public int describeContents() { return 0; @@ -150,6 +181,7 @@ public final class VirtualDeviceParams implements Parcelable { dest.writeArraySet(mUsersWithMatchingAccounts); dest.writeArraySet(mAllowedActivities); dest.writeArraySet(mBlockedActivities); + dest.writeInt(mDefaultActivityPolicy); } @Override @@ -164,12 +196,15 @@ public final class VirtualDeviceParams implements Parcelable { return mLockState == that.mLockState && mUsersWithMatchingAccounts.equals(that.mUsersWithMatchingAccounts) && Objects.equals(mAllowedActivities, that.mAllowedActivities) - && Objects.equals(mBlockedActivities, that.mBlockedActivities); + && Objects.equals(mBlockedActivities, that.mBlockedActivities) + && mDefaultActivityPolicy == that.mDefaultActivityPolicy; } @Override public int hashCode() { - return Objects.hash(mLockState, mUsersWithMatchingAccounts); + return Objects.hash( + mLockState, mUsersWithMatchingAccounts, mAllowedActivities, mBlockedActivities, + mDefaultActivityPolicy); } @Override @@ -180,6 +215,7 @@ public final class VirtualDeviceParams implements Parcelable { + " mUsersWithMatchingAccounts=" + mUsersWithMatchingAccounts + " mAllowedActivities=" + mAllowedActivities + " mBlockedActivities=" + mBlockedActivities + + " mDefaultActivityPolicy=" + mDefaultActivityPolicy + ")"; } @@ -202,8 +238,11 @@ public final class VirtualDeviceParams implements Parcelable { private @LockState int mLockState = LOCK_STATE_DEFAULT; private Set<UserHandle> mUsersWithMatchingAccounts; - @Nullable private Set<ComponentName> mBlockedActivities; - @Nullable private Set<ComponentName> mAllowedActivities; + @NonNull private Set<ComponentName> mBlockedActivities = Collections.emptySet(); + @NonNull private Set<ComponentName> mAllowedActivities = Collections.emptySet(); + @ActivityPolicy + private int mDefaultActivityPolicy = ACTIVITY_POLICY_DEFAULT_ALLOWED; + private boolean mDefaultActivityPolicyConfigured = false; /** * Sets the lock state of the device. The permission {@code ADD_ALWAYS_UNLOCKED_DISPLAY} @@ -248,53 +287,53 @@ public final class VirtualDeviceParams implements Parcelable { } /** - * Sets the activities allowed to be launched in the virtual device. If - * {@code allowedActivities} is non-null, all activities other than the ones in the set will - * be blocked from launching. + * Sets the activities allowed to be launched in the virtual device. Calling this method + * will cause {@link #getDefaultActivityPolicy()} to be + * {@link #ACTIVITY_POLICY_DEFAULT_BLOCKED}, meaning activities not in + * {@code allowedActivities} will be blocked from launching here. * - * <p>{@code allowedActivities} and the set in {@link #setBlockedActivities(Set)} cannot - * both be non-null at the same time. + * <p>This method must not be called if {@link #setBlockedActivities(Set)} has been called. * - * @throws IllegalArgumentException if {@link #setBlockedActivities(Set)} has been set to a - * non-null value. + * @throws IllegalArgumentException if {@link #setBlockedActivities(Set)} has been called. * * @param allowedActivities A set of activity {@link ComponentName} allowed to be launched * in the virtual device. */ - // Null and empty have different semantics - Null allows all activities to be streamed - @SuppressLint("NullableCollection") @NonNull - public Builder setAllowedActivities(@Nullable Set<ComponentName> allowedActivities) { - if (mBlockedActivities != null && allowedActivities != null) { + public Builder setAllowedActivities(@NonNull Set<ComponentName> allowedActivities) { + if (mDefaultActivityPolicyConfigured + && mDefaultActivityPolicy != ACTIVITY_POLICY_DEFAULT_BLOCKED) { throw new IllegalArgumentException( "Allowed activities and Blocked activities cannot both be set."); } + mDefaultActivityPolicy = ACTIVITY_POLICY_DEFAULT_BLOCKED; + mDefaultActivityPolicyConfigured = true; mAllowedActivities = allowedActivities; return this; } /** - * Sets the activities blocked from launching in the virtual device. If the {@code - * blockedActivities} is non-null, activities in the set are blocked from launching in the - * virtual device. + * Sets the activities blocked from launching in the virtual device. Calling this method + * will cause {@link #getDefaultActivityPolicy()} to be + * {@link #ACTIVITY_POLICY_DEFAULT_ALLOWED}, meaning activities are allowed to launch here + * unless they are in {@code blockedActivities}. * - * {@code blockedActivities} and the set in {@link #setAllowedActivities(Set)} cannot both - * be non-null at the same time. + * <p>This method must not be called if {@link #setAllowedActivities(Set)} has been called. * - * @throws IllegalArgumentException if {@link #setAllowedActivities(Set)} has been set to a - * non-null value. + * @throws IllegalArgumentException if {@link #setAllowedActivities(Set)} has been called. * * @param blockedActivities A set of {@link ComponentName} to be blocked launching from * virtual device. */ - // Allowing null to enforce that at most one of allowed / blocked activities can be non-null - @SuppressLint("NullableCollection") @NonNull - public Builder setBlockedActivities(@Nullable Set<ComponentName> blockedActivities) { - if (mAllowedActivities != null && blockedActivities != null) { + public Builder setBlockedActivities(@NonNull Set<ComponentName> blockedActivities) { + if (mDefaultActivityPolicyConfigured + && mDefaultActivityPolicy != ACTIVITY_POLICY_DEFAULT_ALLOWED) { throw new IllegalArgumentException( "Allowed activities and Blocked activities cannot both be set."); } + mDefaultActivityPolicy = ACTIVITY_POLICY_DEFAULT_ALLOWED; + mDefaultActivityPolicyConfigured = true; mBlockedActivities = blockedActivities; return this; } @@ -307,13 +346,12 @@ public final class VirtualDeviceParams implements Parcelable { if (mUsersWithMatchingAccounts == null) { mUsersWithMatchingAccounts = Collections.emptySet(); } - if (mAllowedActivities != null && mBlockedActivities != null) { - // Should never reach here because the setters block this as well. - throw new IllegalStateException( - "Allowed activities and Blocked activities cannot both be set."); - } - return new VirtualDeviceParams(mLockState, mUsersWithMatchingAccounts, - mAllowedActivities, mBlockedActivities); + return new VirtualDeviceParams( + mLockState, + mUsersWithMatchingAccounts, + mAllowedActivities, + mBlockedActivities, + mDefaultActivityPolicy); } } } diff --git a/services/companion/java/com/android/server/companion/virtual/GenericWindowPolicyController.java b/services/companion/java/com/android/server/companion/virtual/GenericWindowPolicyController.java index bc1f28d1c373..b991ba87eef4 100644 --- a/services/companion/java/com/android/server/companion/virtual/GenericWindowPolicyController.java +++ b/services/companion/java/com/android/server/companion/virtual/GenericWindowPolicyController.java @@ -24,6 +24,8 @@ import android.annotation.NonNull; import android.annotation.Nullable; import android.app.compat.CompatChanges; import android.companion.virtual.VirtualDeviceManager.ActivityListener; +import android.companion.virtual.VirtualDeviceParams; +import android.companion.virtual.VirtualDeviceParams.ActivityPolicy; import android.compat.annotation.ChangeId; import android.compat.annotation.EnabledSince; import android.content.ComponentName; @@ -77,7 +79,9 @@ public class GenericWindowPolicyController extends DisplayWindowPolicyController @Nullable private final ArraySet<ComponentName> mBlockedActivities; private final Object mGenericWindowPolicyControllerLock = new Object(); - private Consumer<ActivityInfo> mActivityBlockedCallback; + @ActivityPolicy + private final int mDefaultActivityPolicy; + private final Consumer<ActivityInfo> mActivityBlockedCallback; @NonNull @GuardedBy("mGenericWindowPolicyControllerLock") @@ -95,18 +99,30 @@ public class GenericWindowPolicyController extends DisplayWindowPolicyController * @param windowFlags The window flags that this controller is interested in. * @param systemWindowFlags The system window flags that this controller is interested in. * @param allowedUsers The set of users that are allowed to stream in this display. + * @param allowedActivities The set of activities explicitly allowed to stream on this device. + * Used only if the {@code activityPolicy} is + * {@link VirtualDeviceParams#ACTIVITY_POLICY_DEFAULT_BLOCKED}. + * @param blockedActivities The set of activities explicitly blocked from streaming on this + * device. Used only if the {@code activityPolicy} is + * {@link VirtualDeviceParams#ACTIVITY_POLICY_DEFAULT_ALLOWED} + * @param defaultActivityPolicy Whether activities are default allowed to be displayed or + * blocked. * @param activityListener Activity listener to listen for activity changes. The display ID * is not populated in this callback and is always {@link Display#INVALID_DISPLAY}. + * @param activityBlockedCallback Callback that is called when an activity is blocked from + * launching. */ public GenericWindowPolicyController(int windowFlags, int systemWindowFlags, @NonNull ArraySet<UserHandle> allowedUsers, - @Nullable Set<ComponentName> allowedActivities, - @Nullable Set<ComponentName> blockedActivities, + @NonNull Set<ComponentName> allowedActivities, + @NonNull Set<ComponentName> blockedActivities, + @ActivityPolicy int defaultActivityPolicy, @NonNull ActivityListener activityListener, @NonNull Consumer<ActivityInfo> activityBlockedCallback) { mAllowedUsers = allowedUsers; - mAllowedActivities = allowedActivities == null ? null : new ArraySet<>(allowedActivities); - mBlockedActivities = blockedActivities == null ? null : new ArraySet<>(blockedActivities); + mAllowedActivities = new ArraySet<>(allowedActivities); + mBlockedActivities = new ArraySet<>(blockedActivities); + mDefaultActivityPolicy = defaultActivityPolicy; mActivityBlockedCallback = activityBlockedCallback; setInterestedWindowFlags(windowFlags, systemWindowFlags); mActivityListener = activityListener; @@ -191,11 +207,13 @@ public class GenericWindowPolicyController extends DisplayWindowPolicyController Slog.d(TAG, "Virtual device activity not allowed from user " + activityUser); return false; } - if (mBlockedActivities != null && mBlockedActivities.contains(activityComponent)) { + if (mDefaultActivityPolicy == VirtualDeviceParams.ACTIVITY_POLICY_DEFAULT_ALLOWED + && mBlockedActivities.contains(activityComponent)) { Slog.d(TAG, "Virtual device blocking launch of " + activityComponent); return false; } - if (mAllowedActivities != null && !mAllowedActivities.contains(activityComponent)) { + if (mDefaultActivityPolicy == VirtualDeviceParams.ACTIVITY_POLICY_DEFAULT_BLOCKED + && !mAllowedActivities.contains(activityComponent)) { Slog.d(TAG, activityComponent + " is not in the allowed list."); return false; } diff --git a/services/companion/java/com/android/server/companion/virtual/VirtualDeviceImpl.java b/services/companion/java/com/android/server/companion/virtual/VirtualDeviceImpl.java index c0a904fe3d9a..dbb48aea94ff 100644 --- a/services/companion/java/com/android/server/companion/virtual/VirtualDeviceImpl.java +++ b/services/companion/java/com/android/server/companion/virtual/VirtualDeviceImpl.java @@ -505,6 +505,7 @@ final class VirtualDeviceImpl extends IVirtualDevice.Stub getAllowedUserHandles(), mParams.getAllowedActivities(), mParams.getBlockedActivities(), + mParams.getDefaultActivityPolicy(), createListenerAdapter(displayId), activityInfo -> onActivityBlocked(displayId, activityInfo)); mWindowPolicyControllers.put(displayId, dwpc); diff --git a/services/tests/servicestests/src/com/android/server/companion/virtual/audio/VirtualAudioControllerTest.java b/services/tests/servicestests/src/com/android/server/companion/virtual/audio/VirtualAudioControllerTest.java index 3160272ef9b1..f0c907d49a46 100644 --- a/services/tests/servicestests/src/com/android/server/companion/virtual/audio/VirtualAudioControllerTest.java +++ b/services/tests/servicestests/src/com/android/server/companion/virtual/audio/VirtualAudioControllerTest.java @@ -25,6 +25,7 @@ import static com.google.common.truth.Truth.assertThat; import static org.mockito.Mockito.never; import static org.mockito.Mockito.verify; +import android.companion.virtual.VirtualDeviceParams; import android.companion.virtual.audio.IAudioSessionCallback; import android.content.Context; import android.content.ContextWrapper; @@ -72,7 +73,8 @@ public class VirtualAudioControllerTest { /* allowedUsers= */ new ArraySet<>(), /* allowedActivities= */ new ArraySet<>(), /* blockedActivities= */ new ArraySet<>(), - /* activityListener= */null, + VirtualDeviceParams.ACTIVITY_POLICY_DEFAULT_ALLOWED, + /* activityListener= */ null, /* activityBlockedCallback= */ null); } |