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