• 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.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         return mask;
365     }
366 
registerCallbackIfNeededLocked()367     private void registerCallbackIfNeededLocked() {
368         if (mCallback == null) {
369             mCallback = new DisplayManagerCallback();
370             updateCallbackIfNeededLocked();
371         }
372     }
373 
updateCallbackIfNeededLocked()374     private void updateCallbackIfNeededLocked() {
375         int mask = calculateEventsMaskLocked();
376         if (mask != mRegisteredEventsMask) {
377             try {
378                 mDm.registerCallbackWithEventMask(mCallback, mask);
379                 mRegisteredEventsMask = mask;
380             } catch (RemoteException ex) {
381                 throw ex.rethrowFromSystemServer();
382             }
383         }
384     }
385 
handleDisplayEvent(int displayId, @DisplayEvent int event)386     private void handleDisplayEvent(int displayId, @DisplayEvent int event) {
387         synchronized (mLock) {
388             if (USE_CACHE) {
389                 mDisplayInfoCache.remove(displayId);
390 
391                 if (event == EVENT_DISPLAY_ADDED || event == EVENT_DISPLAY_REMOVED) {
392                     mDisplayIdCache = null;
393                 }
394             }
395 
396             final int numListeners = mDisplayListeners.size();
397             DisplayInfo info = getDisplayInfo(displayId);
398             for (int i = 0; i < numListeners; i++) {
399                 mDisplayListeners.get(i).sendDisplayEvent(displayId, event, info);
400             }
401             if (event == EVENT_DISPLAY_CHANGED && mDispatchNativeCallbacks) {
402                 // Choreographer only supports a single display, so only dispatch refresh rate
403                 // changes for the default display.
404                 if (displayId == Display.DEFAULT_DISPLAY) {
405                     // We can likely save a binder hop if we attach the refresh rate onto the
406                     // listener.
407                     DisplayInfo display = getDisplayInfoLocked(displayId);
408                     if (display != null
409                             && mNativeCallbackReportedRefreshRate != display.getRefreshRate()) {
410                         mNativeCallbackReportedRefreshRate = display.getRefreshRate();
411                         // Signal native callbacks if we ever set a refresh rate.
412                         nSignalNativeCallbacks(mNativeCallbackReportedRefreshRate);
413                     }
414                 }
415             }
416         }
417     }
418 
startWifiDisplayScan()419     public void startWifiDisplayScan() {
420         synchronized (mLock) {
421             if (mWifiDisplayScanNestCount++ == 0) {
422                 registerCallbackIfNeededLocked();
423                 try {
424                     mDm.startWifiDisplayScan();
425                 } catch (RemoteException ex) {
426                     throw ex.rethrowFromSystemServer();
427                 }
428             }
429         }
430     }
431 
stopWifiDisplayScan()432     public void stopWifiDisplayScan() {
433         synchronized (mLock) {
434             if (--mWifiDisplayScanNestCount == 0) {
435                 try {
436                     mDm.stopWifiDisplayScan();
437                 } catch (RemoteException ex) {
438                     throw ex.rethrowFromSystemServer();
439                 }
440             } else if (mWifiDisplayScanNestCount < 0) {
441                 Log.wtf(TAG, "Wifi display scan nest count became negative: "
442                         + mWifiDisplayScanNestCount);
443                 mWifiDisplayScanNestCount = 0;
444             }
445         }
446     }
447 
connectWifiDisplay(String deviceAddress)448     public void connectWifiDisplay(String deviceAddress) {
449         if (deviceAddress == null) {
450             throw new IllegalArgumentException("deviceAddress must not be null");
451         }
452 
453         try {
454             mDm.connectWifiDisplay(deviceAddress);
455         } catch (RemoteException ex) {
456             throw ex.rethrowFromSystemServer();
457         }
458     }
459 
pauseWifiDisplay()460     public void pauseWifiDisplay() {
461         try {
462             mDm.pauseWifiDisplay();
463         } catch (RemoteException ex) {
464             throw ex.rethrowFromSystemServer();
465         }
466     }
467 
resumeWifiDisplay()468     public void resumeWifiDisplay() {
469         try {
470             mDm.resumeWifiDisplay();
471         } catch (RemoteException ex) {
472             throw ex.rethrowFromSystemServer();
473         }
474     }
475 
476     @UnsupportedAppUsage
disconnectWifiDisplay()477     public void disconnectWifiDisplay() {
478         try {
479             mDm.disconnectWifiDisplay();
480         } catch (RemoteException ex) {
481             throw ex.rethrowFromSystemServer();
482         }
483     }
484 
renameWifiDisplay(String deviceAddress, String alias)485     public void renameWifiDisplay(String deviceAddress, String alias) {
486         if (deviceAddress == null) {
487             throw new IllegalArgumentException("deviceAddress must not be null");
488         }
489 
490         try {
491             mDm.renameWifiDisplay(deviceAddress, alias);
492         } catch (RemoteException ex) {
493             throw ex.rethrowFromSystemServer();
494         }
495     }
496 
forgetWifiDisplay(String deviceAddress)497     public void forgetWifiDisplay(String deviceAddress) {
498         if (deviceAddress == null) {
499             throw new IllegalArgumentException("deviceAddress must not be null");
500         }
501 
502         try {
503             mDm.forgetWifiDisplay(deviceAddress);
504         } catch (RemoteException ex) {
505             throw ex.rethrowFromSystemServer();
506         }
507     }
508 
509     @UnsupportedAppUsage
getWifiDisplayStatus()510     public WifiDisplayStatus getWifiDisplayStatus() {
511         try {
512             return mDm.getWifiDisplayStatus();
513         } catch (RemoteException ex) {
514             throw ex.rethrowFromSystemServer();
515         }
516     }
517 
518     /**
519      * Sets the HDR types that have been disabled by user.
520      * @param userDisabledHdrTypes the HDR types to disable. The HDR types are any of
521      */
setUserDisabledHdrTypes(@drType int[] userDisabledHdrTypes)522     public void setUserDisabledHdrTypes(@HdrType int[] userDisabledHdrTypes) {
523         try {
524             mDm.setUserDisabledHdrTypes(userDisabledHdrTypes);
525         } catch (RemoteException ex) {
526             throw ex.rethrowFromSystemServer();
527         }
528     }
529 
530     /**
531      * Sets whether or not the user disabled HDR types are returned from
532      * {@link Display#getHdrCapabilities}.
533      *
534      * @param areUserDisabledHdrTypesAllowed If true, the user-disabled
535      * types are ignored and returned, if the display supports them. If
536      * false, the user-disabled types are taken into consideration and
537      * are never returned, even if the display supports them.
538      */
setAreUserDisabledHdrTypesAllowed(boolean areUserDisabledHdrTypesAllowed)539     public void setAreUserDisabledHdrTypesAllowed(boolean areUserDisabledHdrTypesAllowed) {
540         try {
541             mDm.setAreUserDisabledHdrTypesAllowed(areUserDisabledHdrTypesAllowed);
542         } catch (RemoteException ex) {
543             throw ex.rethrowFromSystemServer();
544         }
545     }
546 
547     /**
548      * Returns whether or not the user-disabled HDR types are returned from
549      * {@link Display#getHdrCapabilities}.
550      */
areUserDisabledHdrTypesAllowed()551     public boolean areUserDisabledHdrTypesAllowed() {
552         try {
553             return mDm.areUserDisabledHdrTypesAllowed();
554         } catch (RemoteException ex) {
555             throw ex.rethrowFromSystemServer();
556         }
557     }
558 
559     /**
560      * Returns the HDR formats disabled by the user.
561      *
562      */
getUserDisabledHdrTypes()563     public int[] getUserDisabledHdrTypes() {
564         try {
565             return mDm.getUserDisabledHdrTypes();
566         } catch (RemoteException ex) {
567             throw ex.rethrowFromSystemServer();
568         }
569     }
570 
requestColorMode(int displayId, int colorMode)571     public void requestColorMode(int displayId, int colorMode) {
572         try {
573             mDm.requestColorMode(displayId, colorMode);
574         } catch (RemoteException ex) {
575             throw ex.rethrowFromSystemServer();
576         }
577     }
578 
createVirtualDisplay(@onNull Context context, MediaProjection projection, @NonNull VirtualDisplayConfig virtualDisplayConfig, VirtualDisplay.Callback callback, Handler handler)579     public VirtualDisplay createVirtualDisplay(@NonNull Context context, MediaProjection projection,
580             @NonNull VirtualDisplayConfig virtualDisplayConfig, VirtualDisplay.Callback callback,
581             Handler handler) {
582         VirtualDisplayCallback callbackWrapper = new VirtualDisplayCallback(callback, handler);
583         IMediaProjection projectionToken = projection != null ? projection.getProjection() : null;
584         int displayId;
585         try {
586             displayId = mDm.createVirtualDisplay(virtualDisplayConfig, callbackWrapper,
587                     projectionToken, context.getPackageName());
588         } catch (RemoteException ex) {
589             throw ex.rethrowFromSystemServer();
590         }
591         if (displayId < 0) {
592             Log.e(TAG, "Could not create virtual display: " + virtualDisplayConfig.getName());
593             return null;
594         }
595         Display display = getRealDisplay(displayId);
596         if (display == null) {
597             Log.wtf(TAG, "Could not obtain display info for newly created "
598                     + "virtual display: " + virtualDisplayConfig.getName());
599             try {
600                 mDm.releaseVirtualDisplay(callbackWrapper);
601             } catch (RemoteException ex) {
602                 throw ex.rethrowFromSystemServer();
603             }
604             return null;
605         }
606         return new VirtualDisplay(this, display, callbackWrapper,
607                 virtualDisplayConfig.getSurface());
608     }
609 
setVirtualDisplaySurface(IVirtualDisplayCallback token, Surface surface)610     public void setVirtualDisplaySurface(IVirtualDisplayCallback token, Surface surface) {
611         try {
612             mDm.setVirtualDisplaySurface(token, surface);
613             setVirtualDisplayState(token, surface != null);
614         } catch (RemoteException ex) {
615             throw ex.rethrowFromSystemServer();
616         }
617     }
618 
resizeVirtualDisplay(IVirtualDisplayCallback token, int width, int height, int densityDpi)619     public void resizeVirtualDisplay(IVirtualDisplayCallback token,
620             int width, int height, int densityDpi) {
621         try {
622             mDm.resizeVirtualDisplay(token, width, height, densityDpi);
623         } catch (RemoteException ex) {
624             throw ex.rethrowFromSystemServer();
625         }
626     }
627 
releaseVirtualDisplay(IVirtualDisplayCallback token)628     public void releaseVirtualDisplay(IVirtualDisplayCallback token) {
629         try {
630             mDm.releaseVirtualDisplay(token);
631         } catch (RemoteException ex) {
632             throw ex.rethrowFromSystemServer();
633         }
634     }
635 
setVirtualDisplayState(IVirtualDisplayCallback token, boolean isOn)636     void setVirtualDisplayState(IVirtualDisplayCallback token, boolean isOn) {
637         try {
638             mDm.setVirtualDisplayState(token, isOn);
639         } catch (RemoteException ex) {
640             throw ex.rethrowFromSystemServer();
641         }
642     }
643 
644     /**
645      * Gets the stable device display size, in pixels.
646      */
getStableDisplaySize()647     public Point getStableDisplaySize() {
648         try {
649             return mDm.getStableDisplaySize();
650         } catch (RemoteException ex) {
651             throw ex.rethrowFromSystemServer();
652         }
653     }
654 
655     /**
656      * Retrieves brightness change events.
657      */
getBrightnessEvents(String callingPackage)658     public List<BrightnessChangeEvent> getBrightnessEvents(String callingPackage) {
659         try {
660             ParceledListSlice<BrightnessChangeEvent> events =
661                     mDm.getBrightnessEvents(callingPackage);
662             if (events == null) {
663                 return Collections.emptyList();
664             }
665             return events.getList();
666         } catch (RemoteException ex) {
667             throw ex.rethrowFromSystemServer();
668         }
669     }
670 
671     /**
672      * Retrieves Brightness Info for the specified display.
673      */
getBrightnessInfo(int displayId)674     public BrightnessInfo getBrightnessInfo(int displayId) {
675         try {
676             return mDm.getBrightnessInfo(displayId);
677         } catch (RemoteException ex) {
678             throw ex.rethrowFromSystemServer();
679         }
680     }
681 
682     /**
683      * Gets the preferred wide gamut color space for all displays.
684      * The wide gamut color space is returned from composition pipeline
685      * based on hardware capability.
686      *
687      * @hide
688      */
getPreferredWideGamutColorSpace()689     public ColorSpace getPreferredWideGamutColorSpace() {
690         return mWideColorSpace;
691     }
692 
693     /**
694      * Sets the global brightness configuration for a given user.
695      *
696      * @hide
697      */
setBrightnessConfigurationForUser(BrightnessConfiguration c, int userId, String packageName)698     public void setBrightnessConfigurationForUser(BrightnessConfiguration c, int userId,
699             String packageName) {
700         try {
701             mDm.setBrightnessConfigurationForUser(c, userId, packageName);
702         } catch (RemoteException ex) {
703             throw ex.rethrowFromSystemServer();
704         }
705     }
706 
707     /**
708      * Gets the global brightness configuration for a given user or null if one hasn't been set.
709      *
710      * @hide
711      */
getBrightnessConfigurationForUser(int userId)712     public BrightnessConfiguration getBrightnessConfigurationForUser(int userId) {
713         try {
714             return mDm.getBrightnessConfigurationForUser(userId);
715         } catch (RemoteException ex) {
716             throw ex.rethrowFromSystemServer();
717         }
718     }
719 
720     /**
721      * Gets the default brightness configuration or null if one hasn't been configured.
722      *
723      * @hide
724      */
getDefaultBrightnessConfiguration()725     public BrightnessConfiguration getDefaultBrightnessConfiguration() {
726         try {
727             return mDm.getDefaultBrightnessConfiguration();
728         } catch (RemoteException ex) {
729             throw ex.rethrowFromSystemServer();
730         }
731     }
732 
733     /**
734      * Gets the last requested minimal post processing setting for the display with displayId.
735      *
736      * @hide
737      */
isMinimalPostProcessingRequested(int displayId)738     public boolean isMinimalPostProcessingRequested(int displayId) {
739         try {
740             return mDm.isMinimalPostProcessingRequested(displayId);
741         } catch (RemoteException ex) {
742             throw ex.rethrowFromSystemServer();
743         }
744     }
745 
746     /**
747      * Temporarily sets the brightness of the display.
748      * <p>
749      * Requires the {@link android.Manifest.permission#CONTROL_DISPLAY_BRIGHTNESS} permission.
750      * </p>
751      *
752      * @param brightness The brightness value from 0.0f to 1.0f.
753      *
754      * @hide Requires signature permission.
755      */
setTemporaryBrightness(int displayId, float brightness)756     public void setTemporaryBrightness(int displayId, float brightness) {
757         try {
758             mDm.setTemporaryBrightness(displayId, brightness);
759         } catch (RemoteException ex) {
760             throw ex.rethrowFromSystemServer();
761         }
762     }
763 
764 
765     /**
766      * Sets the brightness of the display.
767      *
768      * @param brightness The brightness value from 0.0f to 1.0f.
769      *
770      * @hide
771      */
setBrightness(int displayId, float brightness)772     public void setBrightness(int displayId, float brightness) {
773         try {
774             mDm.setBrightness(displayId, brightness);
775         } catch (RemoteException ex) {
776             throw ex.rethrowFromSystemServer();
777         }
778     }
779 
780     /**
781      * Gets the brightness of the display.
782      *
783      * @param displayId The display from which to get the brightness
784      *
785      * @hide
786      */
getBrightness(int displayId)787     public float getBrightness(int displayId) {
788         try {
789             return mDm.getBrightness(displayId);
790         } catch (RemoteException ex) {
791             throw ex.rethrowFromSystemServer();
792         }
793     }
794 
795     /**
796      * Temporarily sets the auto brightness adjustment factor.
797      * <p>
798      * Requires the {@link android.Manifest.permission#CONTROL_DISPLAY_BRIGHTNESS} permission.
799      * </p>
800      *
801      * @param adjustment The adjustment factor from -1.0 to 1.0.
802      *
803      * @hide Requires signature permission.
804      */
setTemporaryAutoBrightnessAdjustment(float adjustment)805     public void setTemporaryAutoBrightnessAdjustment(float adjustment) {
806         try {
807             mDm.setTemporaryAutoBrightnessAdjustment(adjustment);
808         } catch (RemoteException ex) {
809             throw ex.rethrowFromSystemServer();
810         }
811     }
812 
813     /**
814      * Returns the minimum brightness curve, which guarantess that any brightness curve that dips
815      * below it is rejected by the system.
816      * This prevent auto-brightness from setting the screen so dark as to prevent the user from
817      * resetting or disabling it, and maps lux to the absolute minimum nits that are still readable
818      * in that ambient brightness.
819      *
820      * @return The minimum brightness curve (as lux values and their corresponding nits values).
821      */
getMinimumBrightnessCurve()822     public Pair<float[], float[]> getMinimumBrightnessCurve() {
823         try {
824             Curve curve = mDm.getMinimumBrightnessCurve();
825             return Pair.create(curve.getX(), curve.getY());
826         } catch (RemoteException ex) {
827             throw ex.rethrowFromSystemServer();
828         }
829     }
830 
831     /**
832      * Retrieves ambient brightness stats.
833      */
getAmbientBrightnessStats()834     public List<AmbientBrightnessDayStats> getAmbientBrightnessStats() {
835         try {
836             ParceledListSlice<AmbientBrightnessDayStats> stats = mDm.getAmbientBrightnessStats();
837             if (stats == null) {
838                 return Collections.emptyList();
839             }
840             return stats.getList();
841         } catch (RemoteException ex) {
842             throw ex.rethrowFromSystemServer();
843         }
844     }
845 
846     /**
847      * When enabled the app requested display resolution and refresh rate is always selected
848      * in DisplayModeDirector regardless of user settings and policies for low brightness, low
849      * battery etc.
850      */
setShouldAlwaysRespectAppRequestedMode(boolean enabled)851     public void setShouldAlwaysRespectAppRequestedMode(boolean enabled) {
852         try {
853             mDm.setShouldAlwaysRespectAppRequestedMode(enabled);
854         } catch (RemoteException ex) {
855             throw ex.rethrowFromSystemServer();
856         }
857     }
858 
859     /**
860      * Returns whether DisplayModeDirector is running in a mode which always selects the app
861      * requested display mode and ignores user settings and policies for low brightness, low
862      * battery etc.
863      */
shouldAlwaysRespectAppRequestedMode()864     public boolean shouldAlwaysRespectAppRequestedMode() {
865         try {
866             return mDm.shouldAlwaysRespectAppRequestedMode();
867         } catch (RemoteException ex) {
868             throw ex.rethrowFromSystemServer();
869         }
870     }
871 
872     /**
873      * Sets the refresh rate switching type.
874      *
875      * @hide
876      */
setRefreshRateSwitchingType(@isplayManager.SwitchingType int newValue)877     public void setRefreshRateSwitchingType(@DisplayManager.SwitchingType int newValue) {
878         try {
879             mDm.setRefreshRateSwitchingType(newValue);
880         } catch (RemoteException ex) {
881             throw ex.rethrowFromSystemServer();
882         }
883     }
884 
885     /**
886      * Returns the refresh rate switching type.
887      *
888      * @hide
889      */
890     @DisplayManager.SwitchingType
getRefreshRateSwitchingType()891     public int getRefreshRateSwitchingType() {
892         try {
893             return mDm.getRefreshRateSwitchingType();
894         } catch (RemoteException ex) {
895             throw ex.rethrowFromSystemServer();
896         }
897     }
898 
899     private final class DisplayManagerCallback extends IDisplayManagerCallback.Stub {
900         @Override
onDisplayEvent(int displayId, @DisplayEvent int event)901         public void onDisplayEvent(int displayId, @DisplayEvent int event) {
902             if (DEBUG) {
903                 Log.d(TAG, "onDisplayEvent: displayId=" + displayId + ", event=" + event);
904             }
905             handleDisplayEvent(displayId, event);
906         }
907     }
908 
909     private static final class DisplayListenerDelegate extends Handler {
910         public final DisplayListener mListener;
911         public long mEventsMask;
912 
913         private final DisplayInfo mDisplayInfo = new DisplayInfo();
914 
DisplayListenerDelegate(DisplayListener listener, @NonNull Looper looper, @EventsMask long eventsMask)915         DisplayListenerDelegate(DisplayListener listener, @NonNull Looper looper,
916                 @EventsMask long eventsMask) {
917             super(looper, null, true /*async*/);
918             mListener = listener;
919             mEventsMask = eventsMask;
920         }
921 
sendDisplayEvent(int displayId, @DisplayEvent int event, DisplayInfo info)922         public void sendDisplayEvent(int displayId, @DisplayEvent int event, DisplayInfo info) {
923             Message msg = obtainMessage(event, displayId, 0, info);
924             sendMessage(msg);
925         }
926 
clearEvents()927         public void clearEvents() {
928             removeCallbacksAndMessages(null);
929         }
930 
setEventsMask(@ventsMask long newEventsMask)931         public synchronized void setEventsMask(@EventsMask long newEventsMask) {
932             mEventsMask = newEventsMask;
933         }
934 
935         @Override
handleMessage(Message msg)936         public synchronized void handleMessage(Message msg) {
937             switch (msg.what) {
938                 case EVENT_DISPLAY_ADDED:
939                     if ((mEventsMask & DisplayManager.EVENT_FLAG_DISPLAY_ADDED) != 0) {
940                         mListener.onDisplayAdded(msg.arg1);
941                     }
942                     break;
943                 case EVENT_DISPLAY_CHANGED:
944                     if ((mEventsMask & DisplayManager.EVENT_FLAG_DISPLAY_CHANGED) != 0) {
945                         DisplayInfo newInfo = (DisplayInfo) msg.obj;
946                         if (newInfo != null && !newInfo.equals(mDisplayInfo)) {
947                             mDisplayInfo.copyFrom(newInfo);
948                             mListener.onDisplayChanged(msg.arg1);
949                         }
950                     }
951                     break;
952                 case EVENT_DISPLAY_BRIGHTNESS_CHANGED:
953                     if ((mEventsMask & DisplayManager.EVENT_FLAG_DISPLAY_BRIGHTNESS) != 0) {
954                         mListener.onDisplayChanged(msg.arg1);
955                     }
956                     break;
957                 case EVENT_DISPLAY_REMOVED:
958                     if ((mEventsMask & DisplayManager.EVENT_FLAG_DISPLAY_REMOVED) != 0) {
959                         mListener.onDisplayRemoved(msg.arg1);
960                     }
961                     break;
962             }
963         }
964     }
965 
966     private final static class VirtualDisplayCallback extends IVirtualDisplayCallback.Stub {
967         private VirtualDisplayCallbackDelegate mDelegate;
968 
VirtualDisplayCallback(VirtualDisplay.Callback callback, Handler handler)969         public VirtualDisplayCallback(VirtualDisplay.Callback callback, Handler handler) {
970             if (callback != null) {
971                 mDelegate = new VirtualDisplayCallbackDelegate(callback, handler);
972             }
973         }
974 
975         @Override // Binder call
onPaused()976         public void onPaused() {
977             if (mDelegate != null) {
978                 mDelegate.sendEmptyMessage(VirtualDisplayCallbackDelegate.MSG_DISPLAY_PAUSED);
979             }
980         }
981 
982         @Override // Binder call
onResumed()983         public void onResumed() {
984             if (mDelegate != null) {
985                 mDelegate.sendEmptyMessage(VirtualDisplayCallbackDelegate.MSG_DISPLAY_RESUMED);
986             }
987         }
988 
989         @Override // Binder call
onStopped()990         public void onStopped() {
991             if (mDelegate != null) {
992                 mDelegate.sendEmptyMessage(VirtualDisplayCallbackDelegate.MSG_DISPLAY_STOPPED);
993             }
994         }
995     }
996 
997     private final static class VirtualDisplayCallbackDelegate extends Handler {
998         public static final int MSG_DISPLAY_PAUSED = 0;
999         public static final int MSG_DISPLAY_RESUMED = 1;
1000         public static final int MSG_DISPLAY_STOPPED = 2;
1001 
1002         private final VirtualDisplay.Callback mCallback;
1003 
VirtualDisplayCallbackDelegate(VirtualDisplay.Callback callback, Handler handler)1004         public VirtualDisplayCallbackDelegate(VirtualDisplay.Callback callback,
1005                 Handler handler) {
1006             super(handler != null ? handler.getLooper() : Looper.myLooper(), null, true /*async*/);
1007             mCallback = callback;
1008         }
1009 
1010         @Override
handleMessage(Message msg)1011         public void handleMessage(Message msg) {
1012             switch (msg.what) {
1013                 case MSG_DISPLAY_PAUSED:
1014                     mCallback.onPaused();
1015                     break;
1016                 case MSG_DISPLAY_RESUMED:
1017                     mCallback.onResumed();
1018                     break;
1019                 case MSG_DISPLAY_STOPPED:
1020                     mCallback.onStopped();
1021                     break;
1022             }
1023         }
1024     }
1025 
1026     /**
1027      * Name of the property containing a unique token which changes every time we update the
1028      * system's display configuration.
1029      */
1030     public static final String CACHE_KEY_DISPLAY_INFO_PROPERTY =
1031             "cache_key.display_info";
1032 
1033     /**
1034      * Invalidates the contents of the display info cache for all applications. Can only
1035      * be called by system_server.
1036      */
invalidateLocalDisplayInfoCaches()1037     public static void invalidateLocalDisplayInfoCaches() {
1038         PropertyInvalidatedCache.invalidateCache(CACHE_KEY_DISPLAY_INFO_PROPERTY);
1039     }
1040 
1041     /**
1042      * Disables the binder call cache.
1043      */
disableLocalDisplayInfoCaches()1044     public void disableLocalDisplayInfoCaches() {
1045         mDisplayCache = null;
1046     }
1047 
nSignalNativeCallbacks(float refreshRate)1048     private static native void nSignalNativeCallbacks(float refreshRate);
1049 
1050     // Called from AChoreographer via JNI.
1051     // Registers AChoreographer so that refresh rate callbacks can be dispatched from DMS.
registerNativeChoreographerForRefreshRateCallbacks()1052     private void registerNativeChoreographerForRefreshRateCallbacks() {
1053         synchronized (mLock) {
1054             registerCallbackIfNeededLocked();
1055             mDispatchNativeCallbacks = true;
1056             DisplayInfo display = getDisplayInfoLocked(Display.DEFAULT_DISPLAY);
1057             if (display != null) {
1058                 // We need to tell AChoreographer instances the current refresh rate so that apps
1059                 // can get it for free once a callback first registers.
1060                 mNativeCallbackReportedRefreshRate = display.getRefreshRate();
1061                 nSignalNativeCallbacks(mNativeCallbackReportedRefreshRate);
1062             }
1063         }
1064     }
1065 
1066     // Called from AChoreographer via JNI.
1067     // Unregisters AChoreographer from receiving refresh rate callbacks.
unregisterNativeChoreographerForRefreshRateCallbacks()1068     private void unregisterNativeChoreographerForRefreshRateCallbacks() {
1069         synchronized (mLock) {
1070             mDispatchNativeCallbacks = false;
1071         }
1072     }
1073 }
1074