1 /* 2 * Copyright (C) 2021 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package android.companion.virtual; 18 19 import static android.Manifest.permission.ADD_ALWAYS_UNLOCKED_DISPLAY; 20 21 import android.annotation.IntDef; 22 import android.annotation.NonNull; 23 import android.annotation.RequiresPermission; 24 import android.annotation.SystemApi; 25 import android.content.ComponentName; 26 import android.os.Parcel; 27 import android.os.Parcelable; 28 import android.os.UserHandle; 29 import android.util.ArraySet; 30 31 import com.android.internal.util.Preconditions; 32 33 import java.lang.annotation.ElementType; 34 import java.lang.annotation.Retention; 35 import java.lang.annotation.RetentionPolicy; 36 import java.lang.annotation.Target; 37 import java.util.Collections; 38 import java.util.Objects; 39 import java.util.Set; 40 41 /** 42 * Params that can be configured when creating virtual devices. 43 * 44 * @hide 45 */ 46 @SystemApi 47 public final class VirtualDeviceParams implements Parcelable { 48 49 /** @hide */ 50 @IntDef(prefix = "LOCK_STATE_", 51 value = {LOCK_STATE_DEFAULT, LOCK_STATE_ALWAYS_UNLOCKED}) 52 @Retention(RetentionPolicy.SOURCE) 53 @Target({ElementType.TYPE_PARAMETER, ElementType.TYPE_USE}) 54 public @interface LockState {} 55 56 /** 57 * Indicates that the lock state of the virtual device will be the same as the default physical 58 * display. 59 */ 60 public static final int LOCK_STATE_DEFAULT = 0; 61 62 /** 63 * Indicates that the lock state of the virtual device should be always unlocked. 64 */ 65 public static final int LOCK_STATE_ALWAYS_UNLOCKED = 1; 66 67 /** @hide */ 68 @IntDef(prefix = "ACTIVITY_POLICY_", 69 value = {ACTIVITY_POLICY_DEFAULT_ALLOWED, ACTIVITY_POLICY_DEFAULT_BLOCKED}) 70 @Retention(RetentionPolicy.SOURCE) 71 @Target({ElementType.TYPE_PARAMETER, ElementType.TYPE_USE}) 72 public @interface ActivityPolicy {} 73 74 /** 75 * Indicates that activities are allowed by default on this virtual device, unless they are 76 * explicitly blocked by {@link Builder#setBlockedActivities}. 77 */ 78 public static final int ACTIVITY_POLICY_DEFAULT_ALLOWED = 0; 79 80 /** 81 * Indicates that activities are blocked by default on this virtual device, unless they are 82 * allowed by {@link Builder#setAllowedActivities}. 83 */ 84 public static final int ACTIVITY_POLICY_DEFAULT_BLOCKED = 1; 85 86 /** @hide */ 87 @IntDef(prefix = "NAVIGATION_POLICY_", 88 value = {NAVIGATION_POLICY_DEFAULT_ALLOWED, NAVIGATION_POLICY_DEFAULT_BLOCKED}) 89 @Retention(RetentionPolicy.SOURCE) 90 @Target({ElementType.TYPE_PARAMETER, ElementType.TYPE_USE}) 91 public @interface NavigationPolicy {} 92 93 /** 94 * Indicates that tasks are allowed to navigate to other tasks on this virtual device, 95 * unless they are explicitly blocked by {@link Builder#setBlockedCrossTaskNavigations}. 96 */ 97 public static final int NAVIGATION_POLICY_DEFAULT_ALLOWED = 0; 98 99 /** 100 * Indicates that tasks are blocked from navigating to other tasks by default on this virtual 101 * device, unless allowed by {@link Builder#setAllowedCrossTaskNavigations}. 102 */ 103 public static final int NAVIGATION_POLICY_DEFAULT_BLOCKED = 1; 104 105 private final int mLockState; 106 @NonNull private final ArraySet<UserHandle> mUsersWithMatchingAccounts; 107 @NonNull private final ArraySet<ComponentName> mAllowedCrossTaskNavigations; 108 @NonNull private final ArraySet<ComponentName> mBlockedCrossTaskNavigations; 109 @NavigationPolicy 110 private final int mDefaultNavigationPolicy; 111 @NonNull private final ArraySet<ComponentName> mAllowedActivities; 112 @NonNull private final ArraySet<ComponentName> mBlockedActivities; 113 @ActivityPolicy 114 private final int mDefaultActivityPolicy; 115 VirtualDeviceParams( @ockState int lockState, @NonNull Set<UserHandle> usersWithMatchingAccounts, @NonNull Set<ComponentName> allowedCrossTaskNavigations, @NonNull Set<ComponentName> blockedCrossTaskNavigations, @NavigationPolicy int defaultNavigationPolicy, @NonNull Set<ComponentName> allowedActivities, @NonNull Set<ComponentName> blockedActivities, @ActivityPolicy int defaultActivityPolicy)116 private VirtualDeviceParams( 117 @LockState int lockState, 118 @NonNull Set<UserHandle> usersWithMatchingAccounts, 119 @NonNull Set<ComponentName> allowedCrossTaskNavigations, 120 @NonNull Set<ComponentName> blockedCrossTaskNavigations, 121 @NavigationPolicy int defaultNavigationPolicy, 122 @NonNull Set<ComponentName> allowedActivities, 123 @NonNull Set<ComponentName> blockedActivities, 124 @ActivityPolicy int defaultActivityPolicy) { 125 Preconditions.checkNotNull(usersWithMatchingAccounts); 126 Preconditions.checkNotNull(allowedCrossTaskNavigations); 127 Preconditions.checkNotNull(blockedCrossTaskNavigations); 128 Preconditions.checkNotNull(allowedActivities); 129 Preconditions.checkNotNull(blockedActivities); 130 131 mLockState = lockState; 132 mUsersWithMatchingAccounts = new ArraySet<>(usersWithMatchingAccounts); 133 mAllowedCrossTaskNavigations = new ArraySet<>(allowedCrossTaskNavigations); 134 mBlockedCrossTaskNavigations = new ArraySet<>(blockedCrossTaskNavigations); 135 mDefaultNavigationPolicy = defaultNavigationPolicy; 136 mAllowedActivities = new ArraySet<>(allowedActivities); 137 mBlockedActivities = new ArraySet<>(blockedActivities); 138 mDefaultActivityPolicy = defaultActivityPolicy; 139 } 140 141 @SuppressWarnings("unchecked") VirtualDeviceParams(Parcel parcel)142 private VirtualDeviceParams(Parcel parcel) { 143 mLockState = parcel.readInt(); 144 mUsersWithMatchingAccounts = (ArraySet<UserHandle>) parcel.readArraySet(null); 145 mAllowedCrossTaskNavigations = (ArraySet<ComponentName>) parcel.readArraySet(null); 146 mBlockedCrossTaskNavigations = (ArraySet<ComponentName>) parcel.readArraySet(null); 147 mDefaultNavigationPolicy = parcel.readInt(); 148 mAllowedActivities = (ArraySet<ComponentName>) parcel.readArraySet(null); 149 mBlockedActivities = (ArraySet<ComponentName>) parcel.readArraySet(null); 150 mDefaultActivityPolicy = parcel.readInt(); 151 } 152 153 /** 154 * Returns the lock state of the virtual device. 155 */ 156 @LockState getLockState()157 public int getLockState() { 158 return mLockState; 159 } 160 161 /** 162 * Returns the user handles with matching managed accounts on the remote device to which 163 * this virtual device is streaming. 164 * 165 * @see android.app.admin.DevicePolicyManager#NEARBY_STREAMING_SAME_MANAGED_ACCOUNT_ONLY 166 */ 167 @NonNull getUsersWithMatchingAccounts()168 public Set<UserHandle> getUsersWithMatchingAccounts() { 169 return Collections.unmodifiableSet(mUsersWithMatchingAccounts); 170 } 171 172 /** 173 * Returns the set of tasks that are allowed to navigate from current task, 174 * or empty set if all tasks are allowed, except the ones explicitly blocked. 175 * If neither allowed or blocked tasks are provided, all task navigations will 176 * be be allowed by default. 177 * 178 * @see Builder#setAllowedCrossTaskNavigations(Set) 179 */ 180 @NonNull getAllowedCrossTaskNavigations()181 public Set<ComponentName> getAllowedCrossTaskNavigations() { 182 return Collections.unmodifiableSet(mAllowedCrossTaskNavigations); 183 } 184 185 /** 186 * Returns the set of tasks that are blocked from navigating from the current task, 187 * or empty set to indicate that all tasks in {@link #getAllowedCrossTaskNavigations} 188 * are allowed. If neither allowed or blocked tasks are provided, all task navigations 189 * will be be allowed by default. 190 * 191 * @see Builder#setBlockedCrossTaskNavigations(Set) 192 */ 193 @NonNull getBlockedCrossTaskNavigations()194 public Set<ComponentName> getBlockedCrossTaskNavigations() { 195 return Collections.unmodifiableSet(mBlockedCrossTaskNavigations); 196 } 197 198 /** 199 * Returns {@link #NAVIGATION_POLICY_DEFAULT_ALLOWED} if tasks are allowed to navigate on 200 * this virtual device by default, or {@link #NAVIGATION_POLICY_DEFAULT_BLOCKED} if tasks 201 * must be allowed by {@link Builder#setAllowedCrossTaskNavigations} to navigate here. 202 * 203 * @see Builder#setAllowedCrossTaskNavigations 204 * @see Builder#setBlockedCrossTaskNavigations 205 */ 206 @NavigationPolicy getDefaultNavigationPolicy()207 public int getDefaultNavigationPolicy() { 208 return mDefaultNavigationPolicy; 209 } 210 211 /** 212 * Returns the set of activities allowed to be streamed, or empty set if all activities are 213 * allowed, except the ones explicitly blocked. 214 * 215 * @see Builder#setAllowedActivities(Set) 216 */ 217 @NonNull getAllowedActivities()218 public Set<ComponentName> getAllowedActivities() { 219 return Collections.unmodifiableSet(mAllowedActivities); 220 } 221 222 /** 223 * Returns the set of activities that are blocked from streaming, or empty set to indicate 224 * that all activities in {@link #getAllowedActivities} are allowed. 225 * 226 * @see Builder#setBlockedActivities(Set) 227 */ 228 @NonNull getBlockedActivities()229 public Set<ComponentName> getBlockedActivities() { 230 return Collections.unmodifiableSet(mBlockedActivities); 231 } 232 233 /** 234 * Returns {@link #ACTIVITY_POLICY_DEFAULT_ALLOWED} if activities are allowed to launch on this 235 * virtual device by default, or {@link #ACTIVITY_POLICY_DEFAULT_BLOCKED} if activities must be 236 * allowed by {@link Builder#setAllowedActivities} to launch here. 237 * 238 * @see Builder#setBlockedActivities 239 * @see Builder#setAllowedActivities 240 */ 241 @ActivityPolicy getDefaultActivityPolicy()242 public int getDefaultActivityPolicy() { 243 return mDefaultActivityPolicy; 244 } 245 246 @Override describeContents()247 public int describeContents() { 248 return 0; 249 } 250 251 @Override writeToParcel(@onNull Parcel dest, int flags)252 public void writeToParcel(@NonNull Parcel dest, int flags) { 253 dest.writeInt(mLockState); 254 dest.writeArraySet(mUsersWithMatchingAccounts); 255 dest.writeArraySet(mAllowedCrossTaskNavigations); 256 dest.writeArraySet(mBlockedCrossTaskNavigations); 257 dest.writeInt(mDefaultNavigationPolicy); 258 dest.writeArraySet(mAllowedActivities); 259 dest.writeArraySet(mBlockedActivities); 260 dest.writeInt(mDefaultActivityPolicy); 261 } 262 263 @Override equals(Object o)264 public boolean equals(Object o) { 265 if (this == o) { 266 return true; 267 } 268 if (!(o instanceof VirtualDeviceParams)) { 269 return false; 270 } 271 VirtualDeviceParams that = (VirtualDeviceParams) o; 272 return mLockState == that.mLockState 273 && mUsersWithMatchingAccounts.equals(that.mUsersWithMatchingAccounts) 274 && Objects.equals(mAllowedCrossTaskNavigations, that.mAllowedCrossTaskNavigations) 275 && Objects.equals(mBlockedCrossTaskNavigations, that.mBlockedCrossTaskNavigations) 276 && mDefaultNavigationPolicy == that.mDefaultNavigationPolicy 277 && Objects.equals(mAllowedActivities, that.mAllowedActivities) 278 && Objects.equals(mBlockedActivities, that.mBlockedActivities) 279 && mDefaultActivityPolicy == that.mDefaultActivityPolicy; 280 } 281 282 @Override hashCode()283 public int hashCode() { 284 return Objects.hash( 285 mLockState, mUsersWithMatchingAccounts, mAllowedCrossTaskNavigations, 286 mBlockedCrossTaskNavigations, mDefaultNavigationPolicy, mAllowedActivities, 287 mBlockedActivities, mDefaultActivityPolicy); 288 } 289 290 @Override 291 @NonNull toString()292 public String toString() { 293 return "VirtualDeviceParams(" 294 + " mLockState=" + mLockState 295 + " mUsersWithMatchingAccounts=" + mUsersWithMatchingAccounts 296 + " mAllowedCrossTaskNavigations=" + mAllowedCrossTaskNavigations 297 + " mBlockedCrossTaskNavigations=" + mBlockedCrossTaskNavigations 298 + " mDefaultNavigationPolicy=" + mDefaultNavigationPolicy 299 + " mAllowedActivities=" + mAllowedActivities 300 + " mBlockedActivities=" + mBlockedActivities 301 + " mDefaultActivityPolicy=" + mDefaultActivityPolicy 302 + ")"; 303 } 304 305 @NonNull 306 public static final Parcelable.Creator<VirtualDeviceParams> CREATOR = 307 new Parcelable.Creator<VirtualDeviceParams>() { 308 public VirtualDeviceParams createFromParcel(Parcel in) { 309 return new VirtualDeviceParams(in); 310 } 311 312 public VirtualDeviceParams[] newArray(int size) { 313 return new VirtualDeviceParams[size]; 314 } 315 }; 316 317 /** 318 * Builder for {@link VirtualDeviceParams}. 319 */ 320 public static final class Builder { 321 322 private @LockState int mLockState = LOCK_STATE_DEFAULT; 323 @NonNull private Set<UserHandle> mUsersWithMatchingAccounts = Collections.emptySet(); 324 @NonNull private Set<ComponentName> mAllowedCrossTaskNavigations = Collections.emptySet(); 325 @NonNull private Set<ComponentName> mBlockedCrossTaskNavigations = Collections.emptySet(); 326 @NavigationPolicy 327 private int mDefaultNavigationPolicy = NAVIGATION_POLICY_DEFAULT_ALLOWED; 328 private boolean mDefaultNavigationPolicyConfigured = false; 329 @NonNull private Set<ComponentName> mBlockedActivities = Collections.emptySet(); 330 @NonNull private Set<ComponentName> mAllowedActivities = Collections.emptySet(); 331 @ActivityPolicy 332 private int mDefaultActivityPolicy = ACTIVITY_POLICY_DEFAULT_ALLOWED; 333 private boolean mDefaultActivityPolicyConfigured = false; 334 335 /** 336 * Sets the lock state of the device. The permission {@code ADD_ALWAYS_UNLOCKED_DISPLAY} 337 * is required if this is set to {@link #LOCK_STATE_ALWAYS_UNLOCKED}. 338 * The default is {@link #LOCK_STATE_DEFAULT}. 339 * 340 * @param lockState The lock state, either {@link #LOCK_STATE_DEFAULT} or 341 * {@link #LOCK_STATE_ALWAYS_UNLOCKED}. 342 */ 343 @RequiresPermission(value = ADD_ALWAYS_UNLOCKED_DISPLAY, conditional = true) 344 @NonNull setLockState(@ockState int lockState)345 public Builder setLockState(@LockState int lockState) { 346 mLockState = lockState; 347 return this; 348 } 349 350 /** 351 * Sets the user handles with matching managed accounts on the remote device to which 352 * this virtual device is streaming. The caller is responsible for verifying the presence 353 * and legitimacy of a matching managed account on the remote device. 354 * 355 * <p>If the app streaming policy is 356 * {@link android.app.admin.DevicePolicyManager#NEARBY_STREAMING_SAME_MANAGED_ACCOUNT_ONLY 357 * NEARBY_STREAMING_SAME_MANAGED_ACCOUNT_ONLY}, activities not in 358 * {@code usersWithMatchingAccounts} will be blocked from starting. 359 * 360 * <p> If {@code usersWithMatchingAccounts} is empty (the default), streaming is allowed 361 * only if there is no device policy, or if the nearby streaming policy is 362 * {@link android.app.admin.DevicePolicyManager#NEARBY_STREAMING_ENABLED 363 * NEARBY_STREAMING_ENABLED}. 364 * 365 * @param usersWithMatchingAccounts A set of user handles with matching managed 366 * accounts on the remote device this is streaming to. 367 * 368 * @see android.app.admin.DevicePolicyManager#NEARBY_STREAMING_SAME_MANAGED_ACCOUNT_ONLY 369 */ 370 @NonNull setUsersWithMatchingAccounts( @onNull Set<UserHandle> usersWithMatchingAccounts)371 public Builder setUsersWithMatchingAccounts( 372 @NonNull Set<UserHandle> usersWithMatchingAccounts) { 373 Preconditions.checkNotNull(usersWithMatchingAccounts); 374 mUsersWithMatchingAccounts = usersWithMatchingAccounts; 375 return this; 376 } 377 378 /** 379 * Sets the tasks allowed to navigate from current task in the virtual device. Tasks 380 * not in {@code allowedCrossTaskNavigations} will be blocked from navigating to a new 381 * task. Calling this method will cause {@link #getDefaultNavigationPolicy()} to be 382 * {@link #NAVIGATION_POLICY_DEFAULT_BLOCKED}, meaning tasks not in 383 * {@code allowedCrossTaskNavigations} will be blocked from navigating here. 384 * 385 * <p>This method must not be called if {@link #setBlockedCrossTaskNavigations(Set)} has 386 * been called. 387 * 388 * @throws IllegalArgumentException if {@link #setBlockedCrossTaskNavigations(Set)} has been 389 * called. 390 * 391 * @param allowedCrossTaskNavigations A set of tasks {@link ComponentName} allowed to 392 * navigate to new tasks in the virtual device. 393 */ 394 @NonNull setAllowedCrossTaskNavigations( @onNull Set<ComponentName> allowedCrossTaskNavigations)395 public Builder setAllowedCrossTaskNavigations( 396 @NonNull Set<ComponentName> allowedCrossTaskNavigations) { 397 Preconditions.checkNotNull(allowedCrossTaskNavigations); 398 if (mDefaultNavigationPolicyConfigured 399 && mDefaultNavigationPolicy != NAVIGATION_POLICY_DEFAULT_BLOCKED) { 400 throw new IllegalArgumentException( 401 "Allowed cross task navigation and blocked task navigation cannot " 402 + " both be set."); 403 } 404 mDefaultNavigationPolicy = NAVIGATION_POLICY_DEFAULT_BLOCKED; 405 mDefaultNavigationPolicyConfigured = true; 406 mAllowedCrossTaskNavigations = allowedCrossTaskNavigations; 407 return this; 408 } 409 410 /** 411 * Sets the tasks blocked from navigating from current task in the virtual device. 412 * Tasks are allowed to navigate unless they are in 413 * {@code blockedCrossTaskNavigations}. Calling this method will cause 414 * {@link #NAVIGATION_POLICY_DEFAULT_ALLOWED}, meaning activities are allowed to launch 415 * unless they are in {@code blockedCrossTaskNavigations}. 416 * 417 * <p> This method must not be called if {@link #setAllowedCrossTaskNavigations(Set)} has 418 * been called. 419 * 420 * @throws IllegalArgumentException if {@link #setAllowedCrossTaskNavigations(Set)} has 421 * been called. 422 * 423 * @param blockedCrossTaskNavigations A set of tasks {@link ComponentName} to be 424 * blocked from navigating to new tasks in the virtual device. 425 */ 426 @NonNull setBlockedCrossTaskNavigations( @onNull Set<ComponentName> blockedCrossTaskNavigations)427 public Builder setBlockedCrossTaskNavigations( 428 @NonNull Set<ComponentName> blockedCrossTaskNavigations) { 429 Preconditions.checkNotNull(blockedCrossTaskNavigations); 430 if (mDefaultNavigationPolicyConfigured 431 && mDefaultNavigationPolicy != NAVIGATION_POLICY_DEFAULT_ALLOWED) { 432 throw new IllegalArgumentException( 433 "Allowed cross task navigation and blocked task navigation cannot " 434 + " be set."); 435 } 436 mDefaultNavigationPolicy = NAVIGATION_POLICY_DEFAULT_ALLOWED; 437 mDefaultNavigationPolicyConfigured = true; 438 mBlockedCrossTaskNavigations = blockedCrossTaskNavigations; 439 return this; 440 } 441 442 /** 443 * Sets the activities allowed to be launched in the virtual device. Calling this method 444 * will cause {@link #getDefaultActivityPolicy()} to be 445 * {@link #ACTIVITY_POLICY_DEFAULT_BLOCKED}, meaning activities not in 446 * {@code allowedActivities} will be blocked from launching here. 447 * 448 * <p>This method must not be called if {@link #setBlockedActivities(Set)} has been called. 449 * 450 * @throws IllegalArgumentException if {@link #setBlockedActivities(Set)} has been called. 451 * 452 * @param allowedActivities A set of activity {@link ComponentName} allowed to be launched 453 * in the virtual device. 454 */ 455 @NonNull setAllowedActivities(@onNull Set<ComponentName> allowedActivities)456 public Builder setAllowedActivities(@NonNull Set<ComponentName> allowedActivities) { 457 Preconditions.checkNotNull(allowedActivities); 458 if (mDefaultActivityPolicyConfigured 459 && mDefaultActivityPolicy != ACTIVITY_POLICY_DEFAULT_BLOCKED) { 460 throw new IllegalArgumentException( 461 "Allowed activities and Blocked activities cannot both be set."); 462 } 463 mDefaultActivityPolicy = ACTIVITY_POLICY_DEFAULT_BLOCKED; 464 mDefaultActivityPolicyConfigured = true; 465 mAllowedActivities = allowedActivities; 466 return this; 467 } 468 469 /** 470 * Sets the activities blocked from launching in the virtual device. Calling this method 471 * will cause {@link #getDefaultActivityPolicy()} to be 472 * {@link #ACTIVITY_POLICY_DEFAULT_ALLOWED}, meaning activities are allowed to launch here 473 * unless they are in {@code blockedActivities}. 474 * 475 * <p>This method must not be called if {@link #setAllowedActivities(Set)} has been called. 476 * 477 * @throws IllegalArgumentException if {@link #setAllowedActivities(Set)} has been called. 478 * 479 * @param blockedActivities A set of {@link ComponentName} to be blocked launching from 480 * virtual device. 481 */ 482 @NonNull setBlockedActivities(@onNull Set<ComponentName> blockedActivities)483 public Builder setBlockedActivities(@NonNull Set<ComponentName> blockedActivities) { 484 Preconditions.checkNotNull(blockedActivities); 485 if (mDefaultActivityPolicyConfigured 486 && mDefaultActivityPolicy != ACTIVITY_POLICY_DEFAULT_ALLOWED) { 487 throw new IllegalArgumentException( 488 "Allowed activities and Blocked activities cannot both be set."); 489 } 490 mDefaultActivityPolicy = ACTIVITY_POLICY_DEFAULT_ALLOWED; 491 mDefaultActivityPolicyConfigured = true; 492 mBlockedActivities = blockedActivities; 493 return this; 494 } 495 496 /** 497 * Builds the {@link VirtualDeviceParams} instance. 498 */ 499 @NonNull build()500 public VirtualDeviceParams build() { 501 return new VirtualDeviceParams( 502 mLockState, 503 mUsersWithMatchingAccounts, 504 mAllowedCrossTaskNavigations, 505 mBlockedCrossTaskNavigations, 506 mDefaultNavigationPolicy, 507 mAllowedActivities, 508 mBlockedActivities, 509 mDefaultActivityPolicy); 510 } 511 } 512 } 513