1 /*
2  * Copyright (C) 2019 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.mode;
18 
19 import static android.hardware.display.DisplayManager.DISPLAY_CATEGORY_ALL_INCLUDING_DISABLED;
20 import static android.hardware.display.DisplayManagerInternal.REFRESH_RATE_LIMIT_HIGH_BRIGHTNESS_MODE;
21 import static android.os.PowerManager.BRIGHTNESS_INVALID_FLOAT;
22 import static android.view.Display.Mode.INVALID_MODE_ID;
23 
24 import static com.android.server.display.DisplayDeviceConfig.DEFAULT_LOW_REFRESH_RATE;
25 
26 import android.annotation.IntegerRes;
27 import android.annotation.NonNull;
28 import android.annotation.Nullable;
29 import android.content.ContentResolver;
30 import android.content.Context;
31 import android.content.res.Resources;
32 import android.database.ContentObserver;
33 import android.hardware.Sensor;
34 import android.hardware.SensorEvent;
35 import android.hardware.SensorEventListener;
36 import android.hardware.SensorManager;
37 import android.hardware.display.BrightnessInfo;
38 import android.hardware.display.DisplayManager;
39 import android.hardware.display.DisplayManagerInternal;
40 import android.hardware.display.DisplayManagerInternal.RefreshRateLimitation;
41 import android.hardware.fingerprint.IUdfpsRefreshRateRequestCallback;
42 import android.net.Uri;
43 import android.os.Handler;
44 import android.os.IBinder;
45 import android.os.IThermalEventListener;
46 import android.os.IThermalService;
47 import android.os.Looper;
48 import android.os.Message;
49 import android.os.PowerManager;
50 import android.os.RemoteException;
51 import android.os.ServiceManager;
52 import android.os.SystemClock;
53 import android.os.Temperature;
54 import android.os.UserHandle;
55 import android.provider.DeviceConfig;
56 import android.provider.DeviceConfigInterface;
57 import android.provider.Settings;
58 import android.sysprop.SurfaceFlingerProperties;
59 import android.util.IndentingPrintWriter;
60 import android.util.Pair;
61 import android.util.Slog;
62 import android.util.SparseArray;
63 import android.util.SparseBooleanArray;
64 import android.util.SparseIntArray;
65 import android.view.Display;
66 import android.view.DisplayInfo;
67 import android.view.SurfaceControl;
68 import android.view.SurfaceControl.IdleScreenRefreshRateConfig;
69 import android.view.SurfaceControl.RefreshRateRange;
70 import android.view.SurfaceControl.RefreshRateRanges;
71 
72 import com.android.internal.R;
73 import com.android.internal.annotations.GuardedBy;
74 import com.android.internal.annotations.VisibleForTesting;
75 import com.android.internal.display.BrightnessSynchronizer;
76 import com.android.internal.os.BackgroundThread;
77 import com.android.server.LocalServices;
78 import com.android.server.display.DisplayDeviceConfig;
79 import com.android.server.display.config.IdleScreenRefreshRateTimeoutLuxThresholdPoint;
80 import com.android.server.display.config.RefreshRateData;
81 import com.android.server.display.config.SupportedModeData;
82 import com.android.server.display.feature.DeviceConfigParameterProvider;
83 import com.android.server.display.feature.DisplayManagerFlags;
84 import com.android.server.display.utils.AmbientFilter;
85 import com.android.server.display.utils.AmbientFilterFactory;
86 import com.android.server.display.utils.DeviceConfigParsingUtils;
87 import com.android.server.display.utils.SensorUtils;
88 import com.android.server.sensors.SensorManagerInternal;
89 import com.android.server.statusbar.StatusBarManagerInternal;
90 
91 import java.io.PrintWriter;
92 import java.text.SimpleDateFormat;
93 import java.util.ArrayList;
94 import java.util.Arrays;
95 import java.util.Date;
96 import java.util.HashSet;
97 import java.util.List;
98 import java.util.Locale;
99 import java.util.Objects;
100 import java.util.Set;
101 import java.util.concurrent.Callable;
102 import java.util.function.Function;
103 import java.util.function.IntSupplier;
104 
105 /**
106  * The DisplayModeDirector is responsible for determining what modes are allowed to be automatically
107  * picked by the system based on system-wide and display-specific configuration.
108  */
109 public class DisplayModeDirector {
110 
111     public static final float SYNCHRONIZED_REFRESH_RATE_TARGET = DEFAULT_LOW_REFRESH_RATE;
112     public static final float SYNCHRONIZED_REFRESH_RATE_TOLERANCE = 1;
113     private static final String TAG = "DisplayModeDirector";
114     private boolean mLoggingEnabled;
115 
116     private static final int MSG_REFRESH_RATE_RANGE_CHANGED = 1;
117     private static final int MSG_LOW_BRIGHTNESS_THRESHOLDS_CHANGED = 2;
118     private static final int MSG_DEFAULT_PEAK_REFRESH_RATE_CHANGED = 3;
119     private static final int MSG_REFRESH_RATE_IN_LOW_ZONE_CHANGED = 4;
120     private static final int MSG_REFRESH_RATE_IN_HIGH_ZONE_CHANGED = 5;
121     private static final int MSG_HIGH_BRIGHTNESS_THRESHOLDS_CHANGED = 6;
122     private static final int MSG_REFRESH_RATE_IN_HBM_SUNLIGHT_CHANGED = 7;
123     private static final int MSG_REFRESH_RATE_IN_HBM_HDR_CHANGED = 8;
124 
125     private final Object mLock = new Object();
126     private final Context mContext;
127 
128     private final DisplayModeDirectorHandler mHandler;
129     private final Injector mInjector;
130 
131     private final AppRequestObserver mAppRequestObserver;
132     private final SettingsObserver mSettingsObserver;
133     private final DisplayObserver mDisplayObserver;
134     private final UdfpsObserver mUdfpsObserver;
135     private final ProximitySensorObserver mSensorObserver;
136     private final HbmObserver mHbmObserver;
137     private final SkinThermalStatusObserver mSkinThermalStatusObserver;
138 
139     @Nullable
140     private final SystemRequestObserver mSystemRequestObserver;
141     private final DeviceConfigParameterProvider mConfigParameterProvider;
142     private final DeviceConfigDisplaySettings mDeviceConfigDisplaySettings;
143 
144     @GuardedBy("mLock")
145     @Nullable
146     private DisplayDeviceConfig mDefaultDisplayDeviceConfig;
147 
148     // A map from the display ID to the supported modes on that display.
149     private SparseArray<Display.Mode[]> mSupportedModesByDisplay;
150     // A map from the display ID to the app supported modes on that display, might be different from
151     // mSupportedModesByDisplay for VRR displays, used in app mode requests.
152     private SparseArray<Display.Mode[]> mAppSupportedModesByDisplay;
153     // A map from the display ID to the default mode of that display.
154     private SparseArray<Display.Mode> mDefaultModeByDisplay;
155     // a map from display id to display device config
156     private SparseArray<DisplayDeviceConfig> mDisplayDeviceConfigByDisplay = new SparseArray<>();
157 
158     private BrightnessObserver mBrightnessObserver;
159 
160     private DesiredDisplayModeSpecsListener mDesiredDisplayModeSpecsListener;
161 
162     private boolean mAlwaysRespectAppRequest;
163 
164     private final boolean mSupportsFrameRateOverride;
165 
166     private final VotesStorage mVotesStorage;
167 
168     @Nullable
169     private final VotesStatsReporter mVotesStatsReporter;
170 
171     /**
172      * The allowed refresh rate switching type. This is used by SurfaceFlinger.
173      */
174     @DisplayManager.SwitchingType
175     private int mModeSwitchingType = DisplayManager.SWITCHING_TYPE_WITHIN_GROUPS;
176 
177     /**
178      * Whether resolution range voting feature is enabled.
179      */
180     private final boolean mIsDisplayResolutionRangeVotingEnabled;
181 
182     /**
183      * Whether user preferred mode voting feature is enabled.
184      */
185     private final boolean mIsUserPreferredModeVoteEnabled;
186 
187     /**
188      * Whether limit display mode feature is enabled.
189      */
190     private final boolean mIsExternalDisplayLimitModeEnabled;
191 
192     private final boolean mIsDisplaysRefreshRatesSynchronizationEnabled;
193 
194     private final boolean mIsBackUpSmoothDisplayAndForcePeakRefreshRateEnabled;
195 
196     private final DisplayManagerFlags mDisplayManagerFlags;
197 
198     private final DisplayDeviceConfigProvider mDisplayDeviceConfigProvider;
199 
DisplayModeDirector(@onNull Context context, @NonNull Handler handler, @NonNull DisplayManagerFlags displayManagerFlags, @NonNull DisplayDeviceConfigProvider displayDeviceConfigProvider)200     public DisplayModeDirector(@NonNull Context context, @NonNull Handler handler,
201             @NonNull DisplayManagerFlags displayManagerFlags,
202             @NonNull DisplayDeviceConfigProvider displayDeviceConfigProvider) {
203         this(context, handler, new RealInjector(context),
204                 displayManagerFlags, displayDeviceConfigProvider);
205     }
206 
DisplayModeDirector(@onNull Context context, @NonNull Handler handler, @NonNull Injector injector, @NonNull DisplayManagerFlags displayManagerFlags, @NonNull DisplayDeviceConfigProvider displayDeviceConfigProvider)207     public DisplayModeDirector(@NonNull Context context, @NonNull Handler handler,
208             @NonNull Injector injector,
209             @NonNull DisplayManagerFlags displayManagerFlags,
210             @NonNull DisplayDeviceConfigProvider displayDeviceConfigProvider) {
211         mIsDisplayResolutionRangeVotingEnabled = displayManagerFlags
212                 .isDisplayResolutionRangeVotingEnabled();
213         mIsUserPreferredModeVoteEnabled = displayManagerFlags.isUserPreferredModeVoteEnabled();
214         mIsExternalDisplayLimitModeEnabled = displayManagerFlags
215             .isExternalDisplayLimitModeEnabled();
216         mIsDisplaysRefreshRatesSynchronizationEnabled = displayManagerFlags
217             .isDisplaysRefreshRatesSynchronizationEnabled();
218         mIsBackUpSmoothDisplayAndForcePeakRefreshRateEnabled = displayManagerFlags
219                 .isBackUpSmoothDisplayAndForcePeakRefreshRateEnabled();
220         mDisplayManagerFlags = displayManagerFlags;
221         mDisplayDeviceConfigProvider = displayDeviceConfigProvider;
222         mContext = context;
223         mHandler = new DisplayModeDirectorHandler(handler.getLooper());
224         mInjector = injector;
225         mVotesStatsReporter = injector.getVotesStatsReporter(
226                 displayManagerFlags.isRefreshRateVotingTelemetryEnabled());
227         mSupportedModesByDisplay = new SparseArray<>();
228         mAppSupportedModesByDisplay = new SparseArray<>();
229         mDefaultModeByDisplay = new SparseArray<>();
230         mAppRequestObserver = new AppRequestObserver(displayManagerFlags);
231         mConfigParameterProvider = new DeviceConfigParameterProvider(injector.getDeviceConfig());
232         mDeviceConfigDisplaySettings = new DeviceConfigDisplaySettings();
233         mSettingsObserver = new SettingsObserver(context, handler, displayManagerFlags);
234         mBrightnessObserver = new BrightnessObserver(context, handler, injector,
235                 displayManagerFlags);
236         mDefaultDisplayDeviceConfig = null;
237         mUdfpsObserver = new UdfpsObserver();
238         mVotesStorage = new VotesStorage(this::notifyDesiredDisplayModeSpecsChangedLocked,
239                 mVotesStatsReporter);
240         mDisplayObserver = new DisplayObserver(context, handler, mVotesStorage, injector);
241         mSensorObserver = new ProximitySensorObserver(mVotesStorage, injector);
242         mSkinThermalStatusObserver = new SkinThermalStatusObserver(injector, mVotesStorage);
243         mHbmObserver = new HbmObserver(injector, mVotesStorage, BackgroundThread.getHandler(),
244                 mDeviceConfigDisplaySettings);
245         if (displayManagerFlags.isRestrictDisplayModesEnabled()) {
246             mSystemRequestObserver = new SystemRequestObserver(mVotesStorage);
247         } else {
248             mSystemRequestObserver = null;
249         }
250         mAlwaysRespectAppRequest = false;
251         mSupportsFrameRateOverride = injector.supportsFrameRateOverride();
252     }
253 
254     /**
255      * Tells the DisplayModeDirector to update allowed votes and begin observing relevant system
256      * state.
257      *
258      * This has to be deferred because the object may be constructed before the rest of the system
259      * is ready.
260      */
start(SensorManager sensorManager)261     public void start(SensorManager sensorManager) {
262         // This has to be called first to read the supported display modes that will be used by
263         // other observers
264         mDisplayObserver.observe();
265 
266         mSettingsObserver.observe();
267         mBrightnessObserver.observe(sensorManager);
268         mSensorObserver.observe();
269         mHbmObserver.observe();
270         mSkinThermalStatusObserver.observe();
271         synchronized (mLock) {
272             // We may have a listener already registered before the call to start, so go ahead and
273             // notify them to pick up our newly initialized state.
274             notifyDesiredDisplayModeSpecsChangedLocked();
275         }
276     }
277 
278     /**
279      * Same as {@link #start(SensorManager)}, but for observers that need to be delayed even more,
280      * for example until SystemUI is ready.
281      */
onBootCompleted()282     public void onBootCompleted() {
283         // UDFPS observer registers a listener with SystemUI which might not be ready until the
284         // system is fully booted.
285         mUdfpsObserver.observe();
286     }
287 
288     /**
289     * Enables or disables component logging
290     */
setLoggingEnabled(boolean loggingEnabled)291     public void setLoggingEnabled(boolean loggingEnabled) {
292         if (mLoggingEnabled == loggingEnabled) {
293             return;
294         }
295         mLoggingEnabled = loggingEnabled;
296         mBrightnessObserver.setLoggingEnabled(loggingEnabled);
297         mSkinThermalStatusObserver.setLoggingEnabled(loggingEnabled);
298         mVotesStorage.setLoggingEnabled(loggingEnabled);
299     }
300 
301     /**
302      * Calculates the refresh rate ranges and display modes that the system is allowed to freely
303      * switch between based on global and display-specific constraints.
304      *
305      * @param displayId The display to query for.
306      * @return The ID of the default mode the system should use, and the refresh rate range the
307      * system is allowed to switch between.
308      */
309     @NonNull
getDesiredDisplayModeSpecs(int displayId)310     public DesiredDisplayModeSpecs getDesiredDisplayModeSpecs(int displayId) {
311         synchronized (mLock) {
312             SparseArray<Vote> votes = mVotesStorage.getVotes(displayId);
313             Display.Mode[] modes = mSupportedModesByDisplay.get(displayId);
314             Display.Mode defaultMode = mDefaultModeByDisplay.get(displayId);
315             if (modes == null || defaultMode == null) {
316                 Slog.e(TAG,
317                         "Asked about unknown display, returning empty display mode specs!"
318                                 + "(id=" + displayId + ")");
319                 return new DesiredDisplayModeSpecs();
320             }
321 
322             List<Display.Mode> availableModes = new ArrayList<>();
323             availableModes.add(defaultMode);
324             VoteSummary primarySummary = new VoteSummary(mIsDisplayResolutionRangeVotingEnabled,
325                     isVrrSupportedLocked(displayId),
326                     mLoggingEnabled, mSupportsFrameRateOverride);
327             int lowestConsideredPriority = Vote.MIN_PRIORITY;
328             int highestConsideredPriority = Vote.MAX_PRIORITY;
329 
330             if (mAlwaysRespectAppRequest) {
331                 lowestConsideredPriority = Vote.PRIORITY_APP_REQUEST_RENDER_FRAME_RATE_RANGE;
332                 highestConsideredPriority = Vote.PRIORITY_APP_REQUEST_SIZE;
333             }
334 
335             // We try to find a range of priorities which define a non-empty set of allowed display
336             // modes. Each time we fail we increase the lowest priority.
337             while (lowestConsideredPriority <= highestConsideredPriority) {
338                 primarySummary.applyVotes(
339                         votes, lowestConsideredPriority, highestConsideredPriority);
340 
341                 primarySummary.adjustSize(defaultMode, modes);
342 
343                 availableModes = primarySummary.filterModes(modes);
344                 if (!availableModes.isEmpty()) {
345                     if (mLoggingEnabled) {
346                         Slog.w(TAG, "Found available modes=" + availableModes
347                                 + " with lowest priority considered "
348                                 + Vote.priorityToString(lowestConsideredPriority)
349                                 + " and summary: " + primarySummary);
350                     }
351                     break;
352                 }
353 
354                 if (mLoggingEnabled) {
355                     Slog.w(TAG, "Couldn't find available modes with lowest priority set to "
356                             + Vote.priorityToString(lowestConsideredPriority)
357                             + " and with the following summary: " + primarySummary);
358                 }
359 
360                 // If we haven't found anything with the current set of votes, drop the
361                 // current lowest priority vote.
362                 lowestConsideredPriority++;
363             }
364 
365             VoteSummary appRequestSummary = new VoteSummary(mIsDisplayResolutionRangeVotingEnabled,
366                     isVrrSupportedLocked(displayId),
367                     mLoggingEnabled, mSupportsFrameRateOverride);
368 
369             appRequestSummary.applyVotes(votes,
370                     Vote.APP_REQUEST_REFRESH_RATE_RANGE_PRIORITY_CUTOFF,
371                     Vote.MAX_PRIORITY);
372 
373             appRequestSummary.limitRefreshRanges(primarySummary);
374 
375             Display.Mode baseMode = primarySummary.selectBaseMode(availableModes, defaultMode);
376             if (mVotesStatsReporter != null) {
377                 mVotesStatsReporter.reportVotesActivated(displayId, lowestConsideredPriority,
378                         baseMode, votes);
379             }
380 
381             if (baseMode == null) {
382                 Slog.w(TAG, "Can't find a set of allowed modes which satisfies the votes. Falling"
383                         + " back to the default mode. Display = " + displayId + ", votes = " + votes
384                         + ", supported modes = " + Arrays.toString(modes));
385 
386                 float fps = defaultMode.getRefreshRate();
387                 final RefreshRateRange range = new RefreshRateRange(fps, fps);
388                 final RefreshRateRanges ranges = new RefreshRateRanges(range, range);
389                 return new DesiredDisplayModeSpecs(defaultMode.getModeId(),
390                         /*allowGroupSwitching */ false,
391                         ranges, ranges, mBrightnessObserver.getIdleScreenRefreshRateConfig());
392             }
393 
394             boolean modeSwitchingDisabled =
395                     mModeSwitchingType == DisplayManager.SWITCHING_TYPE_NONE
396                             || mModeSwitchingType
397                                 == DisplayManager.SWITCHING_TYPE_RENDER_FRAME_RATE_ONLY;
398 
399             if (modeSwitchingDisabled || primarySummary.disableRefreshRateSwitching) {
400                 float fps = baseMode.getRefreshRate();
401                 primarySummary.disableModeSwitching(fps);
402                 if (modeSwitchingDisabled) {
403                     appRequestSummary.disableModeSwitching(fps);
404                     primarySummary.disableRenderRateSwitching(fps);
405                     if (mModeSwitchingType == DisplayManager.SWITCHING_TYPE_NONE) {
406                         appRequestSummary.disableRenderRateSwitching(fps);
407                     }
408                 }
409             }
410 
411             boolean allowGroupSwitching =
412                     mModeSwitchingType == DisplayManager.SWITCHING_TYPE_ACROSS_AND_WITHIN_GROUPS;
413 
414             // Some external displays physical refresh rate modes are slightly above 60hz.
415             // SurfaceFlinger will not enable these display modes unless it is configured to allow
416             // render rate at least at this frame rate.
417             if (mDisplayObserver.isExternalDisplayLocked(displayId)) {
418                 primarySummary.maxRenderFrameRate = Math.max(baseMode.getRefreshRate(),
419                         primarySummary.maxRenderFrameRate);
420                 appRequestSummary.maxRenderFrameRate = Math.max(baseMode.getRefreshRate(),
421                         appRequestSummary.maxRenderFrameRate);
422             }
423 
424             return new DesiredDisplayModeSpecs(baseMode.getModeId(),
425                     allowGroupSwitching,
426                     new RefreshRateRanges(
427                             new RefreshRateRange(
428                                     primarySummary.minPhysicalRefreshRate,
429                                     primarySummary.maxPhysicalRefreshRate),
430                             new RefreshRateRange(
431                                 primarySummary.minRenderFrameRate,
432                                 primarySummary.maxRenderFrameRate)),
433                     new RefreshRateRanges(
434                             new RefreshRateRange(
435                                     appRequestSummary.minPhysicalRefreshRate,
436                                     appRequestSummary.maxPhysicalRefreshRate),
437                             new RefreshRateRange(
438                                     appRequestSummary.minRenderFrameRate,
439                                     appRequestSummary.maxRenderFrameRate)),
440                     mBrightnessObserver.getIdleScreenRefreshRateConfig());
441         }
442     }
443 
444     /**
445      * Gets the observer responsible for application display mode requests.
446      */
447     @NonNull
getAppRequestObserver()448     public AppRequestObserver getAppRequestObserver() {
449         // We don't need to lock here because mAppRequestObserver is a final field, which is
450         // guaranteed to be visible on all threads after construction.
451         return mAppRequestObserver;
452     }
453 
isVrrSupportedLocked(int displayId)454     private boolean isVrrSupportedLocked(int displayId) {
455         DisplayDeviceConfig config = mDisplayDeviceConfigByDisplay.get(displayId);
456         return config != null && config.isVrrSupportEnabled();
457     }
458 
459     /**
460      * Sets the desiredDisplayModeSpecsListener for changes to display mode and refresh rate ranges.
461      */
setDesiredDisplayModeSpecsListener( @ullable DesiredDisplayModeSpecsListener desiredDisplayModeSpecsListener)462     public void setDesiredDisplayModeSpecsListener(
463             @Nullable DesiredDisplayModeSpecsListener desiredDisplayModeSpecsListener) {
464         synchronized (mLock) {
465             mDesiredDisplayModeSpecsListener = desiredDisplayModeSpecsListener;
466         }
467     }
468 
469     /**
470      * Called when the underlying display device of the default display is changed.
471      * Some data in this class relates to the physical display of the device, and so we need to
472      * reload the configurations based on this.
473      * E.g. the brightness sensors and refresh rate capabilities depend on the physical display
474      * device that is being used, so will be reloaded.
475      *
476      * @param displayDeviceConfig configurations relating to the underlying display device.
477      */
defaultDisplayDeviceUpdated(DisplayDeviceConfig displayDeviceConfig)478     public void defaultDisplayDeviceUpdated(DisplayDeviceConfig displayDeviceConfig) {
479         synchronized (mLock) {
480             mDefaultDisplayDeviceConfig = displayDeviceConfig;
481             mSettingsObserver.setRefreshRates(displayDeviceConfig,
482                 /* attemptReadFromFeatureParams= */ true);
483             mBrightnessObserver.updateBlockingZoneThresholds(displayDeviceConfig,
484                 /* attemptReadFromFeatureParams= */ true);
485             mBrightnessObserver.reloadLightSensor(displayDeviceConfig);
486             mHbmObserver.setupHdrRefreshRates(displayDeviceConfig);
487         }
488     }
489 
490     /**
491      * When enabled the app requested display mode is always selected and all
492      * other votes will be ignored. This is used for testing purposes.
493      */
setShouldAlwaysRespectAppRequestedMode(boolean enabled)494     public void setShouldAlwaysRespectAppRequestedMode(boolean enabled) {
495         synchronized (mLock) {
496             if (mAlwaysRespectAppRequest != enabled) {
497                 mAlwaysRespectAppRequest = enabled;
498                 notifyDesiredDisplayModeSpecsChangedLocked();
499             }
500         }
501     }
502 
503     /**
504      * Returns whether we are running in a mode which always selects the app requested display mode
505      * and ignores user settings and policies for low brightness, low battery etc.
506      */
shouldAlwaysRespectAppRequestedMode()507     public boolean shouldAlwaysRespectAppRequestedMode() {
508         synchronized (mLock) {
509             return mAlwaysRespectAppRequest;
510         }
511     }
512 
513     /**
514      * Sets the display mode switching type.
515      * @param newType new mode switching type
516      */
setModeSwitchingType(@isplayManager.SwitchingType int newType)517     public void setModeSwitchingType(@DisplayManager.SwitchingType int newType) {
518         synchronized (mLock) {
519             if (newType != mModeSwitchingType) {
520                 mModeSwitchingType = newType;
521                 notifyDesiredDisplayModeSpecsChangedLocked();
522             }
523         }
524     }
525 
526     /**
527      * Returns the display mode switching type.
528      */
529     @DisplayManager.SwitchingType
getModeSwitchingType()530     public int getModeSwitchingType() {
531         synchronized (mLock) {
532             return mModeSwitchingType;
533         }
534     }
535 
536     /**
537      * Retrieve the Vote for the given display and priority. Intended only for testing purposes.
538      *
539      * @param displayId the display to query for
540      * @param priority the priority of the vote to return
541      * @return the vote corresponding to the given {@code displayId} and {@code priority},
542      *         or {@code null} if there isn't one
543      */
544     @VisibleForTesting
545     @Nullable
getVote(int displayId, int priority)546     Vote getVote(int displayId, int priority) {
547         SparseArray<Vote> votes = mVotesStorage.getVotes(displayId);
548         return votes.get(priority);
549     }
550 
551     /**
552      * Delegates requestDisplayModes call to SystemRequestObserver
553      */
requestDisplayModes(IBinder token, int displayId, int[] modeIds)554     public void requestDisplayModes(IBinder token, int displayId, int[] modeIds) {
555         if (mSystemRequestObserver != null) {
556             boolean vrrSupported;
557             synchronized (mLock) {
558                 vrrSupported = isVrrSupportedLocked(displayId);
559             }
560             if (vrrSupported) {
561                 mSystemRequestObserver.requestDisplayModes(token, displayId, modeIds);
562             }
563         }
564     }
565 
566     /**
567      * Print the object's state and debug information into the given stream.
568      *
569      * @param pw The stream to dump information to.
570      */
dump(PrintWriter pw)571     public void dump(PrintWriter pw) {
572         pw.println("DisplayModeDirector");
573         synchronized (mLock) {
574             pw.println("  mSupportedModesByDisplay:");
575             for (int i = 0; i < mSupportedModesByDisplay.size(); i++) {
576                 final int id = mSupportedModesByDisplay.keyAt(i);
577                 final Display.Mode[] modes = mSupportedModesByDisplay.valueAt(i);
578                 pw.println("    " + id + " -> " + Arrays.toString(modes));
579             }
580             pw.println("  mAppSupportedModesByDisplay:");
581             for (int i = 0; i < mAppSupportedModesByDisplay.size(); i++) {
582                 final int id = mAppSupportedModesByDisplay.keyAt(i);
583                 final Display.Mode[] modes = mAppSupportedModesByDisplay.valueAt(i);
584                 pw.println("    " + id + " -> " + Arrays.toString(modes));
585             }
586             pw.println("  mDefaultModeByDisplay:");
587             for (int i = 0; i < mDefaultModeByDisplay.size(); i++) {
588                 final int id = mDefaultModeByDisplay.keyAt(i);
589                 final Display.Mode mode = mDefaultModeByDisplay.valueAt(i);
590                 pw.println("    " + id + " -> " + mode);
591             }
592             pw.println("  mModeSwitchingType: " + switchingTypeToString(mModeSwitchingType));
593             pw.println("  mAlwaysRespectAppRequest: " + mAlwaysRespectAppRequest);
594             mSettingsObserver.dumpLocked(pw);
595             mAppRequestObserver.dumpLocked(pw);
596             mBrightnessObserver.dumpLocked(pw);
597             mUdfpsObserver.dumpLocked(pw);
598             mHbmObserver.dumpLocked(pw);
599             mSkinThermalStatusObserver.dumpLocked(pw);
600         }
601         mVotesStorage.dump(pw);
602         mSensorObserver.dump(pw);
603     }
604 
605     @GuardedBy("mLock")
getMaxRefreshRateLocked(int displayId)606     private float getMaxRefreshRateLocked(int displayId) {
607         Display.Mode[] modes = mSupportedModesByDisplay.get(displayId);
608         float maxRefreshRate = 0f;
609         for (Display.Mode mode : modes) {
610             if (mode.getRefreshRate() > maxRefreshRate) {
611                 maxRefreshRate = mode.getRefreshRate();
612             }
613         }
614         return maxRefreshRate;
615     }
616 
notifyDesiredDisplayModeSpecsChangedLocked()617     private void notifyDesiredDisplayModeSpecsChangedLocked() {
618         if (mDesiredDisplayModeSpecsListener != null
619                 && !mHandler.hasMessages(MSG_REFRESH_RATE_RANGE_CHANGED)) {
620             // We need to post this to a handler to avoid calling out while holding the lock
621             // since we know there are things that both listen for changes as well as provide
622             // information. If we did call out while holding the lock, then there's no
623             // guaranteed lock order and we run the real of risk deadlock.
624             Message msg = mHandler.obtainMessage(
625                     MSG_REFRESH_RATE_RANGE_CHANGED, mDesiredDisplayModeSpecsListener);
626             msg.sendToTarget();
627         }
628     }
629 
switchingTypeToString(@isplayManager.SwitchingType int type)630     private static String switchingTypeToString(@DisplayManager.SwitchingType int type) {
631         switch (type) {
632             case DisplayManager.SWITCHING_TYPE_NONE:
633                 return "SWITCHING_TYPE_NONE";
634             case DisplayManager.SWITCHING_TYPE_WITHIN_GROUPS:
635                 return "SWITCHING_TYPE_WITHIN_GROUPS";
636             case DisplayManager.SWITCHING_TYPE_ACROSS_AND_WITHIN_GROUPS:
637                 return "SWITCHING_TYPE_ACROSS_AND_WITHIN_GROUPS";
638             case DisplayManager.SWITCHING_TYPE_RENDER_FRAME_RATE_ONLY:
639                 return "SWITCHING_TYPE_RENDER_FRAME_RATE_ONLY";
640             default:
641                 return "Unknown SwitchingType " + type;
642         }
643     }
644 
645     @VisibleForTesting
injectSupportedModesByDisplay(SparseArray<Display.Mode[]> supportedModesByDisplay)646     void injectSupportedModesByDisplay(SparseArray<Display.Mode[]> supportedModesByDisplay) {
647         mSupportedModesByDisplay = supportedModesByDisplay;
648     }
649 
650     @VisibleForTesting
injectAppSupportedModesByDisplay(SparseArray<Display.Mode[]> appSupportedModesByDisplay)651     void injectAppSupportedModesByDisplay(SparseArray<Display.Mode[]> appSupportedModesByDisplay) {
652         mAppSupportedModesByDisplay = appSupportedModesByDisplay;
653     }
654 
655     @VisibleForTesting
injectDefaultModeByDisplay(SparseArray<Display.Mode> defaultModeByDisplay)656     void injectDefaultModeByDisplay(SparseArray<Display.Mode> defaultModeByDisplay) {
657         mDefaultModeByDisplay = defaultModeByDisplay;
658     }
659 
660     @VisibleForTesting
injectDisplayDeviceConfigByDisplay(SparseArray<DisplayDeviceConfig> ddcByDisplay)661     void injectDisplayDeviceConfigByDisplay(SparseArray<DisplayDeviceConfig> ddcByDisplay) {
662         mDisplayDeviceConfigByDisplay = ddcByDisplay;
663     }
664 
665     @VisibleForTesting
injectVotesByDisplay(SparseArray<SparseArray<Vote>> votesByDisplay)666     void injectVotesByDisplay(SparseArray<SparseArray<Vote>> votesByDisplay) {
667         mVotesStorage.injectVotesByDisplay(votesByDisplay);
668     }
669 
670     @VisibleForTesting
injectBrightnessObserver(BrightnessObserver brightnessObserver)671     void injectBrightnessObserver(BrightnessObserver brightnessObserver) {
672         mBrightnessObserver = brightnessObserver;
673     }
674 
675     @VisibleForTesting
getBrightnessObserver()676     BrightnessObserver getBrightnessObserver() {
677         return mBrightnessObserver;
678     }
679 
680     @VisibleForTesting
getSettingsObserver()681     SettingsObserver getSettingsObserver() {
682         return mSettingsObserver;
683     }
684 
685     @VisibleForTesting
getUdpfsObserver()686     UdfpsObserver getUdpfsObserver() {
687         return mUdfpsObserver;
688     }
689 
690     @VisibleForTesting
getHbmObserver()691     HbmObserver getHbmObserver() {
692         return mHbmObserver;
693     }
694 
695     @VisibleForTesting
getDisplayObserver()696     DisplayObserver getDisplayObserver() {
697         return mDisplayObserver;
698     }
699 
700     @VisibleForTesting
getDesiredDisplayModeSpecsWithInjectedFpsSettings( float minRefreshRate, float peakRefreshRate, float defaultRefreshRate)701     DesiredDisplayModeSpecs getDesiredDisplayModeSpecsWithInjectedFpsSettings(
702             float minRefreshRate, float peakRefreshRate, float defaultRefreshRate) {
703         synchronized (mLock) {
704             mSettingsObserver.updateRefreshRateSettingLocked(minRefreshRate, peakRefreshRate,
705                     defaultRefreshRate, Display.DEFAULT_DISPLAY);
706             return getDesiredDisplayModeSpecs(Display.DEFAULT_DISPLAY);
707         }
708     }
709 
710     /**
711      * Provides access to DisplayDeviceConfig for specific display
712      */
713     public interface DisplayDeviceConfigProvider {
714         /**
715          * Returns DisplayDeviceConfig for specific display
716          */
getDisplayDeviceConfig(int displayId)717         @Nullable DisplayDeviceConfig getDisplayDeviceConfig(int displayId);
718     }
719 
720     /**
721      * Listens for changes refresh rate coordination.
722      */
723     public interface DesiredDisplayModeSpecsListener {
724         /**
725          * Called when the refresh rate range may have changed.
726          */
onDesiredDisplayModeSpecsChanged()727         void onDesiredDisplayModeSpecsChanged();
728     }
729 
730     private final class DisplayModeDirectorHandler extends Handler {
DisplayModeDirectorHandler(Looper looper)731         DisplayModeDirectorHandler(Looper looper) {
732             super(looper, null, true /*async*/);
733         }
734 
735         @Override
handleMessage(Message msg)736         public void handleMessage(Message msg) {
737             switch (msg.what) {
738                 case MSG_LOW_BRIGHTNESS_THRESHOLDS_CHANGED: {
739                     Pair<float[], float[]> thresholds = (Pair<float[], float[]>) msg.obj;
740                     mBrightnessObserver.onDeviceConfigLowBrightnessThresholdsChanged(
741                             thresholds.first, thresholds.second);
742                     break;
743                 }
744 
745                 case MSG_REFRESH_RATE_IN_LOW_ZONE_CHANGED: {
746                     int refreshRateInZone = msg.arg1;
747                     mBrightnessObserver.onDeviceConfigRefreshRateInLowZoneChanged(
748                             refreshRateInZone);
749                     break;
750                 }
751 
752                 case MSG_HIGH_BRIGHTNESS_THRESHOLDS_CHANGED: {
753                     Pair<float[], float[]> thresholds = (Pair<float[], float[]>) msg.obj;
754 
755                     mBrightnessObserver.onDeviceConfigHighBrightnessThresholdsChanged(
756                             thresholds.first, thresholds.second);
757 
758                     break;
759                 }
760 
761                 case MSG_REFRESH_RATE_IN_HIGH_ZONE_CHANGED: {
762                     int refreshRateInZone = msg.arg1;
763                     mBrightnessObserver.onDeviceConfigRefreshRateInHighZoneChanged(
764                             refreshRateInZone);
765                     break;
766                 }
767 
768                 case MSG_DEFAULT_PEAK_REFRESH_RATE_CHANGED:
769                     Float defaultPeakRefreshRate = (Float) msg.obj;
770                     mSettingsObserver.onDeviceConfigDefaultPeakRefreshRateChanged(
771                             defaultPeakRefreshRate);
772                     break;
773 
774                 case MSG_REFRESH_RATE_RANGE_CHANGED:
775                     DesiredDisplayModeSpecsListener desiredDisplayModeSpecsListener =
776                             (DesiredDisplayModeSpecsListener) msg.obj;
777                     desiredDisplayModeSpecsListener.onDesiredDisplayModeSpecsChanged();
778                     break;
779 
780                 case MSG_REFRESH_RATE_IN_HBM_SUNLIGHT_CHANGED: {
781                     int refreshRateInHbmSunlight = msg.arg1;
782                     mHbmObserver.onDeviceConfigRefreshRateInHbmSunlightChanged(
783                             refreshRateInHbmSunlight);
784                     break;
785                 }
786 
787                 case MSG_REFRESH_RATE_IN_HBM_HDR_CHANGED: {
788                     int refreshRateInHbmHdr = msg.arg1;
789                     mHbmObserver.onDeviceConfigRefreshRateInHbmHdrChanged(refreshRateInHbmHdr);
790                     break;
791                 }
792             }
793         }
794     }
795 
796     /**
797      * Information about the desired display mode to be set by the system. Includes the base
798      * mode ID and the primary and app request refresh rate ranges.
799      *
800      * We have this class in addition to SurfaceControl.DesiredDisplayConfigSpecs to make clear the
801      * distinction between the config ID / physical index that
802      * SurfaceControl.DesiredDisplayConfigSpecs uses, and the mode ID used here.
803      */
804     public static final class DesiredDisplayModeSpecs {
805 
806         /**
807          * Base mode ID. This is what system defaults to for all other settings, or
808          * if the refresh rate range is not available.
809          */
810         public int baseModeId;
811 
812         /**
813          * If true this will allow switching between modes in different display configuration
814          * groups. This way the user may see visual interruptions when the display mode changes.
815          */
816         public boolean allowGroupSwitching;
817 
818         /**
819          * Represents the idle time of the screen after which the associated display's refresh rate
820          * is to be reduced to preserve power
821          * Defaults to null, meaning that the device is not configured to have a timeout based on
822          * the surrounding conditions
823          * -1 means that the current conditions require no timeout
824          */
825         @Nullable
826         public IdleScreenRefreshRateConfig mIdleScreenRefreshRateConfig;
827 
828         /**
829          * The primary refresh rate ranges.
830          */
831         public final RefreshRateRanges primary;
832         /**
833          * The app request refresh rate ranges. Lower priority considerations won't be included in
834          * this range, allowing SurfaceFlinger to consider additional refresh rates for apps that
835          * call setFrameRate(). This range will be greater than or equal to the primary refresh rate
836          * range, never smaller.
837          */
838         public final RefreshRateRanges appRequest;
839 
DesiredDisplayModeSpecs()840         public DesiredDisplayModeSpecs() {
841             primary = new RefreshRateRanges();
842             appRequest = new RefreshRateRanges();
843         }
844 
DesiredDisplayModeSpecs(int baseModeId, boolean allowGroupSwitching, @NonNull RefreshRateRanges primary, @NonNull RefreshRateRanges appRequest, @Nullable SurfaceControl.IdleScreenRefreshRateConfig idleScreenRefreshRateConfig)845         public DesiredDisplayModeSpecs(int baseModeId,
846                 boolean allowGroupSwitching,
847                 @NonNull RefreshRateRanges primary,
848                 @NonNull RefreshRateRanges appRequest,
849                 @Nullable SurfaceControl.IdleScreenRefreshRateConfig idleScreenRefreshRateConfig) {
850             this.baseModeId = baseModeId;
851             this.allowGroupSwitching = allowGroupSwitching;
852             this.primary = primary;
853             this.appRequest = appRequest;
854             this.mIdleScreenRefreshRateConfig = idleScreenRefreshRateConfig;
855         }
856 
857         /**
858          * Returns a string representation of the object.
859          */
860         @Override
toString()861         public String toString() {
862             return String.format("baseModeId=%d allowGroupSwitching=%b"
863                             + " primary=%s"
864                             + " appRequest=%s"
865                             + " idleScreenRefreshRateConfig=%s",
866                     baseModeId, allowGroupSwitching, primary.toString(),
867                     appRequest.toString(), String.valueOf(mIdleScreenRefreshRateConfig));
868         }
869 
870         /**
871          * Checks whether the two objects have the same values.
872          */
873         @Override
equals(Object other)874         public boolean equals(Object other) {
875             if (other == this) {
876                 return true;
877             }
878 
879             if (!(other instanceof DesiredDisplayModeSpecs)) {
880                 return false;
881             }
882 
883             DesiredDisplayModeSpecs desiredDisplayModeSpecs = (DesiredDisplayModeSpecs) other;
884 
885             if (baseModeId != desiredDisplayModeSpecs.baseModeId) {
886                 return false;
887             }
888             if (allowGroupSwitching != desiredDisplayModeSpecs.allowGroupSwitching) {
889                 return false;
890             }
891             if (!primary.equals(desiredDisplayModeSpecs.primary)) {
892                 return false;
893             }
894             if (!appRequest.equals(
895                     desiredDisplayModeSpecs.appRequest)) {
896                 return false;
897             }
898 
899             if (!Objects.equals(mIdleScreenRefreshRateConfig,
900                     desiredDisplayModeSpecs.mIdleScreenRefreshRateConfig)) {
901                 return false;
902             }
903             return true;
904         }
905 
906         @Override
hashCode()907         public int hashCode() {
908             return Objects.hash(baseModeId, allowGroupSwitching, primary, appRequest,
909                     mIdleScreenRefreshRateConfig);
910         }
911 
912         /**
913          * Copy values from the other object.
914          */
copyFrom(DesiredDisplayModeSpecs other)915         public void copyFrom(DesiredDisplayModeSpecs other) {
916             baseModeId = other.baseModeId;
917             allowGroupSwitching = other.allowGroupSwitching;
918             primary.physical.min = other.primary.physical.min;
919             primary.physical.max = other.primary.physical.max;
920             primary.render.min = other.primary.render.min;
921             primary.render.max = other.primary.render.max;
922 
923             appRequest.physical.min = other.appRequest.physical.min;
924             appRequest.physical.max = other.appRequest.physical.max;
925             appRequest.render.min = other.appRequest.render.min;
926             appRequest.render.max = other.appRequest.render.max;
927 
928             if (other.mIdleScreenRefreshRateConfig == null) {
929                 mIdleScreenRefreshRateConfig = null;
930             } else {
931                 mIdleScreenRefreshRateConfig =
932                         new IdleScreenRefreshRateConfig(
933                                 other.mIdleScreenRefreshRateConfig.timeoutMillis);
934             }
935         }
936     }
937 
938     @VisibleForTesting
939     final class SettingsObserver extends ContentObserver {
940         private final Uri mPeakRefreshRateSetting =
941                 Settings.System.getUriFor(Settings.System.PEAK_REFRESH_RATE);
942         private final Uri mMinRefreshRateSetting =
943                 Settings.System.getUriFor(Settings.System.MIN_REFRESH_RATE);
944         private final Uri mLowPowerModeSetting =
945                 Settings.Global.getUriFor(Settings.Global.LOW_POWER_MODE);
946         private final Uri mMatchContentFrameRateSetting =
947                 Settings.Secure.getUriFor(Settings.Secure.MATCH_CONTENT_FRAME_RATE);
948 
949         private final boolean mVsyncLowPowerVoteEnabled;
950         private final boolean mPeakRefreshRatePhysicalLimitEnabled;
951 
952         private final Context mContext;
953         private final Handler mHandler;
954         private float mDefaultPeakRefreshRate;
955         private float mDefaultRefreshRate;
956         private boolean mIsLowPower = false;
957 
958         private final DisplayManager.DisplayListener mDisplayListener =
959                 new DisplayManager.DisplayListener() {
960                     @Override
961                     public void onDisplayAdded(int displayId) {
962                         synchronized (mLock) {
963                             updateLowPowerModeAllowedModesLocked();
964                         }
965                     }
966 
967                     @Override
968                     public void onDisplayRemoved(int displayId) {
969                         mVotesStorage.updateVote(displayId, Vote.PRIORITY_LOW_POWER_MODE_MODES,
970                                 null);
971                     }
972 
973                     @Override
974                     public void onDisplayChanged(int displayId) {
975                         synchronized (mLock) {
976                             updateLowPowerModeAllowedModesLocked();
977                         }
978                     }
979                 };
980 
SettingsObserver(@onNull Context context, @NonNull Handler handler, DisplayManagerFlags flags)981         SettingsObserver(@NonNull Context context, @NonNull Handler handler,
982                 DisplayManagerFlags flags) {
983             super(handler);
984             mContext = context;
985             mHandler = handler;
986             mVsyncLowPowerVoteEnabled = flags.isVsyncLowPowerVoteEnabled();
987             mPeakRefreshRatePhysicalLimitEnabled = flags.isPeakRefreshRatePhysicalLimitEnabled();
988             // We don't want to load from the DeviceConfig while constructing since this leads to
989             // a spike in the latency of DisplayManagerService startup. This happens because
990             // reading from the DeviceConfig is an intensive IO operation and having it in the
991             // startup phase where we thrive to keep the latency very low has significant impact.
992             setRefreshRates(/* displayDeviceConfig= */ null,
993                 /* attemptReadFromFeatureParams= */ false);
994         }
995 
996         /**
997          * This is used to update the refresh rate configs from the DeviceConfig, which
998          * if missing from DisplayDeviceConfig, and finally fallback to config.xml.
999          */
setRefreshRates(DisplayDeviceConfig displayDeviceConfig, boolean attemptReadFromFeatureParams)1000         void setRefreshRates(DisplayDeviceConfig displayDeviceConfig,
1001                 boolean attemptReadFromFeatureParams) {
1002             RefreshRateData refreshRateData = displayDeviceConfig == null ? null
1003                     : displayDeviceConfig.getRefreshRateData();
1004             setDefaultPeakRefreshRate(displayDeviceConfig, attemptReadFromFeatureParams);
1005             mDefaultRefreshRate =
1006                     (refreshRateData == null) ? (float) mContext.getResources().getInteger(
1007                             R.integer.config_defaultRefreshRate)
1008                             : (float) refreshRateData.defaultRefreshRate;
1009         }
1010 
observe()1011         public void observe() {
1012             final ContentResolver cr = mContext.getContentResolver();
1013             mInjector.registerPeakRefreshRateObserver(cr, this);
1014             mInjector.registerMinRefreshRateObserver(cr, this);
1015             cr.registerContentObserver(mLowPowerModeSetting, false /*notifyDescendants*/, this,
1016                     UserHandle.USER_SYSTEM);
1017             cr.registerContentObserver(mMatchContentFrameRateSetting, false /*notifyDescendants*/,
1018                     this);
1019             mInjector.registerDisplayListener(mDisplayListener, mHandler);
1020 
1021             float deviceConfigDefaultPeakRefresh =
1022                     mConfigParameterProvider.getPeakRefreshRateDefault();
1023             if (deviceConfigDefaultPeakRefresh != -1) {
1024                 mDefaultPeakRefreshRate = deviceConfigDefaultPeakRefresh;
1025             }
1026 
1027             synchronized (mLock) {
1028                 updateRefreshRateSettingLocked();
1029                 updateLowPowerModeSettingLocked();
1030                 updateModeSwitchingTypeSettingLocked();
1031             }
1032 
1033         }
1034 
setDefaultRefreshRate(float refreshRate)1035         public void setDefaultRefreshRate(float refreshRate) {
1036             synchronized (mLock) {
1037                 mDefaultRefreshRate = refreshRate;
1038                 updateRefreshRateSettingLocked();
1039             }
1040         }
1041 
onDeviceConfigDefaultPeakRefreshRateChanged(Float defaultPeakRefreshRate)1042         public void onDeviceConfigDefaultPeakRefreshRateChanged(Float defaultPeakRefreshRate) {
1043             synchronized (mLock) {
1044                 if (defaultPeakRefreshRate == null) {
1045                     setDefaultPeakRefreshRate(mDefaultDisplayDeviceConfig,
1046                             /* attemptReadFromFeatureParams= */ false);
1047                 } else if (mDefaultPeakRefreshRate != defaultPeakRefreshRate) {
1048                     mDefaultPeakRefreshRate = defaultPeakRefreshRate;
1049                 }
1050                 updateRefreshRateSettingLocked();
1051             }
1052         }
1053 
1054         @Override
onChange(boolean selfChange, Uri uri, int userId)1055         public void onChange(boolean selfChange, Uri uri, int userId) {
1056             synchronized (mLock) {
1057                 if (mPeakRefreshRateSetting.equals(uri) || mMinRefreshRateSetting.equals(uri)) {
1058                     updateRefreshRateSettingLocked();
1059                 } else if (mLowPowerModeSetting.equals(uri)) {
1060                     updateLowPowerModeSettingLocked();
1061                 } else if (mMatchContentFrameRateSetting.equals(uri)) {
1062                     updateModeSwitchingTypeSettingLocked();
1063                 }
1064             }
1065         }
1066 
1067         @VisibleForTesting
getDefaultRefreshRate()1068         float getDefaultRefreshRate() {
1069             return mDefaultRefreshRate;
1070         }
1071 
1072         @VisibleForTesting
getDefaultPeakRefreshRate()1073         float getDefaultPeakRefreshRate() {
1074             return mDefaultPeakRefreshRate;
1075         }
1076 
setDefaultPeakRefreshRate(DisplayDeviceConfig displayDeviceConfig, boolean attemptReadFromFeatureParams)1077         private void setDefaultPeakRefreshRate(DisplayDeviceConfig displayDeviceConfig,
1078                 boolean attemptReadFromFeatureParams) {
1079             float defaultPeakRefreshRate = -1;
1080 
1081             if (attemptReadFromFeatureParams) {
1082                 try {
1083                     defaultPeakRefreshRate = mConfigParameterProvider.getPeakRefreshRateDefault();
1084                 } catch (Exception exception) {
1085                     // Do nothing
1086                 }
1087             }
1088             if (defaultPeakRefreshRate == -1) {
1089                 defaultPeakRefreshRate =
1090                         (displayDeviceConfig == null) ? (float) mContext.getResources().getInteger(
1091                                 R.integer.config_defaultPeakRefreshRate)
1092                                 : (float) displayDeviceConfig.getRefreshRateData()
1093                                         .defaultPeakRefreshRate;
1094             }
1095             mDefaultPeakRefreshRate = defaultPeakRefreshRate;
1096         }
1097 
updateLowPowerModeSettingLocked()1098         private void updateLowPowerModeSettingLocked() {
1099             mIsLowPower = Settings.Global.getInt(mContext.getContentResolver(),
1100                     Settings.Global.LOW_POWER_MODE, 0 /*default*/) != 0;
1101             final Vote vote;
1102             if (mIsLowPower) {
1103                 vote = Vote.forRenderFrameRates(0f, 60f);
1104             } else {
1105                 vote = null;
1106             }
1107             mVotesStorage.updateGlobalVote(Vote.PRIORITY_LOW_POWER_MODE_RENDER_RATE, vote);
1108             mBrightnessObserver.onLowPowerModeEnabledLocked(mIsLowPower);
1109             updateLowPowerModeAllowedModesLocked();
1110         }
1111 
updateLowPowerModeAllowedModesLocked()1112         private void updateLowPowerModeAllowedModesLocked() {
1113             if (!mVsyncLowPowerVoteEnabled) {
1114                 return;
1115             }
1116             if (mIsLowPower) {
1117                 for (int i = 0; i < mDisplayDeviceConfigByDisplay.size(); i++) {
1118                     DisplayDeviceConfig config = mDisplayDeviceConfigByDisplay.valueAt(i);
1119                     if (config == null) {
1120                         continue;
1121                     }
1122                     List<SupportedModeData> supportedModes = config
1123                             .getRefreshRateData().lowPowerSupportedModes;
1124                     mVotesStorage.updateVote(
1125                             mDisplayDeviceConfigByDisplay.keyAt(i),
1126                             Vote.PRIORITY_LOW_POWER_MODE_MODES,
1127                             Vote.forSupportedRefreshRates(supportedModes));
1128                 }
1129             } else {
1130                 mVotesStorage.removeAllVotesForPriority(Vote.PRIORITY_LOW_POWER_MODE_MODES);
1131             }
1132         }
1133 
1134         /**
1135          * Update refresh rate settings for all displays
1136          */
1137         @GuardedBy("mLock")
updateRefreshRateSettingLocked()1138         private void updateRefreshRateSettingLocked() {
1139             for (int i = 0; i < mSupportedModesByDisplay.size(); i++) {
1140                 updateRefreshRateSettingLocked(mSupportedModesByDisplay.keyAt(i));
1141             }
1142         }
1143 
1144         /**
1145          * Update refresh rate settings for a specific display
1146          * @param displayId The display ID
1147          */
1148         @GuardedBy("mLock")
updateRefreshRateSettingLocked(int displayId)1149         private void updateRefreshRateSettingLocked(int displayId) {
1150             final ContentResolver cr = mContext.getContentResolver();
1151             if (!mSupportedModesByDisplay.contains(displayId)) {
1152                 Slog.e(TAG, "Cannot update refresh rate setting: no supported modes for display "
1153                         + displayId);
1154                 return;
1155             }
1156             float highestRefreshRate = getMaxRefreshRateLocked(displayId);
1157 
1158             float minRefreshRate = Settings.System.getFloatForUser(cr,
1159                     Settings.System.MIN_REFRESH_RATE, 0f, cr.getUserId());
1160             if (Float.isInfinite(minRefreshRate)) {
1161                 // Infinity means that we want the highest possible refresh rate
1162                 minRefreshRate = highestRefreshRate;
1163             }
1164 
1165             float peakRefreshRate = Settings.System.getFloatForUser(cr,
1166                     Settings.System.PEAK_REFRESH_RATE, mDefaultPeakRefreshRate, cr.getUserId());
1167             if (Float.isInfinite(peakRefreshRate)) {
1168                 // Infinity means that we want the highest possible refresh rate
1169                 peakRefreshRate = highestRefreshRate;
1170             }
1171 
1172             updateRefreshRateSettingLocked(minRefreshRate, peakRefreshRate, mDefaultRefreshRate,
1173                     displayId);
1174         }
1175 
1176         @GuardedBy("mLock")
updateRefreshRateSettingLocked(float minRefreshRate, float peakRefreshRate, float defaultRefreshRate, int displayId)1177         private void updateRefreshRateSettingLocked(float minRefreshRate, float peakRefreshRate,
1178                 float defaultRefreshRate, int displayId) {
1179             // TODO(b/156304339): The logic in here, aside from updating the refresh rate votes, is
1180             // used to predict if we're going to be doing frequent refresh rate switching, and if
1181             // so, enable the brightness observer. The logic here is more complicated and fragile
1182             // than necessary, and we should improve it. See b/156304339 for more info.
1183             if (mPeakRefreshRatePhysicalLimitEnabled) {
1184                 Vote peakVote = peakRefreshRate == 0f
1185                         ? null
1186                         : Vote.forPhysicalRefreshRates(0f,
1187                                 Math.max(minRefreshRate, peakRefreshRate));
1188                 mVotesStorage.updateVote(displayId, Vote.PRIORITY_USER_SETTING_PEAK_REFRESH_RATE,
1189                         peakVote);
1190             }
1191             Vote peakRenderVote = peakRefreshRate == 0f
1192                     ? null
1193                     : Vote.forRenderFrameRates(0f, Math.max(minRefreshRate, peakRefreshRate));
1194             mVotesStorage.updateVote(displayId, Vote.PRIORITY_USER_SETTING_PEAK_RENDER_FRAME_RATE,
1195                     peakRenderVote);
1196             mVotesStorage.updateVote(displayId, Vote.PRIORITY_USER_SETTING_MIN_RENDER_FRAME_RATE,
1197                     Vote.forRenderFrameRates(minRefreshRate, Float.POSITIVE_INFINITY));
1198             Vote defaultVote =
1199                     defaultRefreshRate == 0f
1200                             ? null : Vote.forRenderFrameRates(0f, defaultRefreshRate);
1201             mVotesStorage.updateGlobalVote(Vote.PRIORITY_DEFAULT_RENDER_FRAME_RATE, defaultVote);
1202 
1203             float maxRefreshRate;
1204             if (peakRefreshRate == 0f && defaultRefreshRate == 0f) {
1205                 // We require that at least one of the peak or default refresh rate values are
1206                 // set. The brightness observer requires that we're able to predict whether or not
1207                 // we're going to do frequent refresh rate switching, and with the way the code is
1208                 // currently written, we need either a default or peak refresh rate value for that.
1209                 Slog.e(TAG, "Default and peak refresh rates are both 0. One of them should be set"
1210                         + " to a valid value.");
1211                 maxRefreshRate = minRefreshRate;
1212             } else if (peakRefreshRate == 0f) {
1213                 maxRefreshRate = defaultRefreshRate;
1214             } else if (defaultRefreshRate == 0f) {
1215                 maxRefreshRate = peakRefreshRate;
1216             } else {
1217                 maxRefreshRate = Math.min(defaultRefreshRate, peakRefreshRate);
1218             }
1219 
1220             // TODO(b/310237068): Make this work for multiple displays
1221             if (displayId == Display.DEFAULT_DISPLAY) {
1222                 mBrightnessObserver.onRefreshRateSettingChangedLocked(minRefreshRate,
1223                         maxRefreshRate);
1224             }
1225         }
1226 
removeRefreshRateSetting(int displayId)1227         private void removeRefreshRateSetting(int displayId) {
1228             mVotesStorage.updateVote(displayId, Vote.PRIORITY_USER_SETTING_PEAK_RENDER_FRAME_RATE,
1229                     null);
1230             mVotesStorage.updateVote(displayId, Vote.PRIORITY_USER_SETTING_MIN_RENDER_FRAME_RATE,
1231                     null);
1232             mVotesStorage.updateVote(displayId, Vote.PRIORITY_DEFAULT_RENDER_FRAME_RATE, null);
1233         }
1234 
updateModeSwitchingTypeSettingLocked()1235         private void updateModeSwitchingTypeSettingLocked() {
1236             final ContentResolver cr = mContext.getContentResolver();
1237             int switchingType = Settings.Secure.getIntForUser(
1238                     cr, Settings.Secure.MATCH_CONTENT_FRAME_RATE, mModeSwitchingType /*default*/,
1239                     cr.getUserId());
1240             if (switchingType != mModeSwitchingType) {
1241                 mModeSwitchingType = switchingType;
1242                 notifyDesiredDisplayModeSpecsChangedLocked();
1243             }
1244         }
1245 
dumpLocked(PrintWriter pw)1246         public void dumpLocked(PrintWriter pw) {
1247             pw.println("  SettingsObserver");
1248             pw.println("    mDefaultRefreshRate: " + mDefaultRefreshRate);
1249             pw.println("    mDefaultPeakRefreshRate: " + mDefaultPeakRefreshRate);
1250         }
1251     }
1252 
1253     /**
1254      *  Responsible for keeping track of app requested refresh rates per display
1255      */
1256     public final class AppRequestObserver {
1257         private final boolean mIgnorePreferredRefreshRate;
1258 
AppRequestObserver(DisplayManagerFlags flags)1259         AppRequestObserver(DisplayManagerFlags flags) {
1260             mIgnorePreferredRefreshRate = flags.ignoreAppPreferredRefreshRateRequest();
1261         }
1262 
1263         /**
1264          * Sets refresh rates from app request
1265          */
setAppRequest(int displayId, int modeId, float requestedRefreshRate, float requestedMinRefreshRateRange, float requestedMaxRefreshRateRange)1266         public void setAppRequest(int displayId, int modeId, float requestedRefreshRate,
1267                 float requestedMinRefreshRateRange, float requestedMaxRefreshRateRange) {
1268             Display.Mode requestedMode;
1269             synchronized (mLock) {
1270                 requestedMode = findModeLocked(displayId, modeId, requestedRefreshRate);
1271             }
1272 
1273             Vote frameRateVote = getFrameRateVote(
1274                     requestedMinRefreshRateRange, requestedMaxRefreshRateRange);
1275             Vote baseModeRefreshRateVote = getBaseModeVote(requestedMode, requestedRefreshRate);
1276             Vote sizeVote = getSizeVote(requestedMode);
1277 
1278             mVotesStorage.updateVote(displayId, Vote.PRIORITY_APP_REQUEST_RENDER_FRAME_RATE_RANGE,
1279                     frameRateVote);
1280             mVotesStorage.updateVote(displayId, Vote.PRIORITY_APP_REQUEST_BASE_MODE_REFRESH_RATE,
1281                     baseModeRefreshRateVote);
1282             mVotesStorage.updateVote(displayId, Vote.PRIORITY_APP_REQUEST_SIZE, sizeVote);
1283         }
1284 
findModeLocked(int displayId, int modeId, float requestedRefreshRate)1285         private Display.Mode findModeLocked(int displayId, int modeId, float requestedRefreshRate) {
1286             Display.Mode mode = null;
1287             if (modeId != 0) {
1288                 mode = findAppModeByIdLocked(displayId, modeId);
1289             } else if (requestedRefreshRate != 0 && !mIgnorePreferredRefreshRate) { // modeId == 0
1290                 // Scan supported modes returned to find a mode with the same
1291                 // size as the default display mode but with the specified refresh rate instead.
1292                 mode = findDefaultModeByRefreshRateLocked(displayId, requestedRefreshRate);
1293                 if (mode == null) {
1294                     Slog.e(TAG, "Couldn't find a mode for the requestedRefreshRate: "
1295                             + requestedRefreshRate + " on Display: " + displayId);
1296                 }
1297             }
1298             return mode;
1299         }
1300 
getFrameRateVote(float minRefreshRate, float maxRefreshRate)1301         private Vote getFrameRateVote(float minRefreshRate, float maxRefreshRate) {
1302             RefreshRateRange refreshRateRange = null;
1303             if (minRefreshRate > 0 || maxRefreshRate > 0) {
1304                 float max = maxRefreshRate > 0
1305                         ? maxRefreshRate : Float.POSITIVE_INFINITY;
1306                 refreshRateRange = new RefreshRateRange(minRefreshRate, max);
1307                 if (refreshRateRange.min == 0 && refreshRateRange.max == 0) {
1308                     // minRefreshRate/maxRefreshRate were invalid
1309                     refreshRateRange = null;
1310                 }
1311             }
1312             return refreshRateRange != null
1313                     ? Vote.forRenderFrameRates(refreshRateRange.min, refreshRateRange.max) : null;
1314         }
1315 
getSizeVote(@ullable Display.Mode mode)1316         private Vote getSizeVote(@Nullable Display.Mode mode) {
1317             return mode != null
1318                     ?  Vote.forSize(mode.getPhysicalWidth(), mode.getPhysicalHeight()) : null;
1319         }
1320 
getBaseModeVote(@ullable Display.Mode mode, float requestedRefreshRate)1321         private Vote getBaseModeVote(@Nullable Display.Mode mode, float requestedRefreshRate) {
1322             Vote vote = null;
1323             if (mode != null) {
1324                 if (mode.isSynthetic()) {
1325                     vote = Vote.forRequestedRefreshRate(mode.getRefreshRate());
1326                 } else {
1327                     vote = Vote.forBaseModeRefreshRate(mode.getRefreshRate());
1328                 }
1329             } else if (requestedRefreshRate != 0f && mIgnorePreferredRefreshRate) {
1330                 vote = Vote.forRequestedRefreshRate(requestedRefreshRate);
1331             } // !mIgnorePreferredRefreshRate case is handled by findModeLocked
1332             return vote;
1333         }
1334 
1335         @Nullable
findDefaultModeByRefreshRateLocked(int displayId, float refreshRate)1336         private Display.Mode findDefaultModeByRefreshRateLocked(int displayId, float refreshRate) {
1337             Display.Mode[] modes = mAppSupportedModesByDisplay.get(displayId);
1338             Display.Mode defaultMode = mDefaultModeByDisplay.get(displayId);
1339             for (int i = 0; i < modes.length; i++) {
1340                 if (modes[i].matches(defaultMode.getPhysicalWidth(),
1341                         defaultMode.getPhysicalHeight(), refreshRate)) {
1342                     return modes[i];
1343                 }
1344             }
1345             return null;
1346         }
1347 
findAppModeByIdLocked(int displayId, int modeId)1348         private Display.Mode findAppModeByIdLocked(int displayId, int modeId) {
1349             Display.Mode[] modes = mAppSupportedModesByDisplay.get(displayId);
1350             if (modes == null) {
1351                 return null;
1352             }
1353             for (Display.Mode mode : modes) {
1354                 if (mode.getModeId() == modeId) {
1355                     return mode;
1356                 }
1357             }
1358             return null;
1359         }
1360 
dumpLocked(PrintWriter pw)1361         private void dumpLocked(PrintWriter pw) {
1362             pw.println("  AppRequestObserver");
1363             pw.println("    mIgnorePreferredRefreshRate: " + mIgnorePreferredRefreshRate);
1364         }
1365     }
1366 
1367     @VisibleForTesting
1368     public final class DisplayObserver implements DisplayManager.DisplayListener {
1369         // Note that we can never call into DisplayManager or any of the non-POD classes it
1370         // returns, while holding mLock since it may call into DMS, which might be simultaneously
1371         // calling into us already holding its own lock.
1372         private final Context mContext;
1373         private final Handler mHandler;
1374         private final VotesStorage mVotesStorage;
1375 
1376         private int mExternalDisplayPeakWidth;
1377         private int mExternalDisplayPeakHeight;
1378         private int mExternalDisplayPeakRefreshRate;
1379         private final boolean mRefreshRateSynchronizationEnabled;
1380         private final Set<Integer> mExternalDisplaysConnected = new HashSet<>();
1381 
DisplayObserver(Context context, Handler handler, VotesStorage votesStorage, Injector injector)1382         DisplayObserver(Context context, Handler handler, VotesStorage votesStorage,
1383                 Injector injector) {
1384             mContext = context;
1385             mHandler = handler;
1386             mVotesStorage = votesStorage;
1387             mExternalDisplayPeakRefreshRate = mContext.getResources().getInteger(
1388                         R.integer.config_externalDisplayPeakRefreshRate);
1389             mExternalDisplayPeakWidth = mContext.getResources().getInteger(
1390                         R.integer.config_externalDisplayPeakWidth);
1391             mExternalDisplayPeakHeight = mContext.getResources().getInteger(
1392                         R.integer.config_externalDisplayPeakHeight);
1393             mRefreshRateSynchronizationEnabled = mContext.getResources().getBoolean(
1394                         R.bool.config_refreshRateSynchronizationEnabled);
1395         }
1396 
isExternalDisplayLimitModeEnabled()1397         private boolean isExternalDisplayLimitModeEnabled() {
1398             return mExternalDisplayPeakWidth > 0
1399                 && mExternalDisplayPeakHeight > 0
1400                 && mExternalDisplayPeakRefreshRate > 0
1401                 && mIsExternalDisplayLimitModeEnabled
1402                 && mIsDisplayResolutionRangeVotingEnabled
1403                 && mIsUserPreferredModeVoteEnabled;
1404         }
1405 
isRefreshRateSynchronizationEnabled()1406         private boolean isRefreshRateSynchronizationEnabled() {
1407             return mRefreshRateSynchronizationEnabled
1408                 && mIsDisplaysRefreshRatesSynchronizationEnabled;
1409         }
1410 
observe()1411         public void observe() {
1412             mInjector.registerDisplayListener(this, mHandler);
1413 
1414             // Populate existing displays
1415             SparseArray<Display.Mode[]> modes = new SparseArray<>();
1416             SparseArray<Display.Mode[]> appModes = new SparseArray<>();
1417             SparseArray<Display.Mode> defaultModes = new SparseArray<>();
1418             Display[] displays = mInjector.getDisplays();
1419             for (Display d : displays) {
1420                 final int displayId = d.getDisplayId();
1421                 DisplayInfo info = getDisplayInfo(displayId);
1422                 modes.put(displayId, info.supportedModes);
1423                 appModes.put(displayId, info.appsSupportedModes);
1424                 defaultModes.put(displayId, info.getDefaultMode());
1425             }
1426             DisplayDeviceConfig defaultDisplayConfig = mDisplayDeviceConfigProvider
1427                     .getDisplayDeviceConfig(Display.DEFAULT_DISPLAY);
1428             synchronized (mLock) {
1429                 final int size = modes.size();
1430                 for (int i = 0; i < size; i++) {
1431                     mSupportedModesByDisplay.put(modes.keyAt(i), modes.valueAt(i));
1432                     mAppSupportedModesByDisplay.put(appModes.keyAt(i), appModes.valueAt(i));
1433                     mDefaultModeByDisplay.put(defaultModes.keyAt(i), defaultModes.valueAt(i));
1434                 }
1435                 mDisplayDeviceConfigByDisplay.put(Display.DEFAULT_DISPLAY, defaultDisplayConfig);
1436             }
1437         }
1438 
1439         @Override
onDisplayAdded(int displayId)1440         public void onDisplayAdded(int displayId) {
1441             updateDisplayDeviceConfig(displayId);
1442             DisplayInfo displayInfo = getDisplayInfo(displayId);
1443             updateDisplayModes(displayId, displayInfo);
1444             updateLayoutLimitedFrameRate(displayId, displayInfo);
1445             updateUserSettingDisplayPreferredSize(displayInfo);
1446             updateDisplaysPeakRefreshRateAndResolution(displayInfo);
1447             addDisplaysSynchronizedPeakRefreshRate(displayInfo);
1448         }
1449 
1450         @Override
onDisplayRemoved(int displayId)1451         public void onDisplayRemoved(int displayId) {
1452             synchronized (mLock) {
1453                 mSupportedModesByDisplay.remove(displayId);
1454                 mAppSupportedModesByDisplay.remove(displayId);
1455                 mDefaultModeByDisplay.remove(displayId);
1456                 mDisplayDeviceConfigByDisplay.remove(displayId);
1457                 mSettingsObserver.removeRefreshRateSetting(displayId);
1458             }
1459             updateLayoutLimitedFrameRate(displayId, null);
1460             removeUserSettingDisplayPreferredSize(displayId);
1461             removeDisplaysPeakRefreshRateAndResolution(displayId);
1462             removeDisplaysSynchronizedPeakRefreshRate(displayId);
1463         }
1464 
1465         @Override
onDisplayChanged(int displayId)1466         public void onDisplayChanged(int displayId) {
1467             updateDisplayDeviceConfig(displayId);
1468             DisplayInfo displayInfo = getDisplayInfo(displayId);
1469             updateDisplayModes(displayId, displayInfo);
1470             updateLayoutLimitedFrameRate(displayId, displayInfo);
1471             updateUserSettingDisplayPreferredSize(displayInfo);
1472         }
1473 
isExternalDisplayLocked(int displayId)1474         boolean isExternalDisplayLocked(int displayId) {
1475             return mExternalDisplaysConnected.contains(displayId);
1476         }
1477 
1478         @Nullable
getDisplayInfo(int displayId)1479         private DisplayInfo getDisplayInfo(int displayId) {
1480             DisplayInfo info = new DisplayInfo();
1481             // Display info might be invalid, in this case return null
1482             return mInjector.getDisplayInfo(displayId, info) ? info : null;
1483         }
1484 
updateLayoutLimitedFrameRate(int displayId, @Nullable DisplayInfo info)1485         private void updateLayoutLimitedFrameRate(int displayId, @Nullable DisplayInfo info) {
1486             Vote vote = info != null && info.layoutLimitedRefreshRate != null
1487                     ? Vote.forPhysicalRefreshRates(info.layoutLimitedRefreshRate.min,
1488                     info.layoutLimitedRefreshRate.max) : null;
1489             mVotesStorage.updateVote(displayId, Vote.PRIORITY_LAYOUT_LIMITED_FRAME_RATE, vote);
1490         }
1491 
removeUserSettingDisplayPreferredSize(int displayId)1492         private void removeUserSettingDisplayPreferredSize(int displayId) {
1493             if (!mIsUserPreferredModeVoteEnabled) {
1494                 return;
1495             }
1496             mVotesStorage.updateVote(displayId, Vote.PRIORITY_USER_SETTING_DISPLAY_PREFERRED_SIZE,
1497                     null);
1498         }
1499 
updateUserSettingDisplayPreferredSize(@ullable DisplayInfo info)1500         private void updateUserSettingDisplayPreferredSize(@Nullable DisplayInfo info) {
1501             if (info == null || !mIsUserPreferredModeVoteEnabled) {
1502                 return;
1503             }
1504 
1505             var preferredMode = findDisplayPreferredMode(info);
1506             if (preferredMode == null) {
1507                 removeUserSettingDisplayPreferredSize(info.displayId);
1508                 return;
1509             }
1510 
1511             mVotesStorage.updateVote(info.displayId,
1512                     Vote.PRIORITY_USER_SETTING_DISPLAY_PREFERRED_SIZE,
1513                     Vote.forSize(/* width */ preferredMode.getPhysicalWidth(),
1514                             /* height */ preferredMode.getPhysicalHeight()));
1515         }
1516 
1517         @Nullable
findDisplayPreferredMode(@onNull DisplayInfo info)1518         private Display.Mode findDisplayPreferredMode(@NonNull DisplayInfo info) {
1519             if (info.userPreferredModeId == INVALID_MODE_ID) {
1520                 return null;
1521             }
1522             for (var mode : info.supportedModes) {
1523                 if (mode.getModeId() == info.userPreferredModeId) {
1524                     return mode;
1525                 }
1526             }
1527             return null;
1528         }
1529 
removeDisplaysPeakRefreshRateAndResolution(int displayId)1530         private void removeDisplaysPeakRefreshRateAndResolution(int displayId) {
1531             if (!isExternalDisplayLimitModeEnabled()) {
1532                 return;
1533             }
1534 
1535             mVotesStorage.updateVote(displayId,
1536                     Vote.PRIORITY_LIMIT_MODE, null);
1537         }
1538 
updateDisplaysPeakRefreshRateAndResolution(@ullable final DisplayInfo info)1539         private void updateDisplaysPeakRefreshRateAndResolution(@Nullable final DisplayInfo info) {
1540             // Only consider external display, only in case the refresh rate and resolution limits
1541             // are non-zero.
1542             if (info == null || info.type != Display.TYPE_EXTERNAL
1543                     || !isExternalDisplayLimitModeEnabled()) {
1544                 return;
1545             }
1546 
1547             mVotesStorage.updateVote(info.displayId,
1548                     Vote.PRIORITY_LIMIT_MODE,
1549                     Vote.forSizeAndPhysicalRefreshRatesRange(
1550                             /* minWidth */ 0, /* minHeight */ 0,
1551                             mExternalDisplayPeakWidth,
1552                             mExternalDisplayPeakHeight,
1553                             /* minPhysicalRefreshRate */ 0,
1554                             mExternalDisplayPeakRefreshRate));
1555         }
1556 
1557         /**
1558          * Sets 60Hz target refresh rate as the vote with
1559          * {@link Vote#PRIORITY_SYNCHRONIZED_REFRESH_RATE} priority.
1560          */
addDisplaysSynchronizedPeakRefreshRate(@ullable final DisplayInfo info)1561         private void addDisplaysSynchronizedPeakRefreshRate(@Nullable final DisplayInfo info) {
1562             if (info == null || info.type != Display.TYPE_EXTERNAL
1563                     || !isRefreshRateSynchronizationEnabled()) {
1564                 return;
1565             }
1566             synchronized (mLock) {
1567                 mExternalDisplaysConnected.add(info.displayId);
1568                 if (mExternalDisplaysConnected.size() != 1) {
1569                     return;
1570                 }
1571             }
1572             // set minRefreshRate as the max refresh rate.
1573             mVotesStorage.updateGlobalVote(Vote.PRIORITY_SYNCHRONIZED_REFRESH_RATE,
1574                     Vote.forPhysicalRefreshRates(
1575                             SYNCHRONIZED_REFRESH_RATE_TARGET
1576                                 - SYNCHRONIZED_REFRESH_RATE_TOLERANCE,
1577                             SYNCHRONIZED_REFRESH_RATE_TARGET
1578                                 + SYNCHRONIZED_REFRESH_RATE_TOLERANCE));
1579         }
1580 
removeDisplaysSynchronizedPeakRefreshRate(final int displayId)1581         private void removeDisplaysSynchronizedPeakRefreshRate(final int displayId) {
1582             if (!isRefreshRateSynchronizationEnabled()) {
1583                 return;
1584             }
1585             synchronized (mLock) {
1586                 if (!isExternalDisplayLocked(displayId)) {
1587                     return;
1588                 }
1589                 mExternalDisplaysConnected.remove(displayId);
1590                 if (mExternalDisplaysConnected.size() != 0) {
1591                     return;
1592                 }
1593             }
1594             mVotesStorage.updateGlobalVote(Vote.PRIORITY_SYNCHRONIZED_REFRESH_RATE, null);
1595         }
1596 
updateDisplayDeviceConfig(int displayId)1597         private void updateDisplayDeviceConfig(int displayId) {
1598             DisplayDeviceConfig config = mDisplayDeviceConfigProvider
1599                     .getDisplayDeviceConfig(displayId);
1600             synchronized (mLock) {
1601                 mDisplayDeviceConfigByDisplay.put(displayId, config);
1602             }
1603         }
1604 
updateDisplayModes(int displayId, @Nullable DisplayInfo info)1605         private void updateDisplayModes(int displayId, @Nullable DisplayInfo info) {
1606             if (info == null) {
1607                 return;
1608             }
1609             boolean changed = false;
1610             synchronized (mLock) {
1611                 if (!Arrays.equals(mSupportedModesByDisplay.get(displayId), info.supportedModes)) {
1612                     mSupportedModesByDisplay.put(displayId, info.supportedModes);
1613                     changed = true;
1614                 }
1615                 if (!Arrays.equals(mAppSupportedModesByDisplay.get(displayId),
1616                         info.appsSupportedModes)) {
1617                     mAppSupportedModesByDisplay.put(displayId, info.appsSupportedModes);
1618                     changed = true;
1619                 }
1620                 if (!Objects.equals(mDefaultModeByDisplay.get(displayId), info.getDefaultMode())) {
1621                     changed = true;
1622                     mDefaultModeByDisplay.put(displayId, info.getDefaultMode());
1623                 }
1624                 if (changed) {
1625                     notifyDesiredDisplayModeSpecsChangedLocked();
1626                     mSettingsObserver.updateRefreshRateSettingLocked(displayId);
1627                 }
1628             }
1629         }
1630     }
1631 
1632     /**
1633      * This class manages brightness threshold for switching between 60 hz and higher refresh rate.
1634      * See more information at the definition of
1635      * {@link R.array#config_brightnessThresholdsOfPeakRefreshRate} and
1636      * {@link R.array#config_ambientThresholdsOfPeakRefreshRate}.
1637      */
1638     @VisibleForTesting
1639     public class BrightnessObserver implements DisplayManager.DisplayListener {
1640         private static final int LIGHT_SENSOR_RATE_MS = 250;
1641 
1642         /**
1643          * Brightness thresholds for the low zone. Paired with lux thresholds.
1644          *
1645          * A negative value means that only the lux threshold should be applied.
1646          */
1647         private float[] mLowDisplayBrightnessThresholds;
1648         /**
1649          * Lux thresholds for the low zone. Paired with brightness thresholds.
1650          *
1651          * A negative value means that only the display brightness threshold should be applied.
1652          */
1653         private float[] mLowAmbientBrightnessThresholds;
1654 
1655         /**
1656          * Brightness thresholds for the high zone. Paired with lux thresholds.
1657          *
1658          * A negative value means that only the lux threshold should be applied.
1659          */
1660         private float[] mHighDisplayBrightnessThresholds;
1661         /**
1662          * Lux thresholds for the high zone. Paired with brightness thresholds.
1663          *
1664          * A negative value means that only the display brightness threshold should be applied.
1665          */
1666         private float[] mHighAmbientBrightnessThresholds;
1667         // valid threshold if any item from the array >= 0
1668         private boolean mShouldObserveDisplayLowChange;
1669         private boolean mShouldObserveAmbientLowChange;
1670         private boolean mShouldObserveDisplayHighChange;
1671         private boolean mShouldObserveAmbientHighChange;
1672         private boolean mLoggingEnabled;
1673 
1674         private SensorManager mSensorManager;
1675         private Sensor mLightSensor;
1676         private Sensor mRegisteredLightSensor;
1677         private String mLightSensorType;
1678         private String mLightSensorName;
1679         private final LightSensorEventListener mLightSensorListener =
1680                 new LightSensorEventListener();
1681         // Take it as low brightness before valid sensor data comes
1682         private float mAmbientLux = -1.0f;
1683         private AmbientFilter mAmbientFilter;
1684 
1685         /**
1686          * The current timeout configuration. This value is used by surface flinger to track the
1687          * time after which an idle screen's refresh rate is to be reduced.
1688          */
1689         @Nullable
1690         private SurfaceControl.IdleScreenRefreshRateConfig mIdleScreenRefreshRateConfig;
1691 
1692         private float mBrightness = PowerManager.BRIGHTNESS_INVALID_FLOAT;
1693 
1694         private final Context mContext;
1695         private final Injector mInjector;
1696         private final Handler mHandler;
1697 
1698 
1699         private final boolean mVsyncLowLightBlockingVoteEnabled;
1700 
1701         private final IThermalEventListener.Stub mThermalListener =
1702                 new IThermalEventListener.Stub() {
1703                     @Override
1704                     public void notifyThrottling(Temperature temp) {
1705                         @Temperature.ThrottlingStatus int currentStatus = temp.getStatus();
1706                         synchronized (mLock) {
1707                             if (mThermalStatus != currentStatus) {
1708                                 mThermalStatus = currentStatus;
1709                             }
1710                             onBrightnessChangedLocked();
1711                         }
1712                     }
1713                 };
1714         private boolean mThermalRegistered;
1715 
1716         // Enable light sensor only when mShouldObserveAmbientLowChange is true or
1717         // mShouldObserveAmbientHighChange is true, screen is on, peak refresh rate
1718         // changeable and low power mode off. After initialization, these states will
1719         // be updated from the same handler thread.
1720         private int mDefaultDisplayState = Display.STATE_UNKNOWN;
1721         private boolean mRefreshRateChangeable = false;
1722         private boolean mLowPowerModeEnabled = false;
1723 
1724         @Nullable
1725         private SparseArray<RefreshRateRange> mLowZoneRefreshRateForThermals;
1726         private int mRefreshRateInLowZone;
1727 
1728         @Nullable
1729         private SparseArray<RefreshRateRange> mHighZoneRefreshRateForThermals;
1730         private int mRefreshRateInHighZone;
1731 
1732         @GuardedBy("mLock")
1733         private @Temperature.ThrottlingStatus int mThermalStatus = Temperature.THROTTLING_NONE;
1734 
BrightnessObserver(Context context, Handler handler, Injector injector, DisplayManagerFlags flags)1735         BrightnessObserver(Context context, Handler handler, Injector injector,
1736                 DisplayManagerFlags flags) {
1737             mContext = context;
1738             mHandler = handler;
1739             mInjector = injector;
1740             updateBlockingZoneThresholds(/* displayDeviceConfig= */ null,
1741                 /* attemptReadFromFeatureParams= */ false);
1742             mRefreshRateInHighZone = context.getResources().getInteger(
1743                     R.integer.config_fixedRefreshRateInHighZone);
1744             mVsyncLowLightBlockingVoteEnabled = flags.isVsyncLowLightVoteEnabled();
1745         }
1746 
1747         /**
1748          * This is used to update the blocking zone thresholds from the DeviceConfig, which
1749          * if missing from DisplayDeviceConfig, and finally fallback to config.xml.
1750          */
updateBlockingZoneThresholds(@ullable DisplayDeviceConfig displayDeviceConfig, boolean attemptReadFromFeatureParams)1751         public void updateBlockingZoneThresholds(@Nullable DisplayDeviceConfig displayDeviceConfig,
1752                 boolean attemptReadFromFeatureParams) {
1753             loadLowBrightnessThresholds(displayDeviceConfig, attemptReadFromFeatureParams);
1754             loadHighBrightnessThresholds(displayDeviceConfig, attemptReadFromFeatureParams);
1755         }
1756 
1757         @VisibleForTesting
getLowDisplayBrightnessThresholds()1758         float[] getLowDisplayBrightnessThresholds() {
1759             return mLowDisplayBrightnessThresholds;
1760         }
1761 
1762         @VisibleForTesting
getLowAmbientBrightnessThresholds()1763         float[] getLowAmbientBrightnessThresholds() {
1764             return mLowAmbientBrightnessThresholds;
1765         }
1766 
1767         @VisibleForTesting
getHighDisplayBrightnessThresholds()1768         float[] getHighDisplayBrightnessThresholds() {
1769             return mHighDisplayBrightnessThresholds;
1770         }
1771 
1772         @VisibleForTesting
getHighAmbientBrightnessThresholds()1773         float[] getHighAmbientBrightnessThresholds() {
1774             return mHighAmbientBrightnessThresholds;
1775         }
1776 
1777         /**
1778          * @return the refresh rate to lock to when in a high brightness zone
1779          */
1780         @VisibleForTesting
getRefreshRateInHighZone()1781         int getRefreshRateInHighZone() {
1782             return mRefreshRateInHighZone;
1783         }
1784 
1785         /**
1786          * @return the refresh rate to lock to when in a low brightness zone
1787          */
1788         @VisibleForTesting
getRefreshRateInLowZone()1789         int getRefreshRateInLowZone() {
1790             return mRefreshRateInLowZone;
1791         }
1792 
1793         @VisibleForTesting
getIdleScreenRefreshRateConfig()1794         IdleScreenRefreshRateConfig getIdleScreenRefreshRateConfig() {
1795             return mIdleScreenRefreshRateConfig;
1796         }
1797 
loadLowBrightnessThresholds(@ullable DisplayDeviceConfig displayDeviceConfig, boolean attemptReadFromFeatureParams)1798         private void loadLowBrightnessThresholds(@Nullable DisplayDeviceConfig displayDeviceConfig,
1799                 boolean attemptReadFromFeatureParams) {
1800             loadRefreshRateInHighZone(displayDeviceConfig, attemptReadFromFeatureParams);
1801             loadRefreshRateInLowZone(displayDeviceConfig, attemptReadFromFeatureParams);
1802             mLowDisplayBrightnessThresholds = loadBrightnessThresholds(
1803                     () -> mConfigParameterProvider.getLowDisplayBrightnessThresholds(),
1804                     () -> displayDeviceConfig.getLowDisplayBrightnessThresholds(),
1805                     R.array.config_brightnessThresholdsOfPeakRefreshRate,
1806                     displayDeviceConfig, attemptReadFromFeatureParams,
1807                     DeviceConfigParsingUtils::displayBrightnessThresholdsIntToFloat);
1808             mLowAmbientBrightnessThresholds = loadBrightnessThresholds(
1809                     () -> mConfigParameterProvider.getLowAmbientBrightnessThresholds(),
1810                     () -> displayDeviceConfig.getLowAmbientBrightnessThresholds(),
1811                     R.array.config_ambientThresholdsOfPeakRefreshRate,
1812                     displayDeviceConfig, attemptReadFromFeatureParams,
1813                     DeviceConfigParsingUtils::ambientBrightnessThresholdsIntToFloat);
1814             if (mLowDisplayBrightnessThresholds.length != mLowAmbientBrightnessThresholds.length) {
1815                 throw new RuntimeException("display low brightness threshold array and ambient "
1816                         + "brightness threshold array have different length: "
1817                         + "displayBrightnessThresholds="
1818                         + Arrays.toString(mLowDisplayBrightnessThresholds)
1819                         + ", ambientBrightnessThresholds="
1820                         + Arrays.toString(mLowAmbientBrightnessThresholds));
1821             }
1822         }
1823 
loadRefreshRateInLowZone(DisplayDeviceConfig displayDeviceConfig, boolean attemptReadFromFeatureParams)1824         private void loadRefreshRateInLowZone(DisplayDeviceConfig displayDeviceConfig,
1825                 boolean attemptReadFromFeatureParams) {
1826             int refreshRateInLowZone = -1;
1827             if (attemptReadFromFeatureParams) {
1828                 try {
1829                     refreshRateInLowZone = mConfigParameterProvider.getRefreshRateInLowZone();
1830                 } catch (Exception exception) {
1831                     // Do nothing
1832                 }
1833             }
1834             if (refreshRateInLowZone == -1) {
1835                 refreshRateInLowZone = (displayDeviceConfig == null)
1836                         ? mContext.getResources().getInteger(
1837                                 R.integer.config_defaultRefreshRateInZone)
1838                         : displayDeviceConfig.getDefaultLowBlockingZoneRefreshRate();
1839             }
1840             mLowZoneRefreshRateForThermals = displayDeviceConfig == null ? null
1841                     : displayDeviceConfig.getLowBlockingZoneThermalMap();
1842             mRefreshRateInLowZone = refreshRateInLowZone;
1843         }
1844 
loadRefreshRateInHighZone(DisplayDeviceConfig displayDeviceConfig, boolean attemptReadFromFeatureParams)1845         private void loadRefreshRateInHighZone(DisplayDeviceConfig displayDeviceConfig,
1846                 boolean attemptReadFromFeatureParams) {
1847             int refreshRateInHighZone = -1;
1848             if (attemptReadFromFeatureParams) {
1849                 try {
1850                     refreshRateInHighZone = mConfigParameterProvider.getRefreshRateInHighZone();
1851                 } catch (Exception exception) {
1852                     // Do nothing
1853                 }
1854             }
1855             if (refreshRateInHighZone == -1) {
1856                 refreshRateInHighZone = (displayDeviceConfig == null)
1857                         ? mContext.getResources().getInteger(
1858                                 R.integer.config_fixedRefreshRateInHighZone)
1859                         : displayDeviceConfig.getDefaultHighBlockingZoneRefreshRate();
1860             }
1861             mHighZoneRefreshRateForThermals = displayDeviceConfig == null ? null
1862                     : displayDeviceConfig.getHighBlockingZoneThermalMap();
1863             mRefreshRateInHighZone = refreshRateInHighZone;
1864         }
1865 
loadHighBrightnessThresholds(DisplayDeviceConfig displayDeviceConfig, boolean attemptReadFromFeatureParams)1866         private void loadHighBrightnessThresholds(DisplayDeviceConfig displayDeviceConfig,
1867                 boolean attemptReadFromFeatureParams) {
1868             mHighDisplayBrightnessThresholds = loadBrightnessThresholds(
1869                     () -> mConfigParameterProvider.getHighDisplayBrightnessThresholds(),
1870                     () -> displayDeviceConfig.getHighDisplayBrightnessThresholds(),
1871                     R.array.config_highDisplayBrightnessThresholdsOfFixedRefreshRate,
1872                     displayDeviceConfig, attemptReadFromFeatureParams,
1873                     DeviceConfigParsingUtils::displayBrightnessThresholdsIntToFloat);
1874             mHighAmbientBrightnessThresholds = loadBrightnessThresholds(
1875                     () -> mConfigParameterProvider.getHighAmbientBrightnessThresholds(),
1876                     () -> displayDeviceConfig.getHighAmbientBrightnessThresholds(),
1877                     R.array.config_highAmbientBrightnessThresholdsOfFixedRefreshRate,
1878                     displayDeviceConfig, attemptReadFromFeatureParams,
1879                     DeviceConfigParsingUtils::ambientBrightnessThresholdsIntToFloat);
1880             if (mHighDisplayBrightnessThresholds.length
1881                     != mHighAmbientBrightnessThresholds.length) {
1882                 throw new RuntimeException("display high brightness threshold array and ambient "
1883                         + "brightness threshold array have different length: "
1884                         + "displayBrightnessThresholds="
1885                         + Arrays.toString(mHighDisplayBrightnessThresholds)
1886                         + ", ambientBrightnessThresholds="
1887                         + Arrays.toString(mHighAmbientBrightnessThresholds));
1888             }
1889         }
1890 
loadBrightnessThresholds( Callable<float[]> loadFromDeviceConfigDisplaySettingsCallable, Callable<float[]> loadFromDisplayDeviceConfigCallable, int brightnessThresholdOfFixedRefreshRateKey, DisplayDeviceConfig displayDeviceConfig, boolean attemptReadFromFeatureParams, Function<int[], float[]> conversion)1891         private float[] loadBrightnessThresholds(
1892                 Callable<float[]> loadFromDeviceConfigDisplaySettingsCallable,
1893                 Callable<float[]> loadFromDisplayDeviceConfigCallable,
1894                 int brightnessThresholdOfFixedRefreshRateKey,
1895                 DisplayDeviceConfig displayDeviceConfig, boolean attemptReadFromFeatureParams,
1896                 Function<int[], float[]> conversion) {
1897             float[] brightnessThresholds = null;
1898 
1899             if (attemptReadFromFeatureParams) {
1900                 try {
1901                     brightnessThresholds = loadFromDeviceConfigDisplaySettingsCallable.call();
1902                 } catch (Exception exception) {
1903                     // Do nothing
1904                 }
1905             }
1906             if (brightnessThresholds == null) {
1907                 try {
1908                     brightnessThresholds = displayDeviceConfig == null ? conversion.apply(
1909                             mContext.getResources().getIntArray(
1910                                     brightnessThresholdOfFixedRefreshRateKey)) :
1911                             loadFromDisplayDeviceConfigCallable.call();
1912                 } catch (Exception e) {
1913                     Slog.e(TAG, "Unexpectedly failed to load display brightness threshold");
1914                     e.printStackTrace();
1915                 }
1916             }
1917             return brightnessThresholds;
1918         }
1919 
observe(SensorManager sensorManager)1920         private void observe(SensorManager sensorManager) {
1921             mSensorManager = sensorManager;
1922             mBrightness = getBrightness(Display.DEFAULT_DISPLAY);
1923 
1924             // DeviceConfig is accessible after system ready.
1925             float[] lowDisplayBrightnessThresholds =
1926                     mConfigParameterProvider.getLowDisplayBrightnessThresholds();
1927             float[] lowAmbientBrightnessThresholds =
1928                     mConfigParameterProvider.getLowAmbientBrightnessThresholds();
1929             if (lowDisplayBrightnessThresholds != null && lowAmbientBrightnessThresholds != null
1930                     && lowDisplayBrightnessThresholds.length
1931                     == lowAmbientBrightnessThresholds.length) {
1932                 mLowDisplayBrightnessThresholds = lowDisplayBrightnessThresholds;
1933                 mLowAmbientBrightnessThresholds = lowAmbientBrightnessThresholds;
1934             }
1935 
1936             float[] highDisplayBrightnessThresholds =
1937                     mConfigParameterProvider.getHighDisplayBrightnessThresholds();
1938             float[] highAmbientBrightnessThresholds =
1939                     mConfigParameterProvider.getHighAmbientBrightnessThresholds();
1940             if (highDisplayBrightnessThresholds != null && highAmbientBrightnessThresholds != null
1941                     && highDisplayBrightnessThresholds.length
1942                     == highAmbientBrightnessThresholds.length) {
1943                 mHighDisplayBrightnessThresholds = highDisplayBrightnessThresholds;
1944                 mHighAmbientBrightnessThresholds = highAmbientBrightnessThresholds;
1945             }
1946 
1947             final int refreshRateInLowZone = mConfigParameterProvider.getRefreshRateInLowZone();
1948             if (refreshRateInLowZone != -1) {
1949                 mRefreshRateInLowZone = refreshRateInLowZone;
1950             }
1951 
1952             final int refreshRateInHighZone = mConfigParameterProvider.getRefreshRateInHighZone();
1953             if (refreshRateInHighZone != -1) {
1954                 mRefreshRateInHighZone = refreshRateInHighZone;
1955             }
1956 
1957             restartObserver();
1958             mDeviceConfigDisplaySettings.startListening();
1959 
1960             mInjector.registerDisplayListener(this, mHandler,
1961                     DisplayManager.EVENT_FLAG_DISPLAY_CHANGED
1962                             | DisplayManager.EVENT_FLAG_DISPLAY_BRIGHTNESS);
1963         }
1964 
setLoggingEnabled(boolean loggingEnabled)1965         private void setLoggingEnabled(boolean loggingEnabled) {
1966             if (mLoggingEnabled == loggingEnabled) {
1967                 return;
1968             }
1969             mLoggingEnabled = loggingEnabled;
1970             mLightSensorListener.setLoggingEnabled(loggingEnabled);
1971         }
1972 
1973         @VisibleForTesting
onRefreshRateSettingChangedLocked(float min, float max)1974         public void onRefreshRateSettingChangedLocked(float min, float max) {
1975             boolean changeable = (max - min > 1f && max > 60f);
1976             if (mRefreshRateChangeable != changeable) {
1977                 mRefreshRateChangeable = changeable;
1978                 updateSensorStatus();
1979                 if (!changeable) {
1980                     removeFlickerRefreshRateVotes();
1981                 }
1982             }
1983         }
1984 
1985         @VisibleForTesting
onLowPowerModeEnabledLocked(boolean enabled)1986         void onLowPowerModeEnabledLocked(boolean enabled) {
1987             if (mLowPowerModeEnabled != enabled) {
1988                 mLowPowerModeEnabled = enabled;
1989                 updateSensorStatus();
1990                 if (enabled) {
1991                     removeFlickerRefreshRateVotes();
1992                 }
1993             }
1994         }
1995 
removeFlickerRefreshRateVotes()1996         private void removeFlickerRefreshRateVotes() {
1997             // Revoke previous vote from BrightnessObserver
1998             mVotesStorage.updateGlobalVote(Vote.PRIORITY_FLICKER_REFRESH_RATE, null);
1999             mVotesStorage.updateGlobalVote(Vote.PRIORITY_FLICKER_REFRESH_RATE_SWITCH, null);
2000         }
2001 
onDeviceConfigLowBrightnessThresholdsChanged(float[] displayThresholds, float[] ambientThresholds)2002         private void onDeviceConfigLowBrightnessThresholdsChanged(float[] displayThresholds,
2003                 float[] ambientThresholds) {
2004             if (displayThresholds != null && ambientThresholds != null
2005                     && displayThresholds.length == ambientThresholds.length) {
2006                 mLowDisplayBrightnessThresholds = displayThresholds;
2007                 mLowAmbientBrightnessThresholds = ambientThresholds;
2008             } else {
2009                 DisplayDeviceConfig displayDeviceConfig;
2010                 synchronized (mLock) {
2011                     displayDeviceConfig = mDefaultDisplayDeviceConfig;
2012                 }
2013                 mLowDisplayBrightnessThresholds = loadBrightnessThresholds(
2014                         () -> mConfigParameterProvider.getLowDisplayBrightnessThresholds(),
2015                         () -> displayDeviceConfig.getLowDisplayBrightnessThresholds(),
2016                         R.array.config_brightnessThresholdsOfPeakRefreshRate,
2017                         displayDeviceConfig, /* attemptReadFromFeatureParams= */ false,
2018                         DeviceConfigParsingUtils::displayBrightnessThresholdsIntToFloat);
2019                 mLowAmbientBrightnessThresholds = loadBrightnessThresholds(
2020                         () -> mConfigParameterProvider.getLowAmbientBrightnessThresholds(),
2021                         () -> displayDeviceConfig.getLowAmbientBrightnessThresholds(),
2022                         R.array.config_ambientThresholdsOfPeakRefreshRate,
2023                         displayDeviceConfig, /* attemptReadFromFeatureParams= */ false,
2024                         DeviceConfigParsingUtils::ambientBrightnessThresholdsIntToFloat);
2025             }
2026             restartObserver();
2027         }
2028 
2029         /**
2030          * Used to reload the lower blocking zone refresh rate in case of changes in the
2031          * DeviceConfig properties.
2032          */
onDeviceConfigRefreshRateInLowZoneChanged(int refreshRate)2033         public void onDeviceConfigRefreshRateInLowZoneChanged(int refreshRate) {
2034             if (refreshRate == -1) {
2035                 // Given there is no value available in DeviceConfig, lets not attempt loading it
2036                 // from there.
2037                 synchronized (mLock) {
2038                     loadRefreshRateInLowZone(mDefaultDisplayDeviceConfig,
2039                             /* attemptReadFromFeatureParams= */ false);
2040                 }
2041                 restartObserver();
2042             } else if (refreshRate != mRefreshRateInLowZone) {
2043                 mRefreshRateInLowZone = refreshRate;
2044                 restartObserver();
2045             }
2046         }
2047 
onDeviceConfigHighBrightnessThresholdsChanged(float[] displayThresholds, float[] ambientThresholds)2048         private void onDeviceConfigHighBrightnessThresholdsChanged(float[] displayThresholds,
2049                 float[] ambientThresholds) {
2050             if (displayThresholds != null && ambientThresholds != null
2051                     && displayThresholds.length == ambientThresholds.length) {
2052                 mHighDisplayBrightnessThresholds = displayThresholds;
2053                 mHighAmbientBrightnessThresholds = ambientThresholds;
2054             } else {
2055                 DisplayDeviceConfig displayDeviceConfig;
2056                 synchronized (mLock) {
2057                     displayDeviceConfig = mDefaultDisplayDeviceConfig;
2058                 }
2059                 mHighDisplayBrightnessThresholds = loadBrightnessThresholds(
2060                         () -> mConfigParameterProvider.getLowDisplayBrightnessThresholds(),
2061                         () -> displayDeviceConfig.getHighDisplayBrightnessThresholds(),
2062                         R.array.config_highDisplayBrightnessThresholdsOfFixedRefreshRate,
2063                         displayDeviceConfig, /* attemptReadFromFeatureParams= */ false,
2064                         DeviceConfigParsingUtils::displayBrightnessThresholdsIntToFloat);
2065                 mHighAmbientBrightnessThresholds = loadBrightnessThresholds(
2066                         () -> mConfigParameterProvider.getHighAmbientBrightnessThresholds(),
2067                         () -> displayDeviceConfig.getHighAmbientBrightnessThresholds(),
2068                         R.array.config_highAmbientBrightnessThresholdsOfFixedRefreshRate,
2069                         displayDeviceConfig, /* attemptReadFromFeatureParams= */ false,
2070                         DeviceConfigParsingUtils::ambientBrightnessThresholdsIntToFloat);
2071             }
2072             restartObserver();
2073         }
2074 
2075         /**
2076          * Used to reload the higher blocking zone refresh rate in case of changes in the
2077          * DeviceConfig properties.
2078          */
onDeviceConfigRefreshRateInHighZoneChanged(int refreshRate)2079         public void onDeviceConfigRefreshRateInHighZoneChanged(int refreshRate) {
2080             if (refreshRate == -1) {
2081                 // Given there is no value available in DeviceConfig, lets not attempt loading it
2082                 // from there.
2083                 synchronized (mLock) {
2084                     loadRefreshRateInHighZone(mDefaultDisplayDeviceConfig,
2085                             /* attemptReadFromFeatureParams= */ false);
2086                 }
2087                 restartObserver();
2088             } else if (refreshRate != mRefreshRateInHighZone) {
2089                 mRefreshRateInHighZone = refreshRate;
2090                 restartObserver();
2091             }
2092         }
2093 
dumpLocked(PrintWriter pw)2094         void dumpLocked(PrintWriter pw) {
2095             pw.println("  BrightnessObserver");
2096             pw.println("    mAmbientLux: " + mAmbientLux);
2097             pw.println("    mBrightness: " + mBrightness);
2098             pw.println("    mDefaultDisplayState: " + mDefaultDisplayState);
2099             pw.println("    mLowPowerModeEnabled: " + mLowPowerModeEnabled);
2100             pw.println("    mRefreshRateChangeable: " + mRefreshRateChangeable);
2101             pw.println("    mShouldObserveDisplayLowChange: " + mShouldObserveDisplayLowChange);
2102             pw.println("    mShouldObserveAmbientLowChange: " + mShouldObserveAmbientLowChange);
2103             pw.println("    mRefreshRateInLowZone: " + mRefreshRateInLowZone);
2104 
2105             for (float d : mLowDisplayBrightnessThresholds) {
2106                 pw.println("    mDisplayLowBrightnessThreshold: " + d);
2107             }
2108 
2109             for (float d : mLowAmbientBrightnessThresholds) {
2110                 pw.println("    mAmbientLowBrightnessThreshold: " + d);
2111             }
2112 
2113             pw.println("    mShouldObserveDisplayHighChange: " + mShouldObserveDisplayHighChange);
2114             pw.println("    mShouldObserveAmbientHighChange: " + mShouldObserveAmbientHighChange);
2115             pw.println("    mRefreshRateInHighZone: " + mRefreshRateInHighZone);
2116 
2117             for (float d : mHighDisplayBrightnessThresholds) {
2118                 pw.println("    mDisplayHighBrightnessThresholds: " + d);
2119             }
2120 
2121             for (float d : mHighAmbientBrightnessThresholds) {
2122                 pw.println("    mAmbientHighBrightnessThresholds: " + d);
2123             }
2124 
2125             pw.println("    mRegisteredLightSensor: " + mRegisteredLightSensor);
2126             pw.println("    mLightSensor: " + mLightSensor);
2127             pw.println("    mLightSensorName: " + mLightSensorName);
2128             pw.println("    mLightSensorType: " + mLightSensorType);
2129             mLightSensorListener.dumpLocked(pw);
2130 
2131             if (mAmbientFilter != null) {
2132                 IndentingPrintWriter ipw = new IndentingPrintWriter(pw, "    ");
2133                 mAmbientFilter.dump(ipw);
2134             }
2135         }
2136 
2137         @Override
onDisplayAdded(int displayId)2138         public void onDisplayAdded(int displayId) {}
2139 
2140         @Override
onDisplayRemoved(int displayId)2141         public void onDisplayRemoved(int displayId) {}
2142 
2143         @Override
onDisplayChanged(int displayId)2144         public void onDisplayChanged(int displayId) {
2145             if (displayId == Display.DEFAULT_DISPLAY) {
2146                 updateDefaultDisplayState();
2147 
2148                 // We don't support multiple display blocking zones yet, so only handle
2149                 // brightness changes for the default display for now.
2150                 float brightness = getBrightness(displayId);
2151                 synchronized (mLock) {
2152                     if (!BrightnessSynchronizer.floatEquals(brightness, mBrightness)) {
2153                         mBrightness = brightness;
2154                         onBrightnessChangedLocked();
2155                     }
2156                 }
2157             }
2158         }
2159 
hasLowLightVrrConfig()2160         private boolean hasLowLightVrrConfig() {
2161             DisplayDeviceConfig config;
2162             synchronized (mLock) {
2163                 config = mDefaultDisplayDeviceConfig;
2164             }
2165             return mVsyncLowLightBlockingVoteEnabled
2166                     && config != null
2167                     && config.isVrrSupportEnabled()
2168                     && !config.getRefreshRateData().lowLightBlockingZoneSupportedModes.isEmpty();
2169         }
2170 
restartObserver()2171         private void restartObserver() {
2172             if (mRefreshRateInLowZone > 0 || hasLowLightVrrConfig()) {
2173                 mShouldObserveDisplayLowChange = hasValidThreshold(
2174                         mLowDisplayBrightnessThresholds);
2175                 mShouldObserveAmbientLowChange = hasValidThreshold(
2176                         mLowAmbientBrightnessThresholds);
2177             } else {
2178                 mShouldObserveDisplayLowChange = false;
2179                 mShouldObserveAmbientLowChange = false;
2180             }
2181 
2182             if (mRefreshRateInHighZone > 0) {
2183                 mShouldObserveDisplayHighChange = hasValidThreshold(
2184                         mHighDisplayBrightnessThresholds);
2185                 mShouldObserveAmbientHighChange = hasValidThreshold(
2186                         mHighAmbientBrightnessThresholds);
2187             } else {
2188                 mShouldObserveDisplayHighChange = false;
2189                 mShouldObserveAmbientHighChange = false;
2190             }
2191 
2192             if (mShouldObserveAmbientLowChange || mShouldObserveAmbientHighChange) {
2193                 Sensor lightSensor = getLightSensor();
2194 
2195                 if (lightSensor != null && lightSensor != mLightSensor) {
2196                     final Resources res = mContext.getResources();
2197 
2198                     mAmbientFilter = AmbientFilterFactory.createBrightnessFilter(TAG, res);
2199                     mLightSensor = lightSensor;
2200                 }
2201             } else {
2202                 mAmbientFilter = null;
2203                 mLightSensor = null;
2204             }
2205 
2206             updateSensorStatus();
2207             synchronized (mLock) {
2208                 onBrightnessChangedLocked();
2209             }
2210         }
2211 
reloadLightSensor(DisplayDeviceConfig displayDeviceConfig)2212         private void reloadLightSensor(DisplayDeviceConfig displayDeviceConfig) {
2213             reloadLightSensorData(displayDeviceConfig);
2214             restartObserver();
2215         }
2216 
reloadLightSensorData(DisplayDeviceConfig displayDeviceConfig)2217         private void reloadLightSensorData(DisplayDeviceConfig displayDeviceConfig) {
2218             // The displayDeviceConfig (ddc) contains display specific preferences. When loaded,
2219             // it naturally falls back to the global config.xml.
2220             if (displayDeviceConfig != null
2221                     && displayDeviceConfig.getAmbientLightSensor() != null) {
2222                 // This covers both the ddc and the config.xml fallback
2223                 mLightSensorType = displayDeviceConfig.getAmbientLightSensor().type;
2224                 mLightSensorName = displayDeviceConfig.getAmbientLightSensor().name;
2225             } else if (mLightSensorName == null && mLightSensorType == null) {
2226                 Resources resources = mContext.getResources();
2227                 mLightSensorType = resources.getString(
2228                         com.android.internal.R.string.config_displayLightSensorType);
2229                 mLightSensorName = "";
2230             }
2231         }
2232 
getLightSensor()2233         private Sensor getLightSensor() {
2234             return SensorUtils.findSensor(mSensorManager, mLightSensorType,
2235                     mLightSensorName, Sensor.TYPE_LIGHT);
2236         }
2237 
2238         /**
2239          * Checks to see if at least one value is positive, in which case it is necessary to listen
2240          * to value changes.
2241          */
hasValidThreshold(float[] a)2242         private boolean hasValidThreshold(float[] a) {
2243             for (float d: a) {
2244                 if (d >= 0) {
2245                     return true;
2246                 }
2247             }
2248 
2249             return false;
2250         }
2251 
2252         /**
2253          * Check if we're in the low zone where higher refresh rates aren't allowed to prevent
2254          * flickering.
2255          * @param brightness The brightness value or a negative value meaning that only the lux
2256          *                   threshold should be applied
2257          * @param lux The lux value. If negative, only the brightness threshold is applied
2258          * @return True if we're in the low zone
2259          */
isInsideLowZone(float brightness, float lux)2260         private boolean isInsideLowZone(float brightness, float lux) {
2261             for (int i = 0; i < mLowDisplayBrightnessThresholds.length; i++) {
2262                 float disp = mLowDisplayBrightnessThresholds[i];
2263                 float ambi = mLowAmbientBrightnessThresholds[i];
2264 
2265                 if (disp >= 0 && ambi >= 0) {
2266                     if (brightness <= disp && lux <= ambi) {
2267                         return true;
2268                     }
2269                 } else if (disp >= 0) {
2270                     if (brightness <= disp) {
2271                         return true;
2272                     }
2273                 } else if (ambi >= 0) {
2274                     if (lux <= ambi) {
2275                         return true;
2276                     }
2277                 }
2278             }
2279 
2280             return false;
2281         }
2282 
2283         /**
2284          * Check if we're in the high zone where higher refresh rates aren't allowed to prevent
2285          * flickering.
2286          * @param brightness The brightness value or a negative value meaning that only the lux
2287          *                   threshold should be applied
2288          * @param lux The lux value. If negative, only the brightness threshold is applied
2289          * @return True if we're in the high zone
2290          */
isInsideHighZone(float brightness, float lux)2291         private boolean isInsideHighZone(float brightness, float lux) {
2292             for (int i = 0; i < mHighDisplayBrightnessThresholds.length; i++) {
2293                 float disp = mHighDisplayBrightnessThresholds[i];
2294                 float ambi = mHighAmbientBrightnessThresholds[i];
2295 
2296                 if (disp >= 0 && ambi >= 0) {
2297                     if (brightness >= disp && lux >= ambi) {
2298                         return true;
2299                     }
2300                 } else if (disp >= 0) {
2301                     if (brightness >= disp) {
2302                         return true;
2303                     }
2304                 } else if (ambi >= 0) {
2305                     if (lux >= ambi) {
2306                         return true;
2307                     }
2308                 }
2309             }
2310 
2311             return false;
2312         }
2313 
2314         @GuardedBy("mLock")
onBrightnessChangedLocked()2315         private void onBrightnessChangedLocked() {
2316             if (!mRefreshRateChangeable || mLowPowerModeEnabled) {
2317                 return;
2318             }
2319             Vote refreshRateVote = null;
2320             Vote refreshRateSwitchingVote = null;
2321 
2322             if (Float.isNaN(mBrightness)) {
2323                 // Either the setting isn't available or we shouldn't be observing yet anyways.
2324                 // Either way, just bail out since there's nothing we can do here.
2325                 return;
2326             }
2327 
2328             boolean insideLowZone = hasValidLowZone() && isInsideLowZone(mBrightness, mAmbientLux);
2329             if (insideLowZone) {
2330                 if (hasLowLightVrrConfig()) {
2331                     refreshRateVote = Vote.forSupportedRefreshRates(mDefaultDisplayDeviceConfig
2332                             .getRefreshRateData().lowLightBlockingZoneSupportedModes);
2333                 } else {
2334                     refreshRateVote = Vote.forPhysicalRefreshRates(
2335                             mRefreshRateInLowZone, mRefreshRateInLowZone);
2336                     refreshRateSwitchingVote = Vote.forDisableRefreshRateSwitching();
2337                 }
2338                 if (mLowZoneRefreshRateForThermals != null) {
2339                     RefreshRateRange range = SkinThermalStatusObserver
2340                             .findBestMatchingRefreshRateRange(mThermalStatus,
2341                                     mLowZoneRefreshRateForThermals);
2342                     if (range != null) {
2343                         refreshRateVote =
2344                                 Vote.forPhysicalRefreshRates(range.min, range.max);
2345                     }
2346                 }
2347             }
2348 
2349             boolean insideHighZone = hasValidHighZone()
2350                     && isInsideHighZone(mBrightness, mAmbientLux);
2351             if (insideHighZone) {
2352                 refreshRateVote =
2353                         Vote.forPhysicalRefreshRates(mRefreshRateInHighZone,
2354                                 mRefreshRateInHighZone);
2355                 if (mHighZoneRefreshRateForThermals != null) {
2356                     RefreshRateRange range = SkinThermalStatusObserver
2357                             .findBestMatchingRefreshRateRange(mThermalStatus,
2358                                     mHighZoneRefreshRateForThermals);
2359                     if (range != null) {
2360                         refreshRateVote =
2361                                 Vote.forPhysicalRefreshRates(range.min, range.max);
2362                     }
2363                 }
2364                 refreshRateSwitchingVote = Vote.forDisableRefreshRateSwitching();
2365             }
2366 
2367             if (mLoggingEnabled) {
2368                 Slog.d(TAG, "Display brightness " + mBrightness + ", ambient lux " +  mAmbientLux
2369                         + ", Vote " + refreshRateVote);
2370             }
2371             mVotesStorage.updateGlobalVote(Vote.PRIORITY_FLICKER_REFRESH_RATE, refreshRateVote);
2372             mVotesStorage.updateGlobalVote(Vote.PRIORITY_FLICKER_REFRESH_RATE_SWITCH,
2373                     refreshRateSwitchingVote);
2374         }
2375 
hasValidLowZone()2376         private boolean hasValidLowZone() {
2377             return (mRefreshRateInLowZone > 0 || hasLowLightVrrConfig())
2378                     && (mShouldObserveDisplayLowChange || mShouldObserveAmbientLowChange);
2379         }
2380 
hasValidHighZone()2381         private boolean hasValidHighZone() {
2382             return mRefreshRateInHighZone > 0
2383                     && (mShouldObserveDisplayHighChange || mShouldObserveAmbientHighChange);
2384         }
2385 
updateDefaultDisplayState()2386         private void updateDefaultDisplayState() {
2387             Display display = mInjector.getDisplay(Display.DEFAULT_DISPLAY);
2388             if (display == null) {
2389                 return;
2390             }
2391 
2392             setDefaultDisplayState(display.getState());
2393         }
2394 
2395         @VisibleForTesting
setDefaultDisplayState(int state)2396         void setDefaultDisplayState(int state) {
2397             if (mLoggingEnabled) {
2398                 Slog.d(TAG, "setDefaultDisplayState: mDefaultDisplayState = "
2399                         + mDefaultDisplayState + ", state = " + state);
2400             }
2401 
2402             if (mDefaultDisplayState != state) {
2403                 mDefaultDisplayState = state;
2404                 updateSensorStatus();
2405             }
2406         }
2407 
updateSensorStatus()2408         private void updateSensorStatus() {
2409             if (mSensorManager == null || mLightSensorListener == null) {
2410                 return;
2411             }
2412 
2413             if (mLoggingEnabled) {
2414                 Slog.d(TAG, "updateSensorStatus: mShouldObserveAmbientLowChange = "
2415                         + mShouldObserveAmbientLowChange + ", mShouldObserveAmbientHighChange = "
2416                         + mShouldObserveAmbientHighChange);
2417                 Slog.d(TAG, "updateSensorStatus: mLowPowerModeEnabled = "
2418                         + mLowPowerModeEnabled + ", mRefreshRateChangeable = "
2419                         + mRefreshRateChangeable);
2420             }
2421 
2422             boolean registerForThermals = false;
2423             if ((mShouldObserveAmbientLowChange || mShouldObserveAmbientHighChange)
2424                      && isDeviceActive() && !mLowPowerModeEnabled && mRefreshRateChangeable) {
2425                 registerLightSensor();
2426                 registerForThermals = mLowZoneRefreshRateForThermals != null
2427                         || mHighZoneRefreshRateForThermals != null;
2428             } else {
2429                 unregisterSensorListener();
2430             }
2431 
2432             if (registerForThermals && !mThermalRegistered) {
2433                 mThermalRegistered = mInjector.registerThermalServiceListener(mThermalListener);
2434             } else if (!registerForThermals && mThermalRegistered) {
2435                 mInjector.unregisterThermalServiceListener(mThermalListener);
2436                 mThermalRegistered = false;
2437                 synchronized (mLock) {
2438                     mThermalStatus = Temperature.THROTTLING_NONE; // reset
2439                 }
2440             }
2441         }
2442 
registerLightSensor()2443         private void registerLightSensor() {
2444             if (mRegisteredLightSensor == mLightSensor) {
2445                 return;
2446             }
2447 
2448             if (mRegisteredLightSensor != null) {
2449                 unregisterSensorListener();
2450             }
2451 
2452             mSensorManager.registerListener(mLightSensorListener,
2453                     mLightSensor, LIGHT_SENSOR_RATE_MS * 1000, mHandler);
2454             mRegisteredLightSensor = mLightSensor;
2455             if (mLoggingEnabled) {
2456                 Slog.d(TAG, "updateSensorStatus: registerListener");
2457             }
2458         }
2459 
unregisterSensorListener()2460         private void unregisterSensorListener() {
2461             mLightSensorListener.removeCallbacks();
2462             mSensorManager.unregisterListener(mLightSensorListener);
2463             mRegisteredLightSensor = null;
2464             if (mLoggingEnabled) {
2465                 Slog.d(TAG, "updateSensorStatus: unregisterListener");
2466             }
2467         }
2468 
isDeviceActive()2469         private boolean isDeviceActive() {
2470             return mDefaultDisplayState == Display.STATE_ON;
2471         }
2472 
2473         /**
2474          * Get the brightness value for a display
2475          * @param displayId The ID of the display
2476          * @return The brightness value
2477          */
getBrightness(int displayId)2478         private float getBrightness(int displayId) {
2479             final BrightnessInfo info = mInjector.getBrightnessInfo(displayId);
2480             if (info != null) {
2481                 return info.adjustedBrightness;
2482             }
2483 
2484             return BRIGHTNESS_INVALID_FLOAT;
2485         }
2486 
2487         private final class LightSensorEventListener implements SensorEventListener {
2488             private static final int INJECT_EVENTS_INTERVAL_MS = LIGHT_SENSOR_RATE_MS;
2489             private float mLastSensorData;
2490             private long mTimestamp;
2491             private boolean mLoggingEnabled;
2492 
dumpLocked(PrintWriter pw)2493             public void dumpLocked(PrintWriter pw) {
2494                 pw.println("    mLastSensorData: " + mLastSensorData);
2495                 pw.println("    mTimestamp: " + formatTimestamp(mTimestamp));
2496             }
2497 
2498 
setLoggingEnabled(boolean loggingEnabled)2499             public void setLoggingEnabled(boolean loggingEnabled) {
2500                 if (mLoggingEnabled == loggingEnabled) {
2501                     return;
2502                 }
2503                 mLoggingEnabled = loggingEnabled;
2504             }
2505 
2506             @Override
onSensorChanged(SensorEvent event)2507             public void onSensorChanged(SensorEvent event) {
2508                 mLastSensorData = event.values[0];
2509                 if (mLoggingEnabled) {
2510                     Slog.d(TAG, "On sensor changed: " + mLastSensorData);
2511                 }
2512 
2513                 boolean lowZoneChanged = isDifferentZone(mLastSensorData, mAmbientLux,
2514                         mLowAmbientBrightnessThresholds);
2515                 boolean highZoneChanged = isDifferentZone(mLastSensorData, mAmbientLux,
2516                         mHighAmbientBrightnessThresholds);
2517                 if ((lowZoneChanged && mLastSensorData < mAmbientLux)
2518                         || (highZoneChanged && mLastSensorData > mAmbientLux)) {
2519                     // Easier to see flicker at lower brightness environment or high brightness
2520                     // environment. Forget the history to get immediate response.
2521                     if (mAmbientFilter != null) {
2522                         mAmbientFilter.clear();
2523                     }
2524                 }
2525 
2526                 long now = SystemClock.uptimeMillis();
2527                 mTimestamp = System.currentTimeMillis();
2528                 if (mAmbientFilter != null) {
2529                     mAmbientFilter.addValue(now, mLastSensorData);
2530                 }
2531 
2532                 mHandler.removeCallbacks(mInjectSensorEventRunnable);
2533                 processSensorData(now);
2534 
2535                 if ((lowZoneChanged && mLastSensorData > mAmbientLux)
2536                         || (highZoneChanged && mLastSensorData < mAmbientLux)) {
2537                     // Sensor may not report new event if there is no brightness change.
2538                     // Need to keep querying the temporal filter for the latest estimation,
2539                     // until sensor readout and filter estimation are in the same zone or
2540                     // is interrupted by a new sensor event.
2541                     mHandler.postDelayed(mInjectSensorEventRunnable, INJECT_EVENTS_INTERVAL_MS);
2542                 }
2543 
2544                 if (mDisplayManagerFlags.isIdleScreenRefreshRateTimeoutEnabled()) {
2545                     updateIdleScreenRefreshRate(mAmbientLux);
2546                 }
2547             }
2548 
2549             @Override
onAccuracyChanged(Sensor sensor, int accuracy)2550             public void onAccuracyChanged(Sensor sensor, int accuracy) {
2551                 // Not used.
2552             }
2553 
removeCallbacks()2554             public void removeCallbacks() {
2555                 mHandler.removeCallbacks(mInjectSensorEventRunnable);
2556             }
2557 
formatTimestamp(long time)2558             private String formatTimestamp(long time) {
2559                 SimpleDateFormat dateFormat =
2560                         new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS", Locale.US);
2561                 return dateFormat.format(new Date(time));
2562             }
2563 
processSensorData(long now)2564             private void processSensorData(long now) {
2565                 if (mAmbientFilter != null) {
2566                     mAmbientLux = mAmbientFilter.getEstimate(now);
2567                 } else {
2568                     mAmbientLux = mLastSensorData;
2569                 }
2570 
2571                 synchronized (mLock) {
2572                     onBrightnessChangedLocked();
2573                 }
2574             }
2575 
isDifferentZone(float lux1, float lux2, float[] luxThresholds)2576             private boolean isDifferentZone(float lux1, float lux2, float[] luxThresholds) {
2577                 for (final float boundary : luxThresholds) {
2578                     // Test each boundary. See if the current value and the new value are at
2579                     // different sides.
2580                     if ((lux1 <= boundary && lux2 > boundary)
2581                             || (lux1 > boundary && lux2 <= boundary)) {
2582                         return true;
2583                     }
2584                 }
2585 
2586                 return false;
2587             }
2588 
2589             private final Runnable mInjectSensorEventRunnable = new Runnable() {
2590                 @Override
2591                 public void run() {
2592                     long now = SystemClock.uptimeMillis();
2593                     // No need to really inject the last event into a temporal filter.
2594                     processSensorData(now);
2595 
2596                     // Inject next event if there is a possible zone change.
2597                     if (isDifferentZone(mLastSensorData, mAmbientLux,
2598                             mLowAmbientBrightnessThresholds)
2599                             || isDifferentZone(mLastSensorData, mAmbientLux,
2600                             mHighAmbientBrightnessThresholds)) {
2601                         mHandler.postDelayed(mInjectSensorEventRunnable, INJECT_EVENTS_INTERVAL_MS);
2602                     }
2603                 }
2604             };
2605         }
2606 
updateIdleScreenRefreshRate(float ambientLux)2607         private void updateIdleScreenRefreshRate(float ambientLux) {
2608             List<IdleScreenRefreshRateTimeoutLuxThresholdPoint>
2609                     idleScreenRefreshRateTimeoutLuxThresholdPoints;
2610             synchronized (mLock) {
2611                 if (mDefaultDisplayDeviceConfig == null || mDefaultDisplayDeviceConfig
2612                         .getIdleScreenRefreshRateTimeoutLuxThresholdPoint().isEmpty()) {
2613                     // Setting this to null will let surface flinger know that the idle timer is not
2614                     // configured in the display configs
2615                     mIdleScreenRefreshRateConfig = null;
2616                     return;
2617                 }
2618 
2619                 idleScreenRefreshRateTimeoutLuxThresholdPoints =
2620                         mDefaultDisplayDeviceConfig
2621                                 .getIdleScreenRefreshRateTimeoutLuxThresholdPoint();
2622             }
2623             int newTimeout = -1;
2624             for (IdleScreenRefreshRateTimeoutLuxThresholdPoint point :
2625                     idleScreenRefreshRateTimeoutLuxThresholdPoints) {
2626                 int newLux = point.getLux().intValue();
2627                 if (newLux <= ambientLux) {
2628                     newTimeout = point.getTimeout().intValue();
2629                 }
2630             }
2631             if (mIdleScreenRefreshRateConfig == null
2632                     || newTimeout != mIdleScreenRefreshRateConfig.timeoutMillis) {
2633                 mIdleScreenRefreshRateConfig =
2634                         new IdleScreenRefreshRateConfig(newTimeout);
2635                 synchronized (mLock) {
2636                     notifyDesiredDisplayModeSpecsChangedLocked();
2637                 }
2638             }
2639         }
2640     }
2641 
2642     private class UdfpsObserver extends IUdfpsRefreshRateRequestCallback.Stub {
2643         private final SparseBooleanArray mUdfpsRefreshRateEnabled = new SparseBooleanArray();
2644         private final SparseBooleanArray mAuthenticationPossible = new SparseBooleanArray();
2645 
observe()2646         public void observe() {
2647             StatusBarManagerInternal statusBar = mInjector.getStatusBarManagerInternal();
2648             if (statusBar == null) {
2649                 return;
2650             }
2651 
2652             // Allow UDFPS vote by registering callback, only
2653             // if the device is configured to not ignore UDFPS vote.
2654             boolean ignoreUdfpsVote = mContext.getResources()
2655                         .getBoolean(R.bool.config_ignoreUdfpsVote);
2656             if (!ignoreUdfpsVote) {
2657                 statusBar.setUdfpsRefreshRateCallback(this);
2658             }
2659         }
2660 
2661         @Override
onRequestEnabled(int displayId)2662         public void onRequestEnabled(int displayId) {
2663             synchronized (mLock) {
2664                 mUdfpsRefreshRateEnabled.put(displayId, true);
2665                 updateVoteLocked(displayId, true, Vote.PRIORITY_UDFPS);
2666             }
2667         }
2668 
2669         @Override
onRequestDisabled(int displayId)2670         public void onRequestDisabled(int displayId) {
2671             synchronized (mLock) {
2672                 mUdfpsRefreshRateEnabled.put(displayId, false);
2673                 updateVoteLocked(displayId, false, Vote.PRIORITY_UDFPS);
2674             }
2675         }
2676 
2677         @Override
onAuthenticationPossible(int displayId, boolean isPossible)2678         public void onAuthenticationPossible(int displayId, boolean isPossible) {
2679             synchronized (mLock) {
2680                 mAuthenticationPossible.put(displayId, isPossible);
2681                 updateVoteLocked(displayId, isPossible,
2682                         Vote.PRIORITY_AUTH_OPTIMIZER_RENDER_FRAME_RATE);
2683             }
2684         }
2685 
2686         @GuardedBy("mLock")
updateVoteLocked(int displayId, boolean enabled, int votePriority)2687         private void updateVoteLocked(int displayId, boolean enabled, int votePriority) {
2688             final Vote vote;
2689             if (enabled) {
2690                 float maxRefreshRate = DisplayModeDirector.this.getMaxRefreshRateLocked(displayId);
2691                 vote = Vote.forPhysicalRefreshRates(maxRefreshRate, maxRefreshRate);
2692             } else {
2693                 vote = null;
2694             }
2695             mVotesStorage.updateVote(displayId, votePriority, vote);
2696         }
2697 
dumpLocked(PrintWriter pw)2698         void dumpLocked(PrintWriter pw) {
2699             pw.println("  UdfpsObserver");
2700             pw.println("    mUdfpsRefreshRateEnabled: ");
2701             for (int i = 0; i < mUdfpsRefreshRateEnabled.size(); i++) {
2702                 final int displayId = mUdfpsRefreshRateEnabled.keyAt(i);
2703                 final String enabled = mUdfpsRefreshRateEnabled.valueAt(i) ? "enabled" : "disabled";
2704                 pw.println("      Display " + displayId + ": " + enabled);
2705             }
2706             pw.println("    mAuthenticationPossible: ");
2707             for (int i = 0; i < mAuthenticationPossible.size(); i++) {
2708                 final int displayId = mAuthenticationPossible.keyAt(i);
2709                 final String isPossible = mAuthenticationPossible.valueAt(i) ? "possible"
2710                         : "impossible";
2711                 pw.println("      Display " + displayId + ": " + isPossible);
2712             }
2713         }
2714     }
2715 
2716 
2717     /**
2718      * Listens to DisplayManager for HBM status and applies any refresh-rate restrictions for
2719      * HBM that are associated with that display. Restrictions are retrieved from
2720      * DisplayManagerInternal but originate in the display-device-config file.
2721      */
2722     public class HbmObserver implements DisplayManager.DisplayListener {
2723         private final VotesStorage mVotesStorage;
2724         private final Handler mHandler;
2725         private final SparseIntArray mHbmMode = new SparseIntArray();
2726         private final SparseBooleanArray mHbmActive = new SparseBooleanArray();
2727         private final Injector mInjector;
2728         private final DeviceConfigDisplaySettings mDeviceConfigDisplaySettings;
2729         private int mRefreshRateInHbmSunlight;
2730         private int mRefreshRateInHbmHdr;
2731 
2732         private DisplayManagerInternal mDisplayManagerInternal;
2733 
HbmObserver(Injector injector, VotesStorage votesStorage, Handler handler, DeviceConfigDisplaySettings displaySettings)2734         HbmObserver(Injector injector, VotesStorage votesStorage, Handler handler,
2735                 DeviceConfigDisplaySettings displaySettings) {
2736             mInjector = injector;
2737             mVotesStorage = votesStorage;
2738             mHandler = handler;
2739             mDeviceConfigDisplaySettings = displaySettings;
2740         }
2741 
2742         /**
2743          * Sets up the refresh rate to be used when HDR is enabled
2744          */
setupHdrRefreshRates(DisplayDeviceConfig displayDeviceConfig)2745         public void setupHdrRefreshRates(DisplayDeviceConfig displayDeviceConfig) {
2746             mRefreshRateInHbmHdr = mDeviceConfigDisplaySettings
2747                 .getRefreshRateInHbmHdr(displayDeviceConfig);
2748             mRefreshRateInHbmSunlight = mDeviceConfigDisplaySettings
2749                 .getRefreshRateInHbmSunlight(displayDeviceConfig);
2750         }
2751 
2752         /**
2753          * Sets up the HDR refresh rates, and starts observing for the changes in the display that
2754          * might impact it
2755          */
observe()2756         public void observe() {
2757             synchronized (mLock) {
2758                 setupHdrRefreshRates(mDefaultDisplayDeviceConfig);
2759             }
2760             mDisplayManagerInternal = mInjector.getDisplayManagerInternal();
2761             mInjector.registerDisplayListener(this, mHandler,
2762                     DisplayManager.EVENT_FLAG_DISPLAY_BRIGHTNESS
2763                     | DisplayManager.EVENT_FLAG_DISPLAY_REMOVED);
2764         }
2765 
2766         /**
2767          * @return the refresh to lock to when the device is in high brightness mode for Sunlight.
2768          */
2769         @VisibleForTesting
getRefreshRateInHbmSunlight()2770         int getRefreshRateInHbmSunlight() {
2771             return mRefreshRateInHbmSunlight;
2772         }
2773 
2774         /**
2775          * @return the refresh to lock to when the device is in high brightness mode for HDR.
2776          */
2777         @VisibleForTesting
getRefreshRateInHbmHdr()2778         int getRefreshRateInHbmHdr() {
2779             return mRefreshRateInHbmHdr;
2780         }
2781 
2782         /**
2783          * Recalculates the HBM vote when the device config has been changed.
2784          */
onDeviceConfigRefreshRateInHbmSunlightChanged(int refreshRate)2785         public void onDeviceConfigRefreshRateInHbmSunlightChanged(int refreshRate) {
2786             if (refreshRate != mRefreshRateInHbmSunlight) {
2787                 mRefreshRateInHbmSunlight = refreshRate;
2788                 onDeviceConfigRefreshRateInHbmChanged();
2789             }
2790         }
2791 
2792         /**
2793          * Recalculates the HBM vote when the device config has been changed.
2794          */
onDeviceConfigRefreshRateInHbmHdrChanged(int refreshRate)2795         public void onDeviceConfigRefreshRateInHbmHdrChanged(int refreshRate) {
2796             if (refreshRate != mRefreshRateInHbmHdr) {
2797                 mRefreshRateInHbmHdr = refreshRate;
2798                 onDeviceConfigRefreshRateInHbmChanged();
2799             }
2800         }
2801 
2802         @Override
onDisplayAdded(int displayId)2803         public void onDisplayAdded(int displayId) {}
2804 
2805         @Override
onDisplayRemoved(int displayId)2806         public void onDisplayRemoved(int displayId) {
2807             mVotesStorage.updateVote(displayId, Vote.PRIORITY_HIGH_BRIGHTNESS_MODE, null);
2808             mHbmMode.delete(displayId);
2809             mHbmActive.delete(displayId);
2810         }
2811 
2812         @Override
onDisplayChanged(int displayId)2813         public void onDisplayChanged(int displayId) {
2814             final BrightnessInfo info = mInjector.getBrightnessInfo(displayId);
2815             if (info == null) {
2816                 // Display no longer there. Assume we'll get an onDisplayRemoved very soon.
2817                 return;
2818             }
2819 
2820             final int hbmMode = info.highBrightnessMode;
2821             final boolean isHbmActive = hbmMode != BrightnessInfo.HIGH_BRIGHTNESS_MODE_OFF
2822                     && info.adjustedBrightness > info.highBrightnessTransitionPoint;
2823             if (hbmMode == mHbmMode.get(displayId)
2824                     && isHbmActive == mHbmActive.get(displayId)) {
2825                 // no change, ignore.
2826                 return;
2827             }
2828             mHbmMode.put(displayId, hbmMode);
2829             mHbmActive.put(displayId, isHbmActive);
2830             recalculateVotesForDisplay(displayId);
2831         }
2832 
onDeviceConfigRefreshRateInHbmChanged()2833         private void onDeviceConfigRefreshRateInHbmChanged() {
2834             final int[] displayIds = mHbmMode.copyKeys();
2835             if (displayIds != null) {
2836                 for (int id : displayIds) {
2837                     recalculateVotesForDisplay(id);
2838                 }
2839             }
2840         }
2841 
recalculateVotesForDisplay(int displayId)2842         private void recalculateVotesForDisplay(int displayId) {
2843             Vote vote = null;
2844             if (mHbmActive.get(displayId, false)) {
2845                 final int hbmMode =
2846                         mHbmMode.get(displayId, BrightnessInfo.HIGH_BRIGHTNESS_MODE_OFF);
2847                 if (hbmMode == BrightnessInfo.HIGH_BRIGHTNESS_MODE_SUNLIGHT) {
2848                     // Device resource properties take priority over DisplayDeviceConfig
2849                     if (mRefreshRateInHbmSunlight > 0) {
2850                         vote = Vote.forPhysicalRefreshRates(mRefreshRateInHbmSunlight,
2851                                 mRefreshRateInHbmSunlight);
2852                     } else {
2853                         final List<RefreshRateLimitation> limits =
2854                                 mDisplayManagerInternal.getRefreshRateLimitations(displayId);
2855                         for (int i = 0; limits != null && i < limits.size(); i++) {
2856                             final RefreshRateLimitation limitation = limits.get(i);
2857                             if (limitation.type == REFRESH_RATE_LIMIT_HIGH_BRIGHTNESS_MODE) {
2858                                 vote = Vote.forPhysicalRefreshRates(limitation.range.min,
2859                                         limitation.range.max);
2860                                 break;
2861                             }
2862                         }
2863                     }
2864                 } else if (hbmMode == BrightnessInfo.HIGH_BRIGHTNESS_MODE_HDR
2865                         && mRefreshRateInHbmHdr > 0) {
2866                     // HBM for HDR vote isn't supported through DisplayDeviceConfig yet, so look for
2867                     // a vote from Device properties
2868                     vote = Vote.forPhysicalRefreshRates(mRefreshRateInHbmHdr, mRefreshRateInHbmHdr);
2869                 } else {
2870                     Slog.w(TAG, "Unexpected HBM mode " + hbmMode + " for display ID " + displayId);
2871                 }
2872 
2873             }
2874             mVotesStorage.updateVote(displayId, Vote.PRIORITY_HIGH_BRIGHTNESS_MODE, vote);
2875         }
2876 
dumpLocked(PrintWriter pw)2877         void dumpLocked(PrintWriter pw) {
2878             pw.println("   HbmObserver");
2879             pw.println("     mHbmMode: " + mHbmMode);
2880             pw.println("     mHbmActive: " + mHbmActive);
2881             pw.println("     mRefreshRateInHbmSunlight: " + mRefreshRateInHbmSunlight);
2882             pw.println("     mRefreshRateInHbmHdr: " + mRefreshRateInHbmHdr);
2883         }
2884     }
2885 
2886     private class DeviceConfigDisplaySettings implements DeviceConfig.OnPropertiesChangedListener {
startListening()2887         public void startListening() {
2888             mConfigParameterProvider.addOnPropertiesChangedListener(
2889                     BackgroundThread.getExecutor(), this);
2890         }
2891 
getRefreshRateInHbmHdr(DisplayDeviceConfig displayDeviceConfig)2892         private int getRefreshRateInHbmHdr(DisplayDeviceConfig displayDeviceConfig) {
2893             return getRefreshRate(
2894                     () -> mConfigParameterProvider.getRefreshRateInHbmHdr(),
2895                     () -> displayDeviceConfig.getRefreshRateData().defaultRefreshRateInHbmHdr,
2896                     R.integer.config_defaultRefreshRateInHbmHdr,
2897                     displayDeviceConfig
2898             );
2899         }
2900 
getRefreshRateInHbmSunlight(DisplayDeviceConfig displayDeviceConfig)2901         private int getRefreshRateInHbmSunlight(DisplayDeviceConfig displayDeviceConfig) {
2902             return getRefreshRate(
2903                     () -> mConfigParameterProvider.getRefreshRateInHbmSunlight(),
2904                     () -> displayDeviceConfig.getRefreshRateData().defaultRefreshRateInHbmSunlight,
2905                     R.integer.config_defaultRefreshRateInHbmSunlight,
2906                     displayDeviceConfig
2907             );
2908         }
2909 
getRefreshRate(IntSupplier fromConfigPram, IntSupplier fromDisplayDeviceConfig, @IntegerRes int configKey, DisplayDeviceConfig displayDeviceConfig)2910         private int getRefreshRate(IntSupplier fromConfigPram, IntSupplier fromDisplayDeviceConfig,
2911                 @IntegerRes int configKey, DisplayDeviceConfig displayDeviceConfig) {
2912             int refreshRate = -1;
2913             try {
2914                 refreshRate = fromConfigPram.getAsInt();
2915             } catch (NullPointerException npe) {
2916                 // Do Nothing
2917             }
2918             if (refreshRate == -1) {
2919                 refreshRate = (displayDeviceConfig == null)
2920                                 ? mContext.getResources().getInteger(configKey)
2921                                 : fromDisplayDeviceConfig.getAsInt();
2922             }
2923             return refreshRate;
2924         }
2925 
2926         @Override
onPropertiesChanged(@onNull DeviceConfig.Properties properties)2927         public void onPropertiesChanged(@NonNull DeviceConfig.Properties properties) {
2928             float defaultPeakRefreshRate = mConfigParameterProvider.getPeakRefreshRateDefault();
2929             mHandler.obtainMessage(MSG_DEFAULT_PEAK_REFRESH_RATE_CHANGED,
2930                     defaultPeakRefreshRate == -1 ? null : defaultPeakRefreshRate).sendToTarget();
2931 
2932             float[] lowDisplayBrightnessThresholds =
2933                     mConfigParameterProvider.getLowDisplayBrightnessThresholds();
2934             float[] lowAmbientBrightnessThresholds =
2935                     mConfigParameterProvider.getLowAmbientBrightnessThresholds();
2936             final int refreshRateInLowZone = mConfigParameterProvider.getRefreshRateInLowZone();
2937 
2938             mHandler.obtainMessage(MSG_LOW_BRIGHTNESS_THRESHOLDS_CHANGED,
2939                     new Pair<>(lowDisplayBrightnessThresholds, lowAmbientBrightnessThresholds))
2940                     .sendToTarget();
2941 
2942             mHandler.obtainMessage(MSG_REFRESH_RATE_IN_LOW_ZONE_CHANGED, refreshRateInLowZone,
2943                     0).sendToTarget();
2944 
2945             float[] highDisplayBrightnessThresholds =
2946                     mConfigParameterProvider.getHighDisplayBrightnessThresholds();
2947             float[] highAmbientBrightnessThresholds =
2948                     mConfigParameterProvider.getHighAmbientBrightnessThresholds();
2949             final int refreshRateInHighZone = mConfigParameterProvider.getRefreshRateInHighZone();
2950 
2951             mHandler.obtainMessage(MSG_HIGH_BRIGHTNESS_THRESHOLDS_CHANGED,
2952                     new Pair<>(highDisplayBrightnessThresholds, highAmbientBrightnessThresholds))
2953                     .sendToTarget();
2954 
2955             mHandler.obtainMessage(MSG_REFRESH_RATE_IN_HIGH_ZONE_CHANGED, refreshRateInHighZone,
2956                     0).sendToTarget();
2957 
2958             synchronized (mLock) {
2959                 final int refreshRateInHbmSunlight =
2960                         getRefreshRateInHbmSunlight(mDefaultDisplayDeviceConfig);
2961                 mHandler.obtainMessage(MSG_REFRESH_RATE_IN_HBM_SUNLIGHT_CHANGED,
2962                         refreshRateInHbmSunlight, 0)
2963                     .sendToTarget();
2964 
2965                 final int refreshRateInHbmHdr =
2966                         getRefreshRateInHbmHdr(mDefaultDisplayDeviceConfig);
2967                 mHandler.obtainMessage(MSG_REFRESH_RATE_IN_HBM_HDR_CHANGED, refreshRateInHbmHdr, 0)
2968                     .sendToTarget();
2969             }
2970         }
2971     }
2972 
2973     interface Injector {
2974         Uri PEAK_REFRESH_RATE_URI = Settings.System.getUriFor(Settings.System.PEAK_REFRESH_RATE);
2975         Uri MIN_REFRESH_RATE_URI = Settings.System.getUriFor(Settings.System.MIN_REFRESH_RATE);
2976 
2977         @NonNull
getDeviceConfig()2978         DeviceConfigInterface getDeviceConfig();
2979 
registerPeakRefreshRateObserver(@onNull ContentResolver cr, @NonNull ContentObserver observer)2980         void registerPeakRefreshRateObserver(@NonNull ContentResolver cr,
2981                 @NonNull ContentObserver observer);
2982 
registerMinRefreshRateObserver(@onNull ContentResolver cr, @NonNull ContentObserver observer)2983         void registerMinRefreshRateObserver(@NonNull ContentResolver cr,
2984                 @NonNull ContentObserver observer);
2985 
registerDisplayListener(@onNull DisplayManager.DisplayListener listener, Handler handler)2986         void registerDisplayListener(@NonNull DisplayManager.DisplayListener listener,
2987                 Handler handler);
2988 
registerDisplayListener(@onNull DisplayManager.DisplayListener listener, Handler handler, long flags)2989         void registerDisplayListener(@NonNull DisplayManager.DisplayListener listener,
2990                 Handler handler, long flags);
2991 
getDisplay(int displayId)2992         Display getDisplay(int displayId);
2993 
getDisplays()2994         Display[] getDisplays();
2995 
getDisplayInfo(int displayId, DisplayInfo displayInfo)2996         boolean getDisplayInfo(int displayId, DisplayInfo displayInfo);
2997 
getBrightnessInfo(int displayId)2998         BrightnessInfo getBrightnessInfo(int displayId);
2999 
isDozeState(Display d)3000         boolean isDozeState(Display d);
3001 
registerThermalServiceListener(IThermalEventListener listener)3002         boolean registerThermalServiceListener(IThermalEventListener listener);
unregisterThermalServiceListener(IThermalEventListener listener)3003         void unregisterThermalServiceListener(IThermalEventListener listener);
3004 
supportsFrameRateOverride()3005         boolean supportsFrameRateOverride();
3006 
getDisplayManagerInternal()3007         DisplayManagerInternal getDisplayManagerInternal();
3008 
getStatusBarManagerInternal()3009         StatusBarManagerInternal getStatusBarManagerInternal();
3010 
getSensorManagerInternal()3011         SensorManagerInternal getSensorManagerInternal();
3012 
3013         @Nullable
getVotesStatsReporter(boolean refreshRateVotingTelemetryEnabled)3014         VotesStatsReporter getVotesStatsReporter(boolean refreshRateVotingTelemetryEnabled);
3015     }
3016 
3017     @VisibleForTesting
3018     static class RealInjector implements Injector {
3019         private final Context mContext;
3020         private DisplayManager mDisplayManager;
3021 
RealInjector(Context context)3022         RealInjector(Context context) {
3023             mContext = context;
3024         }
3025 
3026         @Override
3027         @NonNull
getDeviceConfig()3028         public DeviceConfigInterface getDeviceConfig() {
3029             return DeviceConfigInterface.REAL;
3030         }
3031 
3032         @Override
registerPeakRefreshRateObserver(@onNull ContentResolver cr, @NonNull ContentObserver observer)3033         public void registerPeakRefreshRateObserver(@NonNull ContentResolver cr,
3034                 @NonNull ContentObserver observer) {
3035             cr.registerContentObserver(PEAK_REFRESH_RATE_URI, false /*notifyDescendants*/,
3036                     observer, UserHandle.USER_SYSTEM);
3037         }
3038 
3039         @Override
registerMinRefreshRateObserver(@onNull ContentResolver cr, @NonNull ContentObserver observer)3040         public void registerMinRefreshRateObserver(@NonNull ContentResolver cr,
3041                 @NonNull ContentObserver observer) {
3042             cr.registerContentObserver(MIN_REFRESH_RATE_URI, false /*notifyDescendants*/,
3043                     observer, UserHandle.USER_SYSTEM);
3044         }
3045 
3046         @Override
registerDisplayListener(DisplayManager.DisplayListener listener, Handler handler)3047         public void registerDisplayListener(DisplayManager.DisplayListener listener,
3048                 Handler handler) {
3049             getDisplayManager().registerDisplayListener(listener, handler);
3050         }
3051 
3052         @Override
registerDisplayListener(DisplayManager.DisplayListener listener, Handler handler, long flags)3053         public void registerDisplayListener(DisplayManager.DisplayListener listener,
3054                 Handler handler, long flags) {
3055             getDisplayManager().registerDisplayListener(listener, handler, flags);
3056         }
3057 
3058         @Override
getDisplay(int displayId)3059         public Display getDisplay(int displayId) {
3060             return getDisplayManager().getDisplay(displayId);
3061         }
3062 
3063         @Override
getDisplays()3064         public Display[] getDisplays() {
3065             return getDisplayManager().getDisplays(DISPLAY_CATEGORY_ALL_INCLUDING_DISABLED);
3066         }
3067 
3068         @Override
getDisplayInfo(int displayId, DisplayInfo displayInfo)3069         public boolean getDisplayInfo(int displayId, DisplayInfo displayInfo) {
3070             Display display = getDisplayManager().getDisplay(displayId);
3071             if (display == null) {
3072                 // We can occasionally get a display added or changed event for a display that was
3073                 // subsequently removed, which means this returns null. Check this case and bail
3074                 // out early; if it gets re-attached we'll eventually get another call back for it.
3075                 return false;
3076             }
3077             return display.getDisplayInfo(displayInfo);
3078         }
3079 
3080         @Override
getBrightnessInfo(int displayId)3081         public BrightnessInfo getBrightnessInfo(int displayId) {
3082             final Display display = getDisplayManager().getDisplay(displayId);
3083             if (display != null) {
3084                 return display.getBrightnessInfo();
3085             }
3086             return null;
3087         }
3088 
3089         @Override
isDozeState(Display d)3090         public boolean isDozeState(Display d) {
3091             if (d == null) {
3092                 return false;
3093             }
3094             return Display.isDozeState(d.getState());
3095         }
3096 
3097         @Override
registerThermalServiceListener(IThermalEventListener listener)3098         public boolean registerThermalServiceListener(IThermalEventListener listener) {
3099             IThermalService thermalService = getThermalService();
3100             if (thermalService == null) {
3101                 Slog.w(TAG, "Could not observe thermal status. Service not available");
3102                 return false;
3103             }
3104             try {
3105                 thermalService.registerThermalEventListenerWithType(listener,
3106                         Temperature.TYPE_SKIN);
3107             } catch (RemoteException e) {
3108                 Slog.e(TAG, "Failed to register thermal status listener", e);
3109                 return false;
3110             }
3111             return true;
3112         }
3113 
3114         @Override
unregisterThermalServiceListener(IThermalEventListener listener)3115         public void unregisterThermalServiceListener(IThermalEventListener listener) {
3116             IThermalService thermalService = getThermalService();
3117             if (thermalService == null) {
3118                 Slog.w(TAG, "Could not unregister thermal status. Service not available");
3119             }
3120             try {
3121                 thermalService.unregisterThermalEventListener(listener);
3122             } catch (RemoteException e) {
3123                 Slog.e(TAG, "Failed to unregister thermal status listener", e);
3124             }
3125         }
3126 
3127         @Override
supportsFrameRateOverride()3128         public boolean supportsFrameRateOverride() {
3129             return SurfaceFlingerProperties.enable_frame_rate_override().orElse(true);
3130         }
3131 
3132         @Override
getDisplayManagerInternal()3133         public DisplayManagerInternal getDisplayManagerInternal() {
3134             return LocalServices.getService(DisplayManagerInternal.class);
3135         }
3136 
3137         @Override
getStatusBarManagerInternal()3138         public StatusBarManagerInternal getStatusBarManagerInternal() {
3139             return LocalServices.getService(StatusBarManagerInternal.class);
3140         }
3141 
3142         @Override
getSensorManagerInternal()3143         public SensorManagerInternal getSensorManagerInternal() {
3144             return LocalServices.getService(SensorManagerInternal.class);
3145         }
3146 
3147         @Override
getVotesStatsReporter(boolean refreshRateVotingTelemetryEnabled)3148         public VotesStatsReporter getVotesStatsReporter(boolean refreshRateVotingTelemetryEnabled) {
3149             // if frame rate override supported, renderRates will be ignored in mode selection
3150             return new VotesStatsReporter(supportsFrameRateOverride(),
3151                     refreshRateVotingTelemetryEnabled);
3152         }
3153 
getDisplayManager()3154         private DisplayManager getDisplayManager() {
3155             if (mDisplayManager == null) {
3156                 mDisplayManager = mContext.getSystemService(DisplayManager.class);
3157             }
3158             return mDisplayManager;
3159         }
3160 
getThermalService()3161         private IThermalService getThermalService() {
3162             return IThermalService.Stub.asInterface(
3163                     ServiceManager.getService(Context.THERMAL_SERVICE));
3164         }
3165     }
3166 }
3167