Loading core/api/system-current.txt +7 −4 Original line number Diff line number Diff line Loading @@ -2823,11 +2823,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 Loading @@ -2836,8 +2839,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>); } core/java/android/companion/virtual/VirtualDeviceParams.java +85 −47 Original line number Diff line number Diff line Loading @@ -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; Loading Loading @@ -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") Loading @@ -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(); } /** Loading Loading @@ -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); } Loading @@ -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; Loading @@ -150,6 +181,7 @@ public final class VirtualDeviceParams implements Parcelable { dest.writeArraySet(mUsersWithMatchingAccounts); dest.writeArraySet(mAllowedActivities); dest.writeArraySet(mBlockedActivities); dest.writeInt(mDefaultActivityPolicy); } @Override Loading @@ -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 Loading @@ -180,6 +215,7 @@ public final class VirtualDeviceParams implements Parcelable { + " mUsersWithMatchingAccounts=" + mUsersWithMatchingAccounts + " mAllowedActivities=" + mAllowedActivities + " mBlockedActivities=" + mBlockedActivities + " mDefaultActivityPolicy=" + mDefaultActivityPolicy + ")"; } Loading @@ -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} Loading Loading @@ -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; } Loading @@ -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); } } } services/companion/java/com/android/server/companion/virtual/GenericWindowPolicyController.java +25 −7 Original line number Diff line number Diff line Loading @@ -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; Loading Loading @@ -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") Loading @@ -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; Loading Loading @@ -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; } Loading services/companion/java/com/android/server/companion/virtual/VirtualDeviceImpl.java +1 −0 Original line number Diff line number Diff line Loading @@ -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); Loading services/tests/servicestests/src/com/android/server/companion/virtual/audio/VirtualAudioControllerTest.java +3 −1 Original line number Diff line number Diff line Loading @@ -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; Loading Loading @@ -72,6 +73,7 @@ public class VirtualAudioControllerTest { /* allowedUsers= */ new ArraySet<>(), /* allowedActivities= */ new ArraySet<>(), /* blockedActivities= */ new ArraySet<>(), VirtualDeviceParams.ACTIVITY_POLICY_DEFAULT_ALLOWED, /* activityListener= */ null, /* activityBlockedCallback= */ null); } Loading Loading
core/api/system-current.txt +7 −4 Original line number Diff line number Diff line Loading @@ -2823,11 +2823,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 Loading @@ -2836,8 +2839,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>); }
core/java/android/companion/virtual/VirtualDeviceParams.java +85 −47 Original line number Diff line number Diff line Loading @@ -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; Loading Loading @@ -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") Loading @@ -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(); } /** Loading Loading @@ -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); } Loading @@ -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; Loading @@ -150,6 +181,7 @@ public final class VirtualDeviceParams implements Parcelable { dest.writeArraySet(mUsersWithMatchingAccounts); dest.writeArraySet(mAllowedActivities); dest.writeArraySet(mBlockedActivities); dest.writeInt(mDefaultActivityPolicy); } @Override Loading @@ -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 Loading @@ -180,6 +215,7 @@ public final class VirtualDeviceParams implements Parcelable { + " mUsersWithMatchingAccounts=" + mUsersWithMatchingAccounts + " mAllowedActivities=" + mAllowedActivities + " mBlockedActivities=" + mBlockedActivities + " mDefaultActivityPolicy=" + mDefaultActivityPolicy + ")"; } Loading @@ -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} Loading Loading @@ -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; } Loading @@ -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); } } }
services/companion/java/com/android/server/companion/virtual/GenericWindowPolicyController.java +25 −7 Original line number Diff line number Diff line Loading @@ -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; Loading Loading @@ -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") Loading @@ -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; Loading Loading @@ -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; } Loading
services/companion/java/com/android/server/companion/virtual/VirtualDeviceImpl.java +1 −0 Original line number Diff line number Diff line Loading @@ -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); Loading
services/tests/servicestests/src/com/android/server/companion/virtual/audio/VirtualAudioControllerTest.java +3 −1 Original line number Diff line number Diff line Loading @@ -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; Loading Loading @@ -72,6 +73,7 @@ public class VirtualAudioControllerTest { /* allowedUsers= */ new ArraySet<>(), /* allowedActivities= */ new ArraySet<>(), /* blockedActivities= */ new ArraySet<>(), VirtualDeviceParams.ACTIVITY_POLICY_DEFAULT_ALLOWED, /* activityListener= */ null, /* activityBlockedCallback= */ null); } Loading