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.media.AudioManager.AUDIO_SESSION_ID_GENERATE;
20 
21 import android.annotation.CallbackExecutor;
22 import android.annotation.FlaggedApi;
23 import android.annotation.IntDef;
24 import android.annotation.IntRange;
25 import android.annotation.NonNull;
26 import android.annotation.Nullable;
27 import android.annotation.RequiresPermission;
28 import android.annotation.SdkConstant;
29 import android.annotation.SuppressLint;
30 import android.annotation.SystemApi;
31 import android.annotation.SystemService;
32 import android.annotation.TestApi;
33 import android.annotation.UserIdInt;
34 import android.app.PendingIntent;
35 import android.companion.AssociationInfo;
36 import android.companion.virtual.audio.VirtualAudioDevice;
37 import android.companion.virtual.audio.VirtualAudioDevice.AudioConfigurationChangeCallback;
38 import android.companion.virtual.camera.VirtualCamera;
39 import android.companion.virtual.camera.VirtualCameraConfig;
40 import android.companion.virtual.flags.Flags;
41 import android.companion.virtual.sensor.VirtualSensor;
42 import android.content.ComponentName;
43 import android.content.Context;
44 import android.content.Intent;
45 import android.content.IntentFilter;
46 import android.graphics.Point;
47 import android.hardware.display.DisplayManager;
48 import android.hardware.display.DisplayManager.VirtualDisplayFlag;
49 import android.hardware.display.VirtualDisplay;
50 import android.hardware.display.VirtualDisplayConfig;
51 import android.hardware.input.VirtualDpad;
52 import android.hardware.input.VirtualDpadConfig;
53 import android.hardware.input.VirtualKeyboard;
54 import android.hardware.input.VirtualKeyboardConfig;
55 import android.hardware.input.VirtualMouse;
56 import android.hardware.input.VirtualMouseConfig;
57 import android.hardware.input.VirtualNavigationTouchpad;
58 import android.hardware.input.VirtualNavigationTouchpadConfig;
59 import android.hardware.input.VirtualStylus;
60 import android.hardware.input.VirtualStylusConfig;
61 import android.hardware.input.VirtualTouchscreen;
62 import android.hardware.input.VirtualTouchscreenConfig;
63 import android.media.AudioManager;
64 import android.os.Binder;
65 import android.os.Looper;
66 import android.os.RemoteException;
67 import android.util.ArraySet;
68 import android.util.Log;
69 import android.view.Display;
70 import android.view.Surface;
71 import android.view.WindowManager;
72 
73 import com.android.internal.annotations.GuardedBy;
74 
75 import java.lang.annotation.ElementType;
76 import java.lang.annotation.Retention;
77 import java.lang.annotation.RetentionPolicy;
78 import java.lang.annotation.Target;
79 import java.util.ArrayList;
80 import java.util.Collections;
81 import java.util.Iterator;
82 import java.util.List;
83 import java.util.Objects;
84 import java.util.Set;
85 import java.util.concurrent.Executor;
86 import java.util.function.IntConsumer;
87 
88 /**
89  * System level service for creation and management of virtual devices.
90  *
91  * <p>VirtualDeviceManager enables interactive sharing of capabilities between the host Android
92  * device and a remote device.
93  *
94  * <p class="note">Not to be confused with the Android Studio's Virtual Device Manager, which allows
95  * for device emulation.
96  */
97 @SystemService(Context.VIRTUAL_DEVICE_SERVICE)
98 public final class VirtualDeviceManager {
99 
100     private static final String TAG = "VirtualDeviceManager";
101 
102     /**
103      * Broadcast Action: A Virtual Device was removed.
104      *
105      * <p class="note">This is a protected intent that can only be sent by the system.</p>
106      *
107      * @hide
108      */
109     @SdkConstant(SdkConstant.SdkConstantType.BROADCAST_INTENT_ACTION)
110     public static final String ACTION_VIRTUAL_DEVICE_REMOVED =
111             "android.companion.virtual.action.VIRTUAL_DEVICE_REMOVED";
112 
113     /**
114      * Int intent extra to be used with {@link #ACTION_VIRTUAL_DEVICE_REMOVED}.
115      * Contains the identifier of the virtual device, which was removed.
116      *
117      * @hide
118      */
119     public static final String EXTRA_VIRTUAL_DEVICE_ID =
120             "android.companion.virtual.extra.VIRTUAL_DEVICE_ID";
121 
122     /** @hide */
123     @Retention(RetentionPolicy.SOURCE)
124     @IntDef(
125             prefix = "LAUNCH_",
126             value = {
127                     LAUNCH_SUCCESS,
128                     LAUNCH_FAILURE_PENDING_INTENT_CANCELED,
129                     LAUNCH_FAILURE_NO_ACTIVITY})
130     @Target({ElementType.TYPE_PARAMETER, ElementType.TYPE_USE})
131     public @interface PendingIntentLaunchStatus {}
132 
133     /**
134      * Status for {@link VirtualDevice#launchPendingIntent}, indicating that the launch was
135      * successful.
136      *
137      * @hide
138      */
139     @SystemApi
140     public static final int LAUNCH_SUCCESS = 0;
141 
142     /**
143      * Status for {@link VirtualDevice#launchPendingIntent}, indicating that the launch failed
144      * because the pending intent was canceled.
145      *
146      * @hide
147      */
148     @SystemApi
149     public static final int LAUNCH_FAILURE_PENDING_INTENT_CANCELED = 1;
150 
151     /**
152      * Status for {@link VirtualDevice#launchPendingIntent}, indicating that the launch failed
153      * because no activity starts were detected as a result of calling the pending intent.
154      *
155      * @hide
156      */
157     @SystemApi
158     public static final int LAUNCH_FAILURE_NO_ACTIVITY = 2;
159 
160     /**
161      * Persistent device identifier corresponding to the default device.
162      *
163      * @see Context#DEVICE_ID_DEFAULT
164      * @see VirtualDevice#getPersistentDeviceId()
165      *
166      * @hide
167      */
168     @SystemApi
169     @FlaggedApi(Flags.FLAG_PERSISTENT_DEVICE_ID_API)
170     public static final String PERSISTENT_DEVICE_ID_DEFAULT =
171             "default:" + Context.DEVICE_ID_DEFAULT;
172 
173     private final IVirtualDeviceManager mService;
174     private final Context mContext;
175 
176     @GuardedBy("mVirtualDeviceListeners")
177     private final List<VirtualDeviceListenerDelegate> mVirtualDeviceListeners = new ArrayList<>();
178 
179     /** @hide */
VirtualDeviceManager( @ullable IVirtualDeviceManager service, @NonNull Context context)180     public VirtualDeviceManager(
181             @Nullable IVirtualDeviceManager service, @NonNull Context context) {
182         mService = service;
183         mContext = context;
184     }
185 
186     /**
187      * Creates a virtual device where applications can launch and receive input events injected by
188      * the creator.
189      *
190      * <p>The {@link android.Manifest.permission#CREATE_VIRTUAL_DEVICE} permission is required to
191      * create virtual devices, which is only available to system apps holding specific roles.
192      *
193      * @param associationId The association ID as returned by {@link AssociationInfo#getId()} from
194      *   Companion Device Manager. Virtual devices must have a corresponding association with CDM in
195      *   order to be created.
196      * @param params The parameters for creating virtual devices. See {@link VirtualDeviceParams}
197      *   for the available options.
198      * @return The created virtual device.
199      *
200      * @hide
201      */
202     @SystemApi
203     @RequiresPermission(android.Manifest.permission.CREATE_VIRTUAL_DEVICE)
204     @NonNull
createVirtualDevice( int associationId, @NonNull VirtualDeviceParams params)205     public VirtualDevice createVirtualDevice(
206             int associationId,
207             @NonNull VirtualDeviceParams params) {
208         Objects.requireNonNull(params, "params must not be null");
209         try {
210             return new VirtualDevice(mService, mContext, associationId, params);
211         } catch (RemoteException e) {
212             throw e.rethrowFromSystemServer();
213         }
214     }
215 
216     /**
217      * Returns the details of all available virtual devices.
218      *
219      * <p>The returned objects are read-only representations that expose the properties of all
220      * existing virtual devices.</p>
221      *
222      * <p>Note that if a virtual device is closed and becomes invalid, the returned objects will
223      * not be updated and may contain stale values.</p>
224      */
225     // TODO(b/310912420): Add "Use a VirtualDeviceListener for real time updates of the
226     // availability  of virtual devices." in the note paragraph above with a link annotation.
227     @NonNull
getVirtualDevices()228     public List<android.companion.virtual.VirtualDevice> getVirtualDevices() {
229         if (mService == null) {
230             Log.w(TAG, "Failed to retrieve virtual devices; no virtual device manager service.");
231             return new ArrayList<>();
232         }
233         try {
234             return mService.getVirtualDevices();
235         } catch (RemoteException e) {
236             throw e.rethrowFromSystemServer();
237         }
238     }
239 
240     /**
241      * Returns the details of the virtual device with the given ID, if any.
242      *
243      * <p>The returned object is a read-only representation of the virtual device that expose its
244      * properties.</p>
245      *
246      * <p>Note that if the virtual device is closed and becomes invalid, the returned object will
247      * not be updated and may contain stale values. Use a {@link VirtualDeviceListener} for real
248      * time updates of the availability of virtual devices.</p>
249      *
250      * @return the virtual device with the requested ID, or {@code null} if no such device exists or
251      *   it has already been closed.
252      */
253     @FlaggedApi(Flags.FLAG_VDM_PUBLIC_APIS)
254     @Nullable
getVirtualDevice(int deviceId)255     public android.companion.virtual.VirtualDevice getVirtualDevice(int deviceId) {
256         if (mService == null) {
257             Log.w(TAG, "Failed to retrieve virtual devices; no virtual device manager service.");
258             return null;
259         }
260         if (deviceId == Context.DEVICE_ID_INVALID || deviceId == Context.DEVICE_ID_DEFAULT) {
261             return null;  // Don't even bother making a Binder call.
262         }
263         try {
264             return mService.getVirtualDevice(deviceId);
265         } catch (RemoteException e) {
266             throw e.rethrowFromSystemServer();
267         }
268     }
269 
270     /**
271      * Registers a virtual device listener to receive notifications when virtual devices are created
272      * or closed.
273      *
274      * @param executor The executor where the listener is executed on.
275      * @param listener The listener to add.
276      * @see #unregisterVirtualDeviceListener
277      */
278     @FlaggedApi(Flags.FLAG_VDM_PUBLIC_APIS)
registerVirtualDeviceListener( @onNull @allbackExecutor Executor executor, @NonNull VirtualDeviceListener listener)279     public void registerVirtualDeviceListener(
280             @NonNull @CallbackExecutor Executor executor,
281             @NonNull VirtualDeviceListener listener) {
282         if (mService == null) {
283             Log.w(TAG, "Failed to register listener; no virtual device manager service.");
284             return;
285         }
286         final VirtualDeviceListenerDelegate delegate =
287                 new VirtualDeviceListenerDelegate(Objects.requireNonNull(executor),
288                         Objects.requireNonNull(listener));
289         synchronized (mVirtualDeviceListeners) {
290             try {
291                 mService.registerVirtualDeviceListener(delegate);
292             } catch (RemoteException e) {
293                 throw e.rethrowFromSystemServer();
294             }
295             mVirtualDeviceListeners.add(delegate);
296         }
297     }
298 
299     /**
300      * Unregisters a virtual device listener previously registered with
301      * {@link #registerVirtualDeviceListener}.
302      *
303      * @param listener The listener to unregister.
304      * @see #registerVirtualDeviceListener
305      */
306     @FlaggedApi(Flags.FLAG_VDM_PUBLIC_APIS)
unregisterVirtualDeviceListener(@onNull VirtualDeviceListener listener)307     public void unregisterVirtualDeviceListener(@NonNull VirtualDeviceListener listener) {
308         if (mService == null) {
309             Log.w(TAG, "Failed to unregister listener; no virtual device manager service.");
310             return;
311         }
312         Objects.requireNonNull(listener);
313         synchronized (mVirtualDeviceListeners) {
314             final Iterator<VirtualDeviceListenerDelegate> it = mVirtualDeviceListeners.iterator();
315             while (it.hasNext()) {
316                 final VirtualDeviceListenerDelegate delegate = it.next();
317                 if (delegate.mListener == listener) {
318                     try {
319                         mService.unregisterVirtualDeviceListener(delegate);
320                     } catch (RemoteException e) {
321                         throw e.rethrowFromSystemServer();
322                     }
323                     it.remove();
324                 }
325             }
326         }
327     }
328 
329     /**
330      * Returns the device policy for the given virtual device and policy type.
331      *
332      * <p>In case the virtual device identifier is not valid, or there's no explicitly specified
333      * policy for that device and policy type, then
334      * {@link VirtualDeviceParams#DEVICE_POLICY_DEFAULT} is returned.
335      *
336      * @hide
337      */
338     @SuppressLint("UnflaggedApi") // @TestApi without associated feature.
339     @TestApi
getDevicePolicy( int deviceId, @VirtualDeviceParams.PolicyType int policyType)340     public @VirtualDeviceParams.DevicePolicy int getDevicePolicy(
341             int deviceId, @VirtualDeviceParams.PolicyType int policyType) {
342         if (deviceId == Context.DEVICE_ID_DEFAULT) {
343             // Avoid unnecessary binder call, for default device, policy will be always default.
344             return VirtualDeviceParams.DEVICE_POLICY_DEFAULT;
345         }
346         if (mService == null) {
347             Log.w(TAG, "Failed to retrieve device policy; no virtual device manager service.");
348             return VirtualDeviceParams.DEVICE_POLICY_DEFAULT;
349         }
350         try {
351             return mService.getDevicePolicy(deviceId, policyType);
352         } catch (RemoteException e) {
353             throw e.rethrowFromSystemServer();
354         }
355     }
356 
357     /**
358      * Returns the ID of the device which owns the display with the given ID.
359      *
360      * @hide
361      */
362     @SuppressLint("UnflaggedApi") // @TestApi without associated feature.
363     @TestApi
getDeviceIdForDisplayId(int displayId)364     public int getDeviceIdForDisplayId(int displayId) {
365         if (displayId == Display.DEFAULT_DISPLAY || displayId == Display.INVALID_DISPLAY) {
366             // Avoid unnecessary binder call for default / invalid display id.
367             return Context.DEVICE_ID_DEFAULT;
368         }
369         if (mService == null) {
370             Log.w(TAG, "Failed to retrieve virtual devices; no virtual device manager service.");
371             return Context.DEVICE_ID_DEFAULT;
372         }
373         try {
374             return mService.getDeviceIdForDisplayId(displayId);
375         } catch (RemoteException e) {
376             throw e.rethrowFromSystemServer();
377         }
378     }
379 
380     /**
381      * Get the display name for a given persistent device ID.
382      *
383      * <p>This will work even if currently there is no valid virtual device with the given
384      * persistent ID, as long as such a device has been created or can be created.</p>
385      *
386      * @return the display name associated with the given persistent device ID, or {@code null} if
387      *     the persistent ID is invalid or does not correspond to a virtual device.
388      *
389      * @hide
390      */
391     // TODO(b/315481938): Link @see VirtualDevice#getPersistentDeviceId()
392     @FlaggedApi(Flags.FLAG_PERSISTENT_DEVICE_ID_API)
393     @SystemApi
394     @Nullable
getDisplayNameForPersistentDeviceId(@onNull String persistentDeviceId)395     public CharSequence getDisplayNameForPersistentDeviceId(@NonNull String persistentDeviceId) {
396         if (mService == null) {
397             Log.w(TAG, "Failed to retrieve virtual devices; no virtual device manager service.");
398             return null;
399         }
400         try {
401             return mService.getDisplayNameForPersistentDeviceId(
402                     Objects.requireNonNull(persistentDeviceId));
403         } catch (RemoteException e) {
404             throw e.rethrowFromSystemServer();
405         }
406     }
407 
408     /**
409      * Returns all current persistent device IDs, including the ones for which no virtual device
410      * exists, as long as one may have existed or can be created.
411      *
412      * @hide
413      */
414     // TODO(b/315481938): Link @see VirtualDevice#getPersistentDeviceId()
415     @FlaggedApi(Flags.FLAG_PERSISTENT_DEVICE_ID_API)
416     @SystemApi
417     @NonNull
getAllPersistentDeviceIds()418     public Set<String> getAllPersistentDeviceIds() {
419         if (mService == null) {
420             Log.w(TAG, "Failed to retrieve persistent ids; no virtual device manager service.");
421             return Collections.emptySet();
422         }
423         try {
424             return new ArraySet<>(mService.getAllPersistentDeviceIds());
425         } catch (RemoteException e) {
426             throw e.rethrowFromSystemServer();
427         }
428     }
429 
430     /**
431      * Checks whether the passed {@code deviceId} is a valid virtual device ID or not.
432      * {@link Context#DEVICE_ID_DEFAULT} is not valid as it is the ID of the default
433      * device which is not a virtual device. {@code deviceId} must correspond to a virtual device
434      * created by {@link VirtualDeviceManager#createVirtualDevice(int, VirtualDeviceParams)}.
435      *
436      * @hide
437      */
isValidVirtualDeviceId(int deviceId)438     public boolean isValidVirtualDeviceId(int deviceId) {
439         if (mService == null) {
440             Log.w(TAG, "Failed to retrieve virtual devices; no virtual device manager service.");
441             return false;
442         }
443         try {
444             return mService.isValidVirtualDeviceId(deviceId);
445         } catch (RemoteException e) {
446             throw e.rethrowFromSystemServer();
447         }
448     }
449 
450     /**
451      * Returns device-specific audio session id for audio playback.
452      *
453      * @param deviceId - id of the virtual audio device
454      * @return Device specific session id to be used for audio playback (see
455      *   {@link AudioManager#generateAudioSessionId}) if virtual device has
456      *   {@link VirtualDeviceParams#POLICY_TYPE_AUDIO} set to
457      *   {@link VirtualDeviceParams#DEVICE_POLICY_CUSTOM} and Virtual Audio Device
458      *   is configured in context-aware mode. Otherwise
459      *   {@link AudioManager#AUDIO_SESSION_ID_GENERATE} constant is returned.
460      *
461      * @hide
462      */
463     @SuppressLint("UnflaggedApi") // @TestApi without associated feature.
464     @TestApi
getAudioPlaybackSessionId(int deviceId)465     public int getAudioPlaybackSessionId(int deviceId) {
466         if (mService == null) {
467             return AUDIO_SESSION_ID_GENERATE;
468         }
469         try {
470             return mService.getAudioPlaybackSessionId(deviceId);
471         } catch (RemoteException e) {
472             throw e.rethrowFromSystemServer();
473         }
474     }
475 
476     /**
477      * Returns device-specific audio session id for audio recording.
478      *
479      * @param deviceId - id of the virtual audio device
480      * @return Device specific session id to be used for audio recording (see
481      *   {@link AudioManager#generateAudioSessionId}) if virtual device has
482      *   {@link VirtualDeviceParams#POLICY_TYPE_AUDIO} set to
483      *   {@link VirtualDeviceParams#DEVICE_POLICY_CUSTOM} and Virtual Audio Device
484      *   is configured in context-aware mode. Otherwise
485      *   {@link AudioManager#AUDIO_SESSION_ID_GENERATE} constant is returned.
486      *
487      * @hide
488      */
489     @SuppressLint("UnflaggedApi") // @TestApi without associated feature.
490     @TestApi
getAudioRecordingSessionId(int deviceId)491     public int getAudioRecordingSessionId(int deviceId) {
492         if (mService == null) {
493             return AUDIO_SESSION_ID_GENERATE;
494         }
495         try {
496             return mService.getAudioRecordingSessionId(deviceId);
497         } catch (RemoteException e) {
498             throw e.rethrowFromSystemServer();
499         }
500     }
501 
502     /**
503      * Requests sound effect to be played on virtual device.
504      *
505      * @see AudioManager#playSoundEffect(int)
506      *
507      * @param deviceId - id of the virtual audio device
508      * @param effectType the type of sound effect
509      *
510      * @hide
511      */
512     @SuppressLint("UnflaggedApi") // @TestApi without associated feature.
513     @TestApi
playSoundEffect(int deviceId, @AudioManager.SystemSoundEffect int effectType)514     public void playSoundEffect(int deviceId, @AudioManager.SystemSoundEffect int effectType) {
515         if (mService == null) {
516             Log.w(TAG, "Failed to dispatch sound effect; no virtual device manager service.");
517             return;
518         }
519         try {
520             mService.playSoundEffect(deviceId, effectType);
521         } catch (RemoteException e) {
522             throw e.rethrowFromSystemServer();
523         }
524     }
525 
526     /**
527      * Returns whether the given display is an auto-mirror display owned by a virtual device.
528      *
529      * @hide
530      */
531     @FlaggedApi(Flags.FLAG_INTERACTIVE_SCREEN_MIRROR)
532     @TestApi
isVirtualDeviceOwnedMirrorDisplay(int displayId)533     public boolean isVirtualDeviceOwnedMirrorDisplay(int displayId) {
534         if (mService == null) {
535             Log.w(TAG, "Failed to retrieve virtual devices; no virtual device manager service.");
536             return false;
537         }
538         try {
539             return mService.isVirtualDeviceOwnedMirrorDisplay(displayId);
540         } catch (RemoteException e) {
541             throw e.rethrowFromSystemServer();
542         }
543     }
544 
545     /**
546      * A representation of a virtual device.
547      *
548      * <p>A virtual device can have its own virtual displays, audio input/output, sensors, etc.
549      * The creator of a virtual device can take the output from the virtual display and stream it
550      * over to another device, and inject input and sensor events that are received from the remote
551      * device.
552      *
553      * <p>This object is only used by the virtual device creator and allows them to manage the
554      * device's behavior, peripherals, and the user interaction with that device.
555      *
556      * <p class="note">Not to be confused with {@link android.companion.virtual.VirtualDevice},
557      * which is a read-only representation exposing the properties of an existing virtual device.
558      *
559      * @hide
560      */
561     @SystemApi
562     public static class VirtualDevice implements AutoCloseable {
563 
564         private final VirtualDeviceInternal mVirtualDeviceInternal;
565 
566         @RequiresPermission(android.Manifest.permission.CREATE_VIRTUAL_DEVICE)
VirtualDevice( IVirtualDeviceManager service, Context context, int associationId, VirtualDeviceParams params)567         private VirtualDevice(
568                 IVirtualDeviceManager service,
569                 Context context,
570                 int associationId,
571                 VirtualDeviceParams params) throws RemoteException {
572             mVirtualDeviceInternal =
573                     new VirtualDeviceInternal(service, context, associationId, params);
574         }
575 
576         /**
577          * Returns the unique ID of this virtual device.
578          */
getDeviceId()579         public int getDeviceId() {
580             return mVirtualDeviceInternal.getDeviceId();
581         }
582 
583         /**
584          * Returns the persistent ID of this virtual device.
585          */
586         @FlaggedApi(Flags.FLAG_VDM_PUBLIC_APIS)
getPersistentDeviceId()587         public @Nullable String getPersistentDeviceId() {
588             return mVirtualDeviceInternal.getPersistentDeviceId();
589         }
590 
591         /**
592          * Returns a new context bound to this device.
593          *
594          * <p>This is a convenience method equivalent to calling
595          * {@link Context#createDeviceContext(int)} with the id of this device.
596          */
createContext()597         public @NonNull Context createContext() {
598             return mVirtualDeviceInternal.createContext();
599         }
600 
601         /**
602          * Returns this device's sensors.
603          *
604          * @see VirtualDeviceParams.Builder#addVirtualSensorConfig
605          *
606          * @return A list of all sensors for this device, or an empty list if no sensors exist.
607          */
608         @NonNull
getVirtualSensorList()609         public List<VirtualSensor> getVirtualSensorList() {
610             return mVirtualDeviceInternal.getVirtualSensorList();
611         }
612 
613         /**
614          * Launches a given pending intent on the give display ID.
615          *
616          * @param displayId The display to launch the pending intent on. This display must be
617          *   created from this virtual device.
618          * @param pendingIntent The pending intent to be launched. If the intent is an activity
619          *   intent, the activity will be started on the virtual display using
620          *   {@link android.app.ActivityOptions#setLaunchDisplayId}. If the intent is a service or
621          *   broadcast intent, an attempt will be made to catch activities started as a result of
622          *   sending the pending intent and move them to the given display. When it completes,
623          *   {@code listener} will be called with the status of whether the launch attempt is
624          *   successful or not.
625          * @param executor The executor to run {@code launchCallback} on.
626          * @param listener Listener that is called when the pending intent launching is complete.
627          *   The argument is {@link #LAUNCH_SUCCESS} if the launch successfully started an activity
628          *   on the virtual display, or one of the {@code LAUNCH_FAILED} status explaining why it
629          *   failed.
630          */
launchPendingIntent( int displayId, @NonNull PendingIntent pendingIntent, @NonNull Executor executor, @NonNull IntConsumer listener)631         public void launchPendingIntent(
632                 int displayId,
633                 @NonNull PendingIntent pendingIntent,
634                 @NonNull Executor executor,
635                 @NonNull IntConsumer listener) {
636             Objects.requireNonNull(pendingIntent, "pendingIntent must not be null");
637             Objects.requireNonNull(executor, "executor must not be null");
638             Objects.requireNonNull(listener, "listener must not be null");
639             mVirtualDeviceInternal.launchPendingIntent(
640                     displayId, pendingIntent, executor, listener);
641         }
642 
643         /**
644          * Creates a virtual display for this virtual device. All displays created on the same
645          * device belongs to the same display group.
646          *
647          * @param width The width of the virtual display in pixels, must be greater than 0.
648          * @param height The height of the virtual display in pixels, must be greater than 0.
649          * @param densityDpi The density of the virtual display in dpi, must be greater than 0.
650          * @param surface The surface to which the content of the virtual display should
651          *   be rendered, or null if there is none initially. The surface can also be set later
652          *   using {@link VirtualDisplay#setSurface(Surface)}.
653          * @param flags A combination of virtual display flags accepted by
654          *   {@link DisplayManager#createVirtualDisplay}. In addition, the following flags are
655          *   automatically set for all virtual devices:
656          *   {@link DisplayManager#VIRTUAL_DISPLAY_FLAG_PUBLIC} and
657          *   {@link DisplayManager#VIRTUAL_DISPLAY_FLAG_OWN_CONTENT_ONLY}.
658          * @param executor The executor on which {@code callback} will be invoked. This is ignored
659          *   if {@code callback} is {@code null}. If {@code callback} is specified, this executor
660          *   must not be null.
661          * @param callback Callback to call when the state of the {@link VirtualDisplay} changes
662          * @return The newly created virtual display, or {@code null} if the application could
663          *   not create the virtual display.
664          *
665          * @see DisplayManager#createVirtualDisplay
666          *
667          * @deprecated use {@link #createVirtualDisplay(VirtualDisplayConfig, Executor,
668          * VirtualDisplay.Callback)}
669          */
670         @Deprecated
671         @Nullable
createVirtualDisplay( @ntRangefrom = 1) int width, @IntRange(from = 1) int height, @IntRange(from = 1) int densityDpi, @Nullable Surface surface, @VirtualDisplayFlag int flags, @Nullable @CallbackExecutor Executor executor, @Nullable VirtualDisplay.Callback callback)672         public VirtualDisplay createVirtualDisplay(
673                 @IntRange(from = 1) int width,
674                 @IntRange(from = 1) int height,
675                 @IntRange(from = 1) int densityDpi,
676                 @Nullable Surface surface,
677                 @VirtualDisplayFlag int flags,
678                 @Nullable @CallbackExecutor Executor executor,
679                 @Nullable VirtualDisplay.Callback callback) {
680             // Currently this just uses the device ID, which means all of the virtual displays
681             // created using the same virtual device will have the same name if they use this
682             // deprecated API. The name should only be used for informational purposes, and not for
683             // identifying the display in code.
684             String virtualDisplayName =  "VirtualDevice_" + getDeviceId();
685             VirtualDisplayConfig.Builder builder = new VirtualDisplayConfig.Builder(
686                     virtualDisplayName, width, height, densityDpi)
687                     .setFlags(flags);
688             if (surface != null) {
689                 builder.setSurface(surface);
690             }
691             return mVirtualDeviceInternal.createVirtualDisplay(builder.build(), executor, callback);
692         }
693 
694         /**
695          * Creates a virtual display for this virtual device. All displays created on the same
696          * device belongs to the same display group.
697          *
698          * @param config The configuration of the display.
699          * @param executor The executor on which {@code callback} will be invoked. This is ignored
700          *   if {@code callback} is {@code null}. If {@code callback} is specified, this executor
701          *   must not be null.
702          * @param callback Callback to call when the state of the {@link VirtualDisplay} changes
703          * @return The newly created virtual display, or {@code null} if the application could
704          *   not create the virtual display.
705          *
706          * @see DisplayManager#createVirtualDisplay
707          */
708         @Nullable
createVirtualDisplay( @onNull VirtualDisplayConfig config, @Nullable @CallbackExecutor Executor executor, @Nullable VirtualDisplay.Callback callback)709         public VirtualDisplay createVirtualDisplay(
710                 @NonNull VirtualDisplayConfig config,
711                 @Nullable @CallbackExecutor Executor executor,
712                 @Nullable VirtualDisplay.Callback callback) {
713             Objects.requireNonNull(config, "config must not be null");
714             return mVirtualDeviceInternal.createVirtualDisplay(config, executor, callback);
715         }
716 
717         /**
718          * Closes the virtual device, stopping and tearing down any virtual displays, associated
719          * virtual audio device, and event injection that's currently in progress.
720          */
721         @RequiresPermission(android.Manifest.permission.CREATE_VIRTUAL_DEVICE)
close()722         public void close() {
723             mVirtualDeviceInternal.close();
724         }
725 
726         /**
727          * Specifies a policy for this virtual device.
728          *
729          * <p>Policies define the system behavior that may be specific for this virtual device. The
730          * given policy must be able to be changed dynamically during the lifetime of the device.
731          *
732          * @param policyType the type of policy, i.e. which behavior to specify a policy for.
733          * @param devicePolicy the value of the policy, i.e. how to interpret the device behavior.
734          *
735          * @see VirtualDeviceParams#POLICY_TYPE_RECENTS
736          * @see VirtualDeviceParams#POLICY_TYPE_ACTIVITY
737          */
738         @FlaggedApi(Flags.FLAG_DYNAMIC_POLICY)
739         @RequiresPermission(android.Manifest.permission.CREATE_VIRTUAL_DEVICE)
setDevicePolicy(@irtualDeviceParams.DynamicPolicyType int policyType, @VirtualDeviceParams.DevicePolicy int devicePolicy)740         public void setDevicePolicy(@VirtualDeviceParams.DynamicPolicyType int policyType,
741                 @VirtualDeviceParams.DevicePolicy int devicePolicy) {
742             mVirtualDeviceInternal.setDevicePolicy(policyType, devicePolicy);
743         }
744 
745         /**
746          * Specifies a component name to be exempt from the current activity launch policy.
747          *
748          * <p>If the current {@link VirtualDeviceParams#POLICY_TYPE_ACTIVITY} allows activity
749          * launches by default, (i.e. it is {@link VirtualDeviceParams#DEVICE_POLICY_DEFAULT}),
750          * then the specified component will be blocked from launching.
751          * If the current {@link VirtualDeviceParams#POLICY_TYPE_ACTIVITY} blocks activity launches
752          * by default, (i.e. it is {@link VirtualDeviceParams#DEVICE_POLICY_CUSTOM}), then the
753          * specified component will be allowed to launch.</p>
754          *
755          * <p>Note that changing the activity launch policy will clear current set of exempt
756          * components.</p>
757          *
758          * @see #removeActivityPolicyExemption
759          * @see #setDevicePolicy
760          */
761         @FlaggedApi(Flags.FLAG_DYNAMIC_POLICY)
762         @RequiresPermission(android.Manifest.permission.CREATE_VIRTUAL_DEVICE)
addActivityPolicyExemption(@onNull ComponentName componentName)763         public void addActivityPolicyExemption(@NonNull ComponentName componentName) {
764             mVirtualDeviceInternal.addActivityPolicyExemption(
765                     Objects.requireNonNull(componentName));
766         }
767 
768         /**
769          * Makes the specified component name to adhere to the default activity launch policy.
770          *
771          * <p>If the current {@link VirtualDeviceParams#POLICY_TYPE_ACTIVITY} allows activity
772          * launches by default, (i.e. it is {@link VirtualDeviceParams#DEVICE_POLICY_DEFAULT}),
773          * then the specified component will be allowed to launch.
774          * If the current {@link VirtualDeviceParams#POLICY_TYPE_ACTIVITY} blocks activity launches
775          * by default, (i.e. it is {@link VirtualDeviceParams#DEVICE_POLICY_CUSTOM}), then the
776          * specified component will be blocked from launching.</p>
777          *
778          * <p>Note that changing the activity launch policy will clear current set of exempt
779          * components.</p>
780          *
781          * @see #addActivityPolicyExemption
782          * @see #setDevicePolicy
783          */
784         @FlaggedApi(Flags.FLAG_DYNAMIC_POLICY)
785         @RequiresPermission(android.Manifest.permission.CREATE_VIRTUAL_DEVICE)
removeActivityPolicyExemption(@onNull ComponentName componentName)786         public void removeActivityPolicyExemption(@NonNull ComponentName componentName) {
787             mVirtualDeviceInternal.removeActivityPolicyExemption(
788                     Objects.requireNonNull(componentName));
789         }
790 
791         /**
792          * Creates a virtual dpad.
793          *
794          * @param config the configurations of the virtual dpad.
795          */
796         @RequiresPermission(android.Manifest.permission.CREATE_VIRTUAL_DEVICE)
797         @NonNull
createVirtualDpad(@onNull VirtualDpadConfig config)798         public VirtualDpad createVirtualDpad(@NonNull VirtualDpadConfig config) {
799             Objects.requireNonNull(config, "config must not be null");
800             return mVirtualDeviceInternal.createVirtualDpad(config);
801         }
802 
803         /**
804          * Creates a virtual keyboard.
805          *
806          * @param config the configurations of the virtual keyboard.
807          */
808         @RequiresPermission(android.Manifest.permission.CREATE_VIRTUAL_DEVICE)
809         @NonNull
createVirtualKeyboard(@onNull VirtualKeyboardConfig config)810         public VirtualKeyboard createVirtualKeyboard(@NonNull VirtualKeyboardConfig config) {
811             Objects.requireNonNull(config, "config must not be null");
812             return mVirtualDeviceInternal.createVirtualKeyboard(config);
813         }
814 
815         /**
816          * Creates a virtual keyboard.
817          *
818          * @param display the display that the events inputted through this device should target.
819          * @param inputDeviceName the name of this keyboard device.
820          * @param vendorId the PCI vendor id.
821          * @param productId the product id, as defined by the vendor.
822          * @see #createVirtualKeyboard(VirtualKeyboardConfig config)
823          * @deprecated Use {@link #createVirtualKeyboard(VirtualKeyboardConfig config)} instead
824          */
825         @Deprecated
826         @RequiresPermission(android.Manifest.permission.CREATE_VIRTUAL_DEVICE)
827         @NonNull
createVirtualKeyboard(@onNull VirtualDisplay display, @NonNull String inputDeviceName, int vendorId, int productId)828         public VirtualKeyboard createVirtualKeyboard(@NonNull VirtualDisplay display,
829                 @NonNull String inputDeviceName, int vendorId, int productId) {
830             VirtualKeyboardConfig keyboardConfig =
831                     new VirtualKeyboardConfig.Builder()
832                             .setVendorId(vendorId)
833                             .setProductId(productId)
834                             .setInputDeviceName(inputDeviceName)
835                             .setAssociatedDisplayId(display.getDisplay().getDisplayId())
836                             .build();
837             return mVirtualDeviceInternal.createVirtualKeyboard(keyboardConfig);
838         }
839 
840         /**
841          * Creates a virtual mouse.
842          *
843          * @param config the configurations of the virtual mouse.
844          */
845         @RequiresPermission(android.Manifest.permission.CREATE_VIRTUAL_DEVICE)
846         @NonNull
createVirtualMouse(@onNull VirtualMouseConfig config)847         public VirtualMouse createVirtualMouse(@NonNull VirtualMouseConfig config) {
848             Objects.requireNonNull(config, "config must not be null");
849             return mVirtualDeviceInternal.createVirtualMouse(config);
850         }
851 
852         /**
853          * Creates a virtual mouse.
854          *
855          * @param display the display that the events inputted through this device should target.
856          * @param inputDeviceName the name of this mouse.
857          * @param vendorId the PCI vendor id.
858          * @param productId the product id, as defined by the vendor.
859          * @see #createVirtualMouse(VirtualMouseConfig config)
860          * @deprecated Use {@link #createVirtualMouse(VirtualMouseConfig config)} instead
861          */
862         @Deprecated
863         @RequiresPermission(android.Manifest.permission.CREATE_VIRTUAL_DEVICE)
864         @NonNull
createVirtualMouse(@onNull VirtualDisplay display, @NonNull String inputDeviceName, int vendorId, int productId)865         public VirtualMouse createVirtualMouse(@NonNull VirtualDisplay display,
866                 @NonNull String inputDeviceName, int vendorId, int productId) {
867             VirtualMouseConfig mouseConfig =
868                     new VirtualMouseConfig.Builder()
869                             .setVendorId(vendorId)
870                             .setProductId(productId)
871                             .setInputDeviceName(inputDeviceName)
872                             .setAssociatedDisplayId(display.getDisplay().getDisplayId())
873                             .build();
874             return mVirtualDeviceInternal.createVirtualMouse(mouseConfig);
875         }
876 
877         /**
878          * Creates a virtual touchscreen.
879          *
880          * @param config the configurations of the virtual touchscreen.
881          */
882         @RequiresPermission(android.Manifest.permission.CREATE_VIRTUAL_DEVICE)
883         @NonNull
createVirtualTouchscreen( @onNull VirtualTouchscreenConfig config)884         public VirtualTouchscreen createVirtualTouchscreen(
885                 @NonNull VirtualTouchscreenConfig config) {
886             Objects.requireNonNull(config, "config must not be null");
887             return mVirtualDeviceInternal.createVirtualTouchscreen(config);
888         }
889 
890         /**
891          * Creates a virtual touchscreen.
892          *
893          * @param display the display that the events inputted through this device should target.
894          * @param inputDeviceName the name of this touchscreen device.
895          * @param vendorId the PCI vendor id.
896          * @param productId the product id, as defined by the vendor.
897          * @see #createVirtualTouchscreen(VirtualTouchscreenConfig config)
898          * @deprecated Use {@link #createVirtualTouchscreen(VirtualTouchscreenConfig config)}
899          * instead
900          */
901         @Deprecated
902         @RequiresPermission(android.Manifest.permission.CREATE_VIRTUAL_DEVICE)
903         @NonNull
createVirtualTouchscreen(@onNull VirtualDisplay display, @NonNull String inputDeviceName, int vendorId, int productId)904         public VirtualTouchscreen createVirtualTouchscreen(@NonNull VirtualDisplay display,
905                 @NonNull String inputDeviceName, int vendorId, int productId) {
906             final Point size = new Point();
907             display.getDisplay().getSize(size);
908             VirtualTouchscreenConfig touchscreenConfig =
909                     new VirtualTouchscreenConfig.Builder(size.x, size.y)
910                             .setVendorId(vendorId)
911                             .setProductId(productId)
912                             .setInputDeviceName(inputDeviceName)
913                             .setAssociatedDisplayId(display.getDisplay().getDisplayId())
914                             .build();
915             return mVirtualDeviceInternal.createVirtualTouchscreen(touchscreenConfig);
916         }
917 
918         /**
919          * Creates a virtual touchpad in navigation mode.
920          *
921          * <p>A touchpad in navigation mode means that its events are interpreted as navigation
922          * events (up, down, etc) instead of using them to update a cursor's absolute position. If
923          * the events are not consumed they are converted to DPAD events and delivered to the target
924          * again.
925          *
926          * @param config the configurations of the virtual navigation touchpad.
927          * @see android.view.InputDevice#SOURCE_TOUCH_NAVIGATION
928          */
929         @RequiresPermission(android.Manifest.permission.CREATE_VIRTUAL_DEVICE)
930         @NonNull
createVirtualNavigationTouchpad( @onNull VirtualNavigationTouchpadConfig config)931         public VirtualNavigationTouchpad createVirtualNavigationTouchpad(
932                 @NonNull VirtualNavigationTouchpadConfig config) {
933             return mVirtualDeviceInternal.createVirtualNavigationTouchpad(config);
934         }
935 
936         /**
937          * Creates a virtual stylus.
938          *
939          * @param config the touchscreen configurations for the virtual stylus.
940          */
941         @RequiresPermission(android.Manifest.permission.CREATE_VIRTUAL_DEVICE)
942         @NonNull
943         @FlaggedApi(Flags.FLAG_VIRTUAL_STYLUS)
createVirtualStylus( @onNull VirtualStylusConfig config)944         public VirtualStylus createVirtualStylus(
945                 @NonNull VirtualStylusConfig config) {
946             return mVirtualDeviceInternal.createVirtualStylus(config);
947         }
948 
949         /**
950          * Creates a VirtualAudioDevice, capable of recording audio emanating from this device,
951          * or injecting audio from another device.
952          *
953          * <p>Note: One {@link VirtualDevice} can only create one {@link VirtualAudioDevice}, so
954          * calling this method multiple times will return the same instance. When
955          * {@link VirtualDevice#close()} is called, the associated {@link VirtualAudioDevice} will
956          * also be closed automatically.
957          *
958          * @param display The target virtual display to capture from and inject into.
959          * @param executor The {@link Executor} object for the thread on which to execute
960          *   the callback. If <code>null</code>, the {@link Executor} associated with the main
961          *   {@link Looper} will be used.
962          * @param callback Interface to be notified when playback or recording configuration of
963          *   applications running on virtual display is changed.
964          * @return A {@link VirtualAudioDevice} instance.
965          */
966         @RequiresPermission(android.Manifest.permission.CREATE_VIRTUAL_DEVICE)
967         @NonNull
createVirtualAudioDevice( @onNull VirtualDisplay display, @Nullable Executor executor, @Nullable AudioConfigurationChangeCallback callback)968         public VirtualAudioDevice createVirtualAudioDevice(
969                 @NonNull VirtualDisplay display,
970                 @Nullable Executor executor,
971                 @Nullable AudioConfigurationChangeCallback callback) {
972             Objects.requireNonNull(display, "display must not be null");
973             return mVirtualDeviceInternal.createVirtualAudioDevice(display, executor, callback);
974         }
975 
976         /**
977          * Creates a new virtual camera with the given {@link VirtualCameraConfig}. A virtual device
978          * can create a virtual camera only if it has
979          * {@link VirtualDeviceParams#DEVICE_POLICY_CUSTOM} as its
980          * {@link VirtualDeviceParams#POLICY_TYPE_CAMERA}.
981          *
982          * @param config camera configuration.
983          * @return newly created camera.
984          * @throws UnsupportedOperationException if virtual camera isn't supported on this device.
985          * @see VirtualDeviceParams#POLICY_TYPE_CAMERA
986          */
987         @RequiresPermission(android.Manifest.permission.CREATE_VIRTUAL_DEVICE)
988         @NonNull
989         @FlaggedApi(Flags.FLAG_VIRTUAL_CAMERA)
createVirtualCamera(@onNull VirtualCameraConfig config)990         public VirtualCamera createVirtualCamera(@NonNull VirtualCameraConfig config) {
991             if (!Flags.virtualCamera()) {
992                 throw new UnsupportedOperationException(
993                         "Flag is not enabled: %s".formatted(Flags.FLAG_VIRTUAL_CAMERA));
994             }
995             return mVirtualDeviceInternal.createVirtualCamera(Objects.requireNonNull(config));
996         }
997 
998         /**
999          * Sets the visibility of the pointer icon for this VirtualDevice's associated displays.
1000          *
1001          * @param showPointerIcon True if the pointer should be shown; false otherwise. The default
1002          *   visibility is true.
1003          */
1004         @RequiresPermission(android.Manifest.permission.CREATE_VIRTUAL_DEVICE)
setShowPointerIcon(boolean showPointerIcon)1005         public void setShowPointerIcon(boolean showPointerIcon) {
1006             mVirtualDeviceInternal.setShowPointerIcon(showPointerIcon);
1007         }
1008 
1009         /**
1010          * Specifies the IME behavior on the given display. By default, all displays created by
1011          * virtual devices have {@link WindowManager#DISPLAY_IME_POLICY_LOCAL}.
1012          *
1013          * @param displayId the ID of the display to change the IME policy for. It must be owned by
1014          *                  this virtual device.
1015          * @param policy the IME policy to use on that display
1016          * @throws SecurityException if the display is not owned by this device or is not
1017          *                           {@link DisplayManager#VIRTUAL_DISPLAY_FLAG_TRUSTED trusted}
1018          */
1019         @RequiresPermission(android.Manifest.permission.CREATE_VIRTUAL_DEVICE)
1020         @FlaggedApi(Flags.FLAG_VDM_CUSTOM_IME)
setDisplayImePolicy(int displayId, @WindowManager.DisplayImePolicy int policy)1021         public void setDisplayImePolicy(int displayId, @WindowManager.DisplayImePolicy int policy) {
1022             if (Flags.vdmCustomIme()) {
1023                 mVirtualDeviceInternal.setDisplayImePolicy(displayId, policy);
1024             }
1025         }
1026 
1027         /**
1028          * Adds an activity listener to listen for events such as top activity change or virtual
1029          * display task stack became empty.
1030          *
1031          * @param executor The executor where the listener is executed on.
1032          * @param listener The listener to add.
1033          * @see #removeActivityListener(ActivityListener)
1034          */
addActivityListener( @allbackExecutor @onNull Executor executor, @NonNull ActivityListener listener)1035         public void addActivityListener(
1036                 @CallbackExecutor @NonNull Executor executor, @NonNull ActivityListener listener) {
1037             mVirtualDeviceInternal.addActivityListener(executor, listener);
1038         }
1039 
1040         /**
1041          * Removes an activity listener previously added with {@link #addActivityListener}.
1042          *
1043          * @param listener The listener to remove.
1044          * @see #addActivityListener(Executor, ActivityListener)
1045          */
removeActivityListener(@onNull ActivityListener listener)1046         public void removeActivityListener(@NonNull ActivityListener listener) {
1047             mVirtualDeviceInternal.removeActivityListener(listener);
1048         }
1049 
1050         /**
1051          * Adds a sound effect listener.
1052          *
1053          * @param executor The executor where the listener is executed on.
1054          * @param soundEffectListener The listener to add.
1055          * @see #removeSoundEffectListener(SoundEffectListener)
1056          */
addSoundEffectListener(@allbackExecutor @onNull Executor executor, @NonNull SoundEffectListener soundEffectListener)1057         public void addSoundEffectListener(@CallbackExecutor @NonNull Executor executor,
1058                 @NonNull SoundEffectListener soundEffectListener) {
1059             mVirtualDeviceInternal.addSoundEffectListener(executor, soundEffectListener);
1060         }
1061 
1062         /**
1063          * Removes a sound effect listener previously added with {@link #addSoundEffectListener}.
1064          *
1065          * @param soundEffectListener The listener to remove.
1066          * @see #addSoundEffectListener(Executor, SoundEffectListener)
1067          */
removeSoundEffectListener(@onNull SoundEffectListener soundEffectListener)1068         public void removeSoundEffectListener(@NonNull SoundEffectListener soundEffectListener) {
1069             mVirtualDeviceInternal.removeSoundEffectListener(soundEffectListener);
1070         }
1071 
1072         /**
1073          * Registers an intent interceptor that will intercept an intent attempting to launch
1074          * when matching the provided IntentFilter and calls the callback with the intercepted
1075          * intent.
1076          *
1077          * @param interceptorFilter The filter to match intents intended for interception.
1078          * @param executor The executor where the interceptor is executed on.
1079          * @param interceptorCallback The callback called when an intent matching interceptorFilter
1080          * is intercepted.
1081          * @see #unregisterIntentInterceptor(IntentInterceptorCallback)
1082          */
1083         @RequiresPermission(android.Manifest.permission.CREATE_VIRTUAL_DEVICE)
registerIntentInterceptor( @onNull IntentFilter interceptorFilter, @CallbackExecutor @NonNull Executor executor, @NonNull IntentInterceptorCallback interceptorCallback)1084         public void registerIntentInterceptor(
1085                 @NonNull IntentFilter interceptorFilter,
1086                 @CallbackExecutor @NonNull Executor executor,
1087                 @NonNull IntentInterceptorCallback interceptorCallback) {
1088             mVirtualDeviceInternal.registerIntentInterceptor(
1089                     interceptorFilter, executor, interceptorCallback);
1090         }
1091 
1092         /**
1093          * Unregisters the intent interceptor previously registered with
1094          * {@link #registerIntentInterceptor}.
1095          */
1096         @RequiresPermission(android.Manifest.permission.CREATE_VIRTUAL_DEVICE)
unregisterIntentInterceptor( @onNull IntentInterceptorCallback interceptorCallback)1097         public void unregisterIntentInterceptor(
1098                     @NonNull IntentInterceptorCallback interceptorCallback) {
1099             mVirtualDeviceInternal.unregisterIntentInterceptor(interceptorCallback);
1100         }
1101     }
1102 
1103     /**
1104      * Listener for activity changes in this virtual device.
1105      *
1106      * @hide
1107      */
1108     @SystemApi
1109     public interface ActivityListener {
1110 
1111         /**
1112          * Called when the top activity is changed.
1113          *
1114          * <p>Note: When there are no activities running on the virtual display, the
1115          * {@link #onDisplayEmpty(int)} will be called. If the value topActivity is cached, it
1116          * should be cleared when {@link #onDisplayEmpty(int)} is called.
1117          *
1118          * @param displayId The display ID on which the activity change happened.
1119          * @param topActivity The component name of the top activity.
1120          * @deprecated Use {@link #onTopActivityChanged(int, ComponentName, int)} instead
1121          */
onTopActivityChanged(int displayId, @NonNull ComponentName topActivity)1122         void onTopActivityChanged(int displayId, @NonNull ComponentName topActivity);
1123 
1124         /**
1125          * Called when the top activity is changed.
1126          *
1127          * <p>Note: When there are no activities running on the virtual display, the
1128          * {@link #onDisplayEmpty(int)} will be called. If the value topActivity is cached, it
1129          * should be cleared when {@link #onDisplayEmpty(int)} is called.
1130          *
1131          * @param displayId The display ID on which the activity change happened.
1132          * @param topActivity The component name of the top activity.
1133          * @param userId The user ID associated with the top activity.
1134          */
onTopActivityChanged(int displayId, @NonNull ComponentName topActivity, @UserIdInt int userId)1135         default void onTopActivityChanged(int displayId, @NonNull ComponentName topActivity,
1136                 @UserIdInt int userId) {}
1137 
1138         /**
1139          * Called when the display becomes empty (e.g. if the user hits back on the last
1140          * activity of the root task).
1141          *
1142          * @param displayId The display ID that became empty.
1143          */
onDisplayEmpty(int displayId)1144         void onDisplayEmpty(int displayId);
1145     }
1146 
1147     /**
1148      * Interceptor interface to be called when an intent matches the IntentFilter passed into {@link
1149      * VirtualDevice#registerIntentInterceptor}. When the interceptor is called after matching the
1150      * IntentFilter, the intended activity launch will be aborted and alternatively replaced by
1151      * the interceptor's receiver.
1152      *
1153      * @hide
1154      */
1155     @SystemApi
1156     public interface IntentInterceptorCallback {
1157 
1158         /**
1159          * Called when an intent that matches the IntentFilter registered in {@link
1160          * VirtualDevice#registerIntentInterceptor} is intercepted for the virtual device to
1161          * handle.
1162          *
1163          * @param intent The intent that has been intercepted by the interceptor.
1164          */
onIntentIntercepted(@onNull Intent intent)1165         void onIntentIntercepted(@NonNull Intent intent);
1166     }
1167 
1168     /**
1169      * Listener for system sound effect playback on virtual device.
1170      *
1171      * @hide
1172      */
1173     @SystemApi
1174     public interface SoundEffectListener {
1175 
1176         /**
1177          * Called when there's a system sound effect to be played on virtual device.
1178          *
1179          * @param effectType - system sound effect type
1180          * @see android.media.AudioManager.SystemSoundEffect
1181          */
onPlaySoundEffect(@udioManager.SystemSoundEffect int effectType)1182         void onPlaySoundEffect(@AudioManager.SystemSoundEffect int effectType);
1183     }
1184 
1185     /**
1186      * Listener for changes in the available virtual devices.
1187      *
1188      * @see #registerVirtualDeviceListener
1189      */
1190     @FlaggedApi(Flags.FLAG_VDM_PUBLIC_APIS)
1191     public interface VirtualDeviceListener {
1192         /**
1193          * Called whenever a new virtual device has been added to the system.
1194          * Use {@link VirtualDeviceManager#getVirtualDevice(int)} to get more information about
1195          * the device.
1196          *
1197          * @param deviceId The id of the virtual device that was added.
1198          */
onVirtualDeviceCreated(int deviceId)1199         default void onVirtualDeviceCreated(int deviceId) {}
1200 
1201         /**
1202          * Called whenever a virtual device has been removed from the system.
1203          *
1204          * @param deviceId The id of the virtual device that was removed.
1205          */
onVirtualDeviceClosed(int deviceId)1206         default void onVirtualDeviceClosed(int deviceId) {}
1207     }
1208 
1209     /**
1210      * A wrapper for {@link VirtualDeviceListener} that executes callbacks on the given executor.
1211      */
1212     private static class VirtualDeviceListenerDelegate extends IVirtualDeviceListener.Stub {
1213         private final VirtualDeviceListener mListener;
1214         private final Executor mExecutor;
1215 
VirtualDeviceListenerDelegate(Executor executor, VirtualDeviceListener listener)1216         private VirtualDeviceListenerDelegate(Executor executor, VirtualDeviceListener listener) {
1217             mExecutor = executor;
1218             mListener = listener;
1219         }
1220 
1221         @Override
onVirtualDeviceCreated(int deviceId)1222         public void onVirtualDeviceCreated(int deviceId) {
1223             final long token = Binder.clearCallingIdentity();
1224             try {
1225                 mExecutor.execute(() -> mListener.onVirtualDeviceCreated(deviceId));
1226             } finally {
1227                 Binder.restoreCallingIdentity(token);
1228             }
1229         }
1230 
1231         @Override
onVirtualDeviceClosed(int deviceId)1232         public void onVirtualDeviceClosed(int deviceId) {
1233             final long token = Binder.clearCallingIdentity();
1234             try {
1235                 mExecutor.execute(() -> mListener.onVirtualDeviceClosed(deviceId));
1236             } finally {
1237                 Binder.restoreCallingIdentity(token);
1238             }
1239         }
1240     }
1241 }
1242