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