1 /* 2 * Copyright (C) 2013 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 com.android.server.display; 18 19 import static android.hardware.display.DisplayManager.VIRTUAL_DISPLAY_FLAG_ALWAYS_UNLOCKED; 20 import static android.hardware.display.DisplayManager.VIRTUAL_DISPLAY_FLAG_AUTO_MIRROR; 21 import static android.hardware.display.DisplayManager.VIRTUAL_DISPLAY_FLAG_CAN_SHOW_WITH_INSECURE_KEYGUARD; 22 import static android.hardware.display.DisplayManager.VIRTUAL_DISPLAY_FLAG_DESTROY_CONTENT_ON_REMOVAL; 23 import static android.hardware.display.DisplayManager.VIRTUAL_DISPLAY_FLAG_DEVICE_DISPLAY_GROUP; 24 import static android.hardware.display.DisplayManager.VIRTUAL_DISPLAY_FLAG_OWN_DISPLAY_GROUP; 25 import static android.hardware.display.DisplayManager.VIRTUAL_DISPLAY_FLAG_OWN_FOCUS; 26 import static android.hardware.display.DisplayManager.VIRTUAL_DISPLAY_FLAG_PRESENTATION; 27 import static android.hardware.display.DisplayManager.VIRTUAL_DISPLAY_FLAG_PUBLIC; 28 import static android.hardware.display.DisplayManager.VIRTUAL_DISPLAY_FLAG_ROTATES_WITH_CONTENT; 29 import static android.hardware.display.DisplayManager.VIRTUAL_DISPLAY_FLAG_SECURE; 30 import static android.hardware.display.DisplayManager.VIRTUAL_DISPLAY_FLAG_SHOULD_SHOW_SYSTEM_DECORATIONS; 31 import static android.hardware.display.DisplayManager.VIRTUAL_DISPLAY_FLAG_STEAL_TOP_FOCUS_DISABLED; 32 import static android.hardware.display.DisplayManager.VIRTUAL_DISPLAY_FLAG_SUPPORTS_TOUCH; 33 import static android.hardware.display.DisplayManager.VIRTUAL_DISPLAY_FLAG_TOUCH_FEEDBACK_DISABLED; 34 import static android.hardware.display.DisplayManager.VIRTUAL_DISPLAY_FLAG_TRUSTED; 35 36 import static com.android.server.display.DisplayDeviceInfo.FLAG_ALWAYS_UNLOCKED; 37 import static com.android.server.display.DisplayDeviceInfo.FLAG_DEVICE_DISPLAY_GROUP; 38 import static com.android.server.display.DisplayDeviceInfo.FLAG_OWN_DISPLAY_GROUP; 39 import static com.android.server.display.DisplayDeviceInfo.FLAG_STEAL_TOP_FOCUS_DISABLED; 40 import static com.android.server.display.DisplayDeviceInfo.FLAG_TOUCH_FEEDBACK_DISABLED; 41 import static com.android.server.display.DisplayDeviceInfo.FLAG_TRUSTED; 42 43 import android.annotation.Nullable; 44 import android.content.Context; 45 import android.graphics.Point; 46 import android.hardware.display.IVirtualDisplayCallback; 47 import android.hardware.display.VirtualDisplayConfig; 48 import android.media.projection.IMediaProjection; 49 import android.media.projection.IMediaProjectionCallback; 50 import android.os.Handler; 51 import android.os.IBinder; 52 import android.os.IBinder.DeathRecipient; 53 import android.os.Message; 54 import android.os.RemoteException; 55 import android.os.SystemProperties; 56 import android.util.ArrayMap; 57 import android.util.Slog; 58 import android.view.Display; 59 import android.view.DisplayShape; 60 import android.view.Surface; 61 import android.view.SurfaceControl; 62 63 import com.android.internal.annotations.VisibleForTesting; 64 import com.android.server.display.feature.DisplayManagerFlags; 65 66 import java.io.PrintWriter; 67 import java.util.concurrent.atomic.AtomicInteger; 68 69 /** 70 * A display adapter that provides virtual displays on behalf of applications. 71 * <p> 72 * Display adapters are guarded by the {@link DisplayManagerService.SyncRoot} lock. 73 * </p> 74 */ 75 @VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE) 76 public class VirtualDisplayAdapter extends DisplayAdapter { 77 static final String TAG = "VirtualDisplayAdapter"; 78 79 // Unique id prefix for virtual displays 80 @VisibleForTesting 81 static final String UNIQUE_ID_PREFIX = "virtual:"; 82 83 // Unique id suffix for virtual displays 84 private static final AtomicInteger sNextUniqueIndex = new AtomicInteger(0); 85 86 private final ArrayMap<IBinder, VirtualDisplayDevice> mVirtualDisplayDevices = new ArrayMap<>(); 87 private final Handler mHandler; 88 private final SurfaceControlDisplayFactory mSurfaceControlDisplayFactory; 89 90 // Called with SyncRoot lock held. VirtualDisplayAdapter(DisplayManagerService.SyncRoot syncRoot, Context context, Handler handler, Listener listener, DisplayManagerFlags featureFlags)91 public VirtualDisplayAdapter(DisplayManagerService.SyncRoot syncRoot, 92 Context context, Handler handler, Listener listener, DisplayManagerFlags featureFlags) { 93 this(syncRoot, context, handler, listener, new SurfaceControlDisplayFactory() { 94 @Override 95 public IBinder createDisplay(String name, boolean secure, String uniqueId, 96 float requestedRefreshRate) { 97 return DisplayControl.createVirtualDisplay(name, secure, uniqueId, 98 requestedRefreshRate); 99 } 100 101 @Override 102 public void destroyDisplay(IBinder displayToken) { 103 DisplayControl.destroyVirtualDisplay(displayToken); 104 } 105 }, featureFlags); 106 } 107 108 @VisibleForTesting VirtualDisplayAdapter(DisplayManagerService.SyncRoot syncRoot, Context context, Handler handler, Listener listener, SurfaceControlDisplayFactory surfaceControlDisplayFactory, DisplayManagerFlags featureFlags)109 VirtualDisplayAdapter(DisplayManagerService.SyncRoot syncRoot, 110 Context context, Handler handler, Listener listener, 111 SurfaceControlDisplayFactory surfaceControlDisplayFactory, 112 DisplayManagerFlags featureFlags) { 113 super(syncRoot, context, handler, listener, TAG, featureFlags); 114 mHandler = handler; 115 mSurfaceControlDisplayFactory = surfaceControlDisplayFactory; 116 } 117 createVirtualDisplayLocked(IVirtualDisplayCallback callback, IMediaProjection projection, int ownerUid, String ownerPackageName, String uniqueId, Surface surface, int flags, VirtualDisplayConfig virtualDisplayConfig)118 public DisplayDevice createVirtualDisplayLocked(IVirtualDisplayCallback callback, 119 IMediaProjection projection, int ownerUid, String ownerPackageName, String uniqueId, 120 Surface surface, int flags, VirtualDisplayConfig virtualDisplayConfig) { 121 IBinder appToken = callback.asBinder(); 122 if (mVirtualDisplayDevices.containsKey(appToken)) { 123 Slog.wtfStack(TAG, 124 "Can't create virtual display, display with same appToken already exists"); 125 return null; 126 } 127 128 String name = virtualDisplayConfig.getName(); 129 boolean secure = (flags & VIRTUAL_DISPLAY_FLAG_SECURE) != 0; 130 131 IBinder displayToken = mSurfaceControlDisplayFactory.createDisplay(name, secure, uniqueId, 132 virtualDisplayConfig.getRequestedRefreshRate()); 133 MediaProjectionCallback mediaProjectionCallback = null; 134 if (projection != null) { 135 mediaProjectionCallback = new MediaProjectionCallback(appToken); 136 } 137 VirtualDisplayDevice device = new VirtualDisplayDevice(displayToken, appToken, 138 ownerUid, ownerPackageName, surface, flags, new Callback(callback, mHandler), 139 projection, mediaProjectionCallback, uniqueId, virtualDisplayConfig); 140 141 mVirtualDisplayDevices.put(appToken, device); 142 143 try { 144 if (projection != null) { 145 projection.registerCallback(mediaProjectionCallback); 146 Slog.d(TAG, "Virtual Display: registered media projection callback for new " 147 + "VirtualDisplayDevice"); 148 } 149 appToken.linkToDeath(device, 0); 150 } catch (RemoteException ex) { 151 Slog.e(TAG, "Virtual Display: error while setting up VirtualDisplayDevice", ex); 152 mVirtualDisplayDevices.remove(appToken); 153 device.destroyLocked(false); 154 return null; 155 } 156 157 // Return the display device without actually sending the event indicating 158 // that it was added. The caller will handle it. 159 return device; 160 } 161 resizeVirtualDisplayLocked(IBinder appToken, int width, int height, int densityDpi)162 public void resizeVirtualDisplayLocked(IBinder appToken, 163 int width, int height, int densityDpi) { 164 VirtualDisplayDevice device = mVirtualDisplayDevices.get(appToken); 165 if (device != null) { 166 Slog.v(TAG, "Resize VirtualDisplay " + device.mName + " to " + width 167 + " " + height); 168 device.resizeLocked(width, height, densityDpi); 169 } 170 } 171 172 @VisibleForTesting getVirtualDisplaySurfaceLocked(IBinder appToken)173 Surface getVirtualDisplaySurfaceLocked(IBinder appToken) { 174 VirtualDisplayDevice device = mVirtualDisplayDevices.get(appToken); 175 if (device != null) { 176 return device.getSurfaceLocked(); 177 } 178 return null; 179 } 180 setVirtualDisplaySurfaceLocked(IBinder appToken, Surface surface)181 public void setVirtualDisplaySurfaceLocked(IBinder appToken, Surface surface) { 182 VirtualDisplayDevice device = mVirtualDisplayDevices.get(appToken); 183 if (device != null) { 184 Slog.v(TAG, "Update surface for VirtualDisplay " + device.mName); 185 device.setSurfaceLocked(surface); 186 } 187 } 188 setDisplayIdToMirror(IBinder appToken, int displayId)189 void setDisplayIdToMirror(IBinder appToken, int displayId) { 190 VirtualDisplayDevice device = mVirtualDisplayDevices.get(appToken); 191 if (device != null) { 192 device.setDisplayIdToMirror(displayId); 193 } 194 } 195 releaseVirtualDisplayLocked(IBinder appToken)196 public DisplayDevice releaseVirtualDisplayLocked(IBinder appToken) { 197 VirtualDisplayDevice device = mVirtualDisplayDevices.remove(appToken); 198 if (device != null) { 199 Slog.v(TAG, "Release VirtualDisplay " + device.mName); 200 device.destroyLocked(true); 201 appToken.unlinkToDeath(device, 0); 202 } 203 204 // Return the display device that was removed without actually sending the 205 // event indicating that it was removed. The caller will handle it. 206 return device; 207 } 208 setVirtualDisplayStateLocked(IBinder appToken, boolean isOn)209 void setVirtualDisplayStateLocked(IBinder appToken, boolean isOn) { 210 VirtualDisplayDevice device = mVirtualDisplayDevices.get(appToken); 211 if (device != null) { 212 device.setDisplayState(isOn); 213 } 214 } 215 216 /** 217 * Generates a virtual display's unique identifier. 218 * 219 * <p>It is always prefixed with "virtual:package-name". If the provided config explicitly 220 * specifies a unique ID, then it's simply appended. Otherwise, the UID, display name and a 221 * unique index are appended.</p> 222 * 223 * <p>The unique index is incremented for every virtual display unique ID generation and serves 224 * for differentiating between displays with the same name created by the same owner.</p> 225 */ generateDisplayUniqueId(String packageName, int uid, VirtualDisplayConfig config)226 static String generateDisplayUniqueId(String packageName, int uid, 227 VirtualDisplayConfig config) { 228 return UNIQUE_ID_PREFIX + packageName + ((config.getUniqueId() != null) 229 ? (":" + config.getUniqueId()) 230 : ("," + uid + "," + config.getName() + "," + sNextUniqueIndex.getAndIncrement())); 231 } 232 handleBinderDiedLocked(IBinder appToken)233 private void handleBinderDiedLocked(IBinder appToken) { 234 mVirtualDisplayDevices.remove(appToken); 235 } 236 handleMediaProjectionStoppedLocked(IBinder appToken)237 private void handleMediaProjectionStoppedLocked(IBinder appToken) { 238 VirtualDisplayDevice device = mVirtualDisplayDevices.get(appToken); 239 if (device != null) { 240 Slog.i(TAG, "Virtual display device released because media projection stopped: " 241 + device.mName); 242 device.stopLocked(); 243 } 244 } 245 246 private final class VirtualDisplayDevice extends DisplayDevice implements DeathRecipient { 247 private static final int PENDING_SURFACE_CHANGE = 0x01; 248 private static final int PENDING_RESIZE = 0x02; 249 250 private static final float REFRESH_RATE = 60.0f; 251 252 private final IBinder mAppToken; 253 private final int mOwnerUid; 254 final String mOwnerPackageName; 255 final String mName; 256 private final int mFlags; 257 private final Callback mCallback; 258 @Nullable private final IMediaProjection mProjection; 259 @Nullable private final IMediaProjectionCallback mMediaProjectionCallback; 260 261 private int mWidth; 262 private int mHeight; 263 private int mDensityDpi; 264 private float mRequestedRefreshRate; 265 private Surface mSurface; 266 private DisplayDeviceInfo mInfo; 267 private int mDisplayState; 268 private boolean mStopped; 269 private int mPendingChanges; 270 private Display.Mode mMode; 271 private boolean mIsDisplayOn; 272 private int mDisplayIdToMirror; 273 private boolean mIsWindowManagerMirroring; 274 VirtualDisplayDevice(IBinder displayToken, IBinder appToken, int ownerUid, String ownerPackageName, Surface surface, int flags, Callback callback, IMediaProjection projection, IMediaProjectionCallback mediaProjectionCallback, String uniqueId, VirtualDisplayConfig virtualDisplayConfig)275 public VirtualDisplayDevice(IBinder displayToken, IBinder appToken, 276 int ownerUid, String ownerPackageName, Surface surface, int flags, 277 Callback callback, IMediaProjection projection, 278 IMediaProjectionCallback mediaProjectionCallback, String uniqueId, 279 VirtualDisplayConfig virtualDisplayConfig) { 280 super(VirtualDisplayAdapter.this, displayToken, uniqueId, getContext()); 281 mAppToken = appToken; 282 mOwnerUid = ownerUid; 283 mOwnerPackageName = ownerPackageName; 284 mName = virtualDisplayConfig.getName(); 285 mWidth = virtualDisplayConfig.getWidth(); 286 mHeight = virtualDisplayConfig.getHeight(); 287 mDensityDpi = virtualDisplayConfig.getDensityDpi(); 288 mRequestedRefreshRate = virtualDisplayConfig.getRequestedRefreshRate(); 289 mMode = createMode(mWidth, mHeight, getRefreshRate()); 290 mSurface = surface; 291 mFlags = flags; 292 mCallback = callback; 293 mProjection = projection; 294 mMediaProjectionCallback = mediaProjectionCallback; 295 mDisplayState = Display.STATE_UNKNOWN; 296 mPendingChanges |= PENDING_SURFACE_CHANGE; 297 mIsDisplayOn = surface != null; 298 mDisplayIdToMirror = virtualDisplayConfig.getDisplayIdToMirror(); 299 mIsWindowManagerMirroring = virtualDisplayConfig.isWindowManagerMirroringEnabled(); 300 } 301 302 @Override binderDied()303 public void binderDied() { 304 synchronized (getSyncRoot()) { 305 handleBinderDiedLocked(mAppToken); 306 Slog.i(TAG, "Virtual display device released because application token died: " 307 + mOwnerPackageName); 308 destroyLocked(false); 309 if (mProjection != null && mMediaProjectionCallback != null) { 310 try { 311 mProjection.unregisterCallback(mMediaProjectionCallback); 312 } catch (RemoteException e) { 313 Slog.w(TAG, "Failed to unregister callback in binderDied", e); 314 } 315 } 316 sendDisplayDeviceEventLocked(this, DISPLAY_DEVICE_EVENT_REMOVED); 317 } 318 } 319 destroyLocked(boolean binderAlive)320 public void destroyLocked(boolean binderAlive) { 321 if (mSurface != null) { 322 mSurface.release(); 323 mSurface = null; 324 } 325 mSurfaceControlDisplayFactory.destroyDisplay(getDisplayTokenLocked()); 326 if (mProjection != null && mMediaProjectionCallback != null) { 327 try { 328 mProjection.unregisterCallback(mMediaProjectionCallback); 329 } catch (RemoteException e) { 330 Slog.w(TAG, "Failed to unregister callback in destroy", e); 331 } 332 } 333 if (binderAlive) { 334 mCallback.dispatchDisplayStopped(); 335 } 336 } 337 338 @Override getDisplayIdToMirrorLocked()339 public int getDisplayIdToMirrorLocked() { 340 return mDisplayIdToMirror; 341 } 342 setDisplayIdToMirror(int displayIdToMirror)343 void setDisplayIdToMirror(int displayIdToMirror) { 344 if (mDisplayIdToMirror != displayIdToMirror) { 345 mDisplayIdToMirror = displayIdToMirror; 346 mInfo = null; 347 sendDisplayDeviceEventLocked(this, DISPLAY_DEVICE_EVENT_CHANGED); 348 sendTraversalRequestLocked(); 349 } 350 } 351 352 @Override isWindowManagerMirroringLocked()353 public boolean isWindowManagerMirroringLocked() { 354 return mIsWindowManagerMirroring; 355 } 356 357 @Override setWindowManagerMirroringLocked(boolean mirroring)358 public void setWindowManagerMirroringLocked(boolean mirroring) { 359 if (mIsWindowManagerMirroring != mirroring) { 360 mIsWindowManagerMirroring = mirroring; 361 sendDisplayDeviceEventLocked(this, DISPLAY_DEVICE_EVENT_CHANGED); 362 sendTraversalRequestLocked(); 363 } 364 } 365 366 @Override getDisplaySurfaceDefaultSizeLocked()367 public Point getDisplaySurfaceDefaultSizeLocked() { 368 if (mSurface == null) { 369 return null; 370 } 371 final Point surfaceSize = mSurface.getDefaultSize(); 372 return isRotatedLocked() ? new Point(surfaceSize.y, surfaceSize.x) : surfaceSize; 373 } 374 375 @VisibleForTesting getSurfaceLocked()376 Surface getSurfaceLocked() { 377 return mSurface; 378 } 379 380 @Override hasStableUniqueId()381 public boolean hasStableUniqueId() { 382 return false; 383 } 384 385 @Override requestDisplayStateLocked(int state, float brightnessState, float sdrBrightnessState, DisplayOffloadSessionImpl displayOffloadSession)386 public Runnable requestDisplayStateLocked(int state, float brightnessState, 387 float sdrBrightnessState, DisplayOffloadSessionImpl displayOffloadSession) { 388 if (state != mDisplayState) { 389 mDisplayState = state; 390 if (state == Display.STATE_OFF) { 391 mCallback.dispatchDisplayPaused(); 392 } else { 393 mCallback.dispatchDisplayResumed(); 394 } 395 } 396 return null; 397 } 398 399 @Override performTraversalLocked(SurfaceControl.Transaction t)400 public void performTraversalLocked(SurfaceControl.Transaction t) { 401 if ((mPendingChanges & PENDING_RESIZE) != 0) { 402 t.setDisplaySize(getDisplayTokenLocked(), mWidth, mHeight); 403 } 404 if ((mPendingChanges & PENDING_SURFACE_CHANGE) != 0) { 405 setSurfaceLocked(t, mSurface); 406 } 407 mPendingChanges = 0; 408 } 409 setSurfaceLocked(Surface surface)410 public void setSurfaceLocked(Surface surface) { 411 if (!mStopped && mSurface != surface) { 412 if ((mSurface != null) != (surface != null)) { 413 sendDisplayDeviceEventLocked(this, DISPLAY_DEVICE_EVENT_CHANGED); 414 } 415 sendTraversalRequestLocked(); 416 mSurface = surface; 417 mInfo = null; 418 mPendingChanges |= PENDING_SURFACE_CHANGE; 419 } 420 } 421 resizeLocked(int width, int height, int densityDpi)422 public void resizeLocked(int width, int height, int densityDpi) { 423 if (mWidth != width || mHeight != height || mDensityDpi != densityDpi) { 424 sendDisplayDeviceEventLocked(this, DISPLAY_DEVICE_EVENT_CHANGED); 425 sendTraversalRequestLocked(); 426 mWidth = width; 427 mHeight = height; 428 mMode = createMode(width, height, getRefreshRate()); 429 mDensityDpi = densityDpi; 430 mInfo = null; 431 mPendingChanges |= PENDING_RESIZE; 432 } 433 } 434 setDisplayState(boolean isOn)435 void setDisplayState(boolean isOn) { 436 if (mIsDisplayOn != isOn) { 437 mIsDisplayOn = isOn; 438 mInfo = null; 439 sendDisplayDeviceEventLocked(this, DISPLAY_DEVICE_EVENT_CHANGED); 440 } 441 } 442 stopLocked()443 public void stopLocked() { 444 Slog.d(TAG, "Virtual Display: stopping device " + mName); 445 setSurfaceLocked(null); 446 mStopped = true; 447 } 448 449 @Override dumpLocked(PrintWriter pw)450 public void dumpLocked(PrintWriter pw) { 451 super.dumpLocked(pw); 452 pw.println("mFlags=" + mFlags); 453 pw.println("mDisplayState=" + Display.stateToString(mDisplayState)); 454 pw.println("mStopped=" + mStopped); 455 pw.println("mDisplayIdToMirror=" + mDisplayIdToMirror); 456 pw.println("mWindowManagerMirroring=" + mIsWindowManagerMirroring); 457 pw.println("mRequestedRefreshRate=" + mRequestedRefreshRate); 458 } 459 460 @Override getDisplayDeviceInfoLocked()461 public DisplayDeviceInfo getDisplayDeviceInfoLocked() { 462 if (mInfo == null) { 463 mInfo = new DisplayDeviceInfo(); 464 mInfo.name = mName; 465 mInfo.uniqueId = getUniqueId(); 466 mInfo.width = mWidth; 467 mInfo.height = mHeight; 468 mInfo.modeId = mMode.getModeId(); 469 mInfo.renderFrameRate = mMode.getRefreshRate(); 470 mInfo.defaultModeId = mMode.getModeId(); 471 mInfo.supportedModes = new Display.Mode[] { mMode }; 472 mInfo.densityDpi = mDensityDpi; 473 mInfo.xDpi = mDensityDpi; 474 mInfo.yDpi = mDensityDpi; 475 mInfo.presentationDeadlineNanos = 1000000000L / (int) getRefreshRate(); // 1 frame 476 mInfo.flags = 0; 477 if ((mFlags & VIRTUAL_DISPLAY_FLAG_PUBLIC) == 0) { 478 mInfo.flags |= DisplayDeviceInfo.FLAG_PRIVATE 479 | DisplayDeviceInfo.FLAG_NEVER_BLANK; 480 } 481 if ((mFlags & VIRTUAL_DISPLAY_FLAG_AUTO_MIRROR) != 0) { 482 mInfo.flags &= ~DisplayDeviceInfo.FLAG_NEVER_BLANK; 483 } else { 484 mInfo.flags |= DisplayDeviceInfo.FLAG_OWN_CONTENT_ONLY; 485 486 if ((mFlags & VIRTUAL_DISPLAY_FLAG_OWN_DISPLAY_GROUP) != 0) { 487 mInfo.flags |= FLAG_OWN_DISPLAY_GROUP; 488 } 489 } 490 if ((mFlags & VIRTUAL_DISPLAY_FLAG_DEVICE_DISPLAY_GROUP) != 0) { 491 mInfo.flags |= FLAG_DEVICE_DISPLAY_GROUP; 492 } 493 494 if ((mFlags & VIRTUAL_DISPLAY_FLAG_SECURE) != 0) { 495 mInfo.flags |= DisplayDeviceInfo.FLAG_SECURE; 496 } 497 if ((mFlags & VIRTUAL_DISPLAY_FLAG_PRESENTATION) != 0) { 498 mInfo.flags |= DisplayDeviceInfo.FLAG_PRESENTATION; 499 500 if ((mFlags & VIRTUAL_DISPLAY_FLAG_PUBLIC) != 0) { 501 // For demonstration purposes, allow rotation of the external display. 502 // In the future we might allow the user to configure this directly. 503 if ("portrait".equals(SystemProperties.get( 504 "persist.demo.remoterotation"))) { 505 mInfo.rotation = Surface.ROTATION_270; 506 } 507 } 508 } 509 if ((mFlags & VIRTUAL_DISPLAY_FLAG_CAN_SHOW_WITH_INSECURE_KEYGUARD) != 0) { 510 mInfo.flags |= DisplayDeviceInfo.FLAG_CAN_SHOW_WITH_INSECURE_KEYGUARD; 511 } 512 if ((mFlags & VIRTUAL_DISPLAY_FLAG_ROTATES_WITH_CONTENT) != 0) { 513 mInfo.flags |= DisplayDeviceInfo.FLAG_ROTATES_WITH_CONTENT; 514 } 515 if ((mFlags & VIRTUAL_DISPLAY_FLAG_DESTROY_CONTENT_ON_REMOVAL) != 0) { 516 mInfo.flags |= DisplayDeviceInfo.FLAG_DESTROY_CONTENT_ON_REMOVAL; 517 } 518 if ((mFlags & VIRTUAL_DISPLAY_FLAG_SHOULD_SHOW_SYSTEM_DECORATIONS) != 0) { 519 mInfo.flags |= DisplayDeviceInfo.FLAG_SHOULD_SHOW_SYSTEM_DECORATIONS; 520 } 521 if ((mFlags & VIRTUAL_DISPLAY_FLAG_TRUSTED) != 0) { 522 mInfo.flags |= FLAG_TRUSTED; 523 } 524 if ((mFlags & VIRTUAL_DISPLAY_FLAG_ALWAYS_UNLOCKED) != 0) { 525 if ((mInfo.flags & DisplayDeviceInfo.FLAG_OWN_DISPLAY_GROUP) != 0 526 || (mFlags & VIRTUAL_DISPLAY_FLAG_DEVICE_DISPLAY_GROUP) != 0) { 527 mInfo.flags |= FLAG_ALWAYS_UNLOCKED; 528 } else { 529 Slog.w( 530 TAG, 531 "Ignoring VIRTUAL_DISPLAY_FLAG_ALWAYS_UNLOCKED as it requires" 532 + " VIRTUAL_DISPLAY_FLAG_DEVICE_DISPLAY_GROUP or" 533 + " VIRTUAL_DISPLAY_FLAG_OWN_DISPLAY_GROUP."); 534 } 535 } 536 if ((mFlags & VIRTUAL_DISPLAY_FLAG_TOUCH_FEEDBACK_DISABLED) != 0) { 537 mInfo.flags |= FLAG_TOUCH_FEEDBACK_DISABLED; 538 } 539 if ((mFlags & VIRTUAL_DISPLAY_FLAG_OWN_FOCUS) != 0) { 540 if ((mFlags & VIRTUAL_DISPLAY_FLAG_TRUSTED) != 0) { 541 mInfo.flags |= DisplayDeviceInfo.FLAG_OWN_FOCUS; 542 } else { 543 Slog.w(TAG, "Ignoring VIRTUAL_DISPLAY_FLAG_OWN_FOCUS as it requires " 544 + "VIRTUAL_DISPLAY_FLAG_TRUSTED."); 545 } 546 } 547 if ((mFlags & VIRTUAL_DISPLAY_FLAG_STEAL_TOP_FOCUS_DISABLED) != 0) { 548 if ((mFlags & VIRTUAL_DISPLAY_FLAG_TRUSTED) != 0 549 && (mFlags & VIRTUAL_DISPLAY_FLAG_OWN_FOCUS) != 0) { 550 mInfo.flags |= FLAG_STEAL_TOP_FOCUS_DISABLED; 551 } else { 552 Slog.w(TAG, 553 "Ignoring VIRTUAL_DISPLAY_FLAG_STEAL_TOP_FOCUS_DISABLED as it " 554 + "requires VIRTUAL_DISPLAY_FLAG_OWN_FOCUS which requires " 555 + "VIRTUAL_DISPLAY_FLAG_TRUSTED."); 556 } 557 } 558 559 mInfo.type = Display.TYPE_VIRTUAL; 560 mInfo.touch = ((mFlags & VIRTUAL_DISPLAY_FLAG_SUPPORTS_TOUCH) == 0) ? 561 DisplayDeviceInfo.TOUCH_NONE : DisplayDeviceInfo.TOUCH_VIRTUAL; 562 563 mInfo.state = mIsDisplayOn ? Display.STATE_ON : Display.STATE_OFF; 564 565 mInfo.ownerUid = mOwnerUid; 566 mInfo.ownerPackageName = mOwnerPackageName; 567 568 mInfo.displayShape = 569 DisplayShape.createDefaultDisplayShape(mInfo.width, mInfo.height, false); 570 } 571 return mInfo; 572 } 573 getRefreshRate()574 private float getRefreshRate() { 575 return (mRequestedRefreshRate != 0.0f) ? mRequestedRefreshRate : REFRESH_RATE; 576 } 577 } 578 579 private static class Callback extends Handler { 580 private static final int MSG_ON_DISPLAY_PAUSED = 0; 581 private static final int MSG_ON_DISPLAY_RESUMED = 1; 582 private static final int MSG_ON_DISPLAY_STOPPED = 2; 583 584 private final IVirtualDisplayCallback mCallback; 585 Callback(IVirtualDisplayCallback callback, Handler handler)586 public Callback(IVirtualDisplayCallback callback, Handler handler) { 587 super(handler.getLooper()); 588 mCallback = callback; 589 } 590 591 @Override handleMessage(Message msg)592 public void handleMessage(Message msg) { 593 try { 594 switch (msg.what) { 595 case MSG_ON_DISPLAY_PAUSED: 596 mCallback.onPaused(); 597 break; 598 case MSG_ON_DISPLAY_RESUMED: 599 mCallback.onResumed(); 600 break; 601 case MSG_ON_DISPLAY_STOPPED: 602 mCallback.onStopped(); 603 break; 604 } 605 } catch (RemoteException e) { 606 Slog.w(TAG, "Failed to notify listener of virtual display event.", e); 607 } 608 } 609 dispatchDisplayPaused()610 public void dispatchDisplayPaused() { 611 sendEmptyMessage(MSG_ON_DISPLAY_PAUSED); 612 } 613 dispatchDisplayResumed()614 public void dispatchDisplayResumed() { 615 sendEmptyMessage(MSG_ON_DISPLAY_RESUMED); 616 } 617 dispatchDisplayStopped()618 public void dispatchDisplayStopped() { 619 sendEmptyMessage(MSG_ON_DISPLAY_STOPPED); 620 } 621 } 622 623 private final class MediaProjectionCallback extends IMediaProjectionCallback.Stub { 624 private IBinder mAppToken; MediaProjectionCallback(IBinder appToken)625 public MediaProjectionCallback(IBinder appToken) { 626 mAppToken = appToken; 627 } 628 629 @Override onStop()630 public void onStop() { 631 synchronized (getSyncRoot()) { 632 handleMediaProjectionStoppedLocked(mAppToken); 633 } 634 } 635 636 @Override onCapturedContentResize(int width, int height)637 public void onCapturedContentResize(int width, int height) { 638 // Do nothing when we tell the client that the content is resized - it is up to them 639 // to decide to update the VirtualDisplay and Surface. 640 // We could only update the VirtualDisplay size, anyway (which the client wouldn't 641 // expect), and there will still be letterboxing on the output content since the 642 // Surface and VirtualDisplay would then have different aspect ratios. 643 } 644 645 @Override onCapturedContentVisibilityChanged(boolean isVisible)646 public void onCapturedContentVisibilityChanged(boolean isVisible) { 647 // Do nothing when we tell the client that the content has a visibility change - it is 648 // up to them to decide to pause recording, and update their own UI, depending on their 649 // use case. 650 } 651 } 652 653 @VisibleForTesting 654 public interface SurfaceControlDisplayFactory { 655 /** 656 * Create a virtual display in SurfaceFlinger. 657 * 658 * @param name The name of the display. 659 * @param secure Whether this display is secure. 660 * @param uniqueId The unique ID for the display. 661 * @param requestedRefreshRate 662 * The refresh rate, frames per second, to request on the virtual display. 663 * It should be a divisor of refresh rate of the leader physical display 664 * that drives VSYNC, e.g. 30/60fps on 120fps display. If an arbitrary refresh 665 * rate is specified, SurfaceFlinger rounds up or down to match a divisor of 666 * the refresh rate of the leader physical display. 667 * @return The token reference for the display in SurfaceFlinger. 668 */ createDisplay(String name, boolean secure, String uniqueId, float requestedRefreshRate)669 IBinder createDisplay(String name, boolean secure, String uniqueId, 670 float requestedRefreshRate); 671 672 /** 673 * Destroy a display in SurfaceFlinger. 674 * 675 * @param displayToken The display token for the display to be destroyed. 676 */ destroyDisplay(IBinder displayToken)677 void destroyDisplay(IBinder displayToken); 678 } 679 } 680