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_OWN_DISPLAY_GROUP; 24 import static android.hardware.display.DisplayManager.VIRTUAL_DISPLAY_FLAG_PRESENTATION; 25 import static android.hardware.display.DisplayManager.VIRTUAL_DISPLAY_FLAG_PUBLIC; 26 import static android.hardware.display.DisplayManager.VIRTUAL_DISPLAY_FLAG_ROTATES_WITH_CONTENT; 27 import static android.hardware.display.DisplayManager.VIRTUAL_DISPLAY_FLAG_SECURE; 28 import static android.hardware.display.DisplayManager.VIRTUAL_DISPLAY_FLAG_SHOULD_SHOW_SYSTEM_DECORATIONS; 29 import static android.hardware.display.DisplayManager.VIRTUAL_DISPLAY_FLAG_SUPPORTS_TOUCH; 30 import static android.hardware.display.DisplayManager.VIRTUAL_DISPLAY_FLAG_TOUCH_FEEDBACK_DISABLED; 31 import static android.hardware.display.DisplayManager.VIRTUAL_DISPLAY_FLAG_TRUSTED; 32 33 import static com.android.server.display.DisplayDeviceInfo.FLAG_ALWAYS_UNLOCKED; 34 import static com.android.server.display.DisplayDeviceInfo.FLAG_OWN_DISPLAY_GROUP; 35 import static com.android.server.display.DisplayDeviceInfo.FLAG_TOUCH_FEEDBACK_DISABLED; 36 import static com.android.server.display.DisplayDeviceInfo.FLAG_TRUSTED; 37 38 import android.annotation.Nullable; 39 import android.content.Context; 40 import android.graphics.Point; 41 import android.hardware.display.IVirtualDisplayCallback; 42 import android.hardware.display.VirtualDisplayConfig; 43 import android.media.projection.IMediaProjection; 44 import android.media.projection.IMediaProjectionCallback; 45 import android.os.Handler; 46 import android.os.IBinder; 47 import android.os.IBinder.DeathRecipient; 48 import android.os.Message; 49 import android.os.RemoteException; 50 import android.os.SystemProperties; 51 import android.util.ArrayMap; 52 import android.util.Slog; 53 import android.view.Display; 54 import android.view.Surface; 55 import android.view.SurfaceControl; 56 57 import com.android.internal.annotations.VisibleForTesting; 58 59 import java.io.PrintWriter; 60 import java.util.Iterator; 61 62 /** 63 * A display adapter that provides virtual displays on behalf of applications. 64 * <p> 65 * Display adapters are guarded by the {@link DisplayManagerService.SyncRoot} lock. 66 * </p> 67 */ 68 @VisibleForTesting 69 public class VirtualDisplayAdapter extends DisplayAdapter { 70 static final String TAG = "VirtualDisplayAdapter"; 71 static final boolean DEBUG = false; 72 73 // Unique id prefix for virtual displays 74 @VisibleForTesting 75 static final String UNIQUE_ID_PREFIX = "virtual:"; 76 77 private final ArrayMap<IBinder, VirtualDisplayDevice> mVirtualDisplayDevices = 78 new ArrayMap<IBinder, VirtualDisplayDevice>(); 79 private final Handler mHandler; 80 private final SurfaceControlDisplayFactory mSurfaceControlDisplayFactory; 81 82 // Called with SyncRoot lock held. VirtualDisplayAdapter(DisplayManagerService.SyncRoot syncRoot, Context context, Handler handler, Listener listener)83 public VirtualDisplayAdapter(DisplayManagerService.SyncRoot syncRoot, 84 Context context, Handler handler, Listener listener) { 85 this(syncRoot, context, handler, listener, 86 (String name, boolean secure) -> SurfaceControl.createDisplay(name, secure)); 87 } 88 89 @VisibleForTesting VirtualDisplayAdapter(DisplayManagerService.SyncRoot syncRoot, Context context, Handler handler, Listener listener, SurfaceControlDisplayFactory surfaceControlDisplayFactory)90 VirtualDisplayAdapter(DisplayManagerService.SyncRoot syncRoot, 91 Context context, Handler handler, Listener listener, 92 SurfaceControlDisplayFactory surfaceControlDisplayFactory) { 93 super(syncRoot, context, handler, listener, TAG); 94 mHandler = handler; 95 mSurfaceControlDisplayFactory = surfaceControlDisplayFactory; 96 } 97 createVirtualDisplayLocked(IVirtualDisplayCallback callback, IMediaProjection projection, int ownerUid, String ownerPackageName, Surface surface, int flags, VirtualDisplayConfig virtualDisplayConfig)98 public DisplayDevice createVirtualDisplayLocked(IVirtualDisplayCallback callback, 99 IMediaProjection projection, int ownerUid, String ownerPackageName, Surface surface, 100 int flags, VirtualDisplayConfig virtualDisplayConfig) { 101 String name = virtualDisplayConfig.getName(); 102 boolean secure = (flags & VIRTUAL_DISPLAY_FLAG_SECURE) != 0; 103 IBinder appToken = callback.asBinder(); 104 IBinder displayToken = mSurfaceControlDisplayFactory.createDisplay(name, secure); 105 final String baseUniqueId = 106 UNIQUE_ID_PREFIX + ownerPackageName + "," + ownerUid + "," + name + ","; 107 final int uniqueIndex = getNextUniqueIndex(baseUniqueId); 108 String uniqueId = virtualDisplayConfig.getUniqueId(); 109 if (uniqueId == null) { 110 uniqueId = baseUniqueId + uniqueIndex; 111 } else { 112 uniqueId = UNIQUE_ID_PREFIX + ownerPackageName + ":" + uniqueId; 113 } 114 MediaProjectionCallback mediaProjectionCallback = null; 115 if (projection != null) { 116 mediaProjectionCallback = new MediaProjectionCallback(appToken); 117 } 118 VirtualDisplayDevice device = new VirtualDisplayDevice(displayToken, appToken, 119 ownerUid, ownerPackageName, surface, flags, 120 new Callback(callback, mHandler), projection, mediaProjectionCallback, 121 uniqueId, uniqueIndex, virtualDisplayConfig); 122 123 mVirtualDisplayDevices.put(appToken, device); 124 125 try { 126 if (projection != null) { 127 projection.registerCallback(mediaProjectionCallback); 128 } 129 appToken.linkToDeath(device, 0); 130 } catch (RemoteException ex) { 131 mVirtualDisplayDevices.remove(appToken); 132 device.destroyLocked(false); 133 return null; 134 } 135 136 // Return the display device without actually sending the event indicating 137 // that it was added. The caller will handle it. 138 return device; 139 } 140 resizeVirtualDisplayLocked(IBinder appToken, int width, int height, int densityDpi)141 public void resizeVirtualDisplayLocked(IBinder appToken, 142 int width, int height, int densityDpi) { 143 VirtualDisplayDevice device = mVirtualDisplayDevices.get(appToken); 144 if (device != null) { 145 device.resizeLocked(width, height, densityDpi); 146 } 147 } 148 149 @VisibleForTesting getVirtualDisplaySurfaceLocked(IBinder appToken)150 Surface getVirtualDisplaySurfaceLocked(IBinder appToken) { 151 VirtualDisplayDevice device = mVirtualDisplayDevices.get(appToken); 152 if (device != null) { 153 return device.getSurfaceLocked(); 154 } 155 return null; 156 } 157 setVirtualDisplaySurfaceLocked(IBinder appToken, Surface surface)158 public void setVirtualDisplaySurfaceLocked(IBinder appToken, Surface surface) { 159 VirtualDisplayDevice device = mVirtualDisplayDevices.get(appToken); 160 if (device != null) { 161 device.setSurfaceLocked(surface); 162 } 163 } 164 releaseVirtualDisplayLocked(IBinder appToken)165 public DisplayDevice releaseVirtualDisplayLocked(IBinder appToken) { 166 VirtualDisplayDevice device = mVirtualDisplayDevices.remove(appToken); 167 if (device != null) { 168 device.destroyLocked(true); 169 appToken.unlinkToDeath(device, 0); 170 } 171 172 // Return the display device that was removed without actually sending the 173 // event indicating that it was removed. The caller will handle it. 174 return device; 175 } 176 setVirtualDisplayStateLocked(IBinder appToken, boolean isOn)177 void setVirtualDisplayStateLocked(IBinder appToken, boolean isOn) { 178 VirtualDisplayDevice device = mVirtualDisplayDevices.get(appToken); 179 if (device != null) { 180 device.setDisplayState(isOn); 181 } 182 } 183 184 /** 185 * Returns the next unique index for the uniqueIdPrefix 186 */ getNextUniqueIndex(String uniqueIdPrefix)187 private int getNextUniqueIndex(String uniqueIdPrefix) { 188 if (mVirtualDisplayDevices.isEmpty()) { 189 return 0; 190 } 191 192 int nextUniqueIndex = 0; 193 Iterator<VirtualDisplayDevice> it = mVirtualDisplayDevices.values().iterator(); 194 while (it.hasNext()) { 195 VirtualDisplayDevice device = it.next(); 196 if (device.getUniqueId().startsWith(uniqueIdPrefix) 197 && device.mUniqueIndex >= nextUniqueIndex) { 198 // Increment the next unique index to be greater than ones we have already ran 199 // across for displays that have the same unique Id prefix. 200 nextUniqueIndex = device.mUniqueIndex + 1; 201 } 202 } 203 204 return nextUniqueIndex; 205 } 206 handleBinderDiedLocked(IBinder appToken)207 private void handleBinderDiedLocked(IBinder appToken) { 208 mVirtualDisplayDevices.remove(appToken); 209 } 210 handleMediaProjectionStoppedLocked(IBinder appToken)211 private void handleMediaProjectionStoppedLocked(IBinder appToken) { 212 VirtualDisplayDevice device = mVirtualDisplayDevices.get(appToken); 213 if (device != null) { 214 Slog.i(TAG, "Virtual display device released because media projection stopped: " 215 + device.mName); 216 device.stopLocked(); 217 } 218 } 219 220 private final class VirtualDisplayDevice extends DisplayDevice implements DeathRecipient { 221 private static final int PENDING_SURFACE_CHANGE = 0x01; 222 private static final int PENDING_RESIZE = 0x02; 223 224 private static final float REFRESH_RATE = 60.0f; 225 226 private final IBinder mAppToken; 227 private final int mOwnerUid; 228 final String mOwnerPackageName; 229 final String mName; 230 private final int mFlags; 231 private final Callback mCallback; 232 @Nullable private final IMediaProjection mProjection; 233 @Nullable private final IMediaProjectionCallback mMediaProjectionCallback; 234 235 private int mWidth; 236 private int mHeight; 237 private int mDensityDpi; 238 private Surface mSurface; 239 private DisplayDeviceInfo mInfo; 240 private int mDisplayState; 241 private boolean mStopped; 242 private int mPendingChanges; 243 private int mUniqueIndex; 244 private Display.Mode mMode; 245 private boolean mIsDisplayOn; 246 private int mDisplayIdToMirror; 247 private boolean mIsWindowManagerMirroring; 248 VirtualDisplayDevice(IBinder displayToken, IBinder appToken, int ownerUid, String ownerPackageName, Surface surface, int flags, Callback callback, IMediaProjection projection, IMediaProjectionCallback mediaProjectionCallback, String uniqueId, int uniqueIndex, VirtualDisplayConfig virtualDisplayConfig)249 public VirtualDisplayDevice(IBinder displayToken, IBinder appToken, 250 int ownerUid, String ownerPackageName, Surface surface, int flags, 251 Callback callback, IMediaProjection projection, 252 IMediaProjectionCallback mediaProjectionCallback, String uniqueId, int uniqueIndex, 253 VirtualDisplayConfig virtualDisplayConfig) { 254 super(VirtualDisplayAdapter.this, displayToken, uniqueId, getContext()); 255 mAppToken = appToken; 256 mOwnerUid = ownerUid; 257 mOwnerPackageName = ownerPackageName; 258 mName = virtualDisplayConfig.getName(); 259 mWidth = virtualDisplayConfig.getWidth(); 260 mHeight = virtualDisplayConfig.getHeight(); 261 mMode = createMode(mWidth, mHeight, REFRESH_RATE); 262 mDensityDpi = virtualDisplayConfig.getDensityDpi(); 263 mSurface = surface; 264 mFlags = flags; 265 mCallback = callback; 266 mProjection = projection; 267 mMediaProjectionCallback = mediaProjectionCallback; 268 mDisplayState = Display.STATE_UNKNOWN; 269 mPendingChanges |= PENDING_SURFACE_CHANGE; 270 mUniqueIndex = uniqueIndex; 271 mIsDisplayOn = surface != null; 272 mDisplayIdToMirror = virtualDisplayConfig.getDisplayIdToMirror(); 273 mIsWindowManagerMirroring = virtualDisplayConfig.isWindowManagerMirroring(); 274 } 275 276 @Override binderDied()277 public void binderDied() { 278 synchronized (getSyncRoot()) { 279 handleBinderDiedLocked(mAppToken); 280 Slog.i(TAG, "Virtual display device released because application token died: " 281 + mOwnerPackageName); 282 destroyLocked(false); 283 if (mProjection != null && mMediaProjectionCallback != null) { 284 try { 285 mProjection.unregisterCallback(mMediaProjectionCallback); 286 } catch (RemoteException e) { 287 Slog.w(TAG, "Failed to unregister callback in binderDied", e); 288 } 289 } 290 sendDisplayDeviceEventLocked(this, DISPLAY_DEVICE_EVENT_REMOVED); 291 } 292 } 293 destroyLocked(boolean binderAlive)294 public void destroyLocked(boolean binderAlive) { 295 if (mSurface != null) { 296 mSurface.release(); 297 mSurface = null; 298 } 299 SurfaceControl.destroyDisplay(getDisplayTokenLocked()); 300 if (mProjection != null && mMediaProjectionCallback != null) { 301 try { 302 mProjection.unregisterCallback(mMediaProjectionCallback); 303 } catch (RemoteException e) { 304 Slog.w(TAG, "Failed to unregister callback in destroy", e); 305 } 306 } 307 if (binderAlive) { 308 mCallback.dispatchDisplayStopped(); 309 } 310 } 311 312 @Override getDisplayIdToMirrorLocked()313 public int getDisplayIdToMirrorLocked() { 314 return mDisplayIdToMirror; 315 } 316 317 @Override isWindowManagerMirroringLocked()318 public boolean isWindowManagerMirroringLocked() { 319 return mIsWindowManagerMirroring; 320 } 321 322 @Override setWindowManagerMirroringLocked(boolean mirroring)323 public void setWindowManagerMirroringLocked(boolean mirroring) { 324 if (mIsWindowManagerMirroring != mirroring) { 325 mIsWindowManagerMirroring = mirroring; 326 sendDisplayDeviceEventLocked(this, DISPLAY_DEVICE_EVENT_CHANGED); 327 sendTraversalRequestLocked(); 328 } 329 } 330 331 @Override getDisplaySurfaceDefaultSizeLocked()332 public Point getDisplaySurfaceDefaultSizeLocked() { 333 if (mSurface == null) { 334 return null; 335 } 336 return mSurface.getDefaultSize(); 337 } 338 339 @VisibleForTesting getSurfaceLocked()340 Surface getSurfaceLocked() { 341 return mSurface; 342 } 343 344 @Override hasStableUniqueId()345 public boolean hasStableUniqueId() { 346 return false; 347 } 348 349 @Override requestDisplayStateLocked(int state, float brightnessState, float sdrBrightnessState)350 public Runnable requestDisplayStateLocked(int state, float brightnessState, 351 float sdrBrightnessState) { 352 if (state != mDisplayState) { 353 mDisplayState = state; 354 if (state == Display.STATE_OFF) { 355 mCallback.dispatchDisplayPaused(); 356 } else { 357 mCallback.dispatchDisplayResumed(); 358 } 359 } 360 return null; 361 } 362 363 @Override performTraversalLocked(SurfaceControl.Transaction t)364 public void performTraversalLocked(SurfaceControl.Transaction t) { 365 if ((mPendingChanges & PENDING_RESIZE) != 0) { 366 t.setDisplaySize(getDisplayTokenLocked(), mWidth, mHeight); 367 } 368 if ((mPendingChanges & PENDING_SURFACE_CHANGE) != 0) { 369 setSurfaceLocked(t, mSurface); 370 } 371 mPendingChanges = 0; 372 } 373 setSurfaceLocked(Surface surface)374 public void setSurfaceLocked(Surface surface) { 375 if (!mStopped && mSurface != surface) { 376 if ((mSurface != null) != (surface != null)) { 377 sendDisplayDeviceEventLocked(this, DISPLAY_DEVICE_EVENT_CHANGED); 378 } 379 sendTraversalRequestLocked(); 380 mSurface = surface; 381 mInfo = null; 382 mPendingChanges |= PENDING_SURFACE_CHANGE; 383 } 384 } 385 resizeLocked(int width, int height, int densityDpi)386 public void resizeLocked(int width, int height, int densityDpi) { 387 if (mWidth != width || mHeight != height || mDensityDpi != densityDpi) { 388 sendDisplayDeviceEventLocked(this, DISPLAY_DEVICE_EVENT_CHANGED); 389 sendTraversalRequestLocked(); 390 mWidth = width; 391 mHeight = height; 392 mMode = createMode(width, height, REFRESH_RATE); 393 mDensityDpi = densityDpi; 394 mInfo = null; 395 mPendingChanges |= PENDING_RESIZE; 396 } 397 } 398 setDisplayState(boolean isOn)399 void setDisplayState(boolean isOn) { 400 if (mIsDisplayOn != isOn) { 401 mIsDisplayOn = isOn; 402 mInfo = null; 403 sendDisplayDeviceEventLocked(this, DISPLAY_DEVICE_EVENT_CHANGED); 404 } 405 } 406 stopLocked()407 public void stopLocked() { 408 setSurfaceLocked(null); 409 mStopped = true; 410 } 411 412 @Override dumpLocked(PrintWriter pw)413 public void dumpLocked(PrintWriter pw) { 414 super.dumpLocked(pw); 415 pw.println("mFlags=" + mFlags); 416 pw.println("mDisplayState=" + Display.stateToString(mDisplayState)); 417 pw.println("mStopped=" + mStopped); 418 pw.println("mDisplayIdToMirror=" + mDisplayIdToMirror); 419 pw.println("mWindowManagerMirroring=" + mIsWindowManagerMirroring); 420 } 421 422 423 @Override getDisplayDeviceInfoLocked()424 public DisplayDeviceInfo getDisplayDeviceInfoLocked() { 425 if (mInfo == null) { 426 mInfo = new DisplayDeviceInfo(); 427 mInfo.name = mName; 428 mInfo.uniqueId = getUniqueId(); 429 mInfo.width = mWidth; 430 mInfo.height = mHeight; 431 mInfo.modeId = mMode.getModeId(); 432 mInfo.defaultModeId = mMode.getModeId(); 433 mInfo.supportedModes = new Display.Mode[] { mMode }; 434 mInfo.densityDpi = mDensityDpi; 435 mInfo.xDpi = mDensityDpi; 436 mInfo.yDpi = mDensityDpi; 437 mInfo.presentationDeadlineNanos = 1000000000L / (int) REFRESH_RATE; // 1 frame 438 mInfo.flags = 0; 439 if ((mFlags & VIRTUAL_DISPLAY_FLAG_PUBLIC) == 0) { 440 mInfo.flags |= DisplayDeviceInfo.FLAG_PRIVATE 441 | DisplayDeviceInfo.FLAG_NEVER_BLANK; 442 } 443 if ((mFlags & VIRTUAL_DISPLAY_FLAG_AUTO_MIRROR) != 0) { 444 mInfo.flags &= ~DisplayDeviceInfo.FLAG_NEVER_BLANK; 445 } else { 446 mInfo.flags |= DisplayDeviceInfo.FLAG_OWN_CONTENT_ONLY; 447 448 if ((mFlags & VIRTUAL_DISPLAY_FLAG_OWN_DISPLAY_GROUP) != 0) { 449 mInfo.flags |= FLAG_OWN_DISPLAY_GROUP; 450 } 451 } 452 453 if ((mFlags & VIRTUAL_DISPLAY_FLAG_SECURE) != 0) { 454 mInfo.flags |= DisplayDeviceInfo.FLAG_SECURE; 455 } 456 if ((mFlags & VIRTUAL_DISPLAY_FLAG_PRESENTATION) != 0) { 457 mInfo.flags |= DisplayDeviceInfo.FLAG_PRESENTATION; 458 459 if ((mFlags & VIRTUAL_DISPLAY_FLAG_PUBLIC) != 0) { 460 // For demonstration purposes, allow rotation of the external display. 461 // In the future we might allow the user to configure this directly. 462 if ("portrait".equals(SystemProperties.get( 463 "persist.demo.remoterotation"))) { 464 mInfo.rotation = Surface.ROTATION_270; 465 } 466 } 467 } 468 if ((mFlags & VIRTUAL_DISPLAY_FLAG_CAN_SHOW_WITH_INSECURE_KEYGUARD) != 0) { 469 mInfo.flags |= DisplayDeviceInfo.FLAG_CAN_SHOW_WITH_INSECURE_KEYGUARD; 470 } 471 if ((mFlags & VIRTUAL_DISPLAY_FLAG_ROTATES_WITH_CONTENT) != 0) { 472 mInfo.flags |= DisplayDeviceInfo.FLAG_ROTATES_WITH_CONTENT; 473 } 474 if ((mFlags & VIRTUAL_DISPLAY_FLAG_DESTROY_CONTENT_ON_REMOVAL) != 0) { 475 mInfo.flags |= DisplayDeviceInfo.FLAG_DESTROY_CONTENT_ON_REMOVAL; 476 } 477 if ((mFlags & VIRTUAL_DISPLAY_FLAG_SHOULD_SHOW_SYSTEM_DECORATIONS) != 0) { 478 mInfo.flags |= DisplayDeviceInfo.FLAG_SHOULD_SHOW_SYSTEM_DECORATIONS; 479 } 480 if ((mFlags & VIRTUAL_DISPLAY_FLAG_TRUSTED) != 0) { 481 mInfo.flags |= FLAG_TRUSTED; 482 } 483 if ((mFlags & VIRTUAL_DISPLAY_FLAG_ALWAYS_UNLOCKED) != 0 484 && (mInfo.flags & DisplayDeviceInfo.FLAG_OWN_DISPLAY_GROUP) != 0) { 485 mInfo.flags |= FLAG_ALWAYS_UNLOCKED; 486 } 487 if ((mFlags & VIRTUAL_DISPLAY_FLAG_TOUCH_FEEDBACK_DISABLED) != 0) { 488 mInfo.flags |= FLAG_TOUCH_FEEDBACK_DISABLED; 489 } 490 491 mInfo.type = Display.TYPE_VIRTUAL; 492 mInfo.touch = ((mFlags & VIRTUAL_DISPLAY_FLAG_SUPPORTS_TOUCH) == 0) ? 493 DisplayDeviceInfo.TOUCH_NONE : DisplayDeviceInfo.TOUCH_VIRTUAL; 494 495 mInfo.state = mIsDisplayOn ? Display.STATE_ON : Display.STATE_OFF; 496 497 mInfo.ownerUid = mOwnerUid; 498 mInfo.ownerPackageName = mOwnerPackageName; 499 } 500 return mInfo; 501 } 502 } 503 504 private static class Callback extends Handler { 505 private static final int MSG_ON_DISPLAY_PAUSED = 0; 506 private static final int MSG_ON_DISPLAY_RESUMED = 1; 507 private static final int MSG_ON_DISPLAY_STOPPED = 2; 508 509 private final IVirtualDisplayCallback mCallback; 510 Callback(IVirtualDisplayCallback callback, Handler handler)511 public Callback(IVirtualDisplayCallback callback, Handler handler) { 512 super(handler.getLooper()); 513 mCallback = callback; 514 } 515 516 @Override handleMessage(Message msg)517 public void handleMessage(Message msg) { 518 try { 519 switch (msg.what) { 520 case MSG_ON_DISPLAY_PAUSED: 521 mCallback.onPaused(); 522 break; 523 case MSG_ON_DISPLAY_RESUMED: 524 mCallback.onResumed(); 525 break; 526 case MSG_ON_DISPLAY_STOPPED: 527 mCallback.onStopped(); 528 break; 529 } 530 } catch (RemoteException e) { 531 Slog.w(TAG, "Failed to notify listener of virtual display event.", e); 532 } 533 } 534 dispatchDisplayPaused()535 public void dispatchDisplayPaused() { 536 sendEmptyMessage(MSG_ON_DISPLAY_PAUSED); 537 } 538 dispatchDisplayResumed()539 public void dispatchDisplayResumed() { 540 sendEmptyMessage(MSG_ON_DISPLAY_RESUMED); 541 } 542 dispatchDisplayStopped()543 public void dispatchDisplayStopped() { 544 sendEmptyMessage(MSG_ON_DISPLAY_STOPPED); 545 } 546 } 547 548 private final class MediaProjectionCallback extends IMediaProjectionCallback.Stub { 549 private IBinder mAppToken; MediaProjectionCallback(IBinder appToken)550 public MediaProjectionCallback(IBinder appToken) { 551 mAppToken = appToken; 552 } 553 554 @Override onStop()555 public void onStop() { 556 synchronized (getSyncRoot()) { 557 handleMediaProjectionStoppedLocked(mAppToken); 558 } 559 } 560 } 561 562 @VisibleForTesting 563 public interface SurfaceControlDisplayFactory { createDisplay(String name, boolean secure)564 public IBinder createDisplay(String name, boolean secure); 565 } 566 } 567