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