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