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