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