OSDN Git Service

DO NOT MERGE. Grant MMS Uri permissions as the calling UID.
[android-x86/frameworks-base.git] / core / java / android / hardware / display / DisplayManagerGlobal.java
1 /*
2  * Copyright (C) 2012 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.hardware.display;
18
19 import android.content.Context;
20 import android.content.res.Configuration;
21 import android.hardware.display.DisplayManager.DisplayListener;
22 import android.media.projection.MediaProjection;
23 import android.media.projection.IMediaProjection;
24 import android.os.Handler;
25 import android.os.IBinder;
26 import android.os.Looper;
27 import android.os.Message;
28 import android.os.RemoteException;
29 import android.os.ServiceManager;
30 import android.text.TextUtils;
31 import android.util.Log;
32 import android.util.SparseArray;
33 import android.view.DisplayAdjustments;
34 import android.view.Display;
35 import android.view.DisplayInfo;
36 import android.view.Surface;
37
38 import java.util.ArrayList;
39
40 /**
41  * Manager communication with the display manager service on behalf of
42  * an application process.  You're probably looking for {@link DisplayManager}.
43  *
44  * @hide
45  */
46 public final class DisplayManagerGlobal {
47     private static final String TAG = "DisplayManager";
48     private static final boolean DEBUG = false;
49
50     // True if display info and display ids should be cached.
51     //
52     // FIXME: The cache is currently disabled because it's unclear whether we have the
53     // necessary guarantees that the caches will always be flushed before clients
54     // attempt to observe their new state.  For example, depending on the order
55     // in which the binder transactions take place, we might have a problem where
56     // an application could start processing a configuration change due to a display
57     // orientation change before the display info cache has actually been invalidated.
58     private static final boolean USE_CACHE = false;
59
60     public static final int EVENT_DISPLAY_ADDED = 1;
61     public static final int EVENT_DISPLAY_CHANGED = 2;
62     public static final int EVENT_DISPLAY_REMOVED = 3;
63
64     private static DisplayManagerGlobal sInstance;
65
66     private final Object mLock = new Object();
67
68     private final IDisplayManager mDm;
69
70     private DisplayManagerCallback mCallback;
71     private final ArrayList<DisplayListenerDelegate> mDisplayListeners =
72             new ArrayList<DisplayListenerDelegate>();
73
74     private final SparseArray<DisplayInfo> mDisplayInfoCache = new SparseArray<DisplayInfo>();
75     private int[] mDisplayIdCache;
76
77     private int mWifiDisplayScanNestCount;
78
79     private DisplayManagerGlobal(IDisplayManager dm) {
80         mDm = dm;
81     }
82
83     /**
84      * Gets an instance of the display manager global singleton.
85      *
86      * @return The display manager instance, may be null early in system startup
87      * before the display manager has been fully initialized.
88      */
89     public static DisplayManagerGlobal getInstance() {
90         synchronized (DisplayManagerGlobal.class) {
91             if (sInstance == null) {
92                 IBinder b = ServiceManager.getService(Context.DISPLAY_SERVICE);
93                 if (b != null) {
94                     sInstance = new DisplayManagerGlobal(IDisplayManager.Stub.asInterface(b));
95                 }
96             }
97             return sInstance;
98         }
99     }
100
101     /**
102      * Get information about a particular logical display.
103      *
104      * @param displayId The logical display id.
105      * @return Information about the specified display, or null if it does not exist.
106      * This object belongs to an internal cache and should be treated as if it were immutable.
107      */
108     public DisplayInfo getDisplayInfo(int displayId) {
109         try {
110             synchronized (mLock) {
111                 DisplayInfo info;
112                 if (USE_CACHE) {
113                     info = mDisplayInfoCache.get(displayId);
114                     if (info != null) {
115                         return info;
116                     }
117                 }
118
119                 info = mDm.getDisplayInfo(displayId);
120                 if (info == null) {
121                     return null;
122                 }
123
124                 if (USE_CACHE) {
125                     mDisplayInfoCache.put(displayId, info);
126                 }
127                 registerCallbackIfNeededLocked();
128
129                 if (DEBUG) {
130                     Log.d(TAG, "getDisplayInfo: displayId=" + displayId + ", info=" + info);
131                 }
132                 return info;
133             }
134         } catch (RemoteException ex) {
135             throw ex.rethrowFromSystemServer();
136         }
137     }
138
139     /**
140      * Gets all currently valid logical display ids.
141      *
142      * @return An array containing all display ids.
143      */
144     public int[] getDisplayIds() {
145         try {
146             synchronized (mLock) {
147                 if (USE_CACHE) {
148                     if (mDisplayIdCache != null) {
149                         return mDisplayIdCache;
150                     }
151                 }
152
153                 int[] displayIds = mDm.getDisplayIds();
154                 if (USE_CACHE) {
155                     mDisplayIdCache = displayIds;
156                 }
157                 registerCallbackIfNeededLocked();
158                 return displayIds;
159             }
160         } catch (RemoteException ex) {
161             throw ex.rethrowFromSystemServer();
162         }
163     }
164
165     /**
166      * Gets information about a logical display.
167      *
168      * The display metrics may be adjusted to provide compatibility
169      * for legacy applications or limited screen areas.
170      *
171      * @param displayId The logical display id.
172      * @param daj The compatibility info and activityToken.
173      * @return The display object, or null if there is no display with the given id.
174      */
175     public Display getCompatibleDisplay(int displayId, DisplayAdjustments daj) {
176         DisplayInfo displayInfo = getDisplayInfo(displayId);
177         if (displayInfo == null) {
178             return null;
179         }
180         return new Display(this, displayId, displayInfo, daj);
181     }
182
183     /**
184      * Gets information about a logical display without applying any compatibility metrics.
185      *
186      * @param displayId The logical display id.
187      * @return The display object, or null if there is no display with the given id.
188      */
189     public Display getRealDisplay(int displayId) {
190         return getCompatibleDisplay(displayId, DisplayAdjustments.DEFAULT_DISPLAY_ADJUSTMENTS);
191     }
192
193     public void registerDisplayListener(DisplayListener listener, Handler handler) {
194         if (listener == null) {
195             throw new IllegalArgumentException("listener must not be null");
196         }
197
198         synchronized (mLock) {
199             int index = findDisplayListenerLocked(listener);
200             if (index < 0) {
201                 mDisplayListeners.add(new DisplayListenerDelegate(listener, handler));
202                 registerCallbackIfNeededLocked();
203             }
204         }
205     }
206
207     public void unregisterDisplayListener(DisplayListener listener) {
208         if (listener == null) {
209             throw new IllegalArgumentException("listener must not be null");
210         }
211
212         synchronized (mLock) {
213             int index = findDisplayListenerLocked(listener);
214             if (index >= 0) {
215                 DisplayListenerDelegate d = mDisplayListeners.get(index);
216                 d.clearEvents();
217                 mDisplayListeners.remove(index);
218             }
219         }
220     }
221
222     private int findDisplayListenerLocked(DisplayListener listener) {
223         final int numListeners = mDisplayListeners.size();
224         for (int i = 0; i < numListeners; i++) {
225             if (mDisplayListeners.get(i).mListener == listener) {
226                 return i;
227             }
228         }
229         return -1;
230     }
231
232     private void registerCallbackIfNeededLocked() {
233         if (mCallback == null) {
234             mCallback = new DisplayManagerCallback();
235             try {
236                 mDm.registerCallback(mCallback);
237             } catch (RemoteException ex) {
238                 throw ex.rethrowFromSystemServer();
239             }
240         }
241     }
242
243     private void handleDisplayEvent(int displayId, int event) {
244         synchronized (mLock) {
245             if (USE_CACHE) {
246                 mDisplayInfoCache.remove(displayId);
247
248                 if (event == EVENT_DISPLAY_ADDED || event == EVENT_DISPLAY_REMOVED) {
249                     mDisplayIdCache = null;
250                 }
251             }
252
253             final int numListeners = mDisplayListeners.size();
254             for (int i = 0; i < numListeners; i++) {
255                 mDisplayListeners.get(i).sendDisplayEvent(displayId, event);
256             }
257         }
258     }
259
260     public void startWifiDisplayScan() {
261         synchronized (mLock) {
262             if (mWifiDisplayScanNestCount++ == 0) {
263                 registerCallbackIfNeededLocked();
264                 try {
265                     mDm.startWifiDisplayScan();
266                 } catch (RemoteException ex) {
267                     throw ex.rethrowFromSystemServer();
268                 }
269             }
270         }
271     }
272
273     public void stopWifiDisplayScan() {
274         synchronized (mLock) {
275             if (--mWifiDisplayScanNestCount == 0) {
276                 try {
277                     mDm.stopWifiDisplayScan();
278                 } catch (RemoteException ex) {
279                     throw ex.rethrowFromSystemServer();
280                 }
281             } else if (mWifiDisplayScanNestCount < 0) {
282                 Log.wtf(TAG, "Wifi display scan nest count became negative: "
283                         + mWifiDisplayScanNestCount);
284                 mWifiDisplayScanNestCount = 0;
285             }
286         }
287     }
288
289     public void connectWifiDisplay(String deviceAddress) {
290         if (deviceAddress == null) {
291             throw new IllegalArgumentException("deviceAddress must not be null");
292         }
293
294         try {
295             mDm.connectWifiDisplay(deviceAddress);
296         } catch (RemoteException ex) {
297             throw ex.rethrowFromSystemServer();
298         }
299     }
300
301     public void pauseWifiDisplay() {
302         try {
303             mDm.pauseWifiDisplay();
304         } catch (RemoteException ex) {
305             throw ex.rethrowFromSystemServer();
306         }
307     }
308
309     public void resumeWifiDisplay() {
310         try {
311             mDm.resumeWifiDisplay();
312         } catch (RemoteException ex) {
313             throw ex.rethrowFromSystemServer();
314         }
315     }
316
317     public void disconnectWifiDisplay() {
318         try {
319             mDm.disconnectWifiDisplay();
320         } catch (RemoteException ex) {
321             throw ex.rethrowFromSystemServer();
322         }
323     }
324
325     public void renameWifiDisplay(String deviceAddress, String alias) {
326         if (deviceAddress == null) {
327             throw new IllegalArgumentException("deviceAddress must not be null");
328         }
329
330         try {
331             mDm.renameWifiDisplay(deviceAddress, alias);
332         } catch (RemoteException ex) {
333             throw ex.rethrowFromSystemServer();
334         }
335     }
336
337     public void forgetWifiDisplay(String deviceAddress) {
338         if (deviceAddress == null) {
339             throw new IllegalArgumentException("deviceAddress must not be null");
340         }
341
342         try {
343             mDm.forgetWifiDisplay(deviceAddress);
344         } catch (RemoteException ex) {
345             throw ex.rethrowFromSystemServer();
346         }
347     }
348
349     public WifiDisplayStatus getWifiDisplayStatus() {
350         try {
351             return mDm.getWifiDisplayStatus();
352         } catch (RemoteException ex) {
353             throw ex.rethrowFromSystemServer();
354         }
355     }
356
357     public void requestColorTransform(int displayId, int colorTransformId) {
358         try {
359             mDm.requestColorTransform(displayId, colorTransformId);
360         } catch (RemoteException ex) {
361             throw ex.rethrowFromSystemServer();
362         }
363     }
364
365     public VirtualDisplay createVirtualDisplay(Context context, MediaProjection projection,
366             String name, int width, int height, int densityDpi, Surface surface, int flags,
367             VirtualDisplay.Callback callback, Handler handler) {
368         if (TextUtils.isEmpty(name)) {
369             throw new IllegalArgumentException("name must be non-null and non-empty");
370         }
371         if (width <= 0 || height <= 0 || densityDpi <= 0) {
372             throw new IllegalArgumentException("width, height, and densityDpi must be "
373                     + "greater than 0");
374         }
375
376         VirtualDisplayCallback callbackWrapper = new VirtualDisplayCallback(callback, handler);
377         IMediaProjection projectionToken = projection != null ? projection.getProjection() : null;
378         int displayId;
379         try {
380             displayId = mDm.createVirtualDisplay(callbackWrapper, projectionToken,
381                     context.getPackageName(), name, width, height, densityDpi, surface, flags);
382         } catch (RemoteException ex) {
383             throw ex.rethrowFromSystemServer();
384         }
385         if (displayId < 0) {
386             Log.e(TAG, "Could not create virtual display: " + name);
387             return null;
388         }
389         Display display = getRealDisplay(displayId);
390         if (display == null) {
391             Log.wtf(TAG, "Could not obtain display info for newly created "
392                     + "virtual display: " + name);
393             try {
394                 mDm.releaseVirtualDisplay(callbackWrapper);
395             } catch (RemoteException ex) {
396                 throw ex.rethrowFromSystemServer();
397             }
398             return null;
399         }
400         return new VirtualDisplay(this, display, callbackWrapper, surface);
401     }
402
403     public void setVirtualDisplaySurface(IVirtualDisplayCallback token, Surface surface) {
404         try {
405             mDm.setVirtualDisplaySurface(token, surface);
406         } catch (RemoteException ex) {
407             throw ex.rethrowFromSystemServer();
408         }
409     }
410
411     public void resizeVirtualDisplay(IVirtualDisplayCallback token,
412             int width, int height, int densityDpi) {
413         try {
414             mDm.resizeVirtualDisplay(token, width, height, densityDpi);
415         } catch (RemoteException ex) {
416             throw ex.rethrowFromSystemServer();
417         }
418     }
419
420     public void releaseVirtualDisplay(IVirtualDisplayCallback token) {
421         try {
422             mDm.releaseVirtualDisplay(token);
423         } catch (RemoteException ex) {
424             throw ex.rethrowFromSystemServer();
425         }
426     }
427
428     private final class DisplayManagerCallback extends IDisplayManagerCallback.Stub {
429         @Override
430         public void onDisplayEvent(int displayId, int event) {
431             if (DEBUG) {
432                 Log.d(TAG, "onDisplayEvent: displayId=" + displayId + ", event=" + event);
433             }
434             handleDisplayEvent(displayId, event);
435         }
436     }
437
438     private static final class DisplayListenerDelegate extends Handler {
439         public final DisplayListener mListener;
440
441         public DisplayListenerDelegate(DisplayListener listener, Handler handler) {
442             super(handler != null ? handler.getLooper() : Looper.myLooper(), null, true /*async*/);
443             mListener = listener;
444         }
445
446         public void sendDisplayEvent(int displayId, int event) {
447             Message msg = obtainMessage(event, displayId, 0);
448             sendMessage(msg);
449         }
450
451         public void clearEvents() {
452             removeCallbacksAndMessages(null);
453         }
454
455         @Override
456         public void handleMessage(Message msg) {
457             switch (msg.what) {
458                 case EVENT_DISPLAY_ADDED:
459                     mListener.onDisplayAdded(msg.arg1);
460                     break;
461                 case EVENT_DISPLAY_CHANGED:
462                     mListener.onDisplayChanged(msg.arg1);
463                     break;
464                 case EVENT_DISPLAY_REMOVED:
465                     mListener.onDisplayRemoved(msg.arg1);
466                     break;
467             }
468         }
469     }
470
471     private final static class VirtualDisplayCallback extends IVirtualDisplayCallback.Stub {
472         private VirtualDisplayCallbackDelegate mDelegate;
473
474         public VirtualDisplayCallback(VirtualDisplay.Callback callback, Handler handler) {
475             if (callback != null) {
476                 mDelegate = new VirtualDisplayCallbackDelegate(callback, handler);
477             }
478         }
479
480         @Override // Binder call
481         public void onPaused() {
482             if (mDelegate != null) {
483                 mDelegate.sendEmptyMessage(VirtualDisplayCallbackDelegate.MSG_DISPLAY_PAUSED);
484             }
485         }
486
487         @Override // Binder call
488         public void onResumed() {
489             if (mDelegate != null) {
490                 mDelegate.sendEmptyMessage(VirtualDisplayCallbackDelegate.MSG_DISPLAY_RESUMED);
491             }
492         }
493
494         @Override // Binder call
495         public void onStopped() {
496             if (mDelegate != null) {
497                 mDelegate.sendEmptyMessage(VirtualDisplayCallbackDelegate.MSG_DISPLAY_STOPPED);
498             }
499         }
500     }
501
502     private final static class VirtualDisplayCallbackDelegate extends Handler {
503         public static final int MSG_DISPLAY_PAUSED = 0;
504         public static final int MSG_DISPLAY_RESUMED = 1;
505         public static final int MSG_DISPLAY_STOPPED = 2;
506
507         private final VirtualDisplay.Callback mCallback;
508
509         public VirtualDisplayCallbackDelegate(VirtualDisplay.Callback callback,
510                 Handler handler) {
511             super(handler != null ? handler.getLooper() : Looper.myLooper(), null, true /*async*/);
512             mCallback = callback;
513         }
514
515         @Override
516         public void handleMessage(Message msg) {
517             switch (msg.what) {
518                 case MSG_DISPLAY_PAUSED:
519                     mCallback.onPaused();
520                     break;
521                 case MSG_DISPLAY_RESUMED:
522                     mCallback.onResumed();
523                     break;
524                 case MSG_DISPLAY_STOPPED:
525                     mCallback.onStopped();
526                     break;
527             }
528         }
529     }
530 }