1 /* 2 * Copyright (C) 2016 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.car.systeminterface; 18 19 import static android.car.user.CarUserManager.USER_LIFECYCLE_EVENT_TYPE_SWITCHING; 20 import static android.view.Display.DEFAULT_DISPLAY; 21 22 import static com.android.car.CarServiceUtils.getContentResolverForUser; 23 import static com.android.car.CarServiceUtils.isEventOfType; 24 import static com.android.car.util.BrightnessUtils.GAMMA_SPACE_MAX; 25 import static com.android.car.util.BrightnessUtils.convertGammaToLinear; 26 import static com.android.car.util.BrightnessUtils.convertLinearToGamma; 27 28 import android.car.builtin.display.DisplayManagerHelper; 29 import android.car.builtin.os.UserManagerHelper; 30 import android.car.builtin.power.PowerManagerHelper; 31 import android.car.builtin.util.Slogf; 32 import android.car.builtin.view.DisplayHelper; 33 import android.car.feature.Flags; 34 import android.car.user.CarUserManager.UserLifecycleListener; 35 import android.car.user.UserLifecycleEventFilter; 36 import android.content.Context; 37 import android.database.ContentObserver; 38 import android.hardware.display.DisplayManager; 39 import android.hardware.display.DisplayManager.DisplayListener; 40 import android.os.Handler; 41 import android.os.Looper; 42 import android.os.SystemClock; 43 import android.os.UserHandle; 44 import android.os.UserManager; 45 import android.provider.Settings.SettingNotFoundException; 46 import android.provider.Settings.System; 47 import android.util.Log; 48 import android.util.SparseBooleanArray; 49 import android.view.Display; 50 51 import com.android.car.CarLog; 52 import com.android.car.internal.util.IntArray; 53 import com.android.car.power.CarPowerManagementService; 54 import com.android.car.provider.Settings; 55 import com.android.car.user.CarUserService; 56 import com.android.car.user.CurrentUserFetcher; 57 import com.android.car.util.BrightnessUtils; 58 import com.android.internal.annotations.GuardedBy; 59 60 import java.util.LinkedList; 61 62 /** 63 * Interface that abstracts display operations 64 */ 65 public interface DisplayInterface { 66 67 /** 68 * Sets the required services. 69 * 70 * @param carPowerManagementService {@link CarPowerManagementService} to listen to car power 71 * management changes 72 * @param carUserService {@link CarUserService} to listen to service life cycle 73 * changes 74 */ init(CarPowerManagementService carPowerManagementService, CarUserService carUserService)75 void init(CarPowerManagementService carPowerManagementService, CarUserService carUserService); 76 77 /** 78 * Sets display brightness with the given displayId according to brightness change from VHAL. 79 * 80 * This is used to sync the system settings with VHAL. 81 * 82 * @param displayId ID of a display. 83 * @param brightness Level from 0 to 100. 84 */ onDisplayBrightnessChangeFromVhal(int displayId, int brightness)85 void onDisplayBrightnessChangeFromVhal(int displayId, int brightness); 86 87 /** 88 * Turns on or off display with the given displayId. 89 * 90 * @param displayId ID of a display. 91 * @param on {@code true} to turn on, {@code false} to turn off. 92 */ setDisplayState(int displayId, boolean on)93 void setDisplayState(int displayId, boolean on); 94 95 /** 96 * Turns on or off all displays. 97 * 98 * @param on {@code true} to turn on, {@code false} to turn off. 99 */ setAllDisplayState(boolean on)100 void setAllDisplayState(boolean on); 101 102 /** 103 * Starts monitoring the display state change. 104 * <p> When there is a change, {@link CarPowerManagementService} is notified. 105 */ startDisplayStateMonitoring()106 void startDisplayStateMonitoring(); 107 108 /** 109 * Stops monitoring the display state change. 110 */ stopDisplayStateMonitoring()111 void stopDisplayStateMonitoring(); 112 113 /** 114 * Gets the current on/off state of displays. 115 * 116 * @return {@code true}, if any display is turned on. Otherwise, {@code false}. 117 */ isAnyDisplayEnabled()118 boolean isAnyDisplayEnabled(); 119 120 /** 121 * Gets the current on/off state of display with the given displayId. 122 * 123 * @param displayId ID of a display. 124 */ isDisplayEnabled(int displayId)125 boolean isDisplayEnabled(int displayId); 126 127 /** 128 * Refreshing default display brightness. Used when user is switching and car turned on. 129 */ refreshDefaultDisplayBrightness()130 void refreshDefaultDisplayBrightness(); 131 132 /** 133 * Refreshing display brightness with the given displayId. 134 * Used when brightness change is observed. 135 * 136 * @param displayId ID of a display. 137 */ refreshDisplayBrightness(int displayId)138 void refreshDisplayBrightness(int displayId); 139 140 /** 141 * Default implementation of display operations 142 */ 143 class DefaultImpl implements DisplayInterface { 144 private static final String TAG = DisplayInterface.class.getSimpleName(); 145 private static final boolean DEBUG = Slogf.isLoggable(TAG, Log.DEBUG); 146 147 // In order to prevent flickering caused by 148 // vhal_report_brightness_1 -> vhal_report_brightness_2 -> set_1_to_display_manager 149 // -> set_2_to_display_manager -> on_display_change_1 -> set_vhal_to_1 150 // -> on_display_change_2 -> set_vhal_to_2 -> vhal_report_brightness_1 -> ... 151 // We ignore the display brightness change event from DisplayManager if the value matches 152 // a request we have sent to Displaymanager in a short period. This change is likely caused 153 // by our request (caused by VHAL), rather than user inputs. 154 private static final int PREVENT_LOOP_REQUEST_TIME_WINDOW_MS = 1000; 155 BrightnessForDisplayId(float brightness, int displayId)156 private record BrightnessForDisplayId(float brightness, int displayId) {} 157 158 private final Context mContext; 159 private final DisplayManager mDisplayManager; 160 private final Object mLock = new Object(); 161 private final int mMaximumBacklight; 162 private final int mMinimumBacklight; 163 private final WakeLockInterface mWakeLockInterface; 164 private final Settings mSettings; 165 private final Handler mHandler = new Handler(Looper.getMainLooper()); 166 private final DisplayHelperInterface mDisplayHelper; 167 private final CurrentUserFetcher mCurrentUserFetcher; 168 @GuardedBy("mLock") 169 private CarPowerManagementService mCarPowerManagementService; 170 @GuardedBy("mLock") 171 private CarUserService mCarUserService; 172 @GuardedBy("mLock") 173 private final SparseBooleanArray mDisplayStateSet = new SparseBooleanArray(); 174 @GuardedBy("mLock") 175 private boolean mDisplayStateInitiated; 176 private final UserManager mUserManager; 177 // A FIFO queue that stores the brightness value we recently set to DisplayManagerHelper in 178 // a short time frame. 179 @GuardedBy("mLock") 180 private final LinkedList<BrightnessForDisplayId> mRecentlySetBrightnessForDisplayId = 181 new LinkedList<>(); 182 // A FIFO queue that stores the brightness value we recently set to System Settings in a 183 // short time frame. 184 @GuardedBy("mLock") 185 private final LinkedList<Integer> mRecentlySetGlobalBrightness = new LinkedList<>(); 186 private final UserLifecycleListener mUserLifecycleListener; 187 188 private final ContentObserver mBrightnessObserver = 189 new ContentObserver(mHandler) { 190 @Override 191 public void onChange(boolean selfChange) { 192 Slogf.i(TAG, "Brightness change from Settings: selfChange=%b", selfChange); 193 refreshDefaultDisplayBrightness(); 194 } 195 }; 196 197 private final DisplayManager.DisplayListener mDisplayListener = new DisplayListener() { 198 @Override 199 public void onDisplayAdded(int displayId) { 200 // If in rare case, this is called before initDisplayStateOnce is called, init here. 201 if (initDisplayStateOnce()) { 202 return; 203 } 204 205 Slogf.i(TAG, "onDisplayAdded: displayId=%d", displayId); 206 synchronized (mLock) { 207 boolean isDisplayOn = isDisplayOn(displayId); 208 mDisplayStateSet.put(displayId, isDisplayOn); 209 } 210 } 211 212 @Override 213 public void onDisplayRemoved(int displayId) { 214 // If in rare case, this is called before initDisplayStateOnce is called, init here. 215 if (initDisplayStateOnce()) { 216 return; 217 } 218 219 Slogf.i(TAG, "onDisplayRemoved: displayId=%d", displayId); 220 synchronized (mLock) { 221 mDisplayStateSet.delete(displayId); 222 } 223 } 224 225 @Override 226 public void onDisplayChanged(int displayId) { 227 // If in rare case, this is called before initDisplayStateOnce is called, init here. 228 if (initDisplayStateOnce()) { 229 return; 230 } 231 232 Slogf.i(TAG, "onDisplayChanged: displayId=%d", displayId); 233 handleDisplayChanged(displayId); 234 } 235 }; 236 DefaultImpl(Context context, WakeLockInterface wakeLockInterface, Settings settings, DisplayHelperInterface displayHelper, CurrentUserFetcher currentUserFetcher)237 public DefaultImpl(Context context, WakeLockInterface wakeLockInterface, Settings settings, 238 DisplayHelperInterface displayHelper, CurrentUserFetcher currentUserFetcher) { 239 mContext = context; 240 mDisplayManager = context.getSystemService(DisplayManager.class); 241 mMaximumBacklight = PowerManagerHelper.getMaximumScreenBrightnessSetting(context); 242 mMinimumBacklight = PowerManagerHelper.getMinimumScreenBrightnessSetting(context); 243 mWakeLockInterface = wakeLockInterface; 244 mSettings = settings; 245 mDisplayHelper = displayHelper; 246 mCurrentUserFetcher = currentUserFetcher; 247 mUserManager = context.getSystemService(UserManager.class); 248 mUserLifecycleListener = event -> { 249 if (!isEventOfType(TAG, event, USER_LIFECYCLE_EVENT_TYPE_SWITCHING)) { 250 return; 251 } 252 if (DEBUG) { 253 Slogf.d(TAG, "DisplayInterface.DefaultImpl.onEvent(%s)", event); 254 } 255 if (Flags.multiDisplayBrightnessControl()) { 256 if (event.getUserId() != mCurrentUserFetcher.getCurrentUser()) { 257 Slogf.w(TAG, "The switched user is not the driver user, " 258 + "ignore refreshing display brightness"); 259 return; 260 } 261 } 262 onDriverUserUpdate(); 263 }; 264 } 265 266 @Override refreshDefaultDisplayBrightness()267 public void refreshDefaultDisplayBrightness() { 268 refreshDisplayBrightness(DEFAULT_DISPLAY); 269 } 270 271 @Override refreshDisplayBrightness(int displayId)272 public void refreshDisplayBrightness(int displayId) { 273 CarPowerManagementService carPowerManagementService = null; 274 int mainDisplayIdForDriver; 275 synchronized (mLock) { 276 carPowerManagementService = mCarPowerManagementService; 277 } 278 if (carPowerManagementService == null) { 279 Slogf.e(CarLog.TAG_POWER, "Could not set brightness: " 280 + "no CarPowerManagementService"); 281 return; 282 } 283 if (Flags.multiDisplayBrightnessControl() 284 || UserManagerHelper.isVisibleBackgroundUsersSupported(mUserManager)) { 285 setDisplayBrightnessThroughVhal(carPowerManagementService, displayId); 286 } else { 287 setDisplayBrightnessThroughVhalLegacy(carPowerManagementService); 288 } 289 } 290 setDisplayBrightnessThroughVhal( CarPowerManagementService carPowerManagementService, int displayId)291 private void setDisplayBrightnessThroughVhal( 292 CarPowerManagementService carPowerManagementService, int displayId) { 293 float displayManagerBrightness = DisplayManagerHelper.getBrightness( 294 mContext, displayId); 295 if (hasRecentlySetBrightness(displayManagerBrightness, displayId)) { 296 return; 297 } 298 int linear = BrightnessUtils.brightnessFloatToInt(displayManagerBrightness); 299 int gamma = convertLinearToGamma(linear, mMinimumBacklight, mMaximumBacklight); 300 int percentBright = convertGammaToPercentBright(gamma); 301 302 Slogf.i(TAG, "Refreshing percent brightness(from display %d) to %d", displayId, 303 percentBright); 304 carPowerManagementService.sendDisplayBrightness(displayId, percentBright); 305 } 306 setDisplayBrightnessThroughVhalLegacy( CarPowerManagementService carPowerManagementService)307 private void setDisplayBrightnessThroughVhalLegacy( 308 CarPowerManagementService carPowerManagementService) { 309 int gamma = GAMMA_SPACE_MAX; 310 try { 311 int linear = mSettings.getIntSystem(getContentResolverForUser(mContext, 312 UserHandle.CURRENT.getIdentifier()), System.SCREEN_BRIGHTNESS); 313 if (hasRecentlySetBrightness(linear)) { 314 return; 315 } 316 gamma = convertLinearToGamma(linear, mMinimumBacklight, mMaximumBacklight); 317 } catch (SettingNotFoundException e) { 318 Slogf.e(CarLog.TAG_POWER, "Could not get SCREEN_BRIGHTNESS: ", e); 319 } 320 int percentBright = convertGammaToPercentBright(gamma); 321 322 Slogf.i(TAG, "Refreshing percent brightness(from Setting) to %d", percentBright); 323 carPowerManagementService.sendDisplayBrightnessLegacy(percentBright); 324 } 325 convertGammaToPercentBright(int gamma)326 private static int convertGammaToPercentBright(int gamma) { 327 return (gamma * 100 + ((GAMMA_SPACE_MAX + 1) / 2)) / GAMMA_SPACE_MAX; 328 } 329 handleDisplayChanged(int displayId)330 private void handleDisplayChanged(int displayId) { 331 refreshDisplayBrightness(displayId); 332 boolean isOn = isDisplayOn(displayId); 333 CarPowerManagementService service; 334 synchronized (mLock) { 335 boolean state = mDisplayStateSet.get(displayId, false); 336 if (state == isOn) { // same as what is set 337 return; 338 } 339 service = mCarPowerManagementService; 340 } 341 service.handleDisplayChanged(displayId, isOn); 342 } 343 isDisplayOn(int displayId)344 private boolean isDisplayOn(int displayId) { 345 Display disp = mDisplayManager.getDisplay(displayId); 346 if (disp == null) { 347 return false; 348 } 349 return disp.getState() == Display.STATE_ON; 350 } 351 352 @Override onDisplayBrightnessChangeFromVhal(int displayId, int percentBright)353 public void onDisplayBrightnessChangeFromVhal(int displayId, int percentBright) { 354 int gamma = (percentBright * GAMMA_SPACE_MAX + 50) / 100; 355 int linear = convertGammaToLinear(gamma, mMinimumBacklight, mMaximumBacklight); 356 if (Flags.multiDisplayBrightnessControl() 357 || UserManagerHelper.isVisibleBackgroundUsersSupported(mUserManager)) { 358 Slogf.i(TAG, "set brightness: %d", percentBright); 359 float displayManagerBrightness = BrightnessUtils.brightnessIntToFloat(linear); 360 addRecentlySetBrightness(displayManagerBrightness, displayId); 361 DisplayManagerHelper.setBrightness(mContext, displayId, displayManagerBrightness); 362 } else { 363 addRecentlySetBrightness(linear); 364 mSettings.putIntSystem( 365 getContentResolverForUser(mContext, UserHandle.CURRENT.getIdentifier()), 366 System.SCREEN_BRIGHTNESS, 367 linear); 368 } 369 } 370 371 @Override init(CarPowerManagementService carPowerManagementService, CarUserService carUserService)372 public void init(CarPowerManagementService carPowerManagementService, 373 CarUserService carUserService) { 374 synchronized (mLock) { 375 mCarPowerManagementService = carPowerManagementService; 376 mCarUserService = carUserService; 377 } 378 } 379 380 @Override startDisplayStateMonitoring()381 public void startDisplayStateMonitoring() { 382 Slogf.i(TAG, "Starting to monitor display state change"); 383 CarPowerManagementService carPowerManagementService; 384 CarUserService carUserService; 385 synchronized (mLock) { 386 carPowerManagementService = mCarPowerManagementService; 387 carUserService = mCarUserService; 388 } 389 UserLifecycleEventFilter userSwitchingEventFilter = 390 new UserLifecycleEventFilter.Builder() 391 .addEventType(USER_LIFECYCLE_EVENT_TYPE_SWITCHING).build(); 392 carUserService.addUserLifecycleListener(userSwitchingEventFilter, 393 mUserLifecycleListener); 394 if (Flags.multiDisplayBrightnessControl() 395 || UserManagerHelper.isVisibleBackgroundUsersSupported(mUserManager)) { 396 DisplayManagerHelper.registerDisplayListener(mContext, mDisplayListener, 397 carPowerManagementService.getHandler(), 398 DisplayManagerHelper.EVENT_TYPE_DISPLAY_ADDED 399 | DisplayManagerHelper.EVENT_TYPE_DISPLAY_REMOVED 400 | DisplayManagerHelper.EVENT_TYPE_DISPLAY_CHANGED, 401 DisplayManagerHelper.EVENT_TYPE_DISPLAY_BRIGHTNESS); 402 } else { 403 getContentResolverForUser(mContext, UserHandle.ALL.getIdentifier()) 404 .registerContentObserver(mSettings.getUriForSystem( 405 System.SCREEN_BRIGHTNESS), false, mBrightnessObserver); 406 } 407 408 initDisplayStateOnce(); 409 refreshAllDisplaysBrightness(); 410 } 411 412 @Override stopDisplayStateMonitoring()413 public void stopDisplayStateMonitoring() { 414 CarUserService carUserService; 415 synchronized (mLock) { 416 carUserService = mCarUserService; 417 } 418 carUserService.removeUserLifecycleListener(mUserLifecycleListener); 419 if (Flags.multiDisplayBrightnessControl() 420 || UserManagerHelper.isVisibleBackgroundUsersSupported(mUserManager)) { 421 mDisplayManager.unregisterDisplayListener(mDisplayListener); 422 } else { 423 getContentResolverForUser(mContext, UserHandle.ALL.getIdentifier()) 424 .unregisterContentObserver(mBrightnessObserver); 425 } 426 } 427 428 @Override setDisplayState(int displayId, boolean on)429 public void setDisplayState(int displayId, boolean on) { 430 CarPowerManagementService carPowerManagementService; 431 synchronized (mLock) { 432 carPowerManagementService = mCarPowerManagementService; 433 if (on && carPowerManagementService != null 434 && !carPowerManagementService.canTurnOnDisplay(displayId)) { 435 Slogf.i(CarLog.TAG_POWER, "ignore turning on display %d because " 436 + "CarPowerManagementService doesn't support it", displayId); 437 return; 438 } 439 mDisplayStateSet.put(displayId, on); 440 } 441 if (on) { 442 mWakeLockInterface.switchToFullWakeLock(displayId); 443 Slogf.i(CarLog.TAG_POWER, "on display %d, obtain full wake lock", displayId); 444 } else { 445 mWakeLockInterface.switchToPartialWakeLock(displayId); 446 Slogf.i(CarLog.TAG_POWER, "off display %d, obtain partial wake lock", displayId); 447 try { 448 PowerManagerHelper.goToSleep(mContext, displayId, SystemClock.uptimeMillis()); 449 } catch (IllegalArgumentException e) { 450 Slogf.e(CarLog.TAG_POWER, e, "Can not off display %d", displayId); 451 } 452 } 453 if (carPowerManagementService != null) { 454 carPowerManagementService.handleDisplayChanged(displayId, on); 455 } 456 } 457 458 @Override setAllDisplayState(boolean on)459 public void setAllDisplayState(boolean on) { 460 IntArray displayIds; 461 synchronized (mLock) { 462 displayIds = getDisplayIdsLocked(); 463 } 464 // setDisplayState has a binder call to system_server. Should not wrap setDisplayState 465 // with a lock. 466 for (int i = 0; i < displayIds.size(); i++) { 467 int displayId = displayIds.get(i); 468 try { 469 setDisplayState(displayId, on); 470 } catch (IllegalArgumentException e) { 471 Slogf.w(TAG, "Cannot set display(%d) state(%b)", displayId, on); 472 } 473 } 474 } 475 476 @Override isAnyDisplayEnabled()477 public boolean isAnyDisplayEnabled() { 478 synchronized (mLock) { 479 IntArray displayIds = getDisplayIdsLocked(); 480 for (int i = 0; i < displayIds.size(); i++) { 481 if (isDisplayEnabled(displayIds.get(i))) { 482 return true; 483 } 484 } 485 } 486 return false; 487 } 488 489 @Override isDisplayEnabled(int displayId)490 public boolean isDisplayEnabled(int displayId) { 491 return isDisplayOn(displayId); 492 } 493 494 // Gets the initial display state (on/off) if not already initiated. 495 // Returns true if this is the first init. initDisplayStateOnce()496 private boolean initDisplayStateOnce() { 497 synchronized (mLock) { 498 if (mDisplayStateInitiated) { 499 return false; 500 } 501 for (Display display : mDisplayManager.getDisplays()) { 502 int displayId = display.getDisplayId(); 503 boolean isDisplayOn = isDisplayOn(displayId); 504 mDisplayStateSet.put(displayId, isDisplayOn); 505 Slogf.d(TAG, "Initial display state: " + displayId + "=" + isDisplayOn); 506 } 507 mDisplayStateInitiated = true; 508 } 509 return true; 510 } 511 512 @GuardedBy("mLock") getDisplayIdsLocked()513 private IntArray getDisplayIdsLocked() { 514 IntArray displayIds = new IntArray(); 515 if (mDisplayStateInitiated) { 516 for (int i = 0; i < mDisplayStateSet.size(); i++) { 517 displayIds.add(mDisplayStateSet.keyAt(i)); 518 } 519 return displayIds; 520 } 521 Slogf.d(TAG, "Display state not initiated yet, use displayManager"); 522 for (Display display : mDisplayManager.getDisplays()) { 523 int displayId = display.getDisplayId(); 524 displayIds.add(displayId); 525 } 526 return displayIds; 527 } 528 529 // When the driver users is updated, the brightness settings associated with the driver 530 // user changes. As a result, all display's brightness should be refreshed to represent 531 // the new driver user's settings. onDriverUserUpdate()532 private void onDriverUserUpdate() { 533 synchronized (mLock) { 534 if (mCarPowerManagementService == null) { 535 // CarPowerManagementService is not connected yet 536 return; 537 } 538 } 539 if (Flags.multiDisplayBrightnessControl()) { 540 refreshAllDisplaysBrightness(); 541 } else { 542 refreshDefaultDisplayBrightness(); 543 } 544 } 545 refreshAllDisplaysBrightness()546 private void refreshAllDisplaysBrightness() { 547 for (Display display : mDisplayManager.getDisplays()) { 548 int displayId = display.getDisplayId(); 549 int displayType = mDisplayHelper.getType(display); 550 if (displayType == DisplayHelper.TYPE_VIRTUAL 551 || displayType == DisplayHelper.TYPE_OVERLAY) { 552 Slogf.i(TAG, 553 "Ignore refreshDisplayBrightness for virtual or overlay display: " 554 + displayId); 555 continue; 556 } 557 refreshDisplayBrightness(displayId); 558 } 559 } 560 hasRecentlySetBrightness(float brightness, int displayId)561 private boolean hasRecentlySetBrightness(float brightness, int displayId) { 562 synchronized (mLock) { 563 for (int i = 0; i < mRecentlySetBrightnessForDisplayId.size(); i++) { 564 if (isSameBrightnessForDisplayId(mRecentlySetBrightnessForDisplayId.get(i), 565 brightness, displayId)) { 566 Slogf.v(TAG, 567 "Ignore brightness change from DisplayManager, brightness=%f, " 568 + "displayId=%d, same as recently change set to DisplayManager", 569 brightness, displayId); 570 return true; 571 } 572 } 573 } 574 return false; 575 } 576 addRecentlySetBrightness(float brightness, int displayId)577 private void addRecentlySetBrightness(float brightness, int displayId) { 578 synchronized (mLock) { 579 mRecentlySetBrightnessForDisplayId.add( 580 new BrightnessForDisplayId(brightness, displayId)); 581 mHandler.postDelayed(() -> { 582 synchronized (mLock) { 583 mRecentlySetBrightnessForDisplayId.removeFirst(); 584 } 585 }, PREVENT_LOOP_REQUEST_TIME_WINDOW_MS); 586 } 587 } 588 hasRecentlySetBrightness(int brightness)589 private boolean hasRecentlySetBrightness(int brightness) { 590 synchronized (mLock) { 591 for (int i = 0; i < mRecentlySetGlobalBrightness.size(); i++) { 592 if (mRecentlySetGlobalBrightness.get(i) == brightness) { 593 Slogf.v(TAG, 594 "Ignore brightness change from System Settings, brightness=%d" 595 + ", same as recently change set to System Settings", brightness); 596 return true; 597 } 598 } 599 return false; 600 } 601 } 602 603 @GuardedBy("mLock") addRecentlySetBrightness(int brightness)604 private void addRecentlySetBrightness(int brightness) { 605 synchronized (mLock) { 606 mRecentlySetGlobalBrightness.add(brightness); 607 mHandler.postDelayed(() -> { 608 synchronized (mLock) { 609 mRecentlySetGlobalBrightness.removeFirst(); 610 } 611 }, PREVENT_LOOP_REQUEST_TIME_WINDOW_MS); 612 } 613 } 614 isSameBrightnessForDisplayId(BrightnessForDisplayId toCheck, float brightness, int displayId)615 private boolean isSameBrightnessForDisplayId(BrightnessForDisplayId toCheck, 616 float brightness, int displayId) { 617 return toCheck.brightness() == brightness && toCheck.displayId() == displayId; 618 } 619 } 620 } 621