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