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.IntDef;
23 import android.annotation.IntRange;
24 import android.annotation.NonNull;
25 import android.annotation.Nullable;
26 import android.annotation.RequiresPermission;
27 import android.annotation.SdkConstant;
28 import android.annotation.SystemApi;
29 import android.annotation.SystemService;
30 import android.annotation.UserIdInt;
31 import android.app.PendingIntent;
32 import android.companion.AssociationInfo;
33 import android.companion.virtual.audio.VirtualAudioDevice;
34 import android.companion.virtual.audio.VirtualAudioDevice.AudioConfigurationChangeCallback;
35 import android.companion.virtual.sensor.VirtualSensor;
36 import android.content.ComponentName;
37 import android.content.Context;
38 import android.content.Intent;
39 import android.content.IntentFilter;
40 import android.graphics.Point;
41 import android.hardware.display.DisplayManager;
42 import android.hardware.display.DisplayManager.VirtualDisplayFlag;
43 import android.hardware.display.VirtualDisplay;
44 import android.hardware.display.VirtualDisplayConfig;
45 import android.hardware.input.VirtualDpad;
46 import android.hardware.input.VirtualDpadConfig;
47 import android.hardware.input.VirtualKeyboard;
48 import android.hardware.input.VirtualKeyboardConfig;
49 import android.hardware.input.VirtualMouse;
50 import android.hardware.input.VirtualMouseConfig;
51 import android.hardware.input.VirtualNavigationTouchpad;
52 import android.hardware.input.VirtualNavigationTouchpadConfig;
53 import android.hardware.input.VirtualTouchscreen;
54 import android.hardware.input.VirtualTouchscreenConfig;
55 import android.media.AudioManager;
56 import android.os.Looper;
57 import android.os.RemoteException;
58 import android.util.Log;
59 import android.view.Surface;
60 
61 import java.lang.annotation.ElementType;
62 import java.lang.annotation.Retention;
63 import java.lang.annotation.RetentionPolicy;
64 import java.lang.annotation.Target;
65 import java.util.ArrayList;
66 import java.util.List;
67 import java.util.Objects;
68 import java.util.concurrent.Executor;
69 import java.util.function.IntConsumer;
70 
71 /**
72  * System level service for creation and management of virtual devices.
73  *
74  * <p>VirtualDeviceManager enables interactive sharing of capabilities between the host Android
75  * device and a remote device.
76  *
77  * <p class="note">Not to be confused with the Android Studio's Virtual Device Manager, which allows
78  * for device emulation.
79  */
80 @SystemService(Context.VIRTUAL_DEVICE_SERVICE)
81 public final class VirtualDeviceManager {
82 
83     private static final String TAG = "VirtualDeviceManager";
84 
85     /**
86      * Broadcast Action: A Virtual Device was removed.
87      *
88      * <p class="note">This is a protected intent that can only be sent by the system.</p>
89      *
90      * @hide
91      */
92     @SdkConstant(SdkConstant.SdkConstantType.BROADCAST_INTENT_ACTION)
93     public static final String ACTION_VIRTUAL_DEVICE_REMOVED =
94             "android.companion.virtual.action.VIRTUAL_DEVICE_REMOVED";
95 
96     /**
97      * Int intent extra to be used with {@link #ACTION_VIRTUAL_DEVICE_REMOVED}.
98      * Contains the identifier of the virtual device, which was removed.
99      *
100      * @hide
101      */
102     public static final String EXTRA_VIRTUAL_DEVICE_ID =
103             "android.companion.virtual.extra.VIRTUAL_DEVICE_ID";
104 
105     /** @hide */
106     @Retention(RetentionPolicy.SOURCE)
107     @IntDef(
108             prefix = "LAUNCH_",
109             value = {
110                     LAUNCH_SUCCESS,
111                     LAUNCH_FAILURE_PENDING_INTENT_CANCELED,
112                     LAUNCH_FAILURE_NO_ACTIVITY})
113     @Target({ElementType.TYPE_PARAMETER, ElementType.TYPE_USE})
114     public @interface PendingIntentLaunchStatus {}
115 
116     /**
117      * Status for {@link VirtualDevice#launchPendingIntent}, indicating that the launch was
118      * successful.
119      *
120      * @hide
121      */
122     @SystemApi
123     public static final int LAUNCH_SUCCESS = 0;
124 
125     /**
126      * Status for {@link VirtualDevice#launchPendingIntent}, indicating that the launch failed
127      * because the pending intent was canceled.
128      *
129      * @hide
130      */
131     @SystemApi
132     public static final int LAUNCH_FAILURE_PENDING_INTENT_CANCELED = 1;
133 
134     /**
135      * Status for {@link VirtualDevice#launchPendingIntent}, indicating that the launch failed
136      * because no activity starts were detected as a result of calling the pending intent.
137      *
138      * @hide
139      */
140     @SystemApi
141     public static final int LAUNCH_FAILURE_NO_ACTIVITY = 2;
142 
143     private final IVirtualDeviceManager mService;
144     private final Context mContext;
145 
146     /** @hide */
VirtualDeviceManager( @ullable IVirtualDeviceManager service, @NonNull Context context)147     public VirtualDeviceManager(
148             @Nullable IVirtualDeviceManager service, @NonNull Context context) {
149         mService = service;
150         mContext = context;
151     }
152 
153     /**
154      * Creates a virtual device where applications can launch and receive input events injected by
155      * the creator.
156      *
157      * <p>The {@link android.Manifest.permission#CREATE_VIRTUAL_DEVICE} permission is required to
158      * create virtual devices, which is only available to system apps holding specific roles.
159      *
160      * @param associationId The association ID as returned by {@link AssociationInfo#getId()} from
161      *   Companion Device Manager. Virtual devices must have a corresponding association with CDM in
162      *   order to be created.
163      * @param params The parameters for creating virtual devices. See {@link VirtualDeviceParams}
164      *   for the available options.
165      * @return The created virtual device.
166      *
167      * @hide
168      */
169     @SystemApi
170     @RequiresPermission(android.Manifest.permission.CREATE_VIRTUAL_DEVICE)
171     @NonNull
createVirtualDevice( int associationId, @NonNull VirtualDeviceParams params)172     public VirtualDevice createVirtualDevice(
173             int associationId,
174             @NonNull VirtualDeviceParams params) {
175         Objects.requireNonNull(params, "params must not be null");
176         try {
177             return new VirtualDevice(mService, mContext, associationId, params);
178         } catch (RemoteException e) {
179             throw e.rethrowFromSystemServer();
180         }
181     }
182 
183     /**
184      * Returns the details of all available virtual devices.
185      *
186      * <p>The returned objects are read-only representations that expose the properties of all
187      * existing virtual devices.
188      */
189     @NonNull
getVirtualDevices()190     public List<android.companion.virtual.VirtualDevice> getVirtualDevices() {
191         if (mService == null) {
192             Log.w(TAG, "Failed to retrieve virtual devices; no virtual device manager service.");
193             return new ArrayList<>();
194         }
195         try {
196             return mService.getVirtualDevices();
197         } catch (RemoteException e) {
198             throw e.rethrowFromSystemServer();
199         }
200     }
201 
202     /**
203      * Returns the device policy for the given virtual device and policy type.
204      *
205      * <p>In case the virtual device identifier is not valid, or there's no explicitly specified
206      * policy for that device and policy type, then
207      * {@link VirtualDeviceParams#DEVICE_POLICY_DEFAULT} is returned.
208      *
209      * @hide
210      */
getDevicePolicy( int deviceId, @VirtualDeviceParams.PolicyType int policyType)211     public @VirtualDeviceParams.DevicePolicy int getDevicePolicy(
212             int deviceId, @VirtualDeviceParams.PolicyType int policyType) {
213         if (mService == null) {
214             Log.w(TAG, "Failed to retrieve device policy; no virtual device manager service.");
215             return VirtualDeviceParams.DEVICE_POLICY_DEFAULT;
216         }
217         try {
218             return mService.getDevicePolicy(deviceId, policyType);
219         } catch (RemoteException e) {
220             throw e.rethrowFromSystemServer();
221         }
222     }
223 
224     /**
225      * Returns the ID of the device which owns the display with the given ID.
226      *
227      * @hide
228      */
getDeviceIdForDisplayId(int displayId)229     public int getDeviceIdForDisplayId(int displayId) {
230         if (mService == null) {
231             Log.w(TAG, "Failed to retrieve virtual devices; no virtual device manager service.");
232             return Context.DEVICE_ID_DEFAULT;
233         }
234         try {
235             return mService.getDeviceIdForDisplayId(displayId);
236         } catch (RemoteException e) {
237             throw e.rethrowFromSystemServer();
238         }
239     }
240 
241     /**
242      * Checks whether the passed {@code deviceId} is a valid virtual device ID or not.
243      * {@link Context#DEVICE_ID_DEFAULT} is not valid as it is the ID of the default
244      * device which is not a virtual device. {@code deviceId} must correspond to a virtual device
245      * created by {@link VirtualDeviceManager#createVirtualDevice(int, VirtualDeviceParams)}.
246      *
247      * @hide
248      */
isValidVirtualDeviceId(int deviceId)249     public boolean isValidVirtualDeviceId(int deviceId) {
250         if (mService == null) {
251             Log.w(TAG, "Failed to retrieve virtual devices; no virtual device manager service.");
252             return false;
253         }
254         try {
255             return mService.isValidVirtualDeviceId(deviceId);
256         } catch (RemoteException e) {
257             throw e.rethrowFromSystemServer();
258         }
259     }
260 
261     /**
262      * Returns device-specific audio session id for audio playback.
263      *
264      * @param deviceId - id of the virtual audio device
265      * @return Device specific session id to be used for audio playback (see
266      *   {@link AudioManager#generateAudioSessionId}) if virtual device has
267      *   {@link VirtualDeviceParams#POLICY_TYPE_AUDIO} set to
268      *   {@link VirtualDeviceParams#DEVICE_POLICY_CUSTOM} and Virtual Audio Device
269      *   is configured in context-aware mode. Otherwise
270      *   {@link AudioManager#AUDIO_SESSION_ID_GENERATE} constant is returned.
271      *
272      * @hide
273      */
getAudioPlaybackSessionId(int deviceId)274     public int getAudioPlaybackSessionId(int deviceId) {
275         if (mService == null) {
276             return AUDIO_SESSION_ID_GENERATE;
277         }
278         try {
279             return mService.getAudioPlaybackSessionId(deviceId);
280         } catch (RemoteException e) {
281             throw e.rethrowFromSystemServer();
282         }
283     }
284 
285     /**
286      * Returns device-specific audio session id for audio recording.
287      *
288      * @param deviceId - id of the virtual audio device
289      * @return Device specific session id to be used for audio recording (see
290      *   {@link AudioManager#generateAudioSessionId}) if virtual device has
291      *   {@link VirtualDeviceParams#POLICY_TYPE_AUDIO} set to
292      *   {@link VirtualDeviceParams#DEVICE_POLICY_CUSTOM} and Virtual Audio Device
293      *   is configured in context-aware mode. Otherwise
294      *   {@link AudioManager#AUDIO_SESSION_ID_GENERATE} constant is returned.
295      *
296      * @hide
297      */
getAudioRecordingSessionId(int deviceId)298     public int getAudioRecordingSessionId(int deviceId) {
299         if (mService == null) {
300             return AUDIO_SESSION_ID_GENERATE;
301         }
302         try {
303             return mService.getAudioRecordingSessionId(deviceId);
304         } catch (RemoteException e) {
305             throw e.rethrowFromSystemServer();
306         }
307     }
308 
309     /**
310      * Requests sound effect to be played on virtual device.
311      *
312      * @see AudioManager#playSoundEffect(int)
313      *
314      * @param deviceId - id of the virtual audio device
315      * @param effectType the type of sound effect
316      *
317      * @hide
318      */
playSoundEffect(int deviceId, @AudioManager.SystemSoundEffect int effectType)319     public void playSoundEffect(int deviceId, @AudioManager.SystemSoundEffect int effectType) {
320         if (mService == null) {
321             Log.w(TAG, "Failed to dispatch sound effect; no virtual device manager service.");
322             return;
323         }
324         try {
325             mService.playSoundEffect(deviceId, effectType);
326         } catch (RemoteException e) {
327             throw e.rethrowFromSystemServer();
328         }
329     }
330 
331     /**
332      * A representation of a virtual device.
333      *
334      * <p>A virtual device can have its own virtual displays, audio input/output, sensors, etc.
335      * The creator of a virtual device can take the output from the virtual display and stream it
336      * over to another device, and inject input and sensor events that are received from the remote
337      * device.
338      *
339      * <p>This object is only used by the virtual device creator and allows them to manage the
340      * device's behavior, peripherals, and the user interaction with that device.
341      *
342      * <p class="note">Not to be confused with {@link android.companion.virtual.VirtualDevice},
343      * which is a read-only representation exposing the properties of an existing virtual device.
344      *
345      * @hide
346      */
347     @SystemApi
348     public static class VirtualDevice implements AutoCloseable {
349 
350         private final VirtualDeviceInternal mVirtualDeviceInternal;
351 
352         @RequiresPermission(android.Manifest.permission.CREATE_VIRTUAL_DEVICE)
VirtualDevice( IVirtualDeviceManager service, Context context, int associationId, VirtualDeviceParams params)353         private VirtualDevice(
354                 IVirtualDeviceManager service,
355                 Context context,
356                 int associationId,
357                 VirtualDeviceParams params) throws RemoteException {
358             mVirtualDeviceInternal =
359                     new VirtualDeviceInternal(service, context, associationId, params);
360         }
361 
362         /**
363          * Returns the unique ID of this virtual device.
364          */
getDeviceId()365         public int getDeviceId() {
366             return mVirtualDeviceInternal.getDeviceId();
367         }
368 
369         /**
370          * Returns a new context bound to this device.
371          *
372          * <p>This is a convenience method equivalent to calling
373          * {@link Context#createDeviceContext(int)} with the id of this device.
374          */
createContext()375         public @NonNull Context createContext() {
376             return mVirtualDeviceInternal.createContext();
377         }
378 
379         /**
380          * Returns this device's sensors.
381          *
382          * @see VirtualDeviceParams.Builder#addVirtualSensorConfig
383          *
384          * @return A list of all sensors for this device, or an empty list if no sensors exist.
385          */
386         @NonNull
getVirtualSensorList()387         public List<VirtualSensor> getVirtualSensorList() {
388             return mVirtualDeviceInternal.getVirtualSensorList();
389         }
390 
391         /**
392          * Launches a given pending intent on the give display ID.
393          *
394          * @param displayId The display to launch the pending intent on. This display must be
395          *   created from this virtual device.
396          * @param pendingIntent The pending intent to be launched. If the intent is an activity
397          *   intent, the activity will be started on the virtual display using
398          *   {@link android.app.ActivityOptions#setLaunchDisplayId}. If the intent is a service or
399          *   broadcast intent, an attempt will be made to catch activities started as a result of
400          *   sending the pending intent and move them to the given display. When it completes,
401          *   {@code listener} will be called with the status of whether the launch attempt is
402          *   successful or not.
403          * @param executor The executor to run {@code launchCallback} on.
404          * @param listener Listener that is called when the pending intent launching is complete.
405          *   The argument is {@link #LAUNCH_SUCCESS} if the launch successfully started an activity
406          *   on the virtual display, or one of the {@code LAUNCH_FAILED} status explaining why it
407          *   failed.
408          */
launchPendingIntent( int displayId, @NonNull PendingIntent pendingIntent, @NonNull Executor executor, @NonNull IntConsumer listener)409         public void launchPendingIntent(
410                 int displayId,
411                 @NonNull PendingIntent pendingIntent,
412                 @NonNull Executor executor,
413                 @NonNull IntConsumer listener) {
414             Objects.requireNonNull(pendingIntent, "pendingIntent must not be null");
415             Objects.requireNonNull(executor, "executor must not be null");
416             Objects.requireNonNull(listener, "listener must not be null");
417             mVirtualDeviceInternal.launchPendingIntent(
418                     displayId, pendingIntent, executor, listener);
419         }
420 
421         /**
422          * Creates a virtual display for this virtual device. All displays created on the same
423          * device belongs to the same display group.
424          *
425          * @param width The width of the virtual display in pixels, must be greater than 0.
426          * @param height The height of the virtual display in pixels, must be greater than 0.
427          * @param densityDpi The density of the virtual display in dpi, must be greater than 0.
428          * @param surface The surface to which the content of the virtual display should
429          *   be rendered, or null if there is none initially. The surface can also be set later
430          *   using {@link VirtualDisplay#setSurface(Surface)}.
431          * @param flags A combination of virtual display flags accepted by
432          *   {@link DisplayManager#createVirtualDisplay}. In addition, the following flags are
433          *   automatically set for all virtual devices:
434          *   {@link DisplayManager#VIRTUAL_DISPLAY_FLAG_PUBLIC} and
435          *   {@link DisplayManager#VIRTUAL_DISPLAY_FLAG_OWN_CONTENT_ONLY}.
436          * @param executor The executor on which {@code callback} will be invoked. This is ignored
437          *   if {@code callback} is {@code null}. If {@code callback} is specified, this executor
438          *   must not be null.
439          * @param callback Callback to call when the state of the {@link VirtualDisplay} changes
440          * @return The newly created virtual display, or {@code null} if the application could
441          *   not create the virtual display.
442          *
443          * @see DisplayManager#createVirtualDisplay
444          *
445          * @deprecated use {@link #createVirtualDisplay(VirtualDisplayConfig, Executor,
446          * VirtualDisplay.Callback)}
447          */
448         @Deprecated
449         @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)450         public VirtualDisplay createVirtualDisplay(
451                 @IntRange(from = 1) int width,
452                 @IntRange(from = 1) int height,
453                 @IntRange(from = 1) int densityDpi,
454                 @Nullable Surface surface,
455                 @VirtualDisplayFlag int flags,
456                 @Nullable @CallbackExecutor Executor executor,
457                 @Nullable VirtualDisplay.Callback callback) {
458             // Currently this just uses the device ID, which means all of the virtual displays
459             // created using the same virtual device will have the same name if they use this
460             // deprecated API. The name should only be used for informational purposes, and not for
461             // identifying the display in code.
462             String virtualDisplayName =  "VirtualDevice_" + getDeviceId();
463             VirtualDisplayConfig.Builder builder = new VirtualDisplayConfig.Builder(
464                     virtualDisplayName, width, height, densityDpi)
465                     .setFlags(flags);
466             if (surface != null) {
467                 builder.setSurface(surface);
468             }
469             return mVirtualDeviceInternal.createVirtualDisplay(builder.build(), executor, callback);
470         }
471 
472         /**
473          * Creates a virtual display for this virtual device. All displays created on the same
474          * device belongs to the same display group.
475          *
476          * @param config The configuration of the display.
477          * @param executor The executor on which {@code callback} will be invoked. This is ignored
478          *   if {@code callback} is {@code null}. If {@code callback} is specified, this executor
479          *   must not be null.
480          * @param callback Callback to call when the state of the {@link VirtualDisplay} changes
481          * @return The newly created virtual display, or {@code null} if the application could
482          *   not create the virtual display.
483          *
484          * @see DisplayManager#createVirtualDisplay
485          */
486         @Nullable
createVirtualDisplay( @onNull VirtualDisplayConfig config, @Nullable @CallbackExecutor Executor executor, @Nullable VirtualDisplay.Callback callback)487         public VirtualDisplay createVirtualDisplay(
488                 @NonNull VirtualDisplayConfig config,
489                 @Nullable @CallbackExecutor Executor executor,
490                 @Nullable VirtualDisplay.Callback callback) {
491             Objects.requireNonNull(config, "config must not be null");
492             return mVirtualDeviceInternal.createVirtualDisplay(config, executor, callback);
493         }
494 
495         /**
496          * Closes the virtual device, stopping and tearing down any virtual displays, associated
497          * virtual audio device, and event injection that's currently in progress.
498          */
499         @RequiresPermission(android.Manifest.permission.CREATE_VIRTUAL_DEVICE)
close()500         public void close() {
501             mVirtualDeviceInternal.close();
502         }
503 
504         /**
505          * Creates a virtual dpad.
506          *
507          * @param config the configurations of the virtual dpad.
508          */
509         @RequiresPermission(android.Manifest.permission.CREATE_VIRTUAL_DEVICE)
510         @NonNull
createVirtualDpad(@onNull VirtualDpadConfig config)511         public VirtualDpad createVirtualDpad(@NonNull VirtualDpadConfig config) {
512             Objects.requireNonNull(config, "config must not be null");
513             return mVirtualDeviceInternal.createVirtualDpad(config);
514         }
515 
516         /**
517          * Creates a virtual keyboard.
518          *
519          * @param config the configurations of the virtual keyboard.
520          */
521         @RequiresPermission(android.Manifest.permission.CREATE_VIRTUAL_DEVICE)
522         @NonNull
createVirtualKeyboard(@onNull VirtualKeyboardConfig config)523         public VirtualKeyboard createVirtualKeyboard(@NonNull VirtualKeyboardConfig config) {
524             Objects.requireNonNull(config, "config must not be null");
525             return mVirtualDeviceInternal.createVirtualKeyboard(config);
526         }
527 
528         /**
529          * Creates a virtual keyboard.
530          *
531          * @param display the display that the events inputted through this device should target.
532          * @param inputDeviceName the name of this keyboard device.
533          * @param vendorId the PCI vendor id.
534          * @param productId the product id, as defined by the vendor.
535          * @see #createVirtualKeyboard(VirtualKeyboardConfig config)
536          * @deprecated Use {@link #createVirtualKeyboard(VirtualKeyboardConfig config)} instead
537          */
538         @Deprecated
539         @RequiresPermission(android.Manifest.permission.CREATE_VIRTUAL_DEVICE)
540         @NonNull
createVirtualKeyboard(@onNull VirtualDisplay display, @NonNull String inputDeviceName, int vendorId, int productId)541         public VirtualKeyboard createVirtualKeyboard(@NonNull VirtualDisplay display,
542                 @NonNull String inputDeviceName, int vendorId, int productId) {
543             VirtualKeyboardConfig keyboardConfig =
544                     new VirtualKeyboardConfig.Builder()
545                             .setVendorId(vendorId)
546                             .setProductId(productId)
547                             .setInputDeviceName(inputDeviceName)
548                             .setAssociatedDisplayId(display.getDisplay().getDisplayId())
549                             .build();
550             return mVirtualDeviceInternal.createVirtualKeyboard(keyboardConfig);
551         }
552 
553         /**
554          * Creates a virtual mouse.
555          *
556          * @param config the configurations of the virtual mouse.
557          */
558         @RequiresPermission(android.Manifest.permission.CREATE_VIRTUAL_DEVICE)
559         @NonNull
createVirtualMouse(@onNull VirtualMouseConfig config)560         public VirtualMouse createVirtualMouse(@NonNull VirtualMouseConfig config) {
561             Objects.requireNonNull(config, "config must not be null");
562             return mVirtualDeviceInternal.createVirtualMouse(config);
563         }
564 
565         /**
566          * Creates a virtual mouse.
567          *
568          * @param display the display that the events inputted through this device should target.
569          * @param inputDeviceName the name of this mouse.
570          * @param vendorId the PCI vendor id.
571          * @param productId the product id, as defined by the vendor.
572          * @see #createVirtualMouse(VirtualMouseConfig config)
573          * @deprecated Use {@link #createVirtualMouse(VirtualMouseConfig config)} instead
574          */
575         @Deprecated
576         @RequiresPermission(android.Manifest.permission.CREATE_VIRTUAL_DEVICE)
577         @NonNull
createVirtualMouse(@onNull VirtualDisplay display, @NonNull String inputDeviceName, int vendorId, int productId)578         public VirtualMouse createVirtualMouse(@NonNull VirtualDisplay display,
579                 @NonNull String inputDeviceName, int vendorId, int productId) {
580             VirtualMouseConfig mouseConfig =
581                     new VirtualMouseConfig.Builder()
582                             .setVendorId(vendorId)
583                             .setProductId(productId)
584                             .setInputDeviceName(inputDeviceName)
585                             .setAssociatedDisplayId(display.getDisplay().getDisplayId())
586                             .build();
587             return mVirtualDeviceInternal.createVirtualMouse(mouseConfig);
588         }
589 
590         /**
591          * Creates a virtual touchscreen.
592          *
593          * @param config the configurations of the virtual touchscreen.
594          */
595         @RequiresPermission(android.Manifest.permission.CREATE_VIRTUAL_DEVICE)
596         @NonNull
createVirtualTouchscreen( @onNull VirtualTouchscreenConfig config)597         public VirtualTouchscreen createVirtualTouchscreen(
598                 @NonNull VirtualTouchscreenConfig config) {
599             Objects.requireNonNull(config, "config must not be null");
600             return mVirtualDeviceInternal.createVirtualTouchscreen(config);
601         }
602 
603         /**
604          * Creates a virtual touchscreen.
605          *
606          * @param display the display that the events inputted through this device should target.
607          * @param inputDeviceName the name of this touchscreen device.
608          * @param vendorId the PCI vendor id.
609          * @param productId the product id, as defined by the vendor.
610          * @see #createVirtualTouchscreen(VirtualTouchscreenConfig config)
611          * @deprecated Use {@link #createVirtualTouchscreen(VirtualTouchscreenConfig config)}
612          * instead
613          */
614         @Deprecated
615         @RequiresPermission(android.Manifest.permission.CREATE_VIRTUAL_DEVICE)
616         @NonNull
createVirtualTouchscreen(@onNull VirtualDisplay display, @NonNull String inputDeviceName, int vendorId, int productId)617         public VirtualTouchscreen createVirtualTouchscreen(@NonNull VirtualDisplay display,
618                 @NonNull String inputDeviceName, int vendorId, int productId) {
619             final Point size = new Point();
620             display.getDisplay().getSize(size);
621             VirtualTouchscreenConfig touchscreenConfig =
622                     new VirtualTouchscreenConfig.Builder(size.x, size.y)
623                             .setVendorId(vendorId)
624                             .setProductId(productId)
625                             .setInputDeviceName(inputDeviceName)
626                             .setAssociatedDisplayId(display.getDisplay().getDisplayId())
627                             .build();
628             return mVirtualDeviceInternal.createVirtualTouchscreen(touchscreenConfig);
629         }
630 
631         /**
632          * Creates a virtual touchpad in navigation mode.
633          *
634          * <p>A touchpad in navigation mode means that its events are interpreted as navigation
635          * events (up, down, etc) instead of using them to update a cursor's absolute position. If
636          * the events are not consumed they are converted to DPAD events and delivered to the target
637          * again.
638          *
639          * @param config the configurations of the virtual navigation touchpad.
640          * @see android.view.InputDevice#SOURCE_TOUCH_NAVIGATION
641          */
642         @RequiresPermission(android.Manifest.permission.CREATE_VIRTUAL_DEVICE)
643         @NonNull
createVirtualNavigationTouchpad( @onNull VirtualNavigationTouchpadConfig config)644         public VirtualNavigationTouchpad createVirtualNavigationTouchpad(
645                 @NonNull VirtualNavigationTouchpadConfig config) {
646             return mVirtualDeviceInternal.createVirtualNavigationTouchpad(config);
647         }
648 
649         /**
650          * Creates a VirtualAudioDevice, capable of recording audio emanating from this device,
651          * or injecting audio from another device.
652          *
653          * <p>Note: One {@link VirtualDevice} can only create one {@link VirtualAudioDevice}, so
654          * calling this method multiple times will return the same instance. When
655          * {@link VirtualDevice#close()} is called, the associated {@link VirtualAudioDevice} will
656          * also be closed automatically.
657          *
658          * @param display The target virtual display to capture from and inject into.
659          * @param executor The {@link Executor} object for the thread on which to execute
660          *   the callback. If <code>null</code>, the {@link Executor} associated with the main
661          *   {@link Looper} will be used.
662          * @param callback Interface to be notified when playback or recording configuration of
663          *   applications running on virtual display is changed.
664          * @return A {@link VirtualAudioDevice} instance.
665          */
666         @RequiresPermission(android.Manifest.permission.CREATE_VIRTUAL_DEVICE)
667         @NonNull
createVirtualAudioDevice( @onNull VirtualDisplay display, @Nullable Executor executor, @Nullable AudioConfigurationChangeCallback callback)668         public VirtualAudioDevice createVirtualAudioDevice(
669                 @NonNull VirtualDisplay display,
670                 @Nullable Executor executor,
671                 @Nullable AudioConfigurationChangeCallback callback) {
672             Objects.requireNonNull(display, "display must not be null");
673             return mVirtualDeviceInternal.createVirtualAudioDevice(display, executor, callback);
674         }
675 
676         /**
677          * Sets the visibility of the pointer icon for this VirtualDevice's associated displays.
678          *
679          * @param showPointerIcon True if the pointer should be shown; false otherwise. The default
680          *   visibility is true.
681          */
682         @RequiresPermission(android.Manifest.permission.CREATE_VIRTUAL_DEVICE)
683         @NonNull
setShowPointerIcon(boolean showPointerIcon)684         public void setShowPointerIcon(boolean showPointerIcon) {
685             mVirtualDeviceInternal.setShowPointerIcon(showPointerIcon);
686         }
687 
688         /**
689          * Adds an activity listener to listen for events such as top activity change or virtual
690          * display task stack became empty.
691          *
692          * @param executor The executor where the listener is executed on.
693          * @param listener The listener to add.
694          * @see #removeActivityListener(ActivityListener)
695          */
addActivityListener( @allbackExecutor @onNull Executor executor, @NonNull ActivityListener listener)696         public void addActivityListener(
697                 @CallbackExecutor @NonNull Executor executor, @NonNull ActivityListener listener) {
698             mVirtualDeviceInternal.addActivityListener(executor, listener);
699         }
700 
701         /**
702          * Removes an activity listener previously added with {@link #addActivityListener}.
703          *
704          * @param listener The listener to remove.
705          * @see #addActivityListener(Executor, ActivityListener)
706          */
removeActivityListener(@onNull ActivityListener listener)707         public void removeActivityListener(@NonNull ActivityListener listener) {
708             mVirtualDeviceInternal.removeActivityListener(listener);
709         }
710 
711         /**
712          * Adds a sound effect listener.
713          *
714          * @param executor The executor where the listener is executed on.
715          * @param soundEffectListener The listener to add.
716          * @see #removeActivityListener(ActivityListener)
717          */
addSoundEffectListener(@allbackExecutor @onNull Executor executor, @NonNull SoundEffectListener soundEffectListener)718         public void addSoundEffectListener(@CallbackExecutor @NonNull Executor executor,
719                 @NonNull SoundEffectListener soundEffectListener) {
720             mVirtualDeviceInternal.addSoundEffectListener(executor, soundEffectListener);
721         }
722 
723         /**
724          * Removes a sound effect listener previously added with {@link #addSoundEffectListener}.
725          *
726          * @param soundEffectListener The listener to remove.
727          * @see #addSoundEffectListener(Executor, SoundEffectListener)
728          */
removeSoundEffectListener(@onNull SoundEffectListener soundEffectListener)729         public void removeSoundEffectListener(@NonNull SoundEffectListener soundEffectListener) {
730             mVirtualDeviceInternal.removeSoundEffectListener(soundEffectListener);
731         }
732 
733         /**
734          * Registers an intent interceptor that will intercept an intent attempting to launch
735          * when matching the provided IntentFilter and calls the callback with the intercepted
736          * intent.
737          *
738          * @param interceptorFilter The filter to match intents intended for interception.
739          * @param executor The executor where the interceptor is executed on.
740          * @param interceptorCallback The callback called when an intent matching interceptorFilter
741          * is intercepted.
742          * @see #unregisterIntentInterceptor(IntentInterceptorCallback)
743          */
744         @RequiresPermission(android.Manifest.permission.CREATE_VIRTUAL_DEVICE)
registerIntentInterceptor( @onNull IntentFilter interceptorFilter, @CallbackExecutor @NonNull Executor executor, @NonNull IntentInterceptorCallback interceptorCallback)745         public void registerIntentInterceptor(
746                 @NonNull IntentFilter interceptorFilter,
747                 @CallbackExecutor @NonNull Executor executor,
748                 @NonNull IntentInterceptorCallback interceptorCallback) {
749             mVirtualDeviceInternal.registerIntentInterceptor(
750                     interceptorFilter, executor, interceptorCallback);
751         }
752 
753         /**
754          * Unregisters the intent interceptor previously registered with
755          * {@link #registerIntentInterceptor}.
756          */
757         @RequiresPermission(android.Manifest.permission.CREATE_VIRTUAL_DEVICE)
unregisterIntentInterceptor( @onNull IntentInterceptorCallback interceptorCallback)758         public void unregisterIntentInterceptor(
759                     @NonNull IntentInterceptorCallback interceptorCallback) {
760             mVirtualDeviceInternal.unregisterIntentInterceptor(interceptorCallback);
761         }
762     }
763 
764     /**
765      * Listener for activity changes in this virtual device.
766      *
767      * @hide
768      */
769     @SystemApi
770     public interface ActivityListener {
771 
772         /**
773          * Called when the top activity is changed.
774          *
775          * <p>Note: When there are no activities running on the virtual display, the
776          * {@link #onDisplayEmpty(int)} will be called. If the value topActivity is cached, it
777          * should be cleared when {@link #onDisplayEmpty(int)} is called.
778          *
779          * @param displayId The display ID on which the activity change happened.
780          * @param topActivity The component name of the top activity.
781          * @deprecated Use {@link #onTopActivityChanged(int, ComponentName, int)} instead
782          */
onTopActivityChanged(int displayId, @NonNull ComponentName topActivity)783         void onTopActivityChanged(int displayId, @NonNull ComponentName topActivity);
784 
785         /**
786          * Called when the top activity is changed.
787          *
788          * <p>Note: When there are no activities running on the virtual display, the
789          * {@link #onDisplayEmpty(int)} will be called. If the value topActivity is cached, it
790          * should be cleared when {@link #onDisplayEmpty(int)} is called.
791          *
792          * @param displayId The display ID on which the activity change happened.
793          * @param topActivity The component name of the top activity.
794          * @param userId The user ID associated with the top activity.
795          */
onTopActivityChanged(int displayId, @NonNull ComponentName topActivity, @UserIdInt int userId)796         default void onTopActivityChanged(int displayId, @NonNull ComponentName topActivity,
797                 @UserIdInt int userId) {}
798 
799         /**
800          * Called when the display becomes empty (e.g. if the user hits back on the last
801          * activity of the root task).
802          *
803          * @param displayId The display ID that became empty.
804          */
onDisplayEmpty(int displayId)805         void onDisplayEmpty(int displayId);
806     }
807 
808     /**
809      * Interceptor interface to be called when an intent matches the IntentFilter passed into {@link
810      * VirtualDevice#registerIntentInterceptor}. When the interceptor is called after matching the
811      * IntentFilter, the intended activity launch will be aborted and alternatively replaced by
812      * the interceptor's receiver.
813      *
814      * @hide
815      */
816     @SystemApi
817     public interface IntentInterceptorCallback {
818 
819         /**
820          * Called when an intent that matches the IntentFilter registered in {@link
821          * VirtualDevice#registerIntentInterceptor} is intercepted for the virtual device to
822          * handle.
823          *
824          * @param intent The intent that has been intercepted by the interceptor.
825          */
onIntentIntercepted(@onNull Intent intent)826         void onIntentIntercepted(@NonNull Intent intent);
827     }
828 
829     /**
830      * Listener for system sound effect playback on virtual device.
831      *
832      * @hide
833      */
834     @SystemApi
835     public interface SoundEffectListener {
836 
837         /**
838          * Called when there's a system sound effect to be played on virtual device.
839          *
840          * @param effectType - system sound effect type
841          * @see android.media.AudioManager.SystemSoundEffect
842          */
onPlaySoundEffect(@udioManager.SystemSoundEffect int effectType)843         void onPlaySoundEffect(@AudioManager.SystemSoundEffect int effectType);
844     }
845 }
846