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 com.android.server.display;
18 
19 import android.app.ActivityThread;
20 import android.content.Context;
21 import android.content.res.Resources;
22 import android.hardware.sidekick.SidekickInternal;
23 import android.os.Build;
24 import android.os.Handler;
25 import android.os.IBinder;
26 import android.os.Looper;
27 import android.os.PowerManager;
28 import android.os.SystemProperties;
29 import android.os.Trace;
30 import android.util.LongSparseArray;
31 import android.util.Slog;
32 import android.util.SparseArray;
33 import android.view.Display;
34 import android.view.DisplayAddress;
35 import android.view.DisplayCutout;
36 import android.view.DisplayEventReceiver;
37 import android.view.RoundedCorners;
38 import android.view.SurfaceControl;
39 
40 import com.android.internal.annotations.VisibleForTesting;
41 import com.android.internal.display.BrightnessSynchronizer;
42 import com.android.internal.util.function.pooled.PooledLambda;
43 import com.android.server.LocalServices;
44 import com.android.server.lights.LightsManager;
45 import com.android.server.lights.LogicalLight;
46 
47 import java.io.PrintWriter;
48 import java.util.ArrayList;
49 import java.util.Arrays;
50 import java.util.Collections;
51 import java.util.List;
52 import java.util.Objects;
53 
54 /**
55  * A display adapter for the local displays managed by SurfaceFlinger.
56  * <p>
57  * Display adapters are guarded by the {@link DisplayManagerService.SyncRoot} lock.
58  * </p>
59  */
60 final class LocalDisplayAdapter extends DisplayAdapter {
61     private static final String TAG = "LocalDisplayAdapter";
62     private static final boolean DEBUG = false;
63 
64     private static final String UNIQUE_ID_PREFIX = "local:";
65 
66     private static final String PROPERTY_EMULATOR_CIRCULAR = "ro.emulator.circular";
67 
68     private static final int NO_DISPLAY_MODE_ID = 0;
69 
70     private final LongSparseArray<LocalDisplayDevice> mDevices = new LongSparseArray<>();
71 
72     private final Injector mInjector;
73 
74     private final SurfaceControlProxy mSurfaceControlProxy;
75 
76     // Called with SyncRoot lock held.
LocalDisplayAdapter(DisplayManagerService.SyncRoot syncRoot, Context context, Handler handler, Listener listener)77     public LocalDisplayAdapter(DisplayManagerService.SyncRoot syncRoot,
78             Context context, Handler handler, Listener listener) {
79         this(syncRoot, context, handler, listener, new Injector());
80     }
81 
82     @VisibleForTesting
LocalDisplayAdapter(DisplayManagerService.SyncRoot syncRoot, Context context, Handler handler, Listener listener, Injector injector)83     LocalDisplayAdapter(DisplayManagerService.SyncRoot syncRoot,
84             Context context, Handler handler, Listener listener, Injector injector) {
85         super(syncRoot, context, handler, listener, TAG);
86         mInjector = injector;
87         mSurfaceControlProxy = mInjector.getSurfaceControlProxy();
88     }
89 
90     @Override
registerLocked()91     public void registerLocked() {
92         super.registerLocked();
93 
94         mInjector.setDisplayEventListenerLocked(getHandler().getLooper(),
95                 new LocalDisplayEventListener());
96 
97         for (long physicalDisplayId : mSurfaceControlProxy.getPhysicalDisplayIds()) {
98             tryConnectDisplayLocked(physicalDisplayId);
99         }
100     }
101 
tryConnectDisplayLocked(long physicalDisplayId)102     private void tryConnectDisplayLocked(long physicalDisplayId) {
103         final IBinder displayToken =
104                 mSurfaceControlProxy.getPhysicalDisplayToken(physicalDisplayId);
105         if (displayToken != null) {
106             SurfaceControl.StaticDisplayInfo staticInfo =
107                     mSurfaceControlProxy.getStaticDisplayInfo(displayToken);
108             if (staticInfo == null) {
109                 Slog.w(TAG, "No valid static info found for display device " + physicalDisplayId);
110                 return;
111             }
112             SurfaceControl.DynamicDisplayInfo dynamicInfo =
113                     mSurfaceControlProxy.getDynamicDisplayInfo(displayToken);
114             if (dynamicInfo == null) {
115                 Slog.w(TAG, "No valid dynamic info found for display device " + physicalDisplayId);
116                 return;
117             }
118             if (dynamicInfo.supportedDisplayModes == null) {
119                 // There are no valid modes for this device, so we can't use it
120                 Slog.w(TAG, "No valid modes found for display device " + physicalDisplayId);
121                 return;
122             }
123             if (dynamicInfo.activeDisplayModeId < 0) {
124                 // There is no active mode, and for now we don't have the
125                 // policy to set one.
126                 Slog.w(TAG, "No valid active mode found for display device " + physicalDisplayId);
127                 return;
128             }
129             if (dynamicInfo.activeColorMode < 0) {
130                 // We failed to get the active color mode. We don't bail out here since on the next
131                 // configuration pass we'll go ahead and set it to whatever it was set to last (or
132                 // COLOR_MODE_NATIVE if this is the first configuration).
133                 Slog.w(TAG, "No valid active color mode for display device " + physicalDisplayId);
134                 dynamicInfo.activeColorMode = Display.COLOR_MODE_INVALID;
135             }
136             SurfaceControl.DesiredDisplayModeSpecs modeSpecs =
137                     mSurfaceControlProxy.getDesiredDisplayModeSpecs(displayToken);
138             LocalDisplayDevice device = mDevices.get(physicalDisplayId);
139             if (device == null) {
140                 // Display was added.
141                 final boolean isDefaultDisplay = mDevices.size() == 0;
142                 device = new LocalDisplayDevice(displayToken, physicalDisplayId, staticInfo,
143                         dynamicInfo, modeSpecs, isDefaultDisplay);
144                 mDevices.put(physicalDisplayId, device);
145                 sendDisplayDeviceEventLocked(device, DISPLAY_DEVICE_EVENT_ADDED);
146             } else if (device.updateDisplayPropertiesLocked(staticInfo, dynamicInfo,
147                     modeSpecs)) {
148                 sendDisplayDeviceEventLocked(device, DISPLAY_DEVICE_EVENT_CHANGED);
149             }
150         } else {
151             // The display is no longer available. Ignore the attempt to add it.
152             // If it was connected but has already been disconnected, we'll get a
153             // disconnect event that will remove it from mDevices.
154         }
155     }
156 
tryDisconnectDisplayLocked(long physicalDisplayId)157     private void tryDisconnectDisplayLocked(long physicalDisplayId) {
158         LocalDisplayDevice device = mDevices.get(physicalDisplayId);
159         if (device != null) {
160             // Display was removed.
161             mDevices.remove(physicalDisplayId);
162             sendDisplayDeviceEventLocked(device, DISPLAY_DEVICE_EVENT_REMOVED);
163         }
164     }
165 
getPowerModeForState(int state)166     static int getPowerModeForState(int state) {
167         switch (state) {
168             case Display.STATE_OFF:
169                 return SurfaceControl.POWER_MODE_OFF;
170             case Display.STATE_DOZE:
171                 return SurfaceControl.POWER_MODE_DOZE;
172             case Display.STATE_DOZE_SUSPEND:
173                 return SurfaceControl.POWER_MODE_DOZE_SUSPEND;
174             case Display.STATE_ON_SUSPEND:
175                 return SurfaceControl.POWER_MODE_ON_SUSPEND;
176             default:
177                 return SurfaceControl.POWER_MODE_NORMAL;
178         }
179     }
180 
181     private final class LocalDisplayDevice extends DisplayDevice {
182         private final long mPhysicalDisplayId;
183         private final SparseArray<DisplayModeRecord> mSupportedModes = new SparseArray<>();
184         private final ArrayList<Integer> mSupportedColorModes = new ArrayList<>();
185         private final boolean mIsDefaultDisplay;
186         private final BacklightAdapter mBacklightAdapter;
187 
188         private DisplayDeviceInfo mInfo;
189         private boolean mHavePendingChanges;
190         private int mState = Display.STATE_UNKNOWN;
191         // This is only set in the runnable returned from requestDisplayStateLocked.
192         private float mBrightnessState = PowerManager.BRIGHTNESS_INVALID_FLOAT;
193         private float mSdrBrightnessState = PowerManager.BRIGHTNESS_INVALID_FLOAT;
194         private int mDefaultModeId;
195         private int mDefaultModeGroup;
196         private int mActiveModeId;
197         private DisplayModeDirector.DesiredDisplayModeSpecs mDisplayModeSpecs =
198                 new DisplayModeDirector.DesiredDisplayModeSpecs();
199         private boolean mDisplayModeSpecsInvalid;
200         private int mActiveColorMode;
201         private Display.HdrCapabilities mHdrCapabilities;
202         private boolean mAllmSupported;
203         private boolean mGameContentTypeSupported;
204         private boolean mAllmRequested;
205         private boolean mGameContentTypeRequested;
206         private boolean mSidekickActive;
207         private SidekickInternal mSidekickInternal;
208         private SurfaceControl.StaticDisplayInfo mStaticDisplayInfo;
209         // The supported display modes according in SurfaceFlinger
210         private SurfaceControl.DisplayMode[] mSfDisplayModes;
211         // The active display mode in SurfaceFlinger
212         private SurfaceControl.DisplayMode mActiveSfDisplayMode;
213         private DisplayDeviceConfig mDisplayDeviceConfig;
214 
215         private DisplayEventReceiver.FrameRateOverride[] mFrameRateOverrides =
216                 new DisplayEventReceiver.FrameRateOverride[0];
217 
LocalDisplayDevice(IBinder displayToken, long physicalDisplayId, SurfaceControl.StaticDisplayInfo staticDisplayInfo, SurfaceControl.DynamicDisplayInfo dynamicInfo, SurfaceControl.DesiredDisplayModeSpecs modeSpecs, boolean isDefaultDisplay)218         LocalDisplayDevice(IBinder displayToken, long physicalDisplayId,
219                 SurfaceControl.StaticDisplayInfo staticDisplayInfo,
220                 SurfaceControl.DynamicDisplayInfo dynamicInfo,
221                 SurfaceControl.DesiredDisplayModeSpecs modeSpecs, boolean isDefaultDisplay) {
222             super(LocalDisplayAdapter.this, displayToken, UNIQUE_ID_PREFIX + physicalDisplayId,
223                     getContext());
224             mPhysicalDisplayId = physicalDisplayId;
225             mIsDefaultDisplay = isDefaultDisplay;
226             updateDisplayPropertiesLocked(staticDisplayInfo, dynamicInfo, modeSpecs);
227             mSidekickInternal = LocalServices.getService(SidekickInternal.class);
228             mBacklightAdapter = new BacklightAdapter(displayToken, isDefaultDisplay,
229                     mSurfaceControlProxy);
230             mDisplayDeviceConfig = null;
231         }
232 
233         @Override
hasStableUniqueId()234         public boolean hasStableUniqueId() {
235             return true;
236         }
237 
238         /**
239          * Returns true if there is a change.
240          **/
updateDisplayPropertiesLocked(SurfaceControl.StaticDisplayInfo staticInfo, SurfaceControl.DynamicDisplayInfo dynamicInfo, SurfaceControl.DesiredDisplayModeSpecs modeSpecs)241         public boolean updateDisplayPropertiesLocked(SurfaceControl.StaticDisplayInfo staticInfo,
242                 SurfaceControl.DynamicDisplayInfo dynamicInfo,
243                 SurfaceControl.DesiredDisplayModeSpecs modeSpecs) {
244             boolean changed = updateDisplayModesLocked(
245                     dynamicInfo.supportedDisplayModes, dynamicInfo.activeDisplayModeId, modeSpecs);
246             changed |= updateStaticInfo(staticInfo);
247             changed |= updateColorModesLocked(dynamicInfo.supportedColorModes,
248                     dynamicInfo.activeColorMode);
249             changed |= updateHdrCapabilitiesLocked(dynamicInfo.hdrCapabilities);
250             changed |= updateAllmSupport(dynamicInfo.autoLowLatencyModeSupported);
251             changed |= updateGameContentTypeSupport(dynamicInfo.gameContentTypeSupported);
252 
253             if (changed) {
254                 mHavePendingChanges = true;
255             }
256             return changed;
257         }
258 
updateDisplayModesLocked( SurfaceControl.DisplayMode[] displayModes, int activeDisplayModeId, SurfaceControl.DesiredDisplayModeSpecs modeSpecs)259         public boolean updateDisplayModesLocked(
260                 SurfaceControl.DisplayMode[] displayModes, int activeDisplayModeId,
261                 SurfaceControl.DesiredDisplayModeSpecs modeSpecs) {
262             mSfDisplayModes = Arrays.copyOf(displayModes, displayModes.length);
263             mActiveSfDisplayMode = getModeById(displayModes, activeDisplayModeId);
264 
265             // Build an updated list of all existing modes.
266             ArrayList<DisplayModeRecord> records = new ArrayList<>();
267             boolean modesAdded = false;
268             for (int i = 0; i < displayModes.length; i++) {
269                 SurfaceControl.DisplayMode mode = displayModes[i];
270                 List<Float> alternativeRefreshRates = new ArrayList<>();
271                 for (int j = 0; j < displayModes.length; j++) {
272                     SurfaceControl.DisplayMode other = displayModes[j];
273                     boolean isAlternative = j != i && other.width == mode.width
274                             && other.height == mode.height
275                             && other.refreshRate != mode.refreshRate
276                             && other.group == mode.group;
277                     if (isAlternative) {
278                         alternativeRefreshRates.add(displayModes[j].refreshRate);
279                     }
280                 }
281                 Collections.sort(alternativeRefreshRates);
282 
283                 // First, check to see if we've already added a matching mode. Since not all
284                 // configuration options are exposed via Display.Mode, it's possible that we have
285                 // multiple DisplayModes that would generate the same Display.Mode.
286                 boolean existingMode = false;
287                 for (DisplayModeRecord record : records) {
288                     if (record.hasMatchingMode(mode)
289                             && refreshRatesEquals(alternativeRefreshRates,
290                                     record.mMode.getAlternativeRefreshRates())) {
291                         existingMode = true;
292                         break;
293                     }
294                 }
295                 if (existingMode) {
296                     continue;
297                 }
298                 // If we haven't already added a mode for this configuration to the new set of
299                 // supported modes then check to see if we have one in the prior set of supported
300                 // modes to reuse.
301                 DisplayModeRecord record = findDisplayModeRecord(mode, alternativeRefreshRates);
302                 if (record == null) {
303                     float[] alternativeRates = new float[alternativeRefreshRates.size()];
304                     for (int j = 0; j < alternativeRates.length; j++) {
305                         alternativeRates[j] = alternativeRefreshRates.get(j);
306                     }
307                     record = new DisplayModeRecord(mode, alternativeRates);
308                     modesAdded = true;
309                 }
310                 records.add(record);
311             }
312 
313             // Get the currently active mode
314             DisplayModeRecord activeRecord = null;
315             for (DisplayModeRecord record : records) {
316                 if (record.hasMatchingMode(mActiveSfDisplayMode)) {
317                     activeRecord = record;
318                     break;
319                 }
320             }
321 
322             boolean activeModeChanged = false;
323 
324             // Check whether SurfaceFlinger or the display device changed the active mode out from
325             // under us.
326             if (mActiveModeId != NO_DISPLAY_MODE_ID
327                     && mActiveModeId != activeRecord.mMode.getModeId()) {
328                 Slog.d(TAG, "The active mode was changed from SurfaceFlinger or the display"
329                         + "device.");
330                 mActiveModeId = activeRecord.mMode.getModeId();
331                 activeModeChanged = true;
332                 sendTraversalRequestLocked();
333             }
334 
335             // Check whether surface flinger spontaneously changed display config specs out from
336             // under us. If so, schedule a traversal to reapply our display config specs.
337             if (mDisplayModeSpecs.baseModeId != NO_DISPLAY_MODE_ID) {
338                 int activeBaseMode = findMatchingModeIdLocked(modeSpecs.defaultMode);
339                 // If we can't map the defaultMode index to a mode, then the physical display
340                 // modes must have changed, and the code below for handling changes to the
341                 // list of available modes will take care of updating display mode specs.
342                 if (activeBaseMode == NO_DISPLAY_MODE_ID
343                         || mDisplayModeSpecs.baseModeId != activeBaseMode
344                         || mDisplayModeSpecs.primaryRefreshRateRange.min
345                                 != modeSpecs.primaryRefreshRateMin
346                         || mDisplayModeSpecs.primaryRefreshRateRange.max
347                                 != modeSpecs.primaryRefreshRateMax
348                         || mDisplayModeSpecs.appRequestRefreshRateRange.min
349                                 != modeSpecs.appRequestRefreshRateMin
350                         || mDisplayModeSpecs.appRequestRefreshRateRange.max
351                                 != modeSpecs.appRequestRefreshRateMax) {
352                     mDisplayModeSpecsInvalid = true;
353                     sendTraversalRequestLocked();
354                 }
355             }
356 
357             boolean recordsChanged = records.size() != mSupportedModes.size() || modesAdded;
358             // If the records haven't changed then we're done here.
359             if (!recordsChanged) {
360                 return activeModeChanged;
361             }
362 
363             mSupportedModes.clear();
364             for (DisplayModeRecord record : records) {
365                 mSupportedModes.put(record.mMode.getModeId(), record);
366             }
367 
368             // For a new display, we need to initialize the default mode ID.
369             if (mDefaultModeId == NO_DISPLAY_MODE_ID) {
370                 mDefaultModeId = activeRecord.mMode.getModeId();
371                 mDefaultModeGroup = mActiveSfDisplayMode.group;
372             } else if (modesAdded && activeModeChanged) {
373                 Slog.d(TAG, "New display modes are added and the active mode has changed, "
374                         + "use active mode as default mode.");
375                 mDefaultModeId = activeRecord.mMode.getModeId();
376                 mDefaultModeGroup = mActiveSfDisplayMode.group;
377             } else if (findDisplayModeIdLocked(mDefaultModeId, mDefaultModeGroup) < 0) {
378                 Slog.w(TAG, "Default display mode no longer available, using currently"
379                         + " active mode as default.");
380                 mDefaultModeId = activeRecord.mMode.getModeId();
381                 mDefaultModeGroup = mActiveSfDisplayMode.group;
382             }
383 
384             // Determine whether the display mode specs' base mode is still there.
385             if (mSupportedModes.indexOfKey(mDisplayModeSpecs.baseModeId) < 0) {
386                 if (mDisplayModeSpecs.baseModeId != NO_DISPLAY_MODE_ID) {
387                     Slog.w(TAG,
388                             "DisplayModeSpecs base mode no longer available, using currently"
389                                     + " active mode.");
390                 }
391                 mDisplayModeSpecs.baseModeId = activeRecord.mMode.getModeId();
392                 mDisplayModeSpecsInvalid = true;
393             }
394 
395             // Determine whether the active mode is still there.
396             if (mSupportedModes.indexOfKey(mActiveModeId) < 0) {
397                 if (mActiveModeId != NO_DISPLAY_MODE_ID) {
398                     Slog.w(TAG, "Active display mode no longer available, reverting to default"
399                             + " mode.");
400                 }
401                 mActiveModeId = mDefaultModeId;
402             }
403 
404             // Schedule traversals so that we apply pending changes.
405             sendTraversalRequestLocked();
406             return true;
407         }
408 
409         @Override
getDisplayDeviceConfig()410         public DisplayDeviceConfig getDisplayDeviceConfig() {
411             if (mDisplayDeviceConfig == null) {
412                 loadDisplayDeviceConfig();
413             }
414             return mDisplayDeviceConfig;
415         }
416 
loadDisplayDeviceConfig()417         private void loadDisplayDeviceConfig() {
418             // Load display device config
419             final Context context = getOverlayContext();
420             mDisplayDeviceConfig = DisplayDeviceConfig.create(context, mPhysicalDisplayId,
421                     mIsDefaultDisplay);
422             if (mDisplayDeviceConfig == null) {
423                 return;
424             }
425 
426             // Load brightness HWC quirk
427             mBacklightAdapter.setForceSurfaceControl(mDisplayDeviceConfig.hasQuirk(
428                     DisplayDeviceConfig.QUIRK_CAN_SET_BRIGHTNESS_VIA_HWC));
429         }
430 
updateStaticInfo(SurfaceControl.StaticDisplayInfo info)431         private boolean updateStaticInfo(SurfaceControl.StaticDisplayInfo info) {
432             if (Objects.equals(mStaticDisplayInfo, info)) {
433                 return false;
434             }
435             mStaticDisplayInfo = info;
436             return true;
437         }
438 
updateColorModesLocked(int[] colorModes, int activeColorMode)439         private boolean updateColorModesLocked(int[] colorModes, int activeColorMode) {
440             if (colorModes == null) {
441                 return false;
442             }
443 
444             List<Integer> pendingColorModes = new ArrayList<>();
445             // Build an updated list of all existing color modes.
446             boolean colorModesAdded = false;
447             for (int colorMode : colorModes) {
448                 if (!mSupportedColorModes.contains(colorMode)) {
449                     colorModesAdded = true;
450                 }
451                 pendingColorModes.add(colorMode);
452             }
453 
454             boolean colorModesChanged =
455                     pendingColorModes.size() != mSupportedColorModes.size()
456                     || colorModesAdded;
457 
458             // If the supported color modes haven't changed then we're done here.
459             if (!colorModesChanged) {
460                 return false;
461             }
462 
463             mSupportedColorModes.clear();
464             mSupportedColorModes.addAll(pendingColorModes);
465             Collections.sort(mSupportedColorModes);
466 
467             // Determine whether the active color mode is still there.
468             if (!mSupportedColorModes.contains(mActiveColorMode)) {
469                 if (mActiveColorMode != Display.COLOR_MODE_DEFAULT) {
470                     Slog.w(TAG, "Active color mode no longer available, reverting"
471                             + " to default mode.");
472                     mActiveColorMode = Display.COLOR_MODE_DEFAULT;
473                 } else {
474                     if (!mSupportedColorModes.isEmpty()) {
475                         // This should never happen.
476                         Slog.e(TAG, "Default and active color mode is no longer available!"
477                                 + " Reverting to first available mode.");
478                         mActiveColorMode = mSupportedColorModes.get(0);
479                     } else {
480                         // This should really never happen.
481                         Slog.e(TAG, "No color modes available!");
482                     }
483                 }
484             }
485             return true;
486         }
487 
updateHdrCapabilitiesLocked(Display.HdrCapabilities newHdrCapabilities)488         private boolean updateHdrCapabilitiesLocked(Display.HdrCapabilities newHdrCapabilities) {
489             // If the HDR capabilities haven't changed, then we're done here.
490             if (Objects.equals(mHdrCapabilities, newHdrCapabilities)) {
491                 return false;
492             }
493             mHdrCapabilities = newHdrCapabilities;
494             return true;
495         }
496 
updateAllmSupport(boolean supported)497         private boolean updateAllmSupport(boolean supported) {
498             if (mAllmSupported == supported) {
499                 return false;
500             }
501             mAllmSupported = supported;
502             return true;
503         }
504 
updateGameContentTypeSupport(boolean supported)505         private boolean updateGameContentTypeSupport(boolean supported) {
506             if (mGameContentTypeSupported == supported) {
507                 return false;
508             }
509             mGameContentTypeSupported = supported;
510             return true;
511         }
512 
getModeById(SurfaceControl.DisplayMode[] supportedModes, int modeId)513         private SurfaceControl.DisplayMode getModeById(SurfaceControl.DisplayMode[] supportedModes,
514                 int modeId) {
515             for (SurfaceControl.DisplayMode mode : supportedModes) {
516                 if (mode.id == modeId) {
517                     return mode;
518                 }
519             }
520             Slog.e(TAG, "Can't find display mode with id " + modeId);
521             return null;
522         }
523 
findDisplayModeRecord(SurfaceControl.DisplayMode mode, List<Float> alternativeRefreshRates)524         private DisplayModeRecord findDisplayModeRecord(SurfaceControl.DisplayMode mode,
525                 List<Float> alternativeRefreshRates) {
526             for (int i = 0; i < mSupportedModes.size(); i++) {
527                 DisplayModeRecord record = mSupportedModes.valueAt(i);
528                 if (record.hasMatchingMode(mode)
529                         && refreshRatesEquals(alternativeRefreshRates,
530                                 record.mMode.getAlternativeRefreshRates())) {
531                     return record;
532                 }
533             }
534             return null;
535         }
536 
refreshRatesEquals(List<Float> list, float[] array)537         private boolean refreshRatesEquals(List<Float> list, float[] array) {
538             if (list.size() != array.length) {
539                 return false;
540             }
541             for (int i = 0; i < list.size(); i++) {
542                 if (Float.floatToIntBits(list.get(i)) != Float.floatToIntBits(array[i])) {
543                     return false;
544                 }
545             }
546             return true;
547         }
548 
549         @Override
applyPendingDisplayDeviceInfoChangesLocked()550         public void applyPendingDisplayDeviceInfoChangesLocked() {
551             if (mHavePendingChanges) {
552                 mInfo = null;
553                 mHavePendingChanges = false;
554             }
555         }
556 
557         @Override
getDisplayDeviceInfoLocked()558         public DisplayDeviceInfo getDisplayDeviceInfoLocked() {
559             if (mInfo == null) {
560                 mInfo = new DisplayDeviceInfo();
561                 mInfo.width = mActiveSfDisplayMode.width;
562                 mInfo.height = mActiveSfDisplayMode.height;
563                 mInfo.modeId = mActiveModeId;
564                 mInfo.defaultModeId = mDefaultModeId;
565                 mInfo.supportedModes = getDisplayModes(mSupportedModes);
566                 mInfo.colorMode = mActiveColorMode;
567                 mInfo.allmSupported = mAllmSupported;
568                 mInfo.gameContentTypeSupported = mGameContentTypeSupported;
569                 mInfo.supportedColorModes =
570                         new int[mSupportedColorModes.size()];
571                 for (int i = 0; i < mSupportedColorModes.size(); i++) {
572                     mInfo.supportedColorModes[i] = mSupportedColorModes.get(i);
573                 }
574                 mInfo.hdrCapabilities = mHdrCapabilities;
575                 mInfo.appVsyncOffsetNanos = mActiveSfDisplayMode.appVsyncOffsetNanos;
576                 mInfo.presentationDeadlineNanos = mActiveSfDisplayMode.presentationDeadlineNanos;
577                 mInfo.state = mState;
578                 mInfo.uniqueId = getUniqueId();
579                 final DisplayAddress.Physical physicalAddress =
580                         DisplayAddress.fromPhysicalDisplayId(mPhysicalDisplayId);
581                 mInfo.address = physicalAddress;
582                 mInfo.densityDpi = (int) (mStaticDisplayInfo.density * 160 + 0.5f);
583                 mInfo.xDpi = mActiveSfDisplayMode.xDpi;
584                 mInfo.yDpi = mActiveSfDisplayMode.yDpi;
585                 mInfo.deviceProductInfo = mStaticDisplayInfo.deviceProductInfo;
586 
587                 // Assume that all built-in displays that have secure output (eg. HDCP) also
588                 // support compositing from gralloc protected buffers.
589                 if (mStaticDisplayInfo.secure) {
590                     mInfo.flags = DisplayDeviceInfo.FLAG_SECURE
591                             | DisplayDeviceInfo.FLAG_SUPPORTS_PROTECTED_BUFFERS;
592                 }
593 
594                 final Resources res = getOverlayContext().getResources();
595 
596                 if (mIsDefaultDisplay) {
597                     mInfo.flags |= DisplayDeviceInfo.FLAG_DEFAULT_DISPLAY;
598 
599                     if (res.getBoolean(com.android.internal.R.bool.config_mainBuiltInDisplayIsRound)
600                             || (Build.IS_EMULATOR
601                             && SystemProperties.getBoolean(PROPERTY_EMULATOR_CIRCULAR, false))) {
602                         mInfo.flags |= DisplayDeviceInfo.FLAG_ROUND;
603                     }
604                 } else {
605                     if (!res.getBoolean(
606                                 com.android.internal.R.bool.config_localDisplaysMirrorContent)) {
607                         mInfo.flags |= DisplayDeviceInfo.FLAG_OWN_CONTENT_ONLY;
608                     }
609 
610                     if (isDisplayPrivate(physicalAddress)) {
611                         mInfo.flags |= DisplayDeviceInfo.FLAG_PRIVATE;
612                     }
613                 }
614 
615                 if (DisplayCutout.getMaskBuiltInDisplayCutout(res, mInfo.uniqueId)) {
616                     mInfo.flags |= DisplayDeviceInfo.FLAG_MASK_DISPLAY_CUTOUT;
617                 }
618                 mInfo.displayCutout = DisplayCutout.fromResourcesRectApproximation(res,
619                         mInfo.uniqueId, mInfo.width, mInfo.height);
620 
621                 mInfo.roundedCorners = RoundedCorners.fromResources(
622                         res, mInfo.uniqueId, mInfo.width, mInfo.height);
623 
624                 if (mStaticDisplayInfo.isInternal) {
625                     mInfo.type = Display.TYPE_INTERNAL;
626                     mInfo.touch = DisplayDeviceInfo.TOUCH_INTERNAL;
627                     mInfo.flags |= DisplayDeviceInfo.FLAG_ROTATES_WITH_CONTENT;
628                     mInfo.name = res.getString(
629                             com.android.internal.R.string.display_manager_built_in_display_name);
630                 } else {
631                     mInfo.type = Display.TYPE_EXTERNAL;
632                     mInfo.touch = DisplayDeviceInfo.TOUCH_EXTERNAL;
633                     mInfo.flags |= DisplayDeviceInfo.FLAG_PRESENTATION;
634                     mInfo.name = getContext().getResources().getString(
635                             com.android.internal.R.string.display_manager_hdmi_display_name);
636                 }
637                 mInfo.frameRateOverrides = mFrameRateOverrides;
638 
639                 // The display is trusted since it is created by system.
640                 mInfo.flags |= DisplayDeviceInfo.FLAG_TRUSTED;
641                 mInfo.brightnessMinimum = PowerManager.BRIGHTNESS_MIN;
642                 mInfo.brightnessMaximum = PowerManager.BRIGHTNESS_MAX;
643                 mInfo.brightnessDefault = getDisplayDeviceConfig().getBrightnessDefault();
644             }
645             return mInfo;
646         }
647 
648         @Override
requestDisplayStateLocked(final int state, final float brightnessState, final float sdrBrightnessState)649         public Runnable requestDisplayStateLocked(final int state, final float brightnessState,
650                 final float sdrBrightnessState) {
651             // Assume that the brightness is off if the display is being turned off.
652             assert state != Display.STATE_OFF
653                     || brightnessState == PowerManager.BRIGHTNESS_OFF_FLOAT;
654             final boolean stateChanged = (mState != state);
655             final boolean brightnessChanged = mBrightnessState != brightnessState
656                     || mSdrBrightnessState != sdrBrightnessState;
657             if (stateChanged || brightnessChanged) {
658                 final long physicalDisplayId = mPhysicalDisplayId;
659                 final IBinder token = getDisplayTokenLocked();
660                 final int oldState = mState;
661 
662                 if (stateChanged) {
663                     mState = state;
664                     updateDeviceInfoLocked();
665                 }
666 
667                 // Defer actually setting the display state until after we have exited
668                 // the critical section since it can take hundreds of milliseconds
669                 // to complete.
670                 return new Runnable() {
671                     @Override
672                     public void run() {
673                         // Exit a suspended state before making any changes.
674                         int currentState = oldState;
675                         if (Display.isSuspendedState(oldState)
676                                 || oldState == Display.STATE_UNKNOWN) {
677                             if (!Display.isSuspendedState(state)) {
678                                 setDisplayState(state);
679                                 currentState = state;
680                             } else if (state == Display.STATE_DOZE_SUSPEND
681                                     || oldState == Display.STATE_DOZE_SUSPEND) {
682                                 setDisplayState(Display.STATE_DOZE);
683                                 currentState = Display.STATE_DOZE;
684                             } else if (state == Display.STATE_ON_SUSPEND
685                                     || oldState == Display.STATE_ON_SUSPEND) {
686                                 setDisplayState(Display.STATE_ON);
687                                 currentState = Display.STATE_ON;
688 
689                             // If UNKNOWN, we still want to set the initial display state,
690                             // otherwise, return early.
691                             } else if (oldState != Display.STATE_UNKNOWN) {
692                                 return; // old state and new state is off
693                             }
694                         }
695 
696                         // If the state change was from or to VR, then we need to tell the light
697                         // so that it can apply appropriate VR brightness settings. Also, update the
698                         // brightness so the state is propogated to light.
699                         boolean vrModeChange = false;
700                         if ((state == Display.STATE_VR || currentState == Display.STATE_VR) &&
701                                 currentState != state) {
702                             setVrMode(state == Display.STATE_VR);
703                             vrModeChange = true;
704                         }
705 
706                         // Apply brightness changes given that we are in a non-suspended state.
707                         if (brightnessChanged || vrModeChange) {
708                             setDisplayBrightness(brightnessState, sdrBrightnessState);
709                             mBrightnessState = brightnessState;
710                             mSdrBrightnessState = sdrBrightnessState;
711                         }
712 
713                         // Enter the final desired state, possibly suspended.
714                         if (state != currentState) {
715                             setDisplayState(state);
716                         }
717                     }
718 
719                     private void setVrMode(boolean isVrEnabled) {
720                         if (DEBUG) {
721                             Slog.d(TAG, "setVrMode("
722                                     + "id=" + physicalDisplayId
723                                     + ", state=" + Display.stateToString(state) + ")");
724                         }
725                         mBacklightAdapter.setVrMode(isVrEnabled);
726                     }
727 
728                     private void setDisplayState(int state) {
729                         if (DEBUG) {
730                             Slog.d(TAG, "setDisplayState("
731                                     + "id=" + physicalDisplayId
732                                     + ", state=" + Display.stateToString(state) + ")");
733                         }
734 
735                         // We must tell sidekick to stop controlling the display before we
736                         // can change its power mode, so do that first.
737                         if (mSidekickActive) {
738                             Trace.traceBegin(Trace.TRACE_TAG_POWER,
739                                     "SidekickInternal#endDisplayControl");
740                             try {
741                                 mSidekickInternal.endDisplayControl();
742                             } finally {
743                                 Trace.traceEnd(Trace.TRACE_TAG_POWER);
744                             }
745                             mSidekickActive = false;
746                         }
747                         final int mode = getPowerModeForState(state);
748                         Trace.traceBegin(Trace.TRACE_TAG_POWER, "setDisplayState("
749                                 + "id=" + physicalDisplayId
750                                 + ", state=" + Display.stateToString(state) + ")");
751                         try {
752                             mSurfaceControlProxy.setDisplayPowerMode(token, mode);
753                             Trace.traceCounter(Trace.TRACE_TAG_POWER, "DisplayPowerMode", mode);
754                         } finally {
755                             Trace.traceEnd(Trace.TRACE_TAG_POWER);
756                         }
757                         // If we're entering a suspended (but not OFF) power state and we
758                         // have a sidekick available, tell it now that it can take control.
759                         if (Display.isSuspendedState(state) && state != Display.STATE_OFF
760                                 && mSidekickInternal != null && !mSidekickActive) {
761                             Trace.traceBegin(Trace.TRACE_TAG_POWER,
762                                     "SidekickInternal#startDisplayControl");
763                             try {
764                                 mSidekickActive = mSidekickInternal.startDisplayControl(state);
765                             } finally {
766                                 Trace.traceEnd(Trace.TRACE_TAG_POWER);
767                             }
768                         }
769                     }
770 
771                     private void setDisplayBrightness(float brightnessState,
772                             float sdrBrightnessState) {
773                         // brightnessState includes invalid, off and full range.
774                         if (Float.isNaN(brightnessState) || Float.isNaN(sdrBrightnessState)) {
775                             return;
776                         }
777 
778                         if (DEBUG) {
779                             Slog.d(TAG, "setDisplayBrightness("
780                                     + "id=" + physicalDisplayId
781                                     + ", brightnessState=" + brightnessState
782                                     + ", sdrBrightnessState=" + sdrBrightnessState + ")");
783                         }
784 
785                         Trace.traceBegin(Trace.TRACE_TAG_POWER, "setDisplayBrightness("
786                                 + "id=" + physicalDisplayId + ", brightnessState="
787                                 + brightnessState + ", sdrBrightnessState=" + sdrBrightnessState
788                                 + ")");
789                         try {
790                             final float backlight = brightnessToBacklight(brightnessState);
791                             final float sdrBacklight = brightnessToBacklight(sdrBrightnessState);
792 
793                             final float nits = backlightToNits(backlight);
794                             final float sdrNits = backlightToNits(sdrBacklight);
795 
796                             mBacklightAdapter.setBacklight(sdrBacklight, sdrNits, backlight, nits);
797                             Trace.traceCounter(Trace.TRACE_TAG_POWER,
798                                     "ScreenBrightness",
799                                     BrightnessSynchronizer.brightnessFloatToInt(brightnessState));
800                             Trace.traceCounter(Trace.TRACE_TAG_POWER,
801                                     "SdrScreenBrightness",
802                                     BrightnessSynchronizer.brightnessFloatToInt(
803                                             sdrBrightnessState));
804                         } finally {
805                             Trace.traceEnd(Trace.TRACE_TAG_POWER);
806                         }
807                     }
808 
809                     private float brightnessToBacklight(float brightness) {
810                         if (brightness == PowerManager.BRIGHTNESS_OFF_FLOAT) {
811                             return PowerManager.BRIGHTNESS_OFF_FLOAT;
812                         } else {
813                             return getDisplayDeviceConfig().getBacklightFromBrightness(brightness);
814                         }
815                     }
816 
817                     private float backlightToNits(float backlight) {
818                         return getDisplayDeviceConfig().getNitsFromBacklight(backlight);
819                     }
820                 };
821             }
822             return null;
823         }
824 
825         @Override
setRequestedColorModeLocked(int colorMode)826         public void setRequestedColorModeLocked(int colorMode) {
827             requestColorModeLocked(colorMode);
828         }
829 
830         @Override
setDesiredDisplayModeSpecsLocked( DisplayModeDirector.DesiredDisplayModeSpecs displayModeSpecs)831         public void setDesiredDisplayModeSpecsLocked(
832                 DisplayModeDirector.DesiredDisplayModeSpecs displayModeSpecs) {
833             if (displayModeSpecs.baseModeId == 0) {
834                 // Bail if the caller is requesting a null mode. We'll get called again shortly with
835                 // a valid mode.
836                 return;
837             }
838 
839             // Find the mode Id based on the desired mode specs. In case there is more than one
840             // mode matching the mode spec, prefer the one that is in the default mode group.
841             // For now the default config mode is taken from the active mode when we got the
842             // hotplug event for the display. In the future we might want to change the default
843             // mode based on vendor requirements.
844             // Note: We prefer the default mode group over the current one as this is the mode
845             // group the vendor prefers.
846             int baseModeId = findDisplayModeIdLocked(displayModeSpecs.baseModeId,
847                     mDefaultModeGroup);
848             if (baseModeId < 0) {
849                 // When a display is hotplugged, it's possible for a mode to be removed that was
850                 // previously valid. Because of the way display changes are propagated through the
851                 // framework, and the caching of the display mode specs in LogicalDisplay, it's
852                 // possible we'll get called with a stale mode id that no longer represents a valid
853                 // mode. This should only happen in extremely rare cases. A followup call will
854                 // contain a valid mode id.
855                 Slog.w(TAG,
856                         "Ignoring request for invalid base mode id " + displayModeSpecs.baseModeId);
857                 updateDeviceInfoLocked();
858                 return;
859             }
860             if (mDisplayModeSpecsInvalid || !displayModeSpecs.equals(mDisplayModeSpecs)) {
861                 mDisplayModeSpecsInvalid = false;
862                 mDisplayModeSpecs.copyFrom(displayModeSpecs);
863                 getHandler().sendMessage(PooledLambda.obtainMessage(
864                         LocalDisplayDevice::setDesiredDisplayModeSpecsAsync, this,
865                         getDisplayTokenLocked(),
866                         new SurfaceControl.DesiredDisplayModeSpecs(baseModeId,
867                                 mDisplayModeSpecs.allowGroupSwitching,
868                                 mDisplayModeSpecs.primaryRefreshRateRange.min,
869                                 mDisplayModeSpecs.primaryRefreshRateRange.max,
870                                 mDisplayModeSpecs.appRequestRefreshRateRange.min,
871                                 mDisplayModeSpecs.appRequestRefreshRateRange.max)));
872             }
873         }
874 
setDesiredDisplayModeSpecsAsync(IBinder displayToken, SurfaceControl.DesiredDisplayModeSpecs modeSpecs)875         private void setDesiredDisplayModeSpecsAsync(IBinder displayToken,
876                 SurfaceControl.DesiredDisplayModeSpecs modeSpecs) {
877             // Do not lock when calling these SurfaceControl methods because they are sync
878             // operations that may block for a while when setting display power mode.
879             mSurfaceControlProxy.setDesiredDisplayModeSpecs(displayToken, modeSpecs);
880         }
881 
882         @Override
onOverlayChangedLocked()883         public void onOverlayChangedLocked() {
884             updateDeviceInfoLocked();
885         }
886 
onActiveDisplayModeChangedLocked(int sfModeId)887         public void onActiveDisplayModeChangedLocked(int sfModeId) {
888             if (updateActiveModeLocked(sfModeId)) {
889                 updateDeviceInfoLocked();
890             }
891         }
892 
onFrameRateOverridesChanged( DisplayEventReceiver.FrameRateOverride[] overrides)893         public void onFrameRateOverridesChanged(
894                 DisplayEventReceiver.FrameRateOverride[] overrides) {
895             if (updateFrameRateOverridesLocked(overrides)) {
896                 updateDeviceInfoLocked();
897             }
898         }
899 
updateActiveModeLocked(int activeSfModeId)900         public boolean updateActiveModeLocked(int activeSfModeId) {
901             if (mActiveSfDisplayMode.id == activeSfModeId) {
902                 return false;
903             }
904             mActiveSfDisplayMode = getModeById(mSfDisplayModes, activeSfModeId);
905             mActiveModeId = findMatchingModeIdLocked(activeSfModeId);
906             if (mActiveModeId == NO_DISPLAY_MODE_ID) {
907                 Slog.w(TAG, "In unknown mode after setting allowed modes"
908                         + ", activeModeId=" + activeSfModeId);
909             }
910             return true;
911         }
912 
updateFrameRateOverridesLocked( DisplayEventReceiver.FrameRateOverride[] overrides)913         public boolean updateFrameRateOverridesLocked(
914                 DisplayEventReceiver.FrameRateOverride[] overrides) {
915             if (overrides.equals(mFrameRateOverrides)) {
916                 return false;
917             }
918 
919             mFrameRateOverrides = overrides;
920             return true;
921         }
922 
requestColorModeLocked(int colorMode)923         public void requestColorModeLocked(int colorMode) {
924             if (mActiveColorMode == colorMode) {
925                 return;
926             }
927             if (!mSupportedColorModes.contains(colorMode)) {
928                 Slog.w(TAG, "Unable to find color mode " + colorMode
929                         + ", ignoring request.");
930                 return;
931             }
932 
933             mActiveColorMode = colorMode;
934             getHandler().sendMessage(PooledLambda.obtainMessage(
935                     LocalDisplayDevice::requestColorModeAsync, this,
936                     getDisplayTokenLocked(), colorMode));
937         }
938 
requestColorModeAsync(IBinder displayToken, int colorMode)939         private void requestColorModeAsync(IBinder displayToken, int colorMode) {
940             // Do not lock when calling this SurfaceControl method because it is a sync operation
941             // that may block for a while when setting display power mode.
942             mSurfaceControlProxy.setActiveColorMode(displayToken, colorMode);
943             synchronized (getSyncRoot()) {
944                 updateDeviceInfoLocked();
945             }
946         }
947 
948         @Override
setAutoLowLatencyModeLocked(boolean on)949         public void setAutoLowLatencyModeLocked(boolean on) {
950             if (mAllmRequested == on) {
951                 return;
952             }
953 
954             mAllmRequested = on;
955 
956             if (!mAllmSupported) {
957                 Slog.d(TAG, "Unable to set ALLM because the connected display "
958                         + "does not support ALLM.");
959                 return;
960             }
961 
962             mSurfaceControlProxy.setAutoLowLatencyMode(getDisplayTokenLocked(), on);
963         }
964 
965         @Override
setGameContentTypeLocked(boolean on)966         public void setGameContentTypeLocked(boolean on) {
967             if (mGameContentTypeRequested == on) {
968                 return;
969             }
970 
971             mGameContentTypeRequested = on;
972 
973             if (!mGameContentTypeSupported) {
974                 Slog.d(TAG, "Unable to set game content type because the connected "
975                         + "display does not support game content type.");
976                 return;
977             }
978 
979             mSurfaceControlProxy.setGameContentType(getDisplayTokenLocked(), on);
980         }
981 
982         @Override
dumpLocked(PrintWriter pw)983         public void dumpLocked(PrintWriter pw) {
984             super.dumpLocked(pw);
985             pw.println("mPhysicalDisplayId=" + mPhysicalDisplayId);
986             pw.println("mDisplayModeSpecs={" + mDisplayModeSpecs + "}");
987             pw.println("mDisplayModeSpecsInvalid=" + mDisplayModeSpecsInvalid);
988             pw.println("mActiveModeId=" + mActiveModeId);
989             pw.println("mActiveColorMode=" + mActiveColorMode);
990             pw.println("mDefaultModeId=" + mDefaultModeId);
991             pw.println("mState=" + Display.stateToString(mState));
992             pw.println("mBrightnessState=" + mBrightnessState);
993             pw.println("mBacklightAdapter=" + mBacklightAdapter);
994             pw.println("mAllmSupported=" + mAllmSupported);
995             pw.println("mAllmRequested=" + mAllmRequested);
996             pw.println("mGameContentTypeSupported=" + mGameContentTypeSupported);
997             pw.println("mGameContentTypeRequested=" + mGameContentTypeRequested);
998             pw.println("mStaticDisplayInfo=" + mStaticDisplayInfo);
999             pw.println("mSfDisplayModes=");
1000             for (int i = 0; i < mSfDisplayModes.length; i++) {
1001                 pw.println("  " + mSfDisplayModes[i]);
1002             }
1003             pw.println("mActiveSfDisplayMode=" + mActiveSfDisplayMode);
1004             pw.println("mSupportedModes=");
1005             for (int i = 0; i < mSupportedModes.size(); i++) {
1006                 pw.println("  " + mSupportedModes.valueAt(i));
1007             }
1008             pw.println("mSupportedColorModes=" + mSupportedColorModes.toString());
1009             pw.println("mDisplayDeviceConfig=" + mDisplayDeviceConfig);
1010         }
1011 
findDisplayModeIdLocked(int modeId, int modeGroup)1012         private int findDisplayModeIdLocked(int modeId, int modeGroup) {
1013             int matchingModeId = SurfaceControl.DisplayMode.INVALID_DISPLAY_MODE_ID;
1014             DisplayModeRecord record = mSupportedModes.get(modeId);
1015             if (record != null) {
1016                 for (SurfaceControl.DisplayMode mode : mSfDisplayModes) {
1017                     if (record.hasMatchingMode(mode)) {
1018                         if (matchingModeId
1019                                 == SurfaceControl.DisplayMode.INVALID_DISPLAY_MODE_ID) {
1020                             matchingModeId = mode.id;
1021                         }
1022 
1023                         // Prefer to return a mode that matches the modeGroup
1024                         if (mode.group == modeGroup) {
1025                             return mode.id;
1026                         }
1027                     }
1028                 }
1029             }
1030             return matchingModeId;
1031         }
1032 
findMatchingModeIdLocked(int sfModeId)1033         private int findMatchingModeIdLocked(int sfModeId) {
1034             SurfaceControl.DisplayMode mode = getModeById(mSfDisplayModes, sfModeId);
1035             if (mode == null) {
1036                 Slog.e(TAG, "Invalid display mode ID " + sfModeId);
1037                 return NO_DISPLAY_MODE_ID;
1038             }
1039             for (int i = 0; i < mSupportedModes.size(); i++) {
1040                 DisplayModeRecord record = mSupportedModes.valueAt(i);
1041                 if (record.hasMatchingMode(mode)) {
1042                     return record.mMode.getModeId();
1043                 }
1044             }
1045             return NO_DISPLAY_MODE_ID;
1046         }
1047 
updateDeviceInfoLocked()1048         private void updateDeviceInfoLocked() {
1049             mInfo = null;
1050             sendDisplayDeviceEventLocked(this, DISPLAY_DEVICE_EVENT_CHANGED);
1051         }
1052 
getDisplayModes(SparseArray<DisplayModeRecord> records)1053         private Display.Mode[] getDisplayModes(SparseArray<DisplayModeRecord> records) {
1054             final int size = records.size();
1055             Display.Mode[] modes = new Display.Mode[size];
1056             for (int i = 0; i < size; i++) {
1057                 DisplayModeRecord record = records.valueAt(i);
1058                 modes[i] = record.mMode;
1059             }
1060             return modes;
1061         }
1062 
isDisplayPrivate(DisplayAddress.Physical physicalAddress)1063         private boolean isDisplayPrivate(DisplayAddress.Physical physicalAddress) {
1064             if (physicalAddress == null) {
1065                 return false;
1066             }
1067             final Resources res = getOverlayContext().getResources();
1068             int[] ports = res.getIntArray(
1069                     com.android.internal.R.array.config_localPrivateDisplayPorts);
1070             if (ports != null) {
1071                 int port = physicalAddress.getPort();
1072                 for (int p : ports) {
1073                     if (p == port) {
1074                         return true;
1075                     }
1076                 }
1077             }
1078             return false;
1079         }
1080     }
1081 
1082     /** Supplies a context whose Resources apply runtime-overlays */
1083     Context getOverlayContext() {
1084         return ActivityThread.currentActivityThread().getSystemUiContext();
1085     }
1086 
1087     /**
1088      * Keeps track of a display mode.
1089      */
1090     private static final class DisplayModeRecord {
1091         public final Display.Mode mMode;
1092 
1093         DisplayModeRecord(SurfaceControl.DisplayMode mode,
1094                 float[] alternativeRefreshRates) {
1095             mMode = createMode(mode.width, mode.height, mode.refreshRate,
1096                     alternativeRefreshRates);
1097         }
1098 
1099         /**
1100          * Returns whether the mode generated by the given DisplayModes matches the mode
1101          * contained by the record modulo mode ID.
1102          *
1103          * Note that this doesn't necessarily mean that the DisplayModes are identical, just
1104          * that they generate identical modes.
1105          */
1106         public boolean hasMatchingMode(SurfaceControl.DisplayMode mode) {
1107             return mMode.getPhysicalWidth() == mode.width
1108                     && mMode.getPhysicalHeight() == mode.height
1109                     && Float.floatToIntBits(mMode.getRefreshRate())
1110                         == Float.floatToIntBits(mode.refreshRate);
1111         }
1112 
1113         public String toString() {
1114             return "DisplayModeRecord{mMode=" + mMode + "}";
1115         }
1116     }
1117 
1118     public static class Injector {
1119         private ProxyDisplayEventReceiver mReceiver;
1120         public void setDisplayEventListenerLocked(Looper looper, DisplayEventListener listener) {
1121             mReceiver = new ProxyDisplayEventReceiver(looper, listener);
1122         }
1123         public SurfaceControlProxy getSurfaceControlProxy() {
1124             return new SurfaceControlProxy();
1125         }
1126     }
1127 
1128     public interface DisplayEventListener {
1129         void onHotplug(long timestampNanos, long physicalDisplayId, boolean connected);
1130         void onModeChanged(long timestampNanos, long physicalDisplayId, int modeId);
1131         void onFrameRateOverridesChanged(long timestampNanos, long physicalDisplayId,
1132                 DisplayEventReceiver.FrameRateOverride[] overrides);
1133 
1134     }
1135 
1136     public static final class ProxyDisplayEventReceiver extends DisplayEventReceiver {
1137         private final DisplayEventListener mListener;
1138         ProxyDisplayEventReceiver(Looper looper, DisplayEventListener listener) {
1139             super(looper, VSYNC_SOURCE_APP,
1140                     EVENT_REGISTRATION_MODE_CHANGED_FLAG
1141                             | EVENT_REGISTRATION_FRAME_RATE_OVERRIDE_FLAG);
1142             mListener = listener;
1143         }
1144 
1145         @Override
1146         public void onHotplug(long timestampNanos, long physicalDisplayId, boolean connected) {
1147             mListener.onHotplug(timestampNanos, physicalDisplayId, connected);
1148         }
1149 
1150         @Override
1151         public void onModeChanged(long timestampNanos, long physicalDisplayId, int modeId) {
1152             mListener.onModeChanged(timestampNanos, physicalDisplayId, modeId);
1153         }
1154 
1155         @Override
1156         public void onFrameRateOverridesChanged(long timestampNanos, long physicalDisplayId,
1157                 DisplayEventReceiver.FrameRateOverride[] overrides) {
1158             mListener.onFrameRateOverridesChanged(timestampNanos, physicalDisplayId, overrides);
1159         }
1160     }
1161 
1162     private final class LocalDisplayEventListener implements DisplayEventListener {
1163         @Override
1164         public void onHotplug(long timestampNanos, long physicalDisplayId, boolean connected) {
1165             synchronized (getSyncRoot()) {
1166                 if (connected) {
1167                     tryConnectDisplayLocked(physicalDisplayId);
1168                 } else {
1169                     tryDisconnectDisplayLocked(physicalDisplayId);
1170                 }
1171             }
1172         }
1173 
1174         @Override
1175         public void onModeChanged(long timestampNanos, long physicalDisplayId, int modeId) {
1176             if (DEBUG) {
1177                 Slog.d(TAG, "onModeChanged("
1178                         + "timestampNanos=" + timestampNanos
1179                         + ", physicalDisplayId=" + physicalDisplayId
1180                         + ", modeId=" + modeId + ")");
1181             }
1182             synchronized (getSyncRoot()) {
1183                 LocalDisplayDevice device = mDevices.get(physicalDisplayId);
1184                 if (device == null) {
1185                     if (DEBUG) {
1186                         Slog.d(TAG, "Received mode change for unhandled physical display: "
1187                                 + "physicalDisplayId=" + physicalDisplayId);
1188                     }
1189                     return;
1190                 }
1191                 device.onActiveDisplayModeChangedLocked(modeId);
1192             }
1193         }
1194 
1195         @Override
1196         public void onFrameRateOverridesChanged(long timestampNanos, long physicalDisplayId,
1197                 DisplayEventReceiver.FrameRateOverride[] overrides) {
1198             if (DEBUG) {
1199                 Slog.d(TAG, "onFrameRateOverrideChanged(timestampNanos=" + timestampNanos
1200                         + ", physicalDisplayId=" + physicalDisplayId + " overrides="
1201                         + Arrays.toString(overrides) + ")");
1202             }
1203             synchronized (getSyncRoot()) {
1204                 LocalDisplayDevice device = mDevices.get(physicalDisplayId);
1205                 if (device == null) {
1206                     if (DEBUG) {
1207                         Slog.d(TAG, "Received frame rate override event for unhandled physical"
1208                                 + " display: physicalDisplayId=" + physicalDisplayId);
1209                     }
1210                     return;
1211                 }
1212                 device.onFrameRateOverridesChanged(overrides);
1213             }
1214         }
1215     }
1216 
1217     @VisibleForTesting
1218     static class SurfaceControlProxy {
1219         public SurfaceControl.DynamicDisplayInfo getDynamicDisplayInfo(IBinder token) {
1220             return SurfaceControl.getDynamicDisplayInfo(token);
1221         }
1222 
1223         public long[] getPhysicalDisplayIds() {
1224             return SurfaceControl.getPhysicalDisplayIds();
1225         }
1226 
1227         public IBinder getPhysicalDisplayToken(long physicalDisplayId) {
1228             return SurfaceControl.getPhysicalDisplayToken(physicalDisplayId);
1229         }
1230 
1231         public SurfaceControl.StaticDisplayInfo getStaticDisplayInfo(IBinder displayToken) {
1232             return SurfaceControl.getStaticDisplayInfo(displayToken);
1233         }
1234 
1235         public SurfaceControl.DesiredDisplayModeSpecs getDesiredDisplayModeSpecs(
1236                 IBinder displayToken) {
1237             return SurfaceControl.getDesiredDisplayModeSpecs(displayToken);
1238         }
1239 
1240         public boolean setDesiredDisplayModeSpecs(IBinder token,
1241                 SurfaceControl.DesiredDisplayModeSpecs specs) {
1242             return SurfaceControl.setDesiredDisplayModeSpecs(token, specs);
1243         }
1244 
1245         public void setDisplayPowerMode(IBinder displayToken, int mode) {
1246             SurfaceControl.setDisplayPowerMode(displayToken, mode);
1247         }
1248 
1249         public boolean setActiveColorMode(IBinder displayToken, int colorMode) {
1250             return SurfaceControl.setActiveColorMode(displayToken, colorMode);
1251         }
1252 
1253         public void setAutoLowLatencyMode(IBinder displayToken, boolean on) {
1254             SurfaceControl.setAutoLowLatencyMode(displayToken, on);
1255 
1256         }
1257 
1258         public void setGameContentType(IBinder displayToken, boolean on) {
1259             SurfaceControl.setGameContentType(displayToken, on);
1260         }
1261 
1262         public boolean getDisplayBrightnessSupport(IBinder displayToken) {
1263             return SurfaceControl.getDisplayBrightnessSupport(displayToken);
1264         }
1265 
1266         public boolean setDisplayBrightness(IBinder displayToken, float brightness) {
1267             return SurfaceControl.setDisplayBrightness(displayToken, brightness);
1268         }
1269 
1270         public boolean setDisplayBrightness(IBinder displayToken, float sdrBacklight,
1271                 float sdrNits, float displayBacklight, float displayNits) {
1272             return SurfaceControl.setDisplayBrightness(displayToken, sdrBacklight, sdrNits,
1273                     displayBacklight, displayNits);
1274         }
1275 
1276     }
1277 
1278     static class BacklightAdapter {
1279         private final IBinder mDisplayToken;
1280         private final LogicalLight mBacklight;
1281         private final boolean mUseSurfaceControlBrightness;
1282         private final SurfaceControlProxy mSurfaceControlProxy;
1283 
1284         private boolean mForceSurfaceControl = false;
1285 
1286         /**
1287          * @param displayToken Token for display associated with this backlight.
1288          * @param isDefaultDisplay {@code true} if it is the default display.
1289          */
1290         BacklightAdapter(IBinder displayToken, boolean isDefaultDisplay,
1291                 SurfaceControlProxy surfaceControlProxy) {
1292             mDisplayToken = displayToken;
1293             mSurfaceControlProxy = surfaceControlProxy;
1294 
1295             mUseSurfaceControlBrightness = mSurfaceControlProxy
1296                     .getDisplayBrightnessSupport(mDisplayToken);
1297 
1298             if (!mUseSurfaceControlBrightness && isDefaultDisplay) {
1299                 LightsManager lights = LocalServices.getService(LightsManager.class);
1300                 mBacklight = lights.getLight(LightsManager.LIGHT_ID_BACKLIGHT);
1301             } else {
1302                 mBacklight = null;
1303             }
1304         }
1305 
1306         // Set backlight within min and max backlight values
1307         void setBacklight(float sdrBacklight, float sdrNits, float backlight, float nits) {
1308             if (mUseSurfaceControlBrightness || mForceSurfaceControl) {
1309                 if (BrightnessSynchronizer.floatEquals(
1310                         sdrBacklight, PowerManager.BRIGHTNESS_INVALID_FLOAT)) {
1311                     mSurfaceControlProxy.setDisplayBrightness(mDisplayToken, backlight);
1312                 } else {
1313                     mSurfaceControlProxy.setDisplayBrightness(mDisplayToken, sdrBacklight, sdrNits,
1314                             backlight, nits);
1315                 }
1316             } else if (mBacklight != null) {
1317                 mBacklight.setBrightness(backlight);
1318             }
1319         }
1320 
1321         void setVrMode(boolean isVrModeEnabled) {
1322             if (mBacklight != null) {
1323                 mBacklight.setVrMode(isVrModeEnabled);
1324             }
1325         }
1326 
1327         void setForceSurfaceControl(boolean forceSurfaceControl) {
1328             mForceSurfaceControl = forceSurfaceControl;
1329         }
1330 
1331         @Override
1332         public String toString() {
1333             return "BacklightAdapter [useSurfaceControl=" + mUseSurfaceControlBrightness
1334                     + " (force_anyway? " + mForceSurfaceControl + ")"
1335                     + ", backlight=" + mBacklight + "]";
1336         }
1337     }
1338 }
1339