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 import static android.media.AudioManager.AUDIO_SESSION_ID_GENERATE;
21 
22 import static java.util.concurrent.TimeUnit.MICROSECONDS;
23 
24 import android.annotation.CallbackExecutor;
25 import android.annotation.IntDef;
26 import android.annotation.NonNull;
27 import android.annotation.Nullable;
28 import android.annotation.RequiresPermission;
29 import android.annotation.SuppressLint;
30 import android.annotation.SystemApi;
31 import android.companion.virtual.sensor.IVirtualSensorCallback;
32 import android.companion.virtual.sensor.VirtualSensor;
33 import android.companion.virtual.sensor.VirtualSensorCallback;
34 import android.companion.virtual.sensor.VirtualSensorConfig;
35 import android.companion.virtual.sensor.VirtualSensorDirectChannelCallback;
36 import android.content.ComponentName;
37 import android.content.Context;
38 import android.os.Parcel;
39 import android.os.Parcelable;
40 import android.os.SharedMemory;
41 import android.os.UserHandle;
42 import android.util.ArraySet;
43 import android.util.SparseArray;
44 import android.util.SparseIntArray;
45 
46 import java.lang.annotation.ElementType;
47 import java.lang.annotation.Retention;
48 import java.lang.annotation.RetentionPolicy;
49 import java.lang.annotation.Target;
50 import java.time.Duration;
51 import java.util.ArrayList;
52 import java.util.Collections;
53 import java.util.List;
54 import java.util.Objects;
55 import java.util.Set;
56 import java.util.concurrent.Executor;
57 
58 /**
59  * Params that can be configured when creating virtual devices.
60  *
61  * @hide
62  */
63 @SystemApi
64 public final class VirtualDeviceParams implements Parcelable {
65 
66     /** @hide */
67     @IntDef(prefix = "LOCK_STATE_",
68             value = {LOCK_STATE_DEFAULT, LOCK_STATE_ALWAYS_UNLOCKED})
69     @Retention(RetentionPolicy.SOURCE)
70     @Target({ElementType.TYPE_PARAMETER, ElementType.TYPE_USE})
71     public @interface LockState {}
72 
73     /**
74      * Indicates that the lock state of the virtual device will be the same as the default physical
75      * display.
76      */
77     public static final int LOCK_STATE_DEFAULT = 0;
78 
79     /**
80      * Indicates that the lock state of the virtual device should be always unlocked.
81      */
82     public static final int LOCK_STATE_ALWAYS_UNLOCKED = 1;
83 
84     /** @hide */
85     @IntDef(prefix = "ACTIVITY_POLICY_",
86             value = {ACTIVITY_POLICY_DEFAULT_ALLOWED, ACTIVITY_POLICY_DEFAULT_BLOCKED})
87     @Retention(RetentionPolicy.SOURCE)
88     @Target({ElementType.TYPE_PARAMETER, ElementType.TYPE_USE})
89     public @interface ActivityPolicy {}
90 
91     /**
92      * Indicates that activities are allowed by default on this virtual device, unless they are
93      * explicitly blocked by {@link Builder#setBlockedActivities}.
94      */
95     public static final int ACTIVITY_POLICY_DEFAULT_ALLOWED = 0;
96 
97     /**
98      * Indicates that activities are blocked by default on this virtual device, unless they are
99      * allowed by {@link Builder#setAllowedActivities}.
100      */
101     public static final int ACTIVITY_POLICY_DEFAULT_BLOCKED = 1;
102 
103     /** @hide */
104     @IntDef(prefix = "NAVIGATION_POLICY_",
105         value = {NAVIGATION_POLICY_DEFAULT_ALLOWED, NAVIGATION_POLICY_DEFAULT_BLOCKED})
106     @Retention(RetentionPolicy.SOURCE)
107     @Target({ElementType.TYPE_PARAMETER, ElementType.TYPE_USE})
108     public @interface NavigationPolicy {}
109 
110     /**
111      * Indicates that tasks are allowed to navigate to other tasks on this virtual device,
112      * unless they are explicitly blocked by {@link Builder#setBlockedCrossTaskNavigations}.
113      */
114     public static final int NAVIGATION_POLICY_DEFAULT_ALLOWED = 0;
115 
116     /**
117      * Indicates that tasks are blocked from navigating to other tasks by default on this virtual
118      * device, unless allowed by {@link Builder#setAllowedCrossTaskNavigations}.
119      */
120     public static final int NAVIGATION_POLICY_DEFAULT_BLOCKED = 1;
121 
122     /** @hide */
123     @IntDef(prefix = "DEVICE_POLICY_",  value = {DEVICE_POLICY_DEFAULT, DEVICE_POLICY_CUSTOM})
124     @Retention(RetentionPolicy.SOURCE)
125     @Target({ElementType.TYPE_PARAMETER, ElementType.TYPE_USE})
126     public @interface DevicePolicy {}
127 
128     /**
129      * Indicates that there is no special logic for this virtual device and it should be treated
130      * the same way as the default device, keeping the default behavior unchanged.
131      */
132     public static final int DEVICE_POLICY_DEFAULT = 0;
133 
134     /**
135      * Indicates that there is custom logic, specific to this virtual device, which should be
136      * triggered instead of the default behavior.
137      */
138     public static final int DEVICE_POLICY_CUSTOM = 1;
139 
140     /**
141      * Any relevant component must be able to interpret the correct meaning of a custom policy for
142      * a given policy type.
143      * @hide
144      */
145     @IntDef(prefix = "POLICY_TYPE_", value = {POLICY_TYPE_SENSORS, POLICY_TYPE_AUDIO,
146             POLICY_TYPE_RECENTS})
147     @Retention(RetentionPolicy.SOURCE)
148     @Target({ElementType.TYPE_PARAMETER, ElementType.TYPE_USE})
149     public @interface PolicyType {}
150 
151     /**
152      * Tells the sensor framework how to handle sensor requests from contexts associated with this
153      * virtual device, namely the sensors returned by
154      * {@link android.hardware.SensorManager#getSensorList}:
155      *
156      * <ul>
157      *     <li>{@link #DEVICE_POLICY_DEFAULT}: Return the sensors of the default device.
158      *     <li>{@link #DEVICE_POLICY_CUSTOM}: Return the sensors of the virtual device. Note that if
159      *     the virtual device did not create any virtual sensors, then an empty list is returned.
160      * </ul>
161      */
162     public static final int POLICY_TYPE_SENSORS = 0;
163 
164     /**
165      * Tells the audio framework whether to configure the players ({@link android.media.AudioTrack},
166      * {@link android.media.MediaPlayer}, {@link android.media.SoundPool} and recorders
167      * {@link android.media.AudioRecord}) to use specific session ids re-routed to
168      * VirtualAudioDevice.
169      *
170      * <ul>
171      *     <li>{@link #DEVICE_POLICY_DEFAULT}: fall back to default session id handling.
172      *     <li>{@link #DEVICE_POLICY_CUSTOM}: audio framework will assign device specific session
173      *     ids to players and recorders constructed within device context. The session ids are
174      *     used to re-route corresponding audio streams to VirtualAudioDevice.
175      * </ul>
176      */
177     public static final int POLICY_TYPE_AUDIO = 1;
178 
179     /**
180      * Tells the activity manager how to handle recents entries for activities run on this device.
181      *
182      * <ul>
183      *     <li>{@link #DEVICE_POLICY_DEFAULT}: Activities launched on VirtualDisplays owned by this
184      *     device will appear in the host device recents.
185      *     <li>{@link #DEVICE_POLICY_CUSTOM}: Activities launched on VirtualDisplays owned by this
186      *      *     device will not appear in recents.
187      * </ul>
188      */
189     public static final int POLICY_TYPE_RECENTS = 2;
190 
191     private final int mLockState;
192     @NonNull private final ArraySet<UserHandle> mUsersWithMatchingAccounts;
193     @NonNull private final ArraySet<ComponentName> mAllowedCrossTaskNavigations;
194     @NonNull private final ArraySet<ComponentName> mBlockedCrossTaskNavigations;
195     @NavigationPolicy
196     private final int mDefaultNavigationPolicy;
197     @NonNull private final ArraySet<ComponentName> mAllowedActivities;
198     @NonNull private final ArraySet<ComponentName> mBlockedActivities;
199     @ActivityPolicy
200     private final int mDefaultActivityPolicy;
201     @Nullable private final String mName;
202     // Mapping of @PolicyType to @DevicePolicy
203     @NonNull private final SparseIntArray mDevicePolicies;
204     @NonNull private final List<VirtualSensorConfig> mVirtualSensorConfigs;
205     @Nullable private final IVirtualSensorCallback mVirtualSensorCallback;
206     private final int mAudioPlaybackSessionId;
207     private final int mAudioRecordingSessionId;
208 
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, @Nullable String name, @NonNull SparseIntArray devicePolicies, @NonNull List<VirtualSensorConfig> virtualSensorConfigs, @Nullable IVirtualSensorCallback virtualSensorCallback, int audioPlaybackSessionId, int audioRecordingSessionId)209     private VirtualDeviceParams(
210             @LockState int lockState,
211             @NonNull Set<UserHandle> usersWithMatchingAccounts,
212             @NonNull Set<ComponentName> allowedCrossTaskNavigations,
213             @NonNull Set<ComponentName> blockedCrossTaskNavigations,
214             @NavigationPolicy int defaultNavigationPolicy,
215             @NonNull Set<ComponentName> allowedActivities,
216             @NonNull Set<ComponentName> blockedActivities,
217             @ActivityPolicy int defaultActivityPolicy,
218             @Nullable String name,
219             @NonNull SparseIntArray devicePolicies,
220             @NonNull List<VirtualSensorConfig> virtualSensorConfigs,
221             @Nullable IVirtualSensorCallback virtualSensorCallback,
222             int audioPlaybackSessionId,
223             int audioRecordingSessionId) {
224         mLockState = lockState;
225         mUsersWithMatchingAccounts =
226                 new ArraySet<>(Objects.requireNonNull(usersWithMatchingAccounts));
227         mAllowedCrossTaskNavigations =
228                 new ArraySet<>(Objects.requireNonNull(allowedCrossTaskNavigations));
229         mBlockedCrossTaskNavigations =
230                 new ArraySet<>(Objects.requireNonNull(blockedCrossTaskNavigations));
231         mDefaultNavigationPolicy = defaultNavigationPolicy;
232         mAllowedActivities = new ArraySet<>(Objects.requireNonNull(allowedActivities));
233         mBlockedActivities = new ArraySet<>(Objects.requireNonNull(blockedActivities));
234         mDefaultActivityPolicy = defaultActivityPolicy;
235         mName = name;
236         mDevicePolicies = Objects.requireNonNull(devicePolicies);
237         mVirtualSensorConfigs = Objects.requireNonNull(virtualSensorConfigs);
238         mVirtualSensorCallback = virtualSensorCallback;
239         mAudioPlaybackSessionId = audioPlaybackSessionId;
240         mAudioRecordingSessionId = audioRecordingSessionId;
241     }
242 
243     @SuppressWarnings("unchecked")
VirtualDeviceParams(Parcel parcel)244     private VirtualDeviceParams(Parcel parcel) {
245         mLockState = parcel.readInt();
246         mUsersWithMatchingAccounts = (ArraySet<UserHandle>) parcel.readArraySet(null);
247         mAllowedCrossTaskNavigations = (ArraySet<ComponentName>) parcel.readArraySet(null);
248         mBlockedCrossTaskNavigations = (ArraySet<ComponentName>) parcel.readArraySet(null);
249         mDefaultNavigationPolicy = parcel.readInt();
250         mAllowedActivities = (ArraySet<ComponentName>) parcel.readArraySet(null);
251         mBlockedActivities = (ArraySet<ComponentName>) parcel.readArraySet(null);
252         mDefaultActivityPolicy = parcel.readInt();
253         mName = parcel.readString8();
254         mDevicePolicies = parcel.readSparseIntArray();
255         mVirtualSensorConfigs = new ArrayList<>();
256         parcel.readTypedList(mVirtualSensorConfigs, VirtualSensorConfig.CREATOR);
257         mVirtualSensorCallback =
258                 IVirtualSensorCallback.Stub.asInterface(parcel.readStrongBinder());
259         mAudioPlaybackSessionId = parcel.readInt();
260         mAudioRecordingSessionId = parcel.readInt();
261     }
262 
263     /**
264      * Returns the lock state of the virtual device.
265      */
266     @LockState
getLockState()267     public int getLockState() {
268         return mLockState;
269     }
270 
271     /**
272      * Returns the user handles with matching managed accounts on the remote device to which
273      * this virtual device is streaming.
274      *
275      * @see android.app.admin.DevicePolicyManager#NEARBY_STREAMING_SAME_MANAGED_ACCOUNT_ONLY
276      */
277     @NonNull
getUsersWithMatchingAccounts()278     public Set<UserHandle> getUsersWithMatchingAccounts() {
279         return Collections.unmodifiableSet(mUsersWithMatchingAccounts);
280     }
281 
282     /**
283      * Returns the set of tasks that are allowed to navigate from current task,
284      * or empty set if all tasks are allowed, except the ones explicitly blocked.
285      * If neither allowed or blocked tasks are provided, all task navigations will
286      * be be allowed by default.
287      *
288      * @see Builder#setAllowedCrossTaskNavigations(Set)
289      */
290     @NonNull
getAllowedCrossTaskNavigations()291     public Set<ComponentName> getAllowedCrossTaskNavigations() {
292         return Collections.unmodifiableSet(mAllowedCrossTaskNavigations);
293     }
294 
295     /**
296      * Returns the set of tasks that are blocked from navigating from the current task,
297      * or empty set to indicate that all tasks in {@link #getAllowedCrossTaskNavigations}
298      * are allowed. If neither allowed or blocked tasks are provided, all task navigations
299      * will be be allowed by default.
300      *
301      * @see Builder#setBlockedCrossTaskNavigations(Set)
302      */
303     @NonNull
getBlockedCrossTaskNavigations()304     public Set<ComponentName> getBlockedCrossTaskNavigations() {
305         return Collections.unmodifiableSet(mBlockedCrossTaskNavigations);
306     }
307 
308     /**
309      * Returns {@link #NAVIGATION_POLICY_DEFAULT_ALLOWED} if tasks are allowed to navigate on
310      * this virtual device by default, or {@link #NAVIGATION_POLICY_DEFAULT_BLOCKED} if tasks
311      * must be allowed by {@link Builder#setAllowedCrossTaskNavigations} to navigate here.
312      *
313      * @see Builder#setAllowedCrossTaskNavigations
314      * @see Builder#setBlockedCrossTaskNavigations
315      */
316     @NavigationPolicy
getDefaultNavigationPolicy()317     public int getDefaultNavigationPolicy() {
318         return mDefaultNavigationPolicy;
319     }
320 
321     /**
322      * Returns the set of activities allowed to be streamed, or empty set if all activities are
323      * allowed, except the ones explicitly blocked.
324      *
325      * @see Builder#setAllowedActivities(Set)
326      */
327     @NonNull
getAllowedActivities()328     public Set<ComponentName> getAllowedActivities() {
329         return Collections.unmodifiableSet(mAllowedActivities);
330     }
331 
332     /**
333      * Returns the set of activities that are blocked from streaming, or empty set to indicate
334      * that all activities in {@link #getAllowedActivities} are allowed.
335      *
336      * @see Builder#setBlockedActivities(Set)
337      */
338     @NonNull
getBlockedActivities()339     public Set<ComponentName> getBlockedActivities() {
340         return Collections.unmodifiableSet(mBlockedActivities);
341     }
342 
343     /**
344      * Returns {@link #ACTIVITY_POLICY_DEFAULT_ALLOWED} if activities are allowed to launch on this
345      * virtual device by default, or {@link #ACTIVITY_POLICY_DEFAULT_BLOCKED} if activities must be
346      * allowed by {@link Builder#setAllowedActivities} to launch here.
347      *
348      * @see Builder#setBlockedActivities
349      * @see Builder#setAllowedActivities
350      */
351     @ActivityPolicy
getDefaultActivityPolicy()352     public int getDefaultActivityPolicy() {
353         return mDefaultActivityPolicy;
354     }
355 
356     /**
357      * Returns the (optional) name of the virtual device.
358      *
359      * @see Builder#setName
360      */
361     @Nullable
getName()362     public String getName() {
363         return mName;
364     }
365 
366     /**
367      * Returns the policy specified for this policy type, or {@link #DEVICE_POLICY_DEFAULT} if no
368      * policy for this type has been explicitly specified.
369      *
370      * @see Builder#setDevicePolicy
371      */
getDevicePolicy(@olicyType int policyType)372     public @DevicePolicy int getDevicePolicy(@PolicyType int policyType) {
373         return mDevicePolicies.get(policyType, DEVICE_POLICY_DEFAULT);
374     }
375 
376     /**
377      * Returns the configurations for all sensors that should be created for this device.
378      *
379      * @see Builder#addVirtualSensorConfig
380      */
getVirtualSensorConfigs()381     public @NonNull List<VirtualSensorConfig> getVirtualSensorConfigs() {
382         return mVirtualSensorConfigs;
383     }
384 
385     /**
386      * Returns the callback to get notified about changes in the sensor listeners or sensor direct
387      * channel configuration.
388      * @hide
389      */
390     @Nullable
getVirtualSensorCallback()391     public IVirtualSensorCallback getVirtualSensorCallback() {
392         return mVirtualSensorCallback;
393     }
394 
395     /**
396      * Returns device-specific audio session id for playback.
397      *
398      * @see Builder#setAudioPlaybackSessionId(int)
399      */
getAudioPlaybackSessionId()400     public int getAudioPlaybackSessionId() {
401         return mAudioPlaybackSessionId;
402     }
403 
404     /**
405      * Returns device-specific audio session id for recording.
406      *
407      * @see Builder#setAudioRecordingSessionId(int)
408      */
getAudioRecordingSessionId()409     public int getAudioRecordingSessionId() {
410         return mAudioRecordingSessionId;
411     }
412 
413     @Override
describeContents()414     public int describeContents() {
415         return 0;
416     }
417 
418     @Override
writeToParcel(@onNull Parcel dest, int flags)419     public void writeToParcel(@NonNull Parcel dest, int flags) {
420         dest.writeInt(mLockState);
421         dest.writeArraySet(mUsersWithMatchingAccounts);
422         dest.writeArraySet(mAllowedCrossTaskNavigations);
423         dest.writeArraySet(mBlockedCrossTaskNavigations);
424         dest.writeInt(mDefaultNavigationPolicy);
425         dest.writeArraySet(mAllowedActivities);
426         dest.writeArraySet(mBlockedActivities);
427         dest.writeInt(mDefaultActivityPolicy);
428         dest.writeString8(mName);
429         dest.writeSparseIntArray(mDevicePolicies);
430         dest.writeTypedList(mVirtualSensorConfigs);
431         dest.writeStrongBinder(
432                 mVirtualSensorCallback != null ? mVirtualSensorCallback.asBinder() : null);
433         dest.writeInt(mAudioPlaybackSessionId);
434         dest.writeInt(mAudioRecordingSessionId);
435     }
436 
437     @Override
equals(Object o)438     public boolean equals(Object o) {
439         if (this == o) {
440             return true;
441         }
442         if (!(o instanceof VirtualDeviceParams)) {
443             return false;
444         }
445         VirtualDeviceParams that = (VirtualDeviceParams) o;
446         final int devicePoliciesCount = mDevicePolicies.size();
447         if (devicePoliciesCount != that.mDevicePolicies.size()) {
448             return false;
449         }
450         for (int i = 0; i < devicePoliciesCount; i++) {
451             if (mDevicePolicies.keyAt(i) != that.mDevicePolicies.keyAt(i)) {
452                 return false;
453             }
454             if (mDevicePolicies.valueAt(i) != that.mDevicePolicies.valueAt(i)) {
455                 return false;
456             }
457         }
458         return mLockState == that.mLockState
459                 && mUsersWithMatchingAccounts.equals(that.mUsersWithMatchingAccounts)
460                 && Objects.equals(mAllowedCrossTaskNavigations, that.mAllowedCrossTaskNavigations)
461                 && Objects.equals(mBlockedCrossTaskNavigations, that.mBlockedCrossTaskNavigations)
462                 && mDefaultNavigationPolicy == that.mDefaultNavigationPolicy
463                 && Objects.equals(mAllowedActivities, that.mAllowedActivities)
464                 && Objects.equals(mBlockedActivities, that.mBlockedActivities)
465                 && mDefaultActivityPolicy == that.mDefaultActivityPolicy
466                 && Objects.equals(mName, that.mName)
467                 && mAudioPlaybackSessionId == that.mAudioPlaybackSessionId
468                 && mAudioRecordingSessionId == that.mAudioRecordingSessionId;
469     }
470 
471     @Override
hashCode()472     public int hashCode() {
473         int hashCode = Objects.hash(
474                 mLockState, mUsersWithMatchingAccounts, mAllowedCrossTaskNavigations,
475                 mBlockedCrossTaskNavigations, mDefaultNavigationPolicy, mAllowedActivities,
476                 mBlockedActivities, mDefaultActivityPolicy, mName, mDevicePolicies,
477                 mAudioPlaybackSessionId, mAudioRecordingSessionId);
478         for (int i = 0; i < mDevicePolicies.size(); i++) {
479             hashCode = 31 * hashCode + mDevicePolicies.keyAt(i);
480             hashCode = 31 * hashCode + mDevicePolicies.valueAt(i);
481         }
482         return hashCode;
483     }
484 
485     @Override
486     @NonNull
toString()487     public String toString() {
488         return "VirtualDeviceParams("
489                 + " mLockState=" + mLockState
490                 + " mUsersWithMatchingAccounts=" + mUsersWithMatchingAccounts
491                 + " mAllowedCrossTaskNavigations=" + mAllowedCrossTaskNavigations
492                 + " mBlockedCrossTaskNavigations=" + mBlockedCrossTaskNavigations
493                 + " mDefaultNavigationPolicy=" + mDefaultNavigationPolicy
494                 + " mAllowedActivities=" + mAllowedActivities
495                 + " mBlockedActivities=" + mBlockedActivities
496                 + " mDefaultActivityPolicy=" + mDefaultActivityPolicy
497                 + " mName=" + mName
498                 + " mDevicePolicies=" + mDevicePolicies
499                 + " mAudioPlaybackSessionId=" + mAudioPlaybackSessionId
500                 + " mAudioRecordingSessionId=" + mAudioRecordingSessionId
501                 + ")";
502     }
503 
504     @NonNull
505     public static final Parcelable.Creator<VirtualDeviceParams> CREATOR =
506             new Parcelable.Creator<VirtualDeviceParams>() {
507                 public VirtualDeviceParams createFromParcel(Parcel in) {
508                     return new VirtualDeviceParams(in);
509                 }
510 
511                 public VirtualDeviceParams[] newArray(int size) {
512                     return new VirtualDeviceParams[size];
513                 }
514             };
515 
516     /**
517      * Builder for {@link VirtualDeviceParams}.
518      */
519     public static final class Builder {
520 
521         private @LockState int mLockState = LOCK_STATE_DEFAULT;
522         @NonNull private Set<UserHandle> mUsersWithMatchingAccounts = Collections.emptySet();
523         @NonNull private Set<ComponentName> mAllowedCrossTaskNavigations = Collections.emptySet();
524         @NonNull private Set<ComponentName> mBlockedCrossTaskNavigations = Collections.emptySet();
525         @NavigationPolicy
526         private int mDefaultNavigationPolicy = NAVIGATION_POLICY_DEFAULT_ALLOWED;
527         private boolean mDefaultNavigationPolicyConfigured = false;
528         @NonNull private Set<ComponentName> mBlockedActivities = Collections.emptySet();
529         @NonNull private Set<ComponentName> mAllowedActivities = Collections.emptySet();
530         @ActivityPolicy
531         private int mDefaultActivityPolicy = ACTIVITY_POLICY_DEFAULT_ALLOWED;
532         private boolean mDefaultActivityPolicyConfigured = false;
533         @Nullable private String mName;
534         @NonNull private SparseIntArray mDevicePolicies = new SparseIntArray();
535         private int mAudioPlaybackSessionId = AUDIO_SESSION_ID_GENERATE;
536         private int mAudioRecordingSessionId = AUDIO_SESSION_ID_GENERATE;
537 
538         @NonNull private List<VirtualSensorConfig> mVirtualSensorConfigs = new ArrayList<>();
539         @Nullable private Executor mVirtualSensorCallbackExecutor;
540         @Nullable private VirtualSensorCallback mVirtualSensorCallback;
541         @Nullable private Executor mVirtualSensorDirectChannelCallbackExecutor;
542         @Nullable private VirtualSensorDirectChannelCallback mVirtualSensorDirectChannelCallback;
543 
544         private static class VirtualSensorCallbackDelegate extends IVirtualSensorCallback.Stub {
545             @NonNull
546             private final Executor mExecutor;
547             @NonNull
548             private final VirtualSensorCallback mCallback;
549             @Nullable
550             private final Executor mDirectChannelExecutor;
551             @Nullable
552             private final VirtualSensorDirectChannelCallback mDirectChannelCallback;
553 
VirtualSensorCallbackDelegate(@onNull @allbackExecutor Executor executor, @NonNull VirtualSensorCallback callback, @Nullable @CallbackExecutor Executor directChannelExecutor, @Nullable VirtualSensorDirectChannelCallback directChannelCallback)554             VirtualSensorCallbackDelegate(@NonNull @CallbackExecutor Executor executor,
555                     @NonNull VirtualSensorCallback callback,
556                     @Nullable @CallbackExecutor Executor directChannelExecutor,
557                     @Nullable VirtualSensorDirectChannelCallback directChannelCallback) {
558                 mExecutor = executor;
559                 mCallback = callback;
560                 mDirectChannelExecutor = directChannelExecutor;
561                 mDirectChannelCallback = directChannelCallback;
562             }
563 
564             @Override
onConfigurationChanged(@onNull VirtualSensor sensor, boolean enabled, int samplingPeriodMicros, int batchReportLatencyMicros)565             public void onConfigurationChanged(@NonNull VirtualSensor sensor, boolean enabled,
566                     int samplingPeriodMicros, int batchReportLatencyMicros) {
567                 final Duration samplingPeriod =
568                         Duration.ofNanos(MICROSECONDS.toNanos(samplingPeriodMicros));
569                 final Duration batchReportingLatency =
570                         Duration.ofNanos(MICROSECONDS.toNanos(batchReportLatencyMicros));
571                 mExecutor.execute(() -> mCallback.onConfigurationChanged(
572                         sensor, enabled, samplingPeriod, batchReportingLatency));
573             }
574 
575             @Override
onDirectChannelCreated(int channelHandle, @NonNull SharedMemory sharedMemory)576             public void onDirectChannelCreated(int channelHandle,
577                     @NonNull SharedMemory sharedMemory) {
578                 if (mDirectChannelCallback != null && mDirectChannelExecutor != null) {
579                     mDirectChannelExecutor.execute(
580                             () -> mDirectChannelCallback.onDirectChannelCreated(channelHandle,
581                                     sharedMemory));
582                 }
583             }
584 
585             @Override
onDirectChannelDestroyed(int channelHandle)586             public void onDirectChannelDestroyed(int channelHandle) {
587                 if (mDirectChannelCallback != null && mDirectChannelExecutor != null) {
588                     mDirectChannelExecutor.execute(
589                             () -> mDirectChannelCallback.onDirectChannelDestroyed(channelHandle));
590                 }
591             }
592 
593             @Override
onDirectChannelConfigured(int channelHandle, @NonNull VirtualSensor sensor, int rateLevel, int reportToken)594             public void onDirectChannelConfigured(int channelHandle, @NonNull VirtualSensor sensor,
595                     int rateLevel, int reportToken) {
596                 if (mDirectChannelCallback != null && mDirectChannelExecutor != null) {
597                     mDirectChannelExecutor.execute(
598                             () -> mDirectChannelCallback.onDirectChannelConfigured(
599                                     channelHandle, sensor, rateLevel, reportToken));
600                 }
601             }
602         }
603 
604         /**
605          * Sets the lock state of the device. The permission {@code ADD_ALWAYS_UNLOCKED_DISPLAY}
606          * is required if this is set to {@link #LOCK_STATE_ALWAYS_UNLOCKED}.
607          * The default is {@link #LOCK_STATE_DEFAULT}.
608          *
609          * @param lockState The lock state, either {@link #LOCK_STATE_DEFAULT} or
610          *   {@link #LOCK_STATE_ALWAYS_UNLOCKED}.
611          */
612         @RequiresPermission(value = ADD_ALWAYS_UNLOCKED_DISPLAY, conditional = true)
613         @NonNull
setLockState(@ockState int lockState)614         public Builder setLockState(@LockState int lockState) {
615             mLockState = lockState;
616             return this;
617         }
618 
619         /**
620          * Sets the user handles with matching managed accounts on the remote device to which
621          * this virtual device is streaming. The caller is responsible for verifying the presence
622          * and legitimacy of a matching managed account on the remote device.
623          *
624          * <p>If the app streaming policy is
625          * {@link android.app.admin.DevicePolicyManager#NEARBY_STREAMING_SAME_MANAGED_ACCOUNT_ONLY
626          * NEARBY_STREAMING_SAME_MANAGED_ACCOUNT_ONLY}, activities not in
627          * {@code usersWithMatchingAccounts} will be blocked from starting.
628          *
629          * <p> If {@code usersWithMatchingAccounts} is empty (the default), streaming is allowed
630          * only if there is no device policy, or if the nearby streaming policy is
631          * {@link android.app.admin.DevicePolicyManager#NEARBY_STREAMING_ENABLED
632          * NEARBY_STREAMING_ENABLED}.
633          *
634          * @param usersWithMatchingAccounts A set of user handles with matching managed
635          *   accounts on the remote device this is streaming to.
636          *
637          * @see android.app.admin.DevicePolicyManager#NEARBY_STREAMING_SAME_MANAGED_ACCOUNT_ONLY
638          */
639         @NonNull
setUsersWithMatchingAccounts( @onNull Set<UserHandle> usersWithMatchingAccounts)640         public Builder setUsersWithMatchingAccounts(
641                 @NonNull Set<UserHandle> usersWithMatchingAccounts) {
642             mUsersWithMatchingAccounts = Objects.requireNonNull(usersWithMatchingAccounts);
643             return this;
644         }
645 
646         /**
647          * Sets the tasks allowed to navigate from current task in the virtual device. Tasks
648          * not in {@code allowedCrossTaskNavigations} will be blocked from navigating to a new
649          * task. Calling this method will cause {@link #getDefaultNavigationPolicy()} to be
650          * {@link #NAVIGATION_POLICY_DEFAULT_BLOCKED}, meaning tasks not in
651          * {@code allowedCrossTaskNavigations} will be blocked from navigating here.
652          *
653          * <p>This method must not be called if {@link #setBlockedCrossTaskNavigations(Set)} has
654          * been called.
655          *
656          * @throws IllegalArgumentException if {@link #setBlockedCrossTaskNavigations(Set)} has been
657          * called.
658          *
659          * @param allowedCrossTaskNavigations A set of tasks {@link ComponentName} allowed to
660          *   navigate to new tasks in the virtual device.
661          */
662         @NonNull
setAllowedCrossTaskNavigations( @onNull Set<ComponentName> allowedCrossTaskNavigations)663         public Builder setAllowedCrossTaskNavigations(
664                 @NonNull Set<ComponentName> allowedCrossTaskNavigations) {
665             if (mDefaultNavigationPolicyConfigured
666                     && mDefaultNavigationPolicy != NAVIGATION_POLICY_DEFAULT_BLOCKED) {
667                 throw new IllegalArgumentException(
668                      "Allowed cross task navigation and blocked task navigation cannot "
669                      + " both be set.");
670             }
671             mDefaultNavigationPolicy = NAVIGATION_POLICY_DEFAULT_BLOCKED;
672             mDefaultNavigationPolicyConfigured = true;
673             mAllowedCrossTaskNavigations = Objects.requireNonNull(allowedCrossTaskNavigations);
674             return this;
675         }
676 
677         /**
678          * Sets the tasks blocked from navigating from current task in the virtual device.
679          * Tasks are allowed to navigate unless they are in
680          * {@code blockedCrossTaskNavigations}. Calling this method will cause
681          * {@link #NAVIGATION_POLICY_DEFAULT_ALLOWED}, meaning activities are allowed to launch
682          * unless they are in {@code blockedCrossTaskNavigations}.
683          *
684          * <p>This method must not be called if {@link #setAllowedCrossTaskNavigations(Set)} has
685          * been called.
686          *
687          * @throws IllegalArgumentException if {@link #setAllowedCrossTaskNavigations(Set)} has
688          * been called.
689          *
690          * @param blockedCrossTaskNavigations A set of tasks {@link ComponentName} to be
691          * blocked from navigating to new tasks in the virtual device.
692          */
693         @NonNull
setBlockedCrossTaskNavigations( @onNull Set<ComponentName> blockedCrossTaskNavigations)694         public Builder setBlockedCrossTaskNavigations(
695                 @NonNull Set<ComponentName> blockedCrossTaskNavigations) {
696             if (mDefaultNavigationPolicyConfigured
697                      && mDefaultNavigationPolicy != NAVIGATION_POLICY_DEFAULT_ALLOWED) {
698                 throw new IllegalArgumentException(
699                      "Allowed cross task navigation and blocked task navigation cannot "
700                      + " be set.");
701             }
702             mDefaultNavigationPolicy = NAVIGATION_POLICY_DEFAULT_ALLOWED;
703             mDefaultNavigationPolicyConfigured = true;
704             mBlockedCrossTaskNavigations = Objects.requireNonNull(blockedCrossTaskNavigations);
705             return this;
706         }
707 
708         /**
709          * Sets the activities allowed to be launched in the virtual device. Calling this method
710          * will cause {@link #getDefaultActivityPolicy()} to be
711          * {@link #ACTIVITY_POLICY_DEFAULT_BLOCKED}, meaning activities not in
712          * {@code allowedActivities} will be blocked from launching here.
713          *
714          * <p>This method must not be called if {@link #setBlockedActivities(Set)} has been called.
715          *
716          * @throws IllegalArgumentException if {@link #setBlockedActivities(Set)} has been called.
717          *
718          * @param allowedActivities A set of activity {@link ComponentName} allowed to be launched
719          *   in the virtual device.
720          */
721         @NonNull
setAllowedActivities(@onNull Set<ComponentName> allowedActivities)722         public Builder setAllowedActivities(@NonNull Set<ComponentName> allowedActivities) {
723             if (mDefaultActivityPolicyConfigured
724                     && mDefaultActivityPolicy != ACTIVITY_POLICY_DEFAULT_BLOCKED) {
725                 throw new IllegalArgumentException(
726                         "Allowed activities and Blocked activities cannot both be set.");
727             }
728             mDefaultActivityPolicy = ACTIVITY_POLICY_DEFAULT_BLOCKED;
729             mDefaultActivityPolicyConfigured = true;
730             mAllowedActivities = Objects.requireNonNull(allowedActivities);
731             return this;
732         }
733 
734         /**
735          * Sets the activities blocked from launching in the virtual device. Calling this method
736          * will cause {@link #getDefaultActivityPolicy()} to be
737          * {@link #ACTIVITY_POLICY_DEFAULT_ALLOWED}, meaning activities are allowed to launch here
738          * unless they are in {@code blockedActivities}.
739          *
740          * <p>This method must not be called if {@link #setAllowedActivities(Set)} has been called.
741          *
742          * @throws IllegalArgumentException if {@link #setAllowedActivities(Set)} has been called.
743          *
744          * @param blockedActivities A set of {@link ComponentName} to be blocked launching from
745          *   virtual device.
746          */
747         @NonNull
setBlockedActivities(@onNull Set<ComponentName> blockedActivities)748         public Builder setBlockedActivities(@NonNull Set<ComponentName> blockedActivities) {
749             if (mDefaultActivityPolicyConfigured
750                     && mDefaultActivityPolicy != ACTIVITY_POLICY_DEFAULT_ALLOWED) {
751                 throw new IllegalArgumentException(
752                         "Allowed activities and Blocked activities cannot both be set.");
753             }
754             mDefaultActivityPolicy = ACTIVITY_POLICY_DEFAULT_ALLOWED;
755             mDefaultActivityPolicyConfigured = true;
756             mBlockedActivities = Objects.requireNonNull(blockedActivities);
757             return this;
758         }
759 
760         /**
761          * Sets the optional virtual device name.
762          *
763          * <p>This string is not typically intended to be displayed to end users, but rather for
764          * debugging and other developer-facing purposes.
765          *
766          * <p>3rd party applications may be able to see the name (i.e. it's not private to the
767          * device owner)
768          */
769         @NonNull
setName(@onNull String name)770         public Builder setName(@NonNull String name) {
771             mName = name;
772             return this;
773         }
774 
775         /**
776          * Specifies a policy for this virtual device.
777          *
778          * <p>Policies define the system behavior that may be specific for this virtual device. A
779          * policy can be defined for each {@code PolicyType}, but they are all optional.
780          *
781          * @param policyType the type of policy, i.e. which behavior to specify a policy for.
782          * @param devicePolicy the value of the policy, i.e. how to interpret the device behavior.
783          */
784         @NonNull
setDevicePolicy(@olicyType int policyType, @DevicePolicy int devicePolicy)785         public Builder setDevicePolicy(@PolicyType int policyType, @DevicePolicy int devicePolicy) {
786             mDevicePolicies.put(policyType, devicePolicy);
787             return this;
788         }
789 
790         /**
791          * Adds a configuration for a sensor that should be created for this virtual device.
792          *
793          * <p>Device sensors must remain valid for the entire lifetime of the device, hence they are
794          * created together with the device itself, and removed when the device is removed.
795          *
796          * <p>Requires {@link #DEVICE_POLICY_CUSTOM} to be set for {@link #POLICY_TYPE_SENSORS}.
797          *
798          * @see android.companion.virtual.sensor.VirtualSensor
799          * @see #setDevicePolicy
800          */
801         @NonNull
addVirtualSensorConfig(@onNull VirtualSensorConfig virtualSensorConfig)802         public Builder addVirtualSensorConfig(@NonNull VirtualSensorConfig virtualSensorConfig) {
803             mVirtualSensorConfigs.add(Objects.requireNonNull(virtualSensorConfig));
804             return this;
805         }
806 
807         /**
808          * Sets the callback to get notified about changes in the sensor configuration.
809          *
810          * @param executor The executor where the callback is executed on.
811          * @param callback The callback to get notified when the state of the sensor
812          * configuration has changed, see {@link VirtualSensorCallback}
813          */
814         @SuppressLint("MissingGetterMatchingBuilder")
815         @NonNull
setVirtualSensorCallback( @onNull @allbackExecutor Executor executor, @NonNull VirtualSensorCallback callback)816         public Builder setVirtualSensorCallback(
817                 @NonNull @CallbackExecutor Executor executor,
818                 @NonNull VirtualSensorCallback callback) {
819             mVirtualSensorCallbackExecutor = Objects.requireNonNull(executor);
820             mVirtualSensorCallback = Objects.requireNonNull(callback);
821             return this;
822         }
823 
824         /**
825          * Sets the callback to get notified about changes in
826          * {@link android.hardware.SensorDirectChannel} configuration.
827          *
828          * @param executor The executor where the callback is executed on.
829          * @param callback The callback to get notified when the state of the sensor
830          * configuration has changed, see {@link VirtualSensorDirectChannelCallback}
831          */
832         @SuppressLint("MissingGetterMatchingBuilder")
833         @NonNull
setVirtualSensorDirectChannelCallback( @onNull @allbackExecutor Executor executor, @NonNull VirtualSensorDirectChannelCallback callback)834         public Builder setVirtualSensorDirectChannelCallback(
835                 @NonNull @CallbackExecutor Executor executor,
836                 @NonNull VirtualSensorDirectChannelCallback callback) {
837             mVirtualSensorDirectChannelCallbackExecutor = Objects.requireNonNull(executor);
838             mVirtualSensorDirectChannelCallback = Objects.requireNonNull(callback);
839             return this;
840         }
841 
842         /**
843          * Sets audio playback session id specific for this virtual device.
844          *
845          * <p>Audio players constructed within context associated with this virtual device
846          * will be automatically assigned provided session id.
847          *
848          * <p>Requires {@link #DEVICE_POLICY_CUSTOM} to be set for {@link #POLICY_TYPE_AUDIO},
849          * otherwise {@link #build()} method will throw {@link IllegalArgumentException} if
850          * the playback session id is set to value other than
851          * {@link android.media.AudioManager#AUDIO_SESSION_ID_GENERATE}.
852          *
853          * @param playbackSessionId requested device-specific audio session id for playback
854          * @see android.media.AudioManager#generateAudioSessionId()
855          * @see android.media.AudioTrack.Builder#setContext(Context)
856          */
857         @NonNull
setAudioPlaybackSessionId(int playbackSessionId)858         public Builder setAudioPlaybackSessionId(int playbackSessionId) {
859             if (playbackSessionId < 0) {
860                 throw new IllegalArgumentException("Invalid playback audio session id");
861             }
862             mAudioPlaybackSessionId = playbackSessionId;
863             return this;
864         }
865 
866         /**
867          * Sets audio recording session id specific for this virtual device.
868          *
869          * <p>{@link android.media.AudioRecord} constructed within context associated with this
870          * virtual device will be automatically assigned provided session id.
871          *
872          * <p>Requires {@link #DEVICE_POLICY_CUSTOM} to be set for {@link #POLICY_TYPE_AUDIO},
873          * otherwise {@link #build()} method will throw {@link IllegalArgumentException} if
874          * the recording session id is set to value other than
875          * {@link android.media.AudioManager#AUDIO_SESSION_ID_GENERATE}.
876          *
877          * @param recordingSessionId requested device-specific audio session id for playback
878          * @see android.media.AudioManager#generateAudioSessionId()
879          * @see android.media.AudioRecord.Builder#setContext(Context)
880          */
881         @NonNull
setAudioRecordingSessionId(int recordingSessionId)882         public Builder setAudioRecordingSessionId(int recordingSessionId) {
883             if (recordingSessionId < 0) {
884                 throw new IllegalArgumentException("Invalid recording audio session id");
885             }
886             mAudioRecordingSessionId = recordingSessionId;
887             return this;
888         }
889 
890         /**
891          * Builds the {@link VirtualDeviceParams} instance.
892          *
893          * @throws IllegalArgumentException if there's mismatch between policy definition and
894          * the passed parameters or if there are sensor configs with the same type and name.
895          *
896          */
897         @NonNull
build()898         public VirtualDeviceParams build() {
899             VirtualSensorCallbackDelegate virtualSensorCallbackDelegate = null;
900             if (!mVirtualSensorConfigs.isEmpty()) {
901                 if (mDevicePolicies.get(POLICY_TYPE_SENSORS, DEVICE_POLICY_DEFAULT)
902                         != DEVICE_POLICY_CUSTOM) {
903                     throw new IllegalArgumentException(
904                             "DEVICE_POLICY_CUSTOM for POLICY_TYPE_SENSORS is required for creating "
905                                     + "virtual sensors.");
906                 }
907                 if (mVirtualSensorCallback == null) {
908                     throw new IllegalArgumentException(
909                             "VirtualSensorCallback is required for creating virtual sensors.");
910                 }
911 
912                 for (int i = 0; i < mVirtualSensorConfigs.size(); ++i) {
913                     if (mVirtualSensorConfigs.get(i).getDirectChannelTypesSupported() > 0) {
914                         if (mVirtualSensorDirectChannelCallback == null) {
915                             throw new IllegalArgumentException(
916                                     "VirtualSensorDirectChannelCallback is required for creating "
917                                             + "virtual sensors that support direct channel.");
918                         }
919                         break;
920                     }
921                 }
922                 virtualSensorCallbackDelegate = new VirtualSensorCallbackDelegate(
923                         mVirtualSensorCallbackExecutor,
924                         mVirtualSensorCallback,
925                         mVirtualSensorDirectChannelCallbackExecutor,
926                         mVirtualSensorDirectChannelCallback);
927             }
928 
929             if ((mAudioPlaybackSessionId != AUDIO_SESSION_ID_GENERATE
930                     || mAudioRecordingSessionId != AUDIO_SESSION_ID_GENERATE)
931                     && mDevicePolicies.get(POLICY_TYPE_AUDIO, DEVICE_POLICY_DEFAULT)
932                     != DEVICE_POLICY_CUSTOM) {
933                 throw new IllegalArgumentException("DEVICE_POLICY_CUSTOM for POLICY_TYPE_AUDIO is "
934                         + "required for configuration of device-specific audio session ids.");
935             }
936 
937             SparseArray<Set<String>> sensorNameByType = new SparseArray();
938             for (int i = 0; i < mVirtualSensorConfigs.size(); ++i) {
939                 VirtualSensorConfig config = mVirtualSensorConfigs.get(i);
940                 Set<String> sensorNames = sensorNameByType.get(config.getType(), new ArraySet<>());
941                 if (!sensorNames.add(config.getName())) {
942                     throw new IllegalArgumentException(
943                             "Sensor names must be unique for a particular sensor type.");
944                 }
945                 sensorNameByType.put(config.getType(), sensorNames);
946             }
947 
948             return new VirtualDeviceParams(
949                     mLockState,
950                     mUsersWithMatchingAccounts,
951                     mAllowedCrossTaskNavigations,
952                     mBlockedCrossTaskNavigations,
953                     mDefaultNavigationPolicy,
954                     mAllowedActivities,
955                     mBlockedActivities,
956                     mDefaultActivityPolicy,
957                     mName,
958                     mDevicePolicies,
959                     mVirtualSensorConfigs,
960                     virtualSensorCallbackDelegate,
961                     mAudioPlaybackSessionId,
962                     mAudioRecordingSessionId);
963         }
964     }
965 }
966