• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
20 import static android.hardware.display.DisplayManager.EventsMask;
21 import static android.view.Display.HdrCapabilities.HdrType;
22 
23 import android.annotation.IntDef;
24 import android.annotation.NonNull;
25 import android.annotation.Nullable;
26 import android.app.PropertyInvalidatedCache;
27 import android.compat.annotation.UnsupportedAppUsage;
28 import android.content.Context;
29 import android.content.pm.ParceledListSlice;
30 import android.content.res.Resources;
31 import android.graphics.ColorSpace;
32 import android.graphics.Point;
33 import android.hardware.display.DisplayManager.DisplayListener;
34 import android.hardware.graphics.common.DisplayDecorationSupport;
35 import android.media.projection.IMediaProjection;
36 import android.media.projection.MediaProjection;
37 import android.os.Handler;
38 import android.os.IBinder;
39 import android.os.Looper;
40 import android.os.Message;
41 import android.os.RemoteException;
42 import android.os.ServiceManager;
43 import android.os.Trace;
44 import android.util.Log;
45 import android.util.Pair;
46 import android.util.SparseArray;
47 import android.view.Display;
48 import android.view.DisplayAdjustments;
49 import android.view.DisplayInfo;
50 import android.view.Surface;
51 
52 import com.android.internal.annotations.VisibleForTesting;
53 
54 import java.lang.annotation.Retention;
55 import java.lang.annotation.RetentionPolicy;
56 import java.util.ArrayList;
57 import java.util.Collections;
58 import java.util.List;
59 import java.util.Objects;
60 import java.util.concurrent.Executor;
61 
62 /**
63  * Manager communication with the display manager service on behalf of
64  * an application process.  You're probably looking for {@link DisplayManager}.
65  *
66  * @hide
67  */
68 public final class DisplayManagerGlobal {
69     private static final String TAG = "DisplayManager";
70     private static final boolean DEBUG = false;
71 
72     // True if display info and display ids should be cached.
73     //
74     // FIXME: The cache is currently disabled because it's unclear whether we have the
75     // necessary guarantees that the caches will always be flushed before clients
76     // attempt to observe their new state.  For example, depending on the order
77     // in which the binder transactions take place, we might have a problem where
78     // an application could start processing a configuration change due to a display
79     // orientation change before the display info cache has actually been invalidated.
80     private static final boolean USE_CACHE = false;
81 
82     @IntDef(prefix = {"SWITCHING_TYPE_"}, value = {
83             EVENT_DISPLAY_ADDED,
84             EVENT_DISPLAY_CHANGED,
85             EVENT_DISPLAY_REMOVED,
86             EVENT_DISPLAY_BRIGHTNESS_CHANGED
87     })
88     @Retention(RetentionPolicy.SOURCE)
89     public @interface DisplayEvent {}
90 
91     public static final int EVENT_DISPLAY_ADDED = 1;
92     public static final int EVENT_DISPLAY_CHANGED = 2;
93     public static final int EVENT_DISPLAY_REMOVED = 3;
94     public static final int EVENT_DISPLAY_BRIGHTNESS_CHANGED = 4;
95 
96     @UnsupportedAppUsage
97     private static DisplayManagerGlobal sInstance;
98 
99     // Guarded by mLock
100     private boolean mDispatchNativeCallbacks = false;
101     private float mNativeCallbackReportedRefreshRate;
102     private final Object mLock = new Object();
103 
104     @UnsupportedAppUsage
105     private final IDisplayManager mDm;
106 
107     private DisplayManagerCallback mCallback;
108     private @EventsMask long mRegisteredEventsMask = 0;
109     private final ArrayList<DisplayListenerDelegate> mDisplayListeners = new ArrayList<>();
110 
111     private final SparseArray<DisplayInfo> mDisplayInfoCache = new SparseArray<>();
112     private final ColorSpace mWideColorSpace;
113     private int[] mDisplayIdCache;
114 
115     private int mWifiDisplayScanNestCount;
116 
117     @VisibleForTesting
DisplayManagerGlobal(IDisplayManager dm)118     public DisplayManagerGlobal(IDisplayManager dm) {
119         mDm = dm;
120         try {
121             mWideColorSpace =
122                     ColorSpace.get(
123                             ColorSpace.Named.values()[mDm.getPreferredWideGamutColorSpaceId()]);
124         } catch (RemoteException ex) {
125             throw ex.rethrowFromSystemServer();
126         }
127     }
128 
129     private PropertyInvalidatedCache<Integer, DisplayInfo> mDisplayCache =
130             new PropertyInvalidatedCache<Integer, DisplayInfo>(
131                 8, // size of display cache
132                 CACHE_KEY_DISPLAY_INFO_PROPERTY) {
133                 @Override
134                 public DisplayInfo recompute(Integer id) {
135                     try {
136                         return mDm.getDisplayInfo(id);
137                     } catch (RemoteException ex) {
138                         throw ex.rethrowFromSystemServer();
139                     }
140                 }
141             };
142 
143     /**
144      * Gets an instance of the display manager global singleton.
145      *
146      * @return The display manager instance, may be null early in system startup
147      * before the display manager has been fully initialized.
148      */
149     @UnsupportedAppUsage
getInstance()150     public static DisplayManagerGlobal getInstance() {
151         synchronized (DisplayManagerGlobal.class) {
152             if (sInstance == null) {
153                 IBinder b = ServiceManager.getService(Context.DISPLAY_SERVICE);
154                 if (b != null) {
155                     sInstance = new DisplayManagerGlobal(IDisplayManager.Stub.asInterface(b));
156                 }
157             }
158             return sInstance;
159         }
160     }
161 
162     /**
163      * Get information about a particular logical display.
164      *
165      * @param displayId The logical display id.
166      * @return Information about the specified display, or null if it does not exist.
167      * This object belongs to an internal cache and should be treated as if it were immutable.
168      */
169     @UnsupportedAppUsage
getDisplayInfo(int displayId)170     public DisplayInfo getDisplayInfo(int displayId) {
171         synchronized (mLock) {
172             return getDisplayInfoLocked(displayId);
173         }
174     }
175 
176     /**
177      * Gets information about a particular logical display
178      * See {@link getDisplayInfo}, but assumes that {@link mLock} is held
179      */
getDisplayInfoLocked(int displayId)180     private @Nullable DisplayInfo getDisplayInfoLocked(int displayId) {
181         DisplayInfo info = null;
182         if (mDisplayCache != null) {
183             info = mDisplayCache.query(displayId);
184         } else {
185             try {
186                 info = mDm.getDisplayInfo(displayId);
187             } catch (RemoteException ex) {
188                 ex.rethrowFromSystemServer();
189             }
190         }
191         if (info == null) {
192             return null;
193         }
194 
195         registerCallbackIfNeededLocked();
196 
197         if (DEBUG) {
198             Log.d(TAG, "getDisplayInfo: displayId=" + displayId + ", info=" + info);
199         }
200         return info;
201     }
202 
203     /**
204      * Gets all currently valid logical display ids.
205      *
206      * @return An array containing all display ids.
207      */
208     @UnsupportedAppUsage
getDisplayIds()209     public int[] getDisplayIds() {
210         return getDisplayIds(/* includeDisabled= */ false);
211     }
212 
213     /**
214      * Gets all currently valid logical display ids.
215      *
216      * @param includeDisabled True if the returned list of displays includes disabled displays.
217      * @return An array containing all display ids.
218      */
getDisplayIds(boolean includeDisabled)219     public int[] getDisplayIds(boolean includeDisabled) {
220         try {
221             synchronized (mLock) {
222                 if (USE_CACHE) {
223                     if (mDisplayIdCache != null) {
224                         return mDisplayIdCache;
225                     }
226                 }
227 
228                 int[] displayIds = mDm.getDisplayIds(includeDisabled);
229                 if (USE_CACHE) {
230                     mDisplayIdCache = displayIds;
231                 }
232                 registerCallbackIfNeededLocked();
233                 return displayIds;
234             }
235         } catch (RemoteException ex) {
236             throw ex.rethrowFromSystemServer();
237         }
238     }
239 
240     /**
241      * Check if specified UID's content is present on display and should be granted access to it.
242      *
243      * @param uid UID to be checked.
244      * @param displayId id of the display where presence of the content is checked.
245      * @return {@code true} if UID is present on display, {@code false} otherwise.
246      */
isUidPresentOnDisplay(int uid, int displayId)247     public boolean isUidPresentOnDisplay(int uid, int displayId) {
248         try {
249             return mDm.isUidPresentOnDisplay(uid, displayId);
250         } catch (RemoteException ex) {
251             throw ex.rethrowFromSystemServer();
252         }
253     }
254 
255     /**
256      * Gets information about a logical display.
257      *
258      * The display metrics may be adjusted to provide compatibility
259      * for legacy applications or limited screen areas.
260      *
261      * @param displayId The logical display id.
262      * @param daj The compatibility info and activityToken.
263      * @return The display object, or null if there is no display with the given id.
264      */
getCompatibleDisplay(int displayId, DisplayAdjustments daj)265     public Display getCompatibleDisplay(int displayId, DisplayAdjustments daj) {
266         DisplayInfo displayInfo = getDisplayInfo(displayId);
267         if (displayInfo == null) {
268             return null;
269         }
270         return new Display(this, displayId, displayInfo, daj);
271     }
272 
273     /**
274      * Gets information about a logical display.
275      *
276      * The display metrics may be adjusted to provide compatibility
277      * for legacy applications or limited screen areas.
278      *
279      * @param displayId The logical display id.
280      * @param resources Resources providing compatibility info.
281      * @return The display object, or null if there is no display with the given id.
282      */
getCompatibleDisplay(int displayId, Resources resources)283     public Display getCompatibleDisplay(int displayId, Resources resources) {
284         DisplayInfo displayInfo = getDisplayInfo(displayId);
285         if (displayInfo == null) {
286             return null;
287         }
288         return new Display(this, displayId, displayInfo, resources);
289     }
290 
291     /**
292      * Gets information about a logical display without applying any compatibility metrics.
293      *
294      * @param displayId The logical display id.
295      * @return The display object, or null if there is no display with the given id.
296      */
297     @UnsupportedAppUsage
getRealDisplay(int displayId)298     public Display getRealDisplay(int displayId) {
299         return getCompatibleDisplay(displayId, DisplayAdjustments.DEFAULT_DISPLAY_ADJUSTMENTS);
300     }
301 
302     /**
303      * Register a listener for display-related changes.
304      *
305      * @param listener The listener that will be called when display changes occur.
306      * @param handler Handler for the thread that will be receiving the callbacks. May be null.
307      * If null, listener will use the handler for the current thread, and if still null,
308      * the handler for the main thread.
309      * If that is still null, a runtime exception will be thrown.
310      */
registerDisplayListener(@onNull DisplayListener listener, @Nullable Handler handler, @EventsMask long eventsMask)311     public void registerDisplayListener(@NonNull DisplayListener listener,
312             @Nullable Handler handler, @EventsMask long eventsMask) {
313         if (listener == null) {
314             throw new IllegalArgumentException("listener must not be null");
315         }
316 
317         if (eventsMask == 0) {
318             throw new IllegalArgumentException("The set of events to listen to must not be empty.");
319         }
320 
321         synchronized (mLock) {
322             int index = findDisplayListenerLocked(listener);
323             if (index < 0) {
324                 Looper looper = getLooperForHandler(handler);
325                 mDisplayListeners.add(new DisplayListenerDelegate(listener, looper, eventsMask));
326                 registerCallbackIfNeededLocked();
327             } else {
328                 mDisplayListeners.get(index).setEventsMask(eventsMask);
329             }
330             updateCallbackIfNeededLocked();
331         }
332     }
333 
unregisterDisplayListener(DisplayListener listener)334     public void unregisterDisplayListener(DisplayListener listener) {
335         if (listener == null) {
336             throw new IllegalArgumentException("listener must not be null");
337         }
338 
339         synchronized (mLock) {
340             int index = findDisplayListenerLocked(listener);
341             if (index >= 0) {
342                 DisplayListenerDelegate d = mDisplayListeners.get(index);
343                 d.clearEvents();
344                 mDisplayListeners.remove(index);
345                 updateCallbackIfNeededLocked();
346             }
347         }
348     }
349 
getLooperForHandler(@ullable Handler handler)350     private static Looper getLooperForHandler(@Nullable Handler handler) {
351         Looper looper = handler != null ? handler.getLooper() : Looper.myLooper();
352         if (looper == null) {
353             looper = Looper.getMainLooper();
354         }
355         if (looper == null) {
356             throw new RuntimeException("Could not get Looper for the UI thread.");
357         }
358         return looper;
359     }
360 
findDisplayListenerLocked(DisplayListener listener)361     private int findDisplayListenerLocked(DisplayListener listener) {
362         final int numListeners = mDisplayListeners.size();
363         for (int i = 0; i < numListeners; i++) {
364             if (mDisplayListeners.get(i).mListener == listener) {
365                 return i;
366             }
367         }
368         return -1;
369     }
370 
371     @EventsMask
calculateEventsMaskLocked()372     private int calculateEventsMaskLocked() {
373         int mask = 0;
374         final int numListeners = mDisplayListeners.size();
375         for (int i = 0; i < numListeners; i++) {
376             mask |= mDisplayListeners.get(i).mEventsMask;
377         }
378         if (mDispatchNativeCallbacks) {
379             mask |= DisplayManager.EVENT_FLAG_DISPLAY_ADDED
380                     | DisplayManager.EVENT_FLAG_DISPLAY_CHANGED
381                     | DisplayManager.EVENT_FLAG_DISPLAY_REMOVED;
382         }
383         return mask;
384     }
385 
registerCallbackIfNeededLocked()386     private void registerCallbackIfNeededLocked() {
387         if (mCallback == null) {
388             mCallback = new DisplayManagerCallback();
389             updateCallbackIfNeededLocked();
390         }
391     }
392 
updateCallbackIfNeededLocked()393     private void updateCallbackIfNeededLocked() {
394         int mask = calculateEventsMaskLocked();
395         if (mask != mRegisteredEventsMask) {
396             try {
397                 mDm.registerCallbackWithEventMask(mCallback, mask);
398                 mRegisteredEventsMask = mask;
399             } catch (RemoteException ex) {
400                 throw ex.rethrowFromSystemServer();
401             }
402         }
403     }
404 
handleDisplayEvent(int displayId, @DisplayEvent int event)405     private void handleDisplayEvent(int displayId, @DisplayEvent int event) {
406         synchronized (mLock) {
407             if (USE_CACHE) {
408                 mDisplayInfoCache.remove(displayId);
409 
410                 if (event == EVENT_DISPLAY_ADDED || event == EVENT_DISPLAY_REMOVED) {
411                     mDisplayIdCache = null;
412                 }
413             }
414 
415             final int numListeners = mDisplayListeners.size();
416             DisplayInfo info = getDisplayInfo(displayId);
417             for (int i = 0; i < numListeners; i++) {
418                 mDisplayListeners.get(i).sendDisplayEvent(displayId, event, info);
419             }
420             if (event == EVENT_DISPLAY_CHANGED && mDispatchNativeCallbacks) {
421                 // Choreographer only supports a single display, so only dispatch refresh rate
422                 // changes for the default display.
423                 if (displayId == Display.DEFAULT_DISPLAY) {
424                     // We can likely save a binder hop if we attach the refresh rate onto the
425                     // listener.
426                     DisplayInfo display = getDisplayInfoLocked(displayId);
427                     if (display != null
428                             && mNativeCallbackReportedRefreshRate != display.getRefreshRate()) {
429                         mNativeCallbackReportedRefreshRate = display.getRefreshRate();
430                         // Signal native callbacks if we ever set a refresh rate.
431                         nSignalNativeCallbacks(mNativeCallbackReportedRefreshRate);
432                     }
433                 }
434             }
435         }
436     }
437 
startWifiDisplayScan()438     public void startWifiDisplayScan() {
439         synchronized (mLock) {
440             if (mWifiDisplayScanNestCount++ == 0) {
441                 registerCallbackIfNeededLocked();
442                 try {
443                     mDm.startWifiDisplayScan();
444                 } catch (RemoteException ex) {
445                     throw ex.rethrowFromSystemServer();
446                 }
447             }
448         }
449     }
450 
stopWifiDisplayScan()451     public void stopWifiDisplayScan() {
452         synchronized (mLock) {
453             if (--mWifiDisplayScanNestCount == 0) {
454                 try {
455                     mDm.stopWifiDisplayScan();
456                 } catch (RemoteException ex) {
457                     throw ex.rethrowFromSystemServer();
458                 }
459             } else if (mWifiDisplayScanNestCount < 0) {
460                 Log.wtf(TAG, "Wifi display scan nest count became negative: "
461                         + mWifiDisplayScanNestCount);
462                 mWifiDisplayScanNestCount = 0;
463             }
464         }
465     }
466 
connectWifiDisplay(String deviceAddress)467     public void connectWifiDisplay(String deviceAddress) {
468         if (deviceAddress == null) {
469             throw new IllegalArgumentException("deviceAddress must not be null");
470         }
471 
472         try {
473             mDm.connectWifiDisplay(deviceAddress);
474         } catch (RemoteException ex) {
475             throw ex.rethrowFromSystemServer();
476         }
477     }
478 
pauseWifiDisplay()479     public void pauseWifiDisplay() {
480         try {
481             mDm.pauseWifiDisplay();
482         } catch (RemoteException ex) {
483             throw ex.rethrowFromSystemServer();
484         }
485     }
486 
resumeWifiDisplay()487     public void resumeWifiDisplay() {
488         try {
489             mDm.resumeWifiDisplay();
490         } catch (RemoteException ex) {
491             throw ex.rethrowFromSystemServer();
492         }
493     }
494 
495     @UnsupportedAppUsage
disconnectWifiDisplay()496     public void disconnectWifiDisplay() {
497         try {
498             mDm.disconnectWifiDisplay();
499         } catch (RemoteException ex) {
500             throw ex.rethrowFromSystemServer();
501         }
502     }
503 
renameWifiDisplay(String deviceAddress, String alias)504     public void renameWifiDisplay(String deviceAddress, String alias) {
505         if (deviceAddress == null) {
506             throw new IllegalArgumentException("deviceAddress must not be null");
507         }
508 
509         try {
510             mDm.renameWifiDisplay(deviceAddress, alias);
511         } catch (RemoteException ex) {
512             throw ex.rethrowFromSystemServer();
513         }
514     }
515 
forgetWifiDisplay(String deviceAddress)516     public void forgetWifiDisplay(String deviceAddress) {
517         if (deviceAddress == null) {
518             throw new IllegalArgumentException("deviceAddress must not be null");
519         }
520 
521         try {
522             mDm.forgetWifiDisplay(deviceAddress);
523         } catch (RemoteException ex) {
524             throw ex.rethrowFromSystemServer();
525         }
526     }
527 
528     @UnsupportedAppUsage
getWifiDisplayStatus()529     public WifiDisplayStatus getWifiDisplayStatus() {
530         try {
531             return mDm.getWifiDisplayStatus();
532         } catch (RemoteException ex) {
533             throw ex.rethrowFromSystemServer();
534         }
535     }
536 
537     /**
538      * Sets the HDR types that have been disabled by user.
539      * @param userDisabledHdrTypes the HDR types to disable. The HDR types are any of
540      */
setUserDisabledHdrTypes(@drType int[] userDisabledHdrTypes)541     public void setUserDisabledHdrTypes(@HdrType int[] userDisabledHdrTypes) {
542         try {
543             mDm.setUserDisabledHdrTypes(userDisabledHdrTypes);
544         } catch (RemoteException ex) {
545             throw ex.rethrowFromSystemServer();
546         }
547     }
548 
549     /**
550      * Sets whether or not the user disabled HDR types are returned from
551      * {@link Display#getHdrCapabilities}.
552      *
553      * @param areUserDisabledHdrTypesAllowed If true, the user-disabled
554      * types are ignored and returned, if the display supports them. If
555      * false, the user-disabled types are taken into consideration and
556      * are never returned, even if the display supports them.
557      */
setAreUserDisabledHdrTypesAllowed(boolean areUserDisabledHdrTypesAllowed)558     public void setAreUserDisabledHdrTypesAllowed(boolean areUserDisabledHdrTypesAllowed) {
559         try {
560             mDm.setAreUserDisabledHdrTypesAllowed(areUserDisabledHdrTypesAllowed);
561         } catch (RemoteException ex) {
562             throw ex.rethrowFromSystemServer();
563         }
564     }
565 
566     /**
567      * Returns whether or not the user-disabled HDR types are returned from
568      * {@link Display#getHdrCapabilities}.
569      */
areUserDisabledHdrTypesAllowed()570     public boolean areUserDisabledHdrTypesAllowed() {
571         try {
572             return mDm.areUserDisabledHdrTypesAllowed();
573         } catch (RemoteException ex) {
574             throw ex.rethrowFromSystemServer();
575         }
576     }
577 
578     /**
579      * Returns the HDR formats disabled by the user.
580      *
581      */
getUserDisabledHdrTypes()582     public int[] getUserDisabledHdrTypes() {
583         try {
584             return mDm.getUserDisabledHdrTypes();
585         } catch (RemoteException ex) {
586             throw ex.rethrowFromSystemServer();
587         }
588     }
589 
requestColorMode(int displayId, int colorMode)590     public void requestColorMode(int displayId, int colorMode) {
591         try {
592             mDm.requestColorMode(displayId, colorMode);
593         } catch (RemoteException ex) {
594             throw ex.rethrowFromSystemServer();
595         }
596     }
597 
createVirtualDisplay(@onNull Context context, MediaProjection projection, @NonNull VirtualDisplayConfig virtualDisplayConfig, VirtualDisplay.Callback callback, @Nullable Executor executor, @Nullable Context windowContext)598     public VirtualDisplay createVirtualDisplay(@NonNull Context context, MediaProjection projection,
599             @NonNull VirtualDisplayConfig virtualDisplayConfig, VirtualDisplay.Callback callback,
600             @Nullable Executor executor, @Nullable Context windowContext) {
601         VirtualDisplayCallback callbackWrapper = new VirtualDisplayCallback(callback, executor);
602         IMediaProjection projectionToken = projection != null ? projection.getProjection() : null;
603         int displayId;
604         try {
605             displayId = mDm.createVirtualDisplay(virtualDisplayConfig, callbackWrapper,
606                     projectionToken, context.getPackageName());
607         } catch (RemoteException ex) {
608             throw ex.rethrowFromSystemServer();
609         }
610         return createVirtualDisplayWrapper(virtualDisplayConfig, windowContext, callbackWrapper,
611                 displayId);
612     }
613 
614     /**
615      * Create a VirtualDisplay wrapper object for a newly created virtual display ; to be called
616      * once the display has been created in system_server.
617      */
618     @Nullable
createVirtualDisplayWrapper(VirtualDisplayConfig virtualDisplayConfig, Context windowContext, IVirtualDisplayCallback callbackWrapper, int displayId)619     public VirtualDisplay createVirtualDisplayWrapper(VirtualDisplayConfig virtualDisplayConfig,
620             Context windowContext, IVirtualDisplayCallback callbackWrapper, int displayId) {
621         if (displayId < 0) {
622             Log.e(TAG, "Could not create virtual display: " + virtualDisplayConfig.getName());
623             return null;
624         }
625         Display display = getRealDisplay(displayId);
626         if (display == null) {
627             Log.wtf(TAG, "Could not obtain display info for newly created "
628                     + "virtual display: " + virtualDisplayConfig.getName());
629             try {
630                 mDm.releaseVirtualDisplay(callbackWrapper);
631             } catch (RemoteException ex) {
632                 throw ex.rethrowFromSystemServer();
633             }
634             return null;
635         }
636         return new VirtualDisplay(this, display, callbackWrapper,
637                 virtualDisplayConfig.getSurface(), windowContext);
638     }
639 
setVirtualDisplaySurface(IVirtualDisplayCallback token, Surface surface)640     public void setVirtualDisplaySurface(IVirtualDisplayCallback token, Surface surface) {
641         try {
642             mDm.setVirtualDisplaySurface(token, surface);
643             setVirtualDisplayState(token, surface != null);
644         } catch (RemoteException ex) {
645             throw ex.rethrowFromSystemServer();
646         }
647     }
648 
resizeVirtualDisplay(IVirtualDisplayCallback token, int width, int height, int densityDpi)649     public void resizeVirtualDisplay(IVirtualDisplayCallback token,
650             int width, int height, int densityDpi) {
651         try {
652             mDm.resizeVirtualDisplay(token, width, height, densityDpi);
653         } catch (RemoteException ex) {
654             throw ex.rethrowFromSystemServer();
655         }
656     }
657 
releaseVirtualDisplay(IVirtualDisplayCallback token)658     public void releaseVirtualDisplay(IVirtualDisplayCallback token) {
659         try {
660             mDm.releaseVirtualDisplay(token);
661         } catch (RemoteException ex) {
662             throw ex.rethrowFromSystemServer();
663         }
664     }
665 
setVirtualDisplayState(IVirtualDisplayCallback token, boolean isOn)666     void setVirtualDisplayState(IVirtualDisplayCallback token, boolean isOn) {
667         try {
668             mDm.setVirtualDisplayState(token, isOn);
669         } catch (RemoteException ex) {
670             throw ex.rethrowFromSystemServer();
671         }
672     }
673 
674     /**
675      * Gets the stable device display size, in pixels.
676      */
getStableDisplaySize()677     public Point getStableDisplaySize() {
678         try {
679             return mDm.getStableDisplaySize();
680         } catch (RemoteException ex) {
681             throw ex.rethrowFromSystemServer();
682         }
683     }
684 
685     /**
686      * Retrieves brightness change events.
687      */
getBrightnessEvents(String callingPackage)688     public List<BrightnessChangeEvent> getBrightnessEvents(String callingPackage) {
689         try {
690             ParceledListSlice<BrightnessChangeEvent> events =
691                     mDm.getBrightnessEvents(callingPackage);
692             if (events == null) {
693                 return Collections.emptyList();
694             }
695             return events.getList();
696         } catch (RemoteException ex) {
697             throw ex.rethrowFromSystemServer();
698         }
699     }
700 
701     /**
702      * Retrieves Brightness Info for the specified display.
703      */
getBrightnessInfo(int displayId)704     public BrightnessInfo getBrightnessInfo(int displayId) {
705         try {
706             return mDm.getBrightnessInfo(displayId);
707         } catch (RemoteException ex) {
708             throw ex.rethrowFromSystemServer();
709         }
710     }
711 
712     /**
713      * Gets the preferred wide gamut color space for all displays.
714      * The wide gamut color space is returned from composition pipeline
715      * based on hardware capability.
716      *
717      * @hide
718      */
getPreferredWideGamutColorSpace()719     public ColorSpace getPreferredWideGamutColorSpace() {
720         return mWideColorSpace;
721     }
722 
723     /**
724      * Sets the global brightness configuration for a given user.
725      *
726      * @hide
727      */
setBrightnessConfigurationForUser(BrightnessConfiguration c, int userId, String packageName)728     public void setBrightnessConfigurationForUser(BrightnessConfiguration c, int userId,
729             String packageName) {
730         try {
731             mDm.setBrightnessConfigurationForUser(c, userId, packageName);
732         } catch (RemoteException ex) {
733             throw ex.rethrowFromSystemServer();
734         }
735     }
736 
737     /**
738      * Sets the brightness configuration for a given display.
739      *
740      * @hide
741      */
setBrightnessConfigurationForDisplay(BrightnessConfiguration c, String uniqueDisplayId, int userId, String packageName)742     public void setBrightnessConfigurationForDisplay(BrightnessConfiguration c,
743             String uniqueDisplayId, int userId, String packageName) {
744         try {
745             mDm.setBrightnessConfigurationForDisplay(c, uniqueDisplayId, userId, packageName);
746         } catch (RemoteException ex) {
747             throw ex.rethrowFromSystemServer();
748         }
749     }
750 
751     /**
752      * Gets the brightness configuration for a given display or null if one hasn't been set.
753      *
754      * @hide
755      */
getBrightnessConfigurationForDisplay(String uniqueDisplayId, int userId)756     public BrightnessConfiguration getBrightnessConfigurationForDisplay(String uniqueDisplayId,
757             int userId) {
758         try {
759             return mDm.getBrightnessConfigurationForDisplay(uniqueDisplayId, userId);
760         } catch (RemoteException ex) {
761             throw ex.rethrowFromSystemServer();
762         }
763     }
764 
765     /**
766      * Gets the global brightness configuration for a given user or null if one hasn't been set.
767      *
768      * @hide
769      */
getBrightnessConfigurationForUser(int userId)770     public BrightnessConfiguration getBrightnessConfigurationForUser(int userId) {
771         try {
772             return mDm.getBrightnessConfigurationForUser(userId);
773         } catch (RemoteException ex) {
774             throw ex.rethrowFromSystemServer();
775         }
776     }
777 
778     /**
779      * Gets the default brightness configuration or null if one hasn't been configured.
780      *
781      * @hide
782      */
getDefaultBrightnessConfiguration()783     public BrightnessConfiguration getDefaultBrightnessConfiguration() {
784         try {
785             return mDm.getDefaultBrightnessConfiguration();
786         } catch (RemoteException ex) {
787             throw ex.rethrowFromSystemServer();
788         }
789     }
790 
791     /**
792      * Gets the last requested minimal post processing setting for the display with displayId.
793      *
794      * @hide
795      */
isMinimalPostProcessingRequested(int displayId)796     public boolean isMinimalPostProcessingRequested(int displayId) {
797         try {
798             return mDm.isMinimalPostProcessingRequested(displayId);
799         } catch (RemoteException ex) {
800             throw ex.rethrowFromSystemServer();
801         }
802     }
803 
804     /**
805      * Temporarily sets the brightness of the display.
806      * <p>
807      * Requires the {@link android.Manifest.permission#CONTROL_DISPLAY_BRIGHTNESS} permission.
808      * </p>
809      *
810      * @param brightness The brightness value from 0.0f to 1.0f.
811      *
812      * @hide Requires signature permission.
813      */
setTemporaryBrightness(int displayId, float brightness)814     public void setTemporaryBrightness(int displayId, float brightness) {
815         try {
816             mDm.setTemporaryBrightness(displayId, brightness);
817         } catch (RemoteException ex) {
818             throw ex.rethrowFromSystemServer();
819         }
820     }
821 
822 
823     /**
824      * Sets the brightness of the display.
825      *
826      * @param brightness The brightness value from 0.0f to 1.0f.
827      *
828      * @hide
829      */
setBrightness(int displayId, float brightness)830     public void setBrightness(int displayId, float brightness) {
831         try {
832             mDm.setBrightness(displayId, brightness);
833         } catch (RemoteException ex) {
834             throw ex.rethrowFromSystemServer();
835         }
836     }
837 
838     /**
839      * Report whether/how the display supports DISPLAY_DECORATION.
840      *
841      * @param displayId The display whose support is being queried.
842      *
843      * @hide
844      */
getDisplayDecorationSupport(int displayId)845     public DisplayDecorationSupport getDisplayDecorationSupport(int displayId) {
846         try {
847             return mDm.getDisplayDecorationSupport(displayId);
848         } catch (RemoteException ex) {
849             throw ex.rethrowFromSystemServer();
850         }
851     }
852 
853     /**
854      * Gets the brightness of the display.
855      *
856      * @param displayId The display from which to get the brightness
857      *
858      * @hide
859      */
getBrightness(int displayId)860     public float getBrightness(int displayId) {
861         try {
862             return mDm.getBrightness(displayId);
863         } catch (RemoteException ex) {
864             throw ex.rethrowFromSystemServer();
865         }
866     }
867 
868     /**
869      * Temporarily sets the auto brightness adjustment factor.
870      * <p>
871      * Requires the {@link android.Manifest.permission#CONTROL_DISPLAY_BRIGHTNESS} permission.
872      * </p>
873      *
874      * @param adjustment The adjustment factor from -1.0 to 1.0.
875      *
876      * @hide Requires signature permission.
877      */
setTemporaryAutoBrightnessAdjustment(float adjustment)878     public void setTemporaryAutoBrightnessAdjustment(float adjustment) {
879         try {
880             mDm.setTemporaryAutoBrightnessAdjustment(adjustment);
881         } catch (RemoteException ex) {
882             throw ex.rethrowFromSystemServer();
883         }
884     }
885 
886     /**
887      * Returns the minimum brightness curve, which guarantess that any brightness curve that dips
888      * below it is rejected by the system.
889      * This prevent auto-brightness from setting the screen so dark as to prevent the user from
890      * resetting or disabling it, and maps lux to the absolute minimum nits that are still readable
891      * in that ambient brightness.
892      *
893      * @return The minimum brightness curve (as lux values and their corresponding nits values).
894      */
getMinimumBrightnessCurve()895     public Pair<float[], float[]> getMinimumBrightnessCurve() {
896         try {
897             Curve curve = mDm.getMinimumBrightnessCurve();
898             return Pair.create(curve.getX(), curve.getY());
899         } catch (RemoteException ex) {
900             throw ex.rethrowFromSystemServer();
901         }
902     }
903 
904     /**
905      * Retrieves ambient brightness stats.
906      */
getAmbientBrightnessStats()907     public List<AmbientBrightnessDayStats> getAmbientBrightnessStats() {
908         try {
909             ParceledListSlice<AmbientBrightnessDayStats> stats = mDm.getAmbientBrightnessStats();
910             if (stats == null) {
911                 return Collections.emptyList();
912             }
913             return stats.getList();
914         } catch (RemoteException ex) {
915             throw ex.rethrowFromSystemServer();
916         }
917     }
918 
919     /**
920      * Sets the default display mode, according to the refresh rate and the resolution chosen by the
921      * user.
922      */
setUserPreferredDisplayMode(int displayId, Display.Mode mode)923     public void setUserPreferredDisplayMode(int displayId, Display.Mode mode) {
924         try {
925             mDm.setUserPreferredDisplayMode(displayId, mode);
926         } catch (RemoteException ex) {
927             throw ex.rethrowFromSystemServer();
928         }
929     }
930 
931     /**
932      * Returns the user preferred display mode.
933      */
getUserPreferredDisplayMode(int displayId)934     public Display.Mode getUserPreferredDisplayMode(int displayId) {
935         try {
936             return mDm.getUserPreferredDisplayMode(displayId);
937         } catch (RemoteException ex) {
938             throw ex.rethrowFromSystemServer();
939         }
940     }
941 
942     /**
943      * Returns the system preferred display mode.
944      */
getSystemPreferredDisplayMode(int displayId)945     public Display.Mode getSystemPreferredDisplayMode(int displayId) {
946         try {
947             return mDm.getSystemPreferredDisplayMode(displayId);
948         } catch (RemoteException ex) {
949             throw ex.rethrowFromSystemServer();
950         }
951     }
952 
953     /**
954      * When enabled the app requested display resolution and refresh rate is always selected
955      * in DisplayModeDirector regardless of user settings and policies for low brightness, low
956      * battery etc.
957      */
setShouldAlwaysRespectAppRequestedMode(boolean enabled)958     public void setShouldAlwaysRespectAppRequestedMode(boolean enabled) {
959         try {
960             mDm.setShouldAlwaysRespectAppRequestedMode(enabled);
961         } catch (RemoteException ex) {
962             throw ex.rethrowFromSystemServer();
963         }
964     }
965 
966     /**
967      * Returns whether DisplayModeDirector is running in a mode which always selects the app
968      * requested display mode and ignores user settings and policies for low brightness, low
969      * battery etc.
970      */
shouldAlwaysRespectAppRequestedMode()971     public boolean shouldAlwaysRespectAppRequestedMode() {
972         try {
973             return mDm.shouldAlwaysRespectAppRequestedMode();
974         } catch (RemoteException ex) {
975             throw ex.rethrowFromSystemServer();
976         }
977     }
978 
979     /**
980      * Sets the refresh rate switching type.
981      *
982      * @hide
983      */
setRefreshRateSwitchingType(@isplayManager.SwitchingType int newValue)984     public void setRefreshRateSwitchingType(@DisplayManager.SwitchingType int newValue) {
985         try {
986             mDm.setRefreshRateSwitchingType(newValue);
987         } catch (RemoteException ex) {
988             throw ex.rethrowFromSystemServer();
989         }
990     }
991 
992     /**
993      * Returns the refresh rate switching type.
994      *
995      * @hide
996      */
997     @DisplayManager.SwitchingType
getRefreshRateSwitchingType()998     public int getRefreshRateSwitchingType() {
999         try {
1000             return mDm.getRefreshRateSwitchingType();
1001         } catch (RemoteException ex) {
1002             throw ex.rethrowFromSystemServer();
1003         }
1004     }
1005 
1006     private final class DisplayManagerCallback extends IDisplayManagerCallback.Stub {
1007         @Override
onDisplayEvent(int displayId, @DisplayEvent int event)1008         public void onDisplayEvent(int displayId, @DisplayEvent int event) {
1009             if (DEBUG) {
1010                 Log.d(TAG, "onDisplayEvent: displayId=" + displayId + ", event=" + eventToString(
1011                         event));
1012             }
1013             handleDisplayEvent(displayId, event);
1014         }
1015     }
1016 
1017     private static final class DisplayListenerDelegate extends Handler {
1018         public final DisplayListener mListener;
1019         public volatile long mEventsMask;
1020 
1021         private final DisplayInfo mDisplayInfo = new DisplayInfo();
1022 
DisplayListenerDelegate(DisplayListener listener, @NonNull Looper looper, @EventsMask long eventsMask)1023         DisplayListenerDelegate(DisplayListener listener, @NonNull Looper looper,
1024                 @EventsMask long eventsMask) {
1025             super(looper, null, true /*async*/);
1026             mListener = listener;
1027             mEventsMask = eventsMask;
1028         }
1029 
sendDisplayEvent(int displayId, @DisplayEvent int event, DisplayInfo info)1030         public void sendDisplayEvent(int displayId, @DisplayEvent int event, DisplayInfo info) {
1031             Message msg = obtainMessage(event, displayId, 0, info);
1032             sendMessage(msg);
1033         }
1034 
clearEvents()1035         public void clearEvents() {
1036             removeCallbacksAndMessages(null);
1037         }
1038 
setEventsMask(@ventsMask long newEventsMask)1039         public void setEventsMask(@EventsMask long newEventsMask) {
1040             mEventsMask = newEventsMask;
1041         }
1042 
1043         @Override
handleMessage(Message msg)1044         public void handleMessage(Message msg) {
1045             if (DEBUG) {
1046                 Trace.beginSection(
1047                         "DisplayListenerDelegate(" + eventToString(msg.what)
1048                                 + ", display=" + msg.arg1
1049                                 + ", listener=" + mListener.getClass() + ")");
1050             }
1051             switch (msg.what) {
1052                 case EVENT_DISPLAY_ADDED:
1053                     if ((mEventsMask & DisplayManager.EVENT_FLAG_DISPLAY_ADDED) != 0) {
1054                         mListener.onDisplayAdded(msg.arg1);
1055                     }
1056                     break;
1057                 case EVENT_DISPLAY_CHANGED:
1058                     if ((mEventsMask & DisplayManager.EVENT_FLAG_DISPLAY_CHANGED) != 0) {
1059                         DisplayInfo newInfo = (DisplayInfo) msg.obj;
1060                         if (newInfo != null && !newInfo.equals(mDisplayInfo)) {
1061                             mDisplayInfo.copyFrom(newInfo);
1062                             mListener.onDisplayChanged(msg.arg1);
1063                         }
1064                     }
1065                     break;
1066                 case EVENT_DISPLAY_BRIGHTNESS_CHANGED:
1067                     if ((mEventsMask & DisplayManager.EVENT_FLAG_DISPLAY_BRIGHTNESS) != 0) {
1068                         mListener.onDisplayChanged(msg.arg1);
1069                     }
1070                     break;
1071                 case EVENT_DISPLAY_REMOVED:
1072                     if ((mEventsMask & DisplayManager.EVENT_FLAG_DISPLAY_REMOVED) != 0) {
1073                         mListener.onDisplayRemoved(msg.arg1);
1074                     }
1075                     break;
1076             }
1077             if (DEBUG) {
1078                 Trace.endSection();
1079             }
1080         }
1081     }
1082 
1083     /**
1084      * Assists in dispatching VirtualDisplay lifecycle event callbacks on a given Executor.
1085      */
1086     public static final class VirtualDisplayCallback extends IVirtualDisplayCallback.Stub {
1087         @Nullable private final VirtualDisplay.Callback mCallback;
1088         @Nullable private final Executor mExecutor;
1089 
1090         /**
1091          * Creates a virtual display callback.
1092          *
1093          * @param callback The callback to call for virtual display events, or {@code null} if the
1094          * caller does not wish to receive callback events.
1095          * @param executor The executor to call the {@code callback} on. Must not be {@code null} if
1096          * the callback is not {@code null}.
1097          */
VirtualDisplayCallback(VirtualDisplay.Callback callback, Executor executor)1098         public VirtualDisplayCallback(VirtualDisplay.Callback callback, Executor executor) {
1099             mCallback = callback;
1100             mExecutor = mCallback != null ? Objects.requireNonNull(executor) : null;
1101         }
1102 
1103         // These methods are called from the binder thread, but the AIDL is oneway, so it should be
1104         // safe to call the callback on arbitrary executors directly without risking blocking
1105         // the system.
1106 
1107         @Override // Binder call
onPaused()1108         public void onPaused() {
1109             if (mCallback != null) {
1110                 mExecutor.execute(mCallback::onPaused);
1111             }
1112         }
1113 
1114         @Override // Binder call
onResumed()1115         public void onResumed() {
1116             if (mCallback != null) {
1117                 mExecutor.execute(mCallback::onResumed);
1118             }
1119         }
1120 
1121         @Override // Binder call
onStopped()1122         public void onStopped() {
1123             if (mCallback != null) {
1124                 mExecutor.execute(mCallback::onStopped);
1125             }
1126         }
1127     }
1128 
1129     /**
1130      * Name of the property containing a unique token which changes every time we update the
1131      * system's display configuration.
1132      */
1133     public static final String CACHE_KEY_DISPLAY_INFO_PROPERTY =
1134             "cache_key.display_info";
1135 
1136     /**
1137      * Invalidates the contents of the display info cache for all applications. Can only
1138      * be called by system_server.
1139      */
invalidateLocalDisplayInfoCaches()1140     public static void invalidateLocalDisplayInfoCaches() {
1141         PropertyInvalidatedCache.invalidateCache(CACHE_KEY_DISPLAY_INFO_PROPERTY);
1142     }
1143 
1144     /**
1145      * Disables the binder call cache.
1146      */
disableLocalDisplayInfoCaches()1147     public void disableLocalDisplayInfoCaches() {
1148         mDisplayCache = null;
1149     }
1150 
nSignalNativeCallbacks(float refreshRate)1151     private static native void nSignalNativeCallbacks(float refreshRate);
1152 
1153     /**
1154      * Called from AChoreographer via JNI.
1155      * Registers AChoreographer so that refresh rate callbacks can be dispatched from DMS.
1156      * Public for unit testing to be able to call this method.
1157      */
1158     @VisibleForTesting
registerNativeChoreographerForRefreshRateCallbacks()1159     public void registerNativeChoreographerForRefreshRateCallbacks() {
1160         synchronized (mLock) {
1161             mDispatchNativeCallbacks = true;
1162             registerCallbackIfNeededLocked();
1163             updateCallbackIfNeededLocked();
1164             DisplayInfo display = getDisplayInfoLocked(Display.DEFAULT_DISPLAY);
1165             if (display != null) {
1166                 // We need to tell AChoreographer instances the current refresh rate so that apps
1167                 // can get it for free once a callback first registers.
1168                 mNativeCallbackReportedRefreshRate = display.getRefreshRate();
1169                 nSignalNativeCallbacks(mNativeCallbackReportedRefreshRate);
1170             }
1171         }
1172     }
1173 
1174     /**
1175      * Called from AChoreographer via JNI.
1176      * Unregisters AChoreographer from receiving refresh rate callbacks.
1177      * Public for unit testing to be able to call this method.
1178      */
1179     @VisibleForTesting
unregisterNativeChoreographerForRefreshRateCallbacks()1180     public void unregisterNativeChoreographerForRefreshRateCallbacks() {
1181         synchronized (mLock) {
1182             mDispatchNativeCallbacks = false;
1183             updateCallbackIfNeededLocked();
1184         }
1185     }
1186 
eventToString(@isplayEvent int event)1187     private static String eventToString(@DisplayEvent int event) {
1188         switch (event) {
1189             case EVENT_DISPLAY_ADDED:
1190                 return "ADDED";
1191             case EVENT_DISPLAY_CHANGED:
1192                 return "CHANGED";
1193             case EVENT_DISPLAY_REMOVED:
1194                 return "REMOVED";
1195             case EVENT_DISPLAY_BRIGHTNESS_CHANGED:
1196                 return "BRIGHTNESS_CHANGED";
1197         }
1198         return "UNKNOWN";
1199     }
1200 }
1201