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