• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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