• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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