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 // Revoke previous vote from BrightnessObserver 1816 mVotesStorage.updateGlobalVote(Vote.PRIORITY_FLICKER_REFRESH_RATE, null); 1817 mVotesStorage.updateGlobalVote(Vote.PRIORITY_FLICKER_REFRESH_RATE_SWITCH, null); 1818 } 1819 } 1820 } 1821 onLowPowerModeEnabledLocked(boolean b)1822 private void onLowPowerModeEnabledLocked(boolean b) { 1823 if (mLowPowerModeEnabled != b) { 1824 mLowPowerModeEnabled = b; 1825 updateSensorStatus(); 1826 } 1827 } 1828 onDeviceConfigLowBrightnessThresholdsChanged(float[] displayThresholds, float[] ambientThresholds)1829 private void onDeviceConfigLowBrightnessThresholdsChanged(float[] displayThresholds, 1830 float[] ambientThresholds) { 1831 if (displayThresholds != null && ambientThresholds != null 1832 && displayThresholds.length == ambientThresholds.length) { 1833 mLowDisplayBrightnessThresholds = displayThresholds; 1834 mLowAmbientBrightnessThresholds = ambientThresholds; 1835 } else { 1836 DisplayDeviceConfig displayDeviceConfig; 1837 synchronized (mLock) { 1838 displayDeviceConfig = mDefaultDisplayDeviceConfig; 1839 } 1840 mLowDisplayBrightnessThresholds = loadBrightnessThresholds( 1841 () -> mConfigParameterProvider.getLowDisplayBrightnessThresholds(), 1842 () -> displayDeviceConfig.getLowDisplayBrightnessThresholds(), 1843 R.array.config_brightnessThresholdsOfPeakRefreshRate, 1844 displayDeviceConfig, /* attemptReadFromFeatureParams= */ false, 1845 DeviceConfigParsingUtils::displayBrightnessThresholdsIntToFloat); 1846 mLowAmbientBrightnessThresholds = loadBrightnessThresholds( 1847 () -> mConfigParameterProvider.getLowAmbientBrightnessThresholds(), 1848 () -> displayDeviceConfig.getLowAmbientBrightnessThresholds(), 1849 R.array.config_ambientThresholdsOfPeakRefreshRate, 1850 displayDeviceConfig, /* attemptReadFromFeatureParams= */ false, 1851 DeviceConfigParsingUtils::ambientBrightnessThresholdsIntToFloat); 1852 } 1853 restartObserver(); 1854 } 1855 1856 /** 1857 * Used to reload the lower blocking zone refresh rate in case of changes in the 1858 * DeviceConfig properties. 1859 */ onDeviceConfigRefreshRateInLowZoneChanged(int refreshRate)1860 public void onDeviceConfigRefreshRateInLowZoneChanged(int refreshRate) { 1861 if (refreshRate == -1) { 1862 // Given there is no value available in DeviceConfig, lets not attempt loading it 1863 // from there. 1864 synchronized (mLock) { 1865 loadRefreshRateInLowZone(mDefaultDisplayDeviceConfig, 1866 /* attemptReadFromFeatureParams= */ false); 1867 } 1868 restartObserver(); 1869 } else if (refreshRate != mRefreshRateInLowZone) { 1870 mRefreshRateInLowZone = refreshRate; 1871 restartObserver(); 1872 } 1873 } 1874 onDeviceConfigHighBrightnessThresholdsChanged(float[] displayThresholds, float[] ambientThresholds)1875 private void onDeviceConfigHighBrightnessThresholdsChanged(float[] displayThresholds, 1876 float[] ambientThresholds) { 1877 if (displayThresholds != null && ambientThresholds != null 1878 && displayThresholds.length == ambientThresholds.length) { 1879 mHighDisplayBrightnessThresholds = displayThresholds; 1880 mHighAmbientBrightnessThresholds = ambientThresholds; 1881 } else { 1882 DisplayDeviceConfig displayDeviceConfig; 1883 synchronized (mLock) { 1884 displayDeviceConfig = mDefaultDisplayDeviceConfig; 1885 } 1886 mHighDisplayBrightnessThresholds = loadBrightnessThresholds( 1887 () -> mConfigParameterProvider.getLowDisplayBrightnessThresholds(), 1888 () -> displayDeviceConfig.getHighDisplayBrightnessThresholds(), 1889 R.array.config_highDisplayBrightnessThresholdsOfFixedRefreshRate, 1890 displayDeviceConfig, /* attemptReadFromFeatureParams= */ false, 1891 DeviceConfigParsingUtils::displayBrightnessThresholdsIntToFloat); 1892 mHighAmbientBrightnessThresholds = loadBrightnessThresholds( 1893 () -> mConfigParameterProvider.getHighAmbientBrightnessThresholds(), 1894 () -> displayDeviceConfig.getHighAmbientBrightnessThresholds(), 1895 R.array.config_highAmbientBrightnessThresholdsOfFixedRefreshRate, 1896 displayDeviceConfig, /* attemptReadFromFeatureParams= */ false, 1897 DeviceConfigParsingUtils::ambientBrightnessThresholdsIntToFloat); 1898 } 1899 restartObserver(); 1900 } 1901 1902 /** 1903 * Used to reload the higher blocking zone refresh rate in case of changes in the 1904 * DeviceConfig properties. 1905 */ onDeviceConfigRefreshRateInHighZoneChanged(int refreshRate)1906 public void onDeviceConfigRefreshRateInHighZoneChanged(int refreshRate) { 1907 if (refreshRate == -1) { 1908 // Given there is no value available in DeviceConfig, lets not attempt loading it 1909 // from there. 1910 synchronized (mLock) { 1911 loadRefreshRateInHighZone(mDefaultDisplayDeviceConfig, 1912 /* attemptReadFromFeatureParams= */ false); 1913 } 1914 restartObserver(); 1915 } else if (refreshRate != mRefreshRateInHighZone) { 1916 mRefreshRateInHighZone = refreshRate; 1917 restartObserver(); 1918 } 1919 } 1920 dumpLocked(PrintWriter pw)1921 void dumpLocked(PrintWriter pw) { 1922 pw.println(" BrightnessObserver"); 1923 pw.println(" mAmbientLux: " + mAmbientLux); 1924 pw.println(" mBrightness: " + mBrightness); 1925 pw.println(" mDefaultDisplayState: " + mDefaultDisplayState); 1926 pw.println(" mLowPowerModeEnabled: " + mLowPowerModeEnabled); 1927 pw.println(" mRefreshRateChangeable: " + mRefreshRateChangeable); 1928 pw.println(" mShouldObserveDisplayLowChange: " + mShouldObserveDisplayLowChange); 1929 pw.println(" mShouldObserveAmbientLowChange: " + mShouldObserveAmbientLowChange); 1930 pw.println(" mRefreshRateInLowZone: " + mRefreshRateInLowZone); 1931 1932 for (float d : mLowDisplayBrightnessThresholds) { 1933 pw.println(" mDisplayLowBrightnessThreshold: " + d); 1934 } 1935 1936 for (float d : mLowAmbientBrightnessThresholds) { 1937 pw.println(" mAmbientLowBrightnessThreshold: " + d); 1938 } 1939 1940 pw.println(" mShouldObserveDisplayHighChange: " + mShouldObserveDisplayHighChange); 1941 pw.println(" mShouldObserveAmbientHighChange: " + mShouldObserveAmbientHighChange); 1942 pw.println(" mRefreshRateInHighZone: " + mRefreshRateInHighZone); 1943 1944 for (float d : mHighDisplayBrightnessThresholds) { 1945 pw.println(" mDisplayHighBrightnessThresholds: " + d); 1946 } 1947 1948 for (float d : mHighAmbientBrightnessThresholds) { 1949 pw.println(" mAmbientHighBrightnessThresholds: " + d); 1950 } 1951 1952 pw.println(" mRegisteredLightSensor: " + mRegisteredLightSensor); 1953 pw.println(" mLightSensor: " + mLightSensor); 1954 pw.println(" mLightSensorName: " + mLightSensorName); 1955 pw.println(" mLightSensorType: " + mLightSensorType); 1956 mLightSensorListener.dumpLocked(pw); 1957 1958 if (mAmbientFilter != null) { 1959 IndentingPrintWriter ipw = new IndentingPrintWriter(pw, " "); 1960 mAmbientFilter.dump(ipw); 1961 } 1962 } 1963 1964 @Override onDisplayAdded(int displayId)1965 public void onDisplayAdded(int displayId) {} 1966 1967 @Override onDisplayRemoved(int displayId)1968 public void onDisplayRemoved(int displayId) {} 1969 1970 @Override onDisplayChanged(int displayId)1971 public void onDisplayChanged(int displayId) { 1972 if (displayId == Display.DEFAULT_DISPLAY) { 1973 updateDefaultDisplayState(); 1974 1975 // We don't support multiple display blocking zones yet, so only handle 1976 // brightness changes for the default display for now. 1977 float brightness = getBrightness(displayId); 1978 synchronized (mLock) { 1979 if (!BrightnessSynchronizer.floatEquals(brightness, mBrightness)) { 1980 mBrightness = brightness; 1981 onBrightnessChangedLocked(); 1982 } 1983 } 1984 } 1985 } 1986 restartObserver()1987 private void restartObserver() { 1988 if (mRefreshRateInLowZone > 0) { 1989 mShouldObserveDisplayLowChange = hasValidThreshold( 1990 mLowDisplayBrightnessThresholds); 1991 mShouldObserveAmbientLowChange = hasValidThreshold( 1992 mLowAmbientBrightnessThresholds); 1993 } else { 1994 mShouldObserveDisplayLowChange = false; 1995 mShouldObserveAmbientLowChange = false; 1996 } 1997 1998 if (mRefreshRateInHighZone > 0) { 1999 mShouldObserveDisplayHighChange = hasValidThreshold( 2000 mHighDisplayBrightnessThresholds); 2001 mShouldObserveAmbientHighChange = hasValidThreshold( 2002 mHighAmbientBrightnessThresholds); 2003 } else { 2004 mShouldObserveDisplayHighChange = false; 2005 mShouldObserveAmbientHighChange = false; 2006 } 2007 2008 if (mShouldObserveAmbientLowChange || mShouldObserveAmbientHighChange) { 2009 Sensor lightSensor = getLightSensor(); 2010 2011 if (lightSensor != null && lightSensor != mLightSensor) { 2012 final Resources res = mContext.getResources(); 2013 2014 mAmbientFilter = AmbientFilterFactory.createBrightnessFilter(TAG, res); 2015 mLightSensor = lightSensor; 2016 } 2017 } else { 2018 mAmbientFilter = null; 2019 mLightSensor = null; 2020 } 2021 2022 updateSensorStatus(); 2023 synchronized (mLock) { 2024 onBrightnessChangedLocked(); 2025 } 2026 } 2027 reloadLightSensor(DisplayDeviceConfig displayDeviceConfig)2028 private void reloadLightSensor(DisplayDeviceConfig displayDeviceConfig) { 2029 reloadLightSensorData(displayDeviceConfig); 2030 restartObserver(); 2031 } 2032 reloadLightSensorData(DisplayDeviceConfig displayDeviceConfig)2033 private void reloadLightSensorData(DisplayDeviceConfig displayDeviceConfig) { 2034 // The displayDeviceConfig (ddc) contains display specific preferences. When loaded, 2035 // it naturally falls back to the global config.xml. 2036 if (displayDeviceConfig != null 2037 && displayDeviceConfig.getAmbientLightSensor() != null) { 2038 // This covers both the ddc and the config.xml fallback 2039 mLightSensorType = displayDeviceConfig.getAmbientLightSensor().type; 2040 mLightSensorName = displayDeviceConfig.getAmbientLightSensor().name; 2041 } else if (mLightSensorName == null && mLightSensorType == null) { 2042 Resources resources = mContext.getResources(); 2043 mLightSensorType = resources.getString( 2044 com.android.internal.R.string.config_displayLightSensorType); 2045 mLightSensorName = ""; 2046 } 2047 } 2048 getLightSensor()2049 private Sensor getLightSensor() { 2050 return SensorUtils.findSensor(mSensorManager, mLightSensorType, 2051 mLightSensorName, Sensor.TYPE_LIGHT); 2052 } 2053 2054 /** 2055 * Checks to see if at least one value is positive, in which case it is necessary to listen 2056 * to value changes. 2057 */ hasValidThreshold(float[] a)2058 private boolean hasValidThreshold(float[] a) { 2059 for (float d: a) { 2060 if (d >= 0) { 2061 return true; 2062 } 2063 } 2064 2065 return false; 2066 } 2067 2068 /** 2069 * Check if we're in the low zone where higher refresh rates aren't allowed to prevent 2070 * flickering. 2071 * @param brightness The brightness value or a negative value meaning that only the lux 2072 * threshold should be applied 2073 * @param lux The lux value. If negative, only the brightness threshold is applied 2074 * @return True if we're in the low zone 2075 */ isInsideLowZone(float brightness, float lux)2076 private boolean isInsideLowZone(float brightness, float lux) { 2077 for (int i = 0; i < mLowDisplayBrightnessThresholds.length; i++) { 2078 float disp = mLowDisplayBrightnessThresholds[i]; 2079 float ambi = mLowAmbientBrightnessThresholds[i]; 2080 2081 if (disp >= 0 && ambi >= 0) { 2082 if (brightness <= disp && lux <= ambi) { 2083 return true; 2084 } 2085 } else if (disp >= 0) { 2086 if (brightness <= disp) { 2087 return true; 2088 } 2089 } else if (ambi >= 0) { 2090 if (lux <= ambi) { 2091 return true; 2092 } 2093 } 2094 } 2095 2096 return false; 2097 } 2098 2099 /** 2100 * Check if we're in the high zone where higher refresh rates aren't allowed to prevent 2101 * flickering. 2102 * @param brightness The brightness value or a negative value meaning that only the lux 2103 * threshold should be applied 2104 * @param lux The lux value. If negative, only the brightness threshold is applied 2105 * @return True if we're in the high zone 2106 */ isInsideHighZone(float brightness, float lux)2107 private boolean isInsideHighZone(float brightness, float lux) { 2108 for (int i = 0; i < mHighDisplayBrightnessThresholds.length; i++) { 2109 float disp = mHighDisplayBrightnessThresholds[i]; 2110 float ambi = mHighAmbientBrightnessThresholds[i]; 2111 2112 if (disp >= 0 && ambi >= 0) { 2113 if (brightness >= disp && lux >= ambi) { 2114 return true; 2115 } 2116 } else if (disp >= 0) { 2117 if (brightness >= disp) { 2118 return true; 2119 } 2120 } else if (ambi >= 0) { 2121 if (lux >= ambi) { 2122 return true; 2123 } 2124 } 2125 } 2126 2127 return false; 2128 } 2129 onBrightnessChangedLocked()2130 private void onBrightnessChangedLocked() { 2131 if (!mRefreshRateChangeable) { 2132 return; 2133 } 2134 Vote refreshRateVote = null; 2135 Vote refreshRateSwitchingVote = null; 2136 2137 if (Float.isNaN(mBrightness)) { 2138 // Either the setting isn't available or we shouldn't be observing yet anyways. 2139 // Either way, just bail out since there's nothing we can do here. 2140 return; 2141 } 2142 2143 boolean insideLowZone = hasValidLowZone() && isInsideLowZone(mBrightness, mAmbientLux); 2144 if (insideLowZone) { 2145 refreshRateVote = 2146 Vote.forPhysicalRefreshRates(mRefreshRateInLowZone, mRefreshRateInLowZone); 2147 if (mLowZoneRefreshRateForThermals != null) { 2148 RefreshRateRange range = SkinThermalStatusObserver 2149 .findBestMatchingRefreshRateRange(mThermalStatus, 2150 mLowZoneRefreshRateForThermals); 2151 if (range != null) { 2152 refreshRateVote = 2153 Vote.forPhysicalRefreshRates(range.min, range.max); 2154 } 2155 } 2156 refreshRateSwitchingVote = Vote.forDisableRefreshRateSwitching(); 2157 } 2158 2159 boolean insideHighZone = hasValidHighZone() 2160 && isInsideHighZone(mBrightness, mAmbientLux); 2161 if (insideHighZone) { 2162 refreshRateVote = 2163 Vote.forPhysicalRefreshRates(mRefreshRateInHighZone, 2164 mRefreshRateInHighZone); 2165 if (mHighZoneRefreshRateForThermals != null) { 2166 RefreshRateRange range = SkinThermalStatusObserver 2167 .findBestMatchingRefreshRateRange(mThermalStatus, 2168 mHighZoneRefreshRateForThermals); 2169 if (range != null) { 2170 refreshRateVote = 2171 Vote.forPhysicalRefreshRates(range.min, range.max); 2172 } 2173 } 2174 refreshRateSwitchingVote = Vote.forDisableRefreshRateSwitching(); 2175 } 2176 2177 if (mLoggingEnabled) { 2178 Slog.d(TAG, "Display brightness " + mBrightness + ", ambient lux " + mAmbientLux 2179 + ", Vote " + refreshRateVote); 2180 } 2181 mVotesStorage.updateGlobalVote(Vote.PRIORITY_FLICKER_REFRESH_RATE, refreshRateVote); 2182 mVotesStorage.updateGlobalVote(Vote.PRIORITY_FLICKER_REFRESH_RATE_SWITCH, 2183 refreshRateSwitchingVote); 2184 } 2185 hasValidLowZone()2186 private boolean hasValidLowZone() { 2187 return mRefreshRateInLowZone > 0 2188 && (mShouldObserveDisplayLowChange || mShouldObserveAmbientLowChange); 2189 } 2190 hasValidHighZone()2191 private boolean hasValidHighZone() { 2192 return mRefreshRateInHighZone > 0 2193 && (mShouldObserveDisplayHighChange || mShouldObserveAmbientHighChange); 2194 } 2195 updateDefaultDisplayState()2196 private void updateDefaultDisplayState() { 2197 Display display = mInjector.getDisplay(Display.DEFAULT_DISPLAY); 2198 if (display == null) { 2199 return; 2200 } 2201 2202 setDefaultDisplayState(display.getState()); 2203 } 2204 2205 @VisibleForTesting setDefaultDisplayState(int state)2206 void setDefaultDisplayState(int state) { 2207 if (mLoggingEnabled) { 2208 Slog.d(TAG, "setDefaultDisplayState: mDefaultDisplayState = " 2209 + mDefaultDisplayState + ", state = " + state); 2210 } 2211 2212 if (mDefaultDisplayState != state) { 2213 mDefaultDisplayState = state; 2214 updateSensorStatus(); 2215 } 2216 } 2217 updateSensorStatus()2218 private void updateSensorStatus() { 2219 if (mSensorManager == null || mLightSensorListener == null) { 2220 return; 2221 } 2222 2223 if (mLoggingEnabled) { 2224 Slog.d(TAG, "updateSensorStatus: mShouldObserveAmbientLowChange = " 2225 + mShouldObserveAmbientLowChange + ", mShouldObserveAmbientHighChange = " 2226 + mShouldObserveAmbientHighChange); 2227 Slog.d(TAG, "updateSensorStatus: mLowPowerModeEnabled = " 2228 + mLowPowerModeEnabled + ", mRefreshRateChangeable = " 2229 + mRefreshRateChangeable); 2230 } 2231 2232 boolean registerForThermals = false; 2233 if ((mShouldObserveAmbientLowChange || mShouldObserveAmbientHighChange) 2234 && isDeviceActive() && !mLowPowerModeEnabled && mRefreshRateChangeable) { 2235 registerLightSensor(); 2236 registerForThermals = mLowZoneRefreshRateForThermals != null 2237 || mHighZoneRefreshRateForThermals != null; 2238 } else { 2239 unregisterSensorListener(); 2240 } 2241 2242 if (registerForThermals && !mThermalRegistered) { 2243 mThermalRegistered = mInjector.registerThermalServiceListener(mThermalListener); 2244 } else if (!registerForThermals && mThermalRegistered) { 2245 mInjector.unregisterThermalServiceListener(mThermalListener); 2246 mThermalRegistered = false; 2247 synchronized (mLock) { 2248 mThermalStatus = Temperature.THROTTLING_NONE; // reset 2249 } 2250 } 2251 } 2252 registerLightSensor()2253 private void registerLightSensor() { 2254 if (mRegisteredLightSensor == mLightSensor) { 2255 return; 2256 } 2257 2258 if (mRegisteredLightSensor != null) { 2259 unregisterSensorListener(); 2260 } 2261 2262 mSensorManager.registerListener(mLightSensorListener, 2263 mLightSensor, LIGHT_SENSOR_RATE_MS * 1000, mHandler); 2264 mRegisteredLightSensor = mLightSensor; 2265 if (mLoggingEnabled) { 2266 Slog.d(TAG, "updateSensorStatus: registerListener"); 2267 } 2268 } 2269 unregisterSensorListener()2270 private void unregisterSensorListener() { 2271 mLightSensorListener.removeCallbacks(); 2272 mSensorManager.unregisterListener(mLightSensorListener); 2273 mRegisteredLightSensor = null; 2274 if (mLoggingEnabled) { 2275 Slog.d(TAG, "updateSensorStatus: unregisterListener"); 2276 } 2277 } 2278 isDeviceActive()2279 private boolean isDeviceActive() { 2280 return mDefaultDisplayState == Display.STATE_ON; 2281 } 2282 2283 /** 2284 * Get the brightness value for a display 2285 * @param displayId The ID of the display 2286 * @return The brightness value 2287 */ getBrightness(int displayId)2288 private float getBrightness(int displayId) { 2289 final BrightnessInfo info = mInjector.getBrightnessInfo(displayId); 2290 if (info != null) { 2291 return info.adjustedBrightness; 2292 } 2293 2294 return BRIGHTNESS_INVALID_FLOAT; 2295 } 2296 2297 private final class LightSensorEventListener implements SensorEventListener { 2298 private static final int INJECT_EVENTS_INTERVAL_MS = LIGHT_SENSOR_RATE_MS; 2299 private float mLastSensorData; 2300 private long mTimestamp; 2301 private boolean mLoggingEnabled; 2302 dumpLocked(PrintWriter pw)2303 public void dumpLocked(PrintWriter pw) { 2304 pw.println(" mLastSensorData: " + mLastSensorData); 2305 pw.println(" mTimestamp: " + formatTimestamp(mTimestamp)); 2306 } 2307 2308 setLoggingEnabled(boolean loggingEnabled)2309 public void setLoggingEnabled(boolean loggingEnabled) { 2310 if (mLoggingEnabled == loggingEnabled) { 2311 return; 2312 } 2313 mLoggingEnabled = loggingEnabled; 2314 } 2315 2316 @Override onSensorChanged(SensorEvent event)2317 public void onSensorChanged(SensorEvent event) { 2318 mLastSensorData = event.values[0]; 2319 if (mLoggingEnabled) { 2320 Slog.d(TAG, "On sensor changed: " + mLastSensorData); 2321 } 2322 2323 boolean lowZoneChanged = isDifferentZone(mLastSensorData, mAmbientLux, 2324 mLowAmbientBrightnessThresholds); 2325 boolean highZoneChanged = isDifferentZone(mLastSensorData, mAmbientLux, 2326 mHighAmbientBrightnessThresholds); 2327 if ((lowZoneChanged && mLastSensorData < mAmbientLux) 2328 || (highZoneChanged && mLastSensorData > mAmbientLux)) { 2329 // Easier to see flicker at lower brightness environment or high brightness 2330 // environment. Forget the history to get immediate response. 2331 if (mAmbientFilter != null) { 2332 mAmbientFilter.clear(); 2333 } 2334 } 2335 2336 long now = SystemClock.uptimeMillis(); 2337 mTimestamp = System.currentTimeMillis(); 2338 if (mAmbientFilter != null) { 2339 mAmbientFilter.addValue(now, mLastSensorData); 2340 } 2341 2342 mHandler.removeCallbacks(mInjectSensorEventRunnable); 2343 processSensorData(now); 2344 2345 if ((lowZoneChanged && mLastSensorData > mAmbientLux) 2346 || (highZoneChanged && mLastSensorData < mAmbientLux)) { 2347 // Sensor may not report new event if there is no brightness change. 2348 // Need to keep querying the temporal filter for the latest estimation, 2349 // until sensor readout and filter estimation are in the same zone or 2350 // is interrupted by a new sensor event. 2351 mHandler.postDelayed(mInjectSensorEventRunnable, INJECT_EVENTS_INTERVAL_MS); 2352 } 2353 } 2354 2355 @Override onAccuracyChanged(Sensor sensor, int accuracy)2356 public void onAccuracyChanged(Sensor sensor, int accuracy) { 2357 // Not used. 2358 } 2359 removeCallbacks()2360 public void removeCallbacks() { 2361 mHandler.removeCallbacks(mInjectSensorEventRunnable); 2362 } 2363 formatTimestamp(long time)2364 private String formatTimestamp(long time) { 2365 SimpleDateFormat dateFormat = 2366 new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS", Locale.US); 2367 return dateFormat.format(new Date(time)); 2368 } 2369 processSensorData(long now)2370 private void processSensorData(long now) { 2371 if (mAmbientFilter != null) { 2372 mAmbientLux = mAmbientFilter.getEstimate(now); 2373 } else { 2374 mAmbientLux = mLastSensorData; 2375 } 2376 2377 synchronized (mLock) { 2378 onBrightnessChangedLocked(); 2379 } 2380 } 2381 isDifferentZone(float lux1, float lux2, float[] luxThresholds)2382 private boolean isDifferentZone(float lux1, float lux2, float[] luxThresholds) { 2383 for (final float boundary : luxThresholds) { 2384 // Test each boundary. See if the current value and the new value are at 2385 // different sides. 2386 if ((lux1 <= boundary && lux2 > boundary) 2387 || (lux1 > boundary && lux2 <= boundary)) { 2388 return true; 2389 } 2390 } 2391 2392 return false; 2393 } 2394 2395 private final Runnable mInjectSensorEventRunnable = new Runnable() { 2396 @Override 2397 public void run() { 2398 long now = SystemClock.uptimeMillis(); 2399 // No need to really inject the last event into a temporal filter. 2400 processSensorData(now); 2401 2402 // Inject next event if there is a possible zone change. 2403 if (isDifferentZone(mLastSensorData, mAmbientLux, 2404 mLowAmbientBrightnessThresholds) 2405 || isDifferentZone(mLastSensorData, mAmbientLux, 2406 mHighAmbientBrightnessThresholds)) { 2407 mHandler.postDelayed(mInjectSensorEventRunnable, INJECT_EVENTS_INTERVAL_MS); 2408 } 2409 } 2410 }; 2411 } 2412 } 2413 2414 private class UdfpsObserver extends IUdfpsRefreshRateRequestCallback.Stub { 2415 private final SparseBooleanArray mUdfpsRefreshRateEnabled = new SparseBooleanArray(); 2416 private final SparseBooleanArray mAuthenticationPossible = new SparseBooleanArray(); 2417 observe()2418 public void observe() { 2419 StatusBarManagerInternal statusBar = 2420 LocalServices.getService(StatusBarManagerInternal.class); 2421 if (statusBar == null) { 2422 return; 2423 } 2424 2425 // Allow UDFPS vote by registering callback, only 2426 // if the device is configured to not ignore UDFPS vote. 2427 boolean ignoreUdfpsVote = mContext.getResources() 2428 .getBoolean(R.bool.config_ignoreUdfpsVote); 2429 if (!ignoreUdfpsVote) { 2430 statusBar.setUdfpsRefreshRateCallback(this); 2431 } 2432 } 2433 2434 @Override onRequestEnabled(int displayId)2435 public void onRequestEnabled(int displayId) { 2436 synchronized (mLock) { 2437 mUdfpsRefreshRateEnabled.put(displayId, true); 2438 updateVoteLocked(displayId, true, Vote.PRIORITY_UDFPS); 2439 } 2440 } 2441 2442 @Override onRequestDisabled(int displayId)2443 public void onRequestDisabled(int displayId) { 2444 synchronized (mLock) { 2445 mUdfpsRefreshRateEnabled.put(displayId, false); 2446 updateVoteLocked(displayId, false, Vote.PRIORITY_UDFPS); 2447 } 2448 } 2449 2450 @Override onAuthenticationPossible(int displayId, boolean isPossible)2451 public void onAuthenticationPossible(int displayId, boolean isPossible) { 2452 synchronized (mLock) { 2453 mAuthenticationPossible.put(displayId, isPossible); 2454 updateVoteLocked(displayId, isPossible, 2455 Vote.PRIORITY_AUTH_OPTIMIZER_RENDER_FRAME_RATE); 2456 } 2457 } 2458 2459 @GuardedBy("mLock") updateVoteLocked(int displayId, boolean enabled, int votePriority)2460 private void updateVoteLocked(int displayId, boolean enabled, int votePriority) { 2461 final Vote vote; 2462 if (enabled) { 2463 float maxRefreshRate = DisplayModeDirector.this.getMaxRefreshRateLocked(displayId); 2464 vote = Vote.forPhysicalRefreshRates(maxRefreshRate, maxRefreshRate); 2465 } else { 2466 vote = null; 2467 } 2468 mVotesStorage.updateVote(displayId, votePriority, vote); 2469 } 2470 dumpLocked(PrintWriter pw)2471 void dumpLocked(PrintWriter pw) { 2472 pw.println(" UdfpsObserver"); 2473 pw.println(" mUdfpsRefreshRateEnabled: "); 2474 for (int i = 0; i < mUdfpsRefreshRateEnabled.size(); i++) { 2475 final int displayId = mUdfpsRefreshRateEnabled.keyAt(i); 2476 final String enabled = mUdfpsRefreshRateEnabled.valueAt(i) ? "enabled" : "disabled"; 2477 pw.println(" Display " + displayId + ": " + enabled); 2478 } 2479 pw.println(" mAuthenticationPossible: "); 2480 for (int i = 0; i < mAuthenticationPossible.size(); i++) { 2481 final int displayId = mAuthenticationPossible.keyAt(i); 2482 final String isPossible = mAuthenticationPossible.valueAt(i) ? "possible" 2483 : "impossible"; 2484 pw.println(" Display " + displayId + ": " + isPossible); 2485 } 2486 } 2487 } 2488 2489 protected static final class SensorObserver implements ProximityActiveListener, 2490 DisplayManager.DisplayListener { 2491 private final String mProximitySensorName = null; 2492 private final String mProximitySensorType = Sensor.STRING_TYPE_PROXIMITY; 2493 2494 private final VotesStorage mVotesStorage; 2495 private final Context mContext; 2496 private final Injector mInjector; 2497 @GuardedBy("mSensorObserverLock") 2498 private final SparseBooleanArray mDozeStateByDisplay = new SparseBooleanArray(); 2499 private final Object mSensorObserverLock = new Object(); 2500 2501 private DisplayManager mDisplayManager; 2502 private DisplayManagerInternal mDisplayManagerInternal; 2503 @GuardedBy("mSensorObserverLock") 2504 private boolean mIsProxActive = false; 2505 SensorObserver(Context context, VotesStorage votesStorage, Injector injector)2506 SensorObserver(Context context, VotesStorage votesStorage, Injector injector) { 2507 mContext = context; 2508 mVotesStorage = votesStorage; 2509 mInjector = injector; 2510 } 2511 2512 @Override onProximityActive(boolean isActive)2513 public void onProximityActive(boolean isActive) { 2514 synchronized (mSensorObserverLock) { 2515 if (mIsProxActive != isActive) { 2516 mIsProxActive = isActive; 2517 recalculateVotesLocked(); 2518 } 2519 } 2520 } 2521 observe()2522 public void observe() { 2523 mDisplayManager = mContext.getSystemService(DisplayManager.class); 2524 mDisplayManagerInternal = LocalServices.getService(DisplayManagerInternal.class); 2525 2526 final SensorManagerInternal sensorManager = 2527 LocalServices.getService(SensorManagerInternal.class); 2528 sensorManager.addProximityActiveListener(BackgroundThread.getExecutor(), this); 2529 2530 synchronized (mSensorObserverLock) { 2531 for (Display d : mInjector.getDisplays()) { 2532 mDozeStateByDisplay.put(d.getDisplayId(), mInjector.isDozeState(d)); 2533 } 2534 } 2535 mInjector.registerDisplayListener(this, BackgroundThread.getHandler(), 2536 DisplayManager.EVENT_FLAG_DISPLAY_ADDED 2537 | DisplayManager.EVENT_FLAG_DISPLAY_CHANGED 2538 | DisplayManager.EVENT_FLAG_DISPLAY_REMOVED); 2539 } 2540 recalculateVotesLocked()2541 private void recalculateVotesLocked() { 2542 final Display[] displays = mInjector.getDisplays(); 2543 for (Display d : displays) { 2544 int displayId = d.getDisplayId(); 2545 Vote vote = null; 2546 if (mIsProxActive && !mDozeStateByDisplay.get(displayId)) { 2547 final RefreshRateRange rate = 2548 mDisplayManagerInternal.getRefreshRateForDisplayAndSensor( 2549 displayId, mProximitySensorName, mProximitySensorType); 2550 if (rate != null) { 2551 vote = Vote.forPhysicalRefreshRates(rate.min, rate.max); 2552 } 2553 } 2554 mVotesStorage.updateVote(displayId, Vote.PRIORITY_PROXIMITY, vote); 2555 } 2556 } 2557 dump(PrintWriter pw)2558 void dump(PrintWriter pw) { 2559 pw.println(" SensorObserver"); 2560 synchronized (mSensorObserverLock) { 2561 pw.println(" mIsProxActive=" + mIsProxActive); 2562 pw.println(" mDozeStateByDisplay:"); 2563 for (int i = 0; i < mDozeStateByDisplay.size(); i++) { 2564 final int id = mDozeStateByDisplay.keyAt(i); 2565 final boolean dozed = mDozeStateByDisplay.valueAt(i); 2566 pw.println(" " + id + " -> " + dozed); 2567 } 2568 } 2569 } 2570 2571 @Override onDisplayAdded(int displayId)2572 public void onDisplayAdded(int displayId) { 2573 boolean isDozeState = mInjector.isDozeState(mInjector.getDisplay(displayId)); 2574 synchronized (mSensorObserverLock) { 2575 mDozeStateByDisplay.put(displayId, isDozeState); 2576 recalculateVotesLocked(); 2577 } 2578 } 2579 2580 @Override onDisplayChanged(int displayId)2581 public void onDisplayChanged(int displayId) { 2582 boolean wasDozeState = mDozeStateByDisplay.get(displayId); 2583 synchronized (mSensorObserverLock) { 2584 mDozeStateByDisplay.put(displayId, 2585 mInjector.isDozeState(mInjector.getDisplay(displayId))); 2586 if (wasDozeState != mDozeStateByDisplay.get(displayId)) { 2587 recalculateVotesLocked(); 2588 } 2589 } 2590 } 2591 2592 @Override onDisplayRemoved(int displayId)2593 public void onDisplayRemoved(int displayId) { 2594 synchronized (mSensorObserverLock) { 2595 mDozeStateByDisplay.delete(displayId); 2596 recalculateVotesLocked(); 2597 } 2598 } 2599 } 2600 2601 /** 2602 * Listens to DisplayManager for HBM status and applies any refresh-rate restrictions for 2603 * HBM that are associated with that display. Restrictions are retrieved from 2604 * DisplayManagerInternal but originate in the display-device-config file. 2605 */ 2606 public class HbmObserver implements DisplayManager.DisplayListener { 2607 private final VotesStorage mVotesStorage; 2608 private final Handler mHandler; 2609 private final SparseIntArray mHbmMode = new SparseIntArray(); 2610 private final SparseBooleanArray mHbmActive = new SparseBooleanArray(); 2611 private final Injector mInjector; 2612 private final DeviceConfigDisplaySettings mDeviceConfigDisplaySettings; 2613 private int mRefreshRateInHbmSunlight; 2614 private int mRefreshRateInHbmHdr; 2615 2616 private DisplayManagerInternal mDisplayManagerInternal; 2617 HbmObserver(Injector injector, VotesStorage votesStorage, Handler handler, DeviceConfigDisplaySettings displaySettings)2618 HbmObserver(Injector injector, VotesStorage votesStorage, Handler handler, 2619 DeviceConfigDisplaySettings displaySettings) { 2620 mInjector = injector; 2621 mVotesStorage = votesStorage; 2622 mHandler = handler; 2623 mDeviceConfigDisplaySettings = displaySettings; 2624 } 2625 2626 /** 2627 * Sets up the refresh rate to be used when HDR is enabled 2628 */ setupHdrRefreshRates(DisplayDeviceConfig displayDeviceConfig)2629 public void setupHdrRefreshRates(DisplayDeviceConfig displayDeviceConfig) { 2630 mRefreshRateInHbmHdr = mDeviceConfigDisplaySettings 2631 .getRefreshRateInHbmHdr(displayDeviceConfig); 2632 mRefreshRateInHbmSunlight = mDeviceConfigDisplaySettings 2633 .getRefreshRateInHbmSunlight(displayDeviceConfig); 2634 } 2635 2636 /** 2637 * Sets up the HDR refresh rates, and starts observing for the changes in the display that 2638 * might impact it 2639 */ observe()2640 public void observe() { 2641 synchronized (mLock) { 2642 setupHdrRefreshRates(mDefaultDisplayDeviceConfig); 2643 } 2644 mDisplayManagerInternal = LocalServices.getService(DisplayManagerInternal.class); 2645 mInjector.registerDisplayListener(this, mHandler, 2646 DisplayManager.EVENT_FLAG_DISPLAY_BRIGHTNESS 2647 | DisplayManager.EVENT_FLAG_DISPLAY_REMOVED); 2648 } 2649 2650 /** 2651 * @return the refresh to lock to when the device is in high brightness mode for Sunlight. 2652 */ 2653 @VisibleForTesting getRefreshRateInHbmSunlight()2654 int getRefreshRateInHbmSunlight() { 2655 return mRefreshRateInHbmSunlight; 2656 } 2657 2658 /** 2659 * @return the refresh to lock to when the device is in high brightness mode for HDR. 2660 */ 2661 @VisibleForTesting getRefreshRateInHbmHdr()2662 int getRefreshRateInHbmHdr() { 2663 return mRefreshRateInHbmHdr; 2664 } 2665 2666 /** 2667 * Recalculates the HBM vote when the device config has been changed. 2668 */ onDeviceConfigRefreshRateInHbmSunlightChanged(int refreshRate)2669 public void onDeviceConfigRefreshRateInHbmSunlightChanged(int refreshRate) { 2670 if (refreshRate != mRefreshRateInHbmSunlight) { 2671 mRefreshRateInHbmSunlight = refreshRate; 2672 onDeviceConfigRefreshRateInHbmChanged(); 2673 } 2674 } 2675 2676 /** 2677 * Recalculates the HBM vote when the device config has been changed. 2678 */ onDeviceConfigRefreshRateInHbmHdrChanged(int refreshRate)2679 public void onDeviceConfigRefreshRateInHbmHdrChanged(int refreshRate) { 2680 if (refreshRate != mRefreshRateInHbmHdr) { 2681 mRefreshRateInHbmHdr = refreshRate; 2682 onDeviceConfigRefreshRateInHbmChanged(); 2683 } 2684 } 2685 2686 @Override onDisplayAdded(int displayId)2687 public void onDisplayAdded(int displayId) {} 2688 2689 @Override onDisplayRemoved(int displayId)2690 public void onDisplayRemoved(int displayId) { 2691 mVotesStorage.updateVote(displayId, Vote.PRIORITY_HIGH_BRIGHTNESS_MODE, null); 2692 mHbmMode.delete(displayId); 2693 mHbmActive.delete(displayId); 2694 } 2695 2696 @Override onDisplayChanged(int displayId)2697 public void onDisplayChanged(int displayId) { 2698 final BrightnessInfo info = mInjector.getBrightnessInfo(displayId); 2699 if (info == null) { 2700 // Display no longer there. Assume we'll get an onDisplayRemoved very soon. 2701 return; 2702 } 2703 2704 final int hbmMode = info.highBrightnessMode; 2705 final boolean isHbmActive = hbmMode != BrightnessInfo.HIGH_BRIGHTNESS_MODE_OFF 2706 && info.adjustedBrightness > info.highBrightnessTransitionPoint; 2707 if (hbmMode == mHbmMode.get(displayId) 2708 && isHbmActive == mHbmActive.get(displayId)) { 2709 // no change, ignore. 2710 return; 2711 } 2712 mHbmMode.put(displayId, hbmMode); 2713 mHbmActive.put(displayId, isHbmActive); 2714 recalculateVotesForDisplay(displayId); 2715 } 2716 onDeviceConfigRefreshRateInHbmChanged()2717 private void onDeviceConfigRefreshRateInHbmChanged() { 2718 final int[] displayIds = mHbmMode.copyKeys(); 2719 if (displayIds != null) { 2720 for (int id : displayIds) { 2721 recalculateVotesForDisplay(id); 2722 } 2723 } 2724 } 2725 recalculateVotesForDisplay(int displayId)2726 private void recalculateVotesForDisplay(int displayId) { 2727 Vote vote = null; 2728 if (mHbmActive.get(displayId, false)) { 2729 final int hbmMode = 2730 mHbmMode.get(displayId, BrightnessInfo.HIGH_BRIGHTNESS_MODE_OFF); 2731 if (hbmMode == BrightnessInfo.HIGH_BRIGHTNESS_MODE_SUNLIGHT) { 2732 // Device resource properties take priority over DisplayDeviceConfig 2733 if (mRefreshRateInHbmSunlight > 0) { 2734 vote = Vote.forPhysicalRefreshRates(mRefreshRateInHbmSunlight, 2735 mRefreshRateInHbmSunlight); 2736 } else { 2737 final List<RefreshRateLimitation> limits = 2738 mDisplayManagerInternal.getRefreshRateLimitations(displayId); 2739 for (int i = 0; limits != null && i < limits.size(); i++) { 2740 final RefreshRateLimitation limitation = limits.get(i); 2741 if (limitation.type == REFRESH_RATE_LIMIT_HIGH_BRIGHTNESS_MODE) { 2742 vote = Vote.forPhysicalRefreshRates(limitation.range.min, 2743 limitation.range.max); 2744 break; 2745 } 2746 } 2747 } 2748 } else if (hbmMode == BrightnessInfo.HIGH_BRIGHTNESS_MODE_HDR 2749 && mRefreshRateInHbmHdr > 0) { 2750 // HBM for HDR vote isn't supported through DisplayDeviceConfig yet, so look for 2751 // a vote from Device properties 2752 vote = Vote.forPhysicalRefreshRates(mRefreshRateInHbmHdr, mRefreshRateInHbmHdr); 2753 } else { 2754 Slog.w(TAG, "Unexpected HBM mode " + hbmMode + " for display ID " + displayId); 2755 } 2756 2757 } 2758 mVotesStorage.updateVote(displayId, Vote.PRIORITY_HIGH_BRIGHTNESS_MODE, vote); 2759 } 2760 dumpLocked(PrintWriter pw)2761 void dumpLocked(PrintWriter pw) { 2762 pw.println(" HbmObserver"); 2763 pw.println(" mHbmMode: " + mHbmMode); 2764 pw.println(" mHbmActive: " + mHbmActive); 2765 pw.println(" mRefreshRateInHbmSunlight: " + mRefreshRateInHbmSunlight); 2766 pw.println(" mRefreshRateInHbmHdr: " + mRefreshRateInHbmHdr); 2767 } 2768 } 2769 2770 private class DeviceConfigDisplaySettings implements DeviceConfig.OnPropertiesChangedListener { startListening()2771 public void startListening() { 2772 mConfigParameterProvider.addOnPropertiesChangedListener( 2773 BackgroundThread.getExecutor(), this); 2774 } 2775 getRefreshRateInHbmHdr(DisplayDeviceConfig displayDeviceConfig)2776 private int getRefreshRateInHbmHdr(DisplayDeviceConfig displayDeviceConfig) { 2777 return getRefreshRate( 2778 () -> mConfigParameterProvider.getRefreshRateInHbmHdr(), 2779 () -> displayDeviceConfig.getDefaultRefreshRateInHbmHdr(), 2780 R.integer.config_defaultRefreshRateInHbmHdr, 2781 displayDeviceConfig 2782 ); 2783 } 2784 getRefreshRateInHbmSunlight(DisplayDeviceConfig displayDeviceConfig)2785 private int getRefreshRateInHbmSunlight(DisplayDeviceConfig displayDeviceConfig) { 2786 return getRefreshRate( 2787 () -> mConfigParameterProvider.getRefreshRateInHbmSunlight(), 2788 () -> displayDeviceConfig.getDefaultRefreshRateInHbmSunlight(), 2789 R.integer.config_defaultRefreshRateInHbmSunlight, 2790 displayDeviceConfig 2791 ); 2792 } 2793 getRefreshRate(IntSupplier fromConfigPram, IntSupplier fromDisplayDeviceConfig, @IntegerRes int configKey, DisplayDeviceConfig displayDeviceConfig)2794 private int getRefreshRate(IntSupplier fromConfigPram, IntSupplier fromDisplayDeviceConfig, 2795 @IntegerRes int configKey, DisplayDeviceConfig displayDeviceConfig) { 2796 int refreshRate = -1; 2797 try { 2798 refreshRate = fromConfigPram.getAsInt(); 2799 } catch (NullPointerException npe) { 2800 // Do Nothing 2801 } 2802 if (refreshRate == -1) { 2803 refreshRate = (displayDeviceConfig == null) 2804 ? mContext.getResources().getInteger(configKey) 2805 : fromDisplayDeviceConfig.getAsInt(); 2806 } 2807 return refreshRate; 2808 } 2809 2810 @Override onPropertiesChanged(@onNull DeviceConfig.Properties properties)2811 public void onPropertiesChanged(@NonNull DeviceConfig.Properties properties) { 2812 float defaultPeakRefreshRate = mConfigParameterProvider.getPeakRefreshRateDefault(); 2813 mHandler.obtainMessage(MSG_DEFAULT_PEAK_REFRESH_RATE_CHANGED, 2814 defaultPeakRefreshRate == -1 ? null : defaultPeakRefreshRate).sendToTarget(); 2815 2816 float[] lowDisplayBrightnessThresholds = 2817 mConfigParameterProvider.getLowDisplayBrightnessThresholds(); 2818 float[] lowAmbientBrightnessThresholds = 2819 mConfigParameterProvider.getLowAmbientBrightnessThresholds(); 2820 final int refreshRateInLowZone = mConfigParameterProvider.getRefreshRateInLowZone(); 2821 2822 mHandler.obtainMessage(MSG_LOW_BRIGHTNESS_THRESHOLDS_CHANGED, 2823 new Pair<>(lowDisplayBrightnessThresholds, lowAmbientBrightnessThresholds)) 2824 .sendToTarget(); 2825 2826 mHandler.obtainMessage(MSG_REFRESH_RATE_IN_LOW_ZONE_CHANGED, refreshRateInLowZone, 2827 0).sendToTarget(); 2828 2829 float[] highDisplayBrightnessThresholds = 2830 mConfigParameterProvider.getHighDisplayBrightnessThresholds(); 2831 float[] highAmbientBrightnessThresholds = 2832 mConfigParameterProvider.getHighAmbientBrightnessThresholds(); 2833 final int refreshRateInHighZone = mConfigParameterProvider.getRefreshRateInHighZone(); 2834 2835 mHandler.obtainMessage(MSG_HIGH_BRIGHTNESS_THRESHOLDS_CHANGED, 2836 new Pair<>(highDisplayBrightnessThresholds, highAmbientBrightnessThresholds)) 2837 .sendToTarget(); 2838 2839 mHandler.obtainMessage(MSG_REFRESH_RATE_IN_HIGH_ZONE_CHANGED, refreshRateInHighZone, 2840 0).sendToTarget(); 2841 2842 synchronized (mLock) { 2843 final int refreshRateInHbmSunlight = 2844 getRefreshRateInHbmSunlight(mDefaultDisplayDeviceConfig); 2845 mHandler.obtainMessage(MSG_REFRESH_RATE_IN_HBM_SUNLIGHT_CHANGED, 2846 refreshRateInHbmSunlight, 0) 2847 .sendToTarget(); 2848 2849 final int refreshRateInHbmHdr = 2850 getRefreshRateInHbmHdr(mDefaultDisplayDeviceConfig); 2851 mHandler.obtainMessage(MSG_REFRESH_RATE_IN_HBM_HDR_CHANGED, refreshRateInHbmHdr, 0) 2852 .sendToTarget(); 2853 } 2854 } 2855 } 2856 2857 interface Injector { 2858 Uri PEAK_REFRESH_RATE_URI = Settings.System.getUriFor(Settings.System.PEAK_REFRESH_RATE); 2859 2860 @NonNull getDeviceConfig()2861 DeviceConfigInterface getDeviceConfig(); 2862 registerPeakRefreshRateObserver(@onNull ContentResolver cr, @NonNull ContentObserver observer)2863 void registerPeakRefreshRateObserver(@NonNull ContentResolver cr, 2864 @NonNull ContentObserver observer); 2865 registerDisplayListener(@onNull DisplayManager.DisplayListener listener, Handler handler)2866 void registerDisplayListener(@NonNull DisplayManager.DisplayListener listener, 2867 Handler handler); 2868 registerDisplayListener(@onNull DisplayManager.DisplayListener listener, Handler handler, long flags)2869 void registerDisplayListener(@NonNull DisplayManager.DisplayListener listener, 2870 Handler handler, long flags); 2871 getDisplay(int displayId)2872 Display getDisplay(int displayId); 2873 getDisplays()2874 Display[] getDisplays(); 2875 getDisplayInfo(int displayId, DisplayInfo displayInfo)2876 boolean getDisplayInfo(int displayId, DisplayInfo displayInfo); 2877 getBrightnessInfo(int displayId)2878 BrightnessInfo getBrightnessInfo(int displayId); 2879 isDozeState(Display d)2880 boolean isDozeState(Display d); 2881 registerThermalServiceListener(IThermalEventListener listener)2882 boolean registerThermalServiceListener(IThermalEventListener listener); unregisterThermalServiceListener(IThermalEventListener listener)2883 void unregisterThermalServiceListener(IThermalEventListener listener); 2884 supportsFrameRateOverride()2885 boolean supportsFrameRateOverride(); 2886 } 2887 2888 @VisibleForTesting 2889 static class RealInjector implements Injector { 2890 private final Context mContext; 2891 private DisplayManager mDisplayManager; 2892 RealInjector(Context context)2893 RealInjector(Context context) { 2894 mContext = context; 2895 } 2896 2897 @Override 2898 @NonNull getDeviceConfig()2899 public DeviceConfigInterface getDeviceConfig() { 2900 return DeviceConfigInterface.REAL; 2901 } 2902 2903 @Override registerPeakRefreshRateObserver(@onNull ContentResolver cr, @NonNull ContentObserver observer)2904 public void registerPeakRefreshRateObserver(@NonNull ContentResolver cr, 2905 @NonNull ContentObserver observer) { 2906 cr.registerContentObserver(PEAK_REFRESH_RATE_URI, false /*notifyDescendants*/, 2907 observer, UserHandle.USER_SYSTEM); 2908 } 2909 2910 @Override registerDisplayListener(DisplayManager.DisplayListener listener, Handler handler)2911 public void registerDisplayListener(DisplayManager.DisplayListener listener, 2912 Handler handler) { 2913 getDisplayManager().registerDisplayListener(listener, handler); 2914 } 2915 2916 @Override registerDisplayListener(DisplayManager.DisplayListener listener, Handler handler, long flags)2917 public void registerDisplayListener(DisplayManager.DisplayListener listener, 2918 Handler handler, long flags) { 2919 getDisplayManager().registerDisplayListener(listener, handler, flags); 2920 } 2921 2922 @Override getDisplay(int displayId)2923 public Display getDisplay(int displayId) { 2924 return getDisplayManager().getDisplay(displayId); 2925 } 2926 2927 @Override getDisplays()2928 public Display[] getDisplays() { 2929 return getDisplayManager().getDisplays(DISPLAY_CATEGORY_ALL_INCLUDING_DISABLED); 2930 } 2931 2932 @Override getDisplayInfo(int displayId, DisplayInfo displayInfo)2933 public boolean getDisplayInfo(int displayId, DisplayInfo displayInfo) { 2934 Display display = getDisplayManager().getDisplay(displayId); 2935 if (display == null) { 2936 // We can occasionally get a display added or changed event for a display that was 2937 // subsequently removed, which means this returns null. Check this case and bail 2938 // out early; if it gets re-attached we'll eventually get another call back for it. 2939 return false; 2940 } 2941 return display.getDisplayInfo(displayInfo); 2942 } 2943 2944 @Override getBrightnessInfo(int displayId)2945 public BrightnessInfo getBrightnessInfo(int displayId) { 2946 final Display display = getDisplayManager().getDisplay(displayId); 2947 if (display != null) { 2948 return display.getBrightnessInfo(); 2949 } 2950 return null; 2951 } 2952 2953 @Override isDozeState(Display d)2954 public boolean isDozeState(Display d) { 2955 if (d == null) { 2956 return false; 2957 } 2958 return Display.isDozeState(d.getState()); 2959 } 2960 2961 @Override registerThermalServiceListener(IThermalEventListener listener)2962 public boolean registerThermalServiceListener(IThermalEventListener listener) { 2963 IThermalService thermalService = getThermalService(); 2964 if (thermalService == null) { 2965 Slog.w(TAG, "Could not observe thermal status. Service not available"); 2966 return false; 2967 } 2968 try { 2969 thermalService.registerThermalEventListenerWithType(listener, 2970 Temperature.TYPE_SKIN); 2971 } catch (RemoteException e) { 2972 Slog.e(TAG, "Failed to register thermal status listener", e); 2973 return false; 2974 } 2975 return true; 2976 } 2977 2978 @Override unregisterThermalServiceListener(IThermalEventListener listener)2979 public void unregisterThermalServiceListener(IThermalEventListener listener) { 2980 IThermalService thermalService = getThermalService(); 2981 if (thermalService == null) { 2982 Slog.w(TAG, "Could not unregister thermal status. Service not available"); 2983 } 2984 try { 2985 thermalService.unregisterThermalEventListener(listener); 2986 } catch (RemoteException e) { 2987 Slog.e(TAG, "Failed to unregister thermal status listener", e); 2988 } 2989 } 2990 2991 @Override supportsFrameRateOverride()2992 public boolean supportsFrameRateOverride() { 2993 return SurfaceFlingerProperties.enable_frame_rate_override().orElse(true); 2994 } 2995 getDisplayManager()2996 private DisplayManager getDisplayManager() { 2997 if (mDisplayManager == null) { 2998 mDisplayManager = mContext.getSystemService(DisplayManager.class); 2999 } 3000 return mDisplayManager; 3001 } 3002 getThermalService()3003 private IThermalService getThermalService() { 3004 return IThermalService.Stub.asInterface( 3005 ServiceManager.getService(Context.THERMAL_SERVICE)); 3006 } 3007 } 3008 } 3009