1 /*
2  * Copyright (C) 2023 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 package com.android.server.display.brightness.strategy;
17 
18 import android.annotation.Nullable;
19 import android.content.Context;
20 import android.hardware.display.BrightnessConfiguration;
21 import android.os.PowerManager;
22 import android.os.UserHandle;
23 import android.provider.Settings;
24 import android.view.Display;
25 
26 import com.android.internal.annotations.VisibleForTesting;
27 import com.android.server.display.AutomaticBrightnessController;
28 import com.android.server.display.brightness.BrightnessEvent;
29 import com.android.server.display.brightness.BrightnessReason;
30 import com.android.server.display.brightness.BrightnessUtils;
31 
32 import java.io.PrintWriter;
33 
34 /**
35  * Helps manage the brightness based on the ambient environment (Ambient Light/lux sensor) using
36  * mappings from lux to nits to brightness, configured in the
37  * {@link com.android.server.display.DisplayDeviceConfig} class. This class inherently assumes
38  * that it is being executed from the power thread, and hence doesn't synchronize
39  * any of its resources
40  */
41 public class AutomaticBrightnessStrategy {
42     private final Context mContext;
43     // The DisplayId of the associated logical display
44     private final int mDisplayId;
45     // The last auto brightness adjustment that was set by the user and is not temporary. Set to
46     // Float.NaN when an auto-brightness adjustment hasn't been recorded yet.
47     private float mAutoBrightnessAdjustment;
48     // The pending auto brightness adjustment that will take effect on the next power state update.
49     private float mPendingAutoBrightnessAdjustment;
50     // The temporary auto brightness adjustment. This was historically used when a user interacts
51     // with the adjustment slider but hasn't settled on a choice yet.
52     // Set to PowerManager.BRIGHTNESS_INVALID_FLOAT when there's no temporary adjustment set.
53     private float mTemporaryAutoBrightnessAdjustment;
54     // Indicates if the temporary auto brightness adjustment has been applied while updating the
55     // associated display brightness
56     private boolean mAppliedTemporaryAutoBrightnessAdjustment;
57     // Indicates if the auto brightness adjustment has happened.
58     private boolean mAutoBrightnessAdjustmentChanged;
59     // Indicates the reasons for the auto-brightness adjustment
60     private int mAutoBrightnessAdjustmentReasonsFlags = 0;
61     // Indicates if the short term model should be reset before fetching the new brightness
62     // Todo(273543270): Short term model is an internal information of
63     //  AutomaticBrightnessController and shouldn't be exposed outside of that class
64     private boolean mShouldResetShortTermModel = false;
65     // Remembers whether the auto-brightness has been applied in the latest brightness update.
66     private boolean mAppliedAutoBrightness = false;
67     // The controller for the automatic brightness level.
68     @Nullable
69     private AutomaticBrightnessController mAutomaticBrightnessController;
70     // The system setting denoting if the auto-brightness for the current user is enabled or not
71     private boolean mUseAutoBrightness = false;
72     // Indicates if the auto-brightness is currently enabled or not. It's possible that even if
73     // the user has enabled the auto-brightness from the settings, it is disabled because the
74     // display is off
75     private boolean mIsAutoBrightnessEnabled = false;
76     // Indicates if auto-brightness is disabled due to the display being off. Needed for metric
77     // purposes.
78     private boolean mAutoBrightnessDisabledDueToDisplayOff;
79     // If the auto-brightness model for the last manual changes done by the user.
80     private boolean mIsShortTermModelActive = false;
81 
82     // The BrightnessConfiguration currently being used
83     // Todo(273543270): BrightnessConfiguration is an internal implementation detail of
84     //  AutomaticBrightnessController, and AutomaticBrightnessStrategy shouldn't be aware of its
85     //  existence.
86     @Nullable
87     private BrightnessConfiguration mBrightnessConfiguration;
88 
AutomaticBrightnessStrategy(Context context, int displayId)89     public AutomaticBrightnessStrategy(Context context, int displayId) {
90         mContext = context;
91         mDisplayId = displayId;
92         mAutoBrightnessAdjustment = getAutoBrightnessAdjustmentSetting();
93         mPendingAutoBrightnessAdjustment = PowerManager.BRIGHTNESS_INVALID_FLOAT;
94         mTemporaryAutoBrightnessAdjustment = PowerManager.BRIGHTNESS_INVALID_FLOAT;
95     }
96 
97     /**
98      * Sets up the automatic brightness states of this class. Also configures
99      * AutomaticBrightnessController accounting for any manual changes made by the user.
100      */
setAutoBrightnessState(int targetDisplayState, boolean allowAutoBrightnessWhileDozingConfig, int brightnessReason, int policy, float lastUserSetScreenBrightness, boolean userSetBrightnessChanged)101     public void setAutoBrightnessState(int targetDisplayState,
102             boolean allowAutoBrightnessWhileDozingConfig, int brightnessReason, int policy,
103             float lastUserSetScreenBrightness, boolean userSetBrightnessChanged) {
104         final boolean autoBrightnessEnabledInDoze =
105                 allowAutoBrightnessWhileDozingConfig
106                         && Display.isDozeState(targetDisplayState);
107         mIsAutoBrightnessEnabled = shouldUseAutoBrightness()
108                 && (targetDisplayState == Display.STATE_ON || autoBrightnessEnabledInDoze)
109                 && brightnessReason != BrightnessReason.REASON_OVERRIDE
110                 && mAutomaticBrightnessController != null;
111         mAutoBrightnessDisabledDueToDisplayOff = shouldUseAutoBrightness()
112                 && !(targetDisplayState == Display.STATE_ON || autoBrightnessEnabledInDoze);
113         final int autoBrightnessState = mIsAutoBrightnessEnabled
114                     && brightnessReason != BrightnessReason.REASON_FOLLOWER
115                 ? AutomaticBrightnessController.AUTO_BRIGHTNESS_ENABLED
116                 : mAutoBrightnessDisabledDueToDisplayOff
117                         ? AutomaticBrightnessController.AUTO_BRIGHTNESS_OFF_DUE_TO_DISPLAY_STATE
118                         : AutomaticBrightnessController.AUTO_BRIGHTNESS_DISABLED;
119 
120         accommodateUserBrightnessChanges(userSetBrightnessChanged, lastUserSetScreenBrightness,
121                 policy, mBrightnessConfiguration, autoBrightnessState);
122     }
123 
isAutoBrightnessEnabled()124     public boolean isAutoBrightnessEnabled() {
125         return mIsAutoBrightnessEnabled;
126     }
127 
isAutoBrightnessDisabledDueToDisplayOff()128     public boolean isAutoBrightnessDisabledDueToDisplayOff() {
129         return mAutoBrightnessDisabledDueToDisplayOff;
130     }
131 
132     /**
133      * Updates the {@link BrightnessConfiguration} that is currently being used by the associated
134      * display.
135      */
setBrightnessConfiguration(BrightnessConfiguration brightnessConfiguration, boolean shouldResetShortTermModel)136     public void setBrightnessConfiguration(BrightnessConfiguration brightnessConfiguration,
137             boolean shouldResetShortTermModel) {
138         mBrightnessConfiguration = brightnessConfiguration;
139         setShouldResetShortTermModel(shouldResetShortTermModel);
140     }
141 
142     /**
143      * Promotes the pending auto-brightness adjustments which are yet to be applied to the current
144      * adjustments. Note that this is not applying the new adjustments to the AutoBrightness mapping
145      * strategies, but is only accommodating the changes in this class.
146      */
processPendingAutoBrightnessAdjustments()147     public boolean processPendingAutoBrightnessAdjustments() {
148         mAutoBrightnessAdjustmentChanged = false;
149         if (Float.isNaN(mPendingAutoBrightnessAdjustment)) {
150             return false;
151         }
152         if (mAutoBrightnessAdjustment == mPendingAutoBrightnessAdjustment) {
153             mPendingAutoBrightnessAdjustment = Float.NaN;
154             return false;
155         }
156         mAutoBrightnessAdjustment = mPendingAutoBrightnessAdjustment;
157         mPendingAutoBrightnessAdjustment = Float.NaN;
158         mTemporaryAutoBrightnessAdjustment = Float.NaN;
159         mAutoBrightnessAdjustmentChanged = true;
160         return true;
161     }
162 
163     /**
164      * Updates the associated AutomaticBrightnessController
165      */
setAutomaticBrightnessController( AutomaticBrightnessController automaticBrightnessController)166     public void setAutomaticBrightnessController(
167             AutomaticBrightnessController automaticBrightnessController) {
168         if (automaticBrightnessController == mAutomaticBrightnessController) {
169             return;
170         }
171         if (mAutomaticBrightnessController != null) {
172             mAutomaticBrightnessController.stop();
173         }
174         mAutomaticBrightnessController = automaticBrightnessController;
175     }
176 
177     /**
178      * Returns if the auto-brightness of the associated display has been enabled or not
179      */
shouldUseAutoBrightness()180     public boolean shouldUseAutoBrightness() {
181         return mUseAutoBrightness;
182     }
183 
184     /**
185      * Sets the auto-brightness state of the associated display. Called when the user makes a change
186      * in the system setting to enable/disable the auto-brightness.
187      */
setUseAutoBrightness(boolean useAutoBrightness)188     public void setUseAutoBrightness(boolean useAutoBrightness) {
189         mUseAutoBrightness = useAutoBrightness;
190     }
191 
192     /**
193      * Returns if the user made brightness change events(Typically when they interact with the
194      * brightness slider) were accommodated in the auto-brightness mapping strategies. This doesn't
195      * account for the latest changes that have been made by the user.
196      */
isShortTermModelActive()197     public boolean isShortTermModelActive() {
198         return mIsShortTermModelActive;
199     }
200 
201     /**
202      * Sets the pending auto-brightness adjustments in the system settings. Executed
203      * when there is a change in the brightness system setting, or when there is a user switch.
204      */
updatePendingAutoBrightnessAdjustments(boolean userSwitch)205     public void updatePendingAutoBrightnessAdjustments(boolean userSwitch) {
206         final float adj = Settings.System.getFloatForUser(mContext.getContentResolver(),
207                 Settings.System.SCREEN_AUTO_BRIGHTNESS_ADJ, 0.0f, UserHandle.USER_CURRENT);
208         mPendingAutoBrightnessAdjustment = Float.isNaN(adj) ? Float.NaN
209                 : BrightnessUtils.clampBrightnessAdjustment(adj);
210         if (userSwitch) {
211             processPendingAutoBrightnessAdjustments();
212         }
213     }
214 
215     /**
216      * Sets the temporary auto-brightness adjustments
217      */
setTemporaryAutoBrightnessAdjustment(float temporaryAutoBrightnessAdjustment)218     public void setTemporaryAutoBrightnessAdjustment(float temporaryAutoBrightnessAdjustment) {
219         mTemporaryAutoBrightnessAdjustment = temporaryAutoBrightnessAdjustment;
220     }
221 
222     /**
223      * Dumps the state of this class.
224      */
dump(PrintWriter writer)225     public void dump(PrintWriter writer) {
226         writer.println("AutomaticBrightnessStrategy:");
227         writer.println("  mDisplayId=" + mDisplayId);
228         writer.println("  mAutoBrightnessAdjustment=" + mAutoBrightnessAdjustment);
229         writer.println("  mPendingAutoBrightnessAdjustment=" + mPendingAutoBrightnessAdjustment);
230         writer.println(
231                 "  mTemporaryAutoBrightnessAdjustment=" + mTemporaryAutoBrightnessAdjustment);
232         writer.println("  mShouldResetShortTermModel=" + mShouldResetShortTermModel);
233         writer.println("  mAppliedAutoBrightness=" + mAppliedAutoBrightness);
234         writer.println("  mAutoBrightnessAdjustmentChanged=" + mAutoBrightnessAdjustmentChanged);
235         writer.println("  mAppliedTemporaryAutoBrightnessAdjustment="
236                 + mAppliedTemporaryAutoBrightnessAdjustment);
237         writer.println("  mUseAutoBrightness=" + mUseAutoBrightness);
238         writer.println("  mWasShortTermModelActive=" + mIsShortTermModelActive);
239         writer.println("  mAutoBrightnessAdjustmentReasonsFlags="
240                 + mAutoBrightnessAdjustmentReasonsFlags);
241     }
242 
243     /**
244      * Indicates if any auto-brightness adjustments have happened since the last auto-brightness was
245      * set.
246      */
getAutoBrightnessAdjustmentChanged()247     public boolean getAutoBrightnessAdjustmentChanged() {
248         return mAutoBrightnessAdjustmentChanged;
249     }
250 
251     /**
252      * Returns whether the latest temporary auto-brightness adjustments have been applied or not
253      */
isTemporaryAutoBrightnessAdjustmentApplied()254     public boolean isTemporaryAutoBrightnessAdjustmentApplied() {
255         return mAppliedTemporaryAutoBrightnessAdjustment;
256     }
257 
258     /**
259      * Evaluates the target automatic brightness of the associated display.
260      * @param brightnessEvent Event object to populate with details about why the specific
261      *                        brightness was chosen.
262      */
getAutomaticScreenBrightness(BrightnessEvent brightnessEvent)263     public float getAutomaticScreenBrightness(BrightnessEvent brightnessEvent) {
264         float brightness = (mAutomaticBrightnessController != null)
265                 ? mAutomaticBrightnessController.getAutomaticScreenBrightness(brightnessEvent)
266                 : PowerManager.BRIGHTNESS_INVALID_FLOAT;
267         adjustAutomaticBrightnessStateIfValid(brightness);
268         return brightness;
269     }
270 
271     /**
272      * Gets the auto-brightness adjustment flag change reason
273      */
getAutoBrightnessAdjustmentReasonsFlags()274     public int getAutoBrightnessAdjustmentReasonsFlags() {
275         return mAutoBrightnessAdjustmentReasonsFlags;
276     }
277 
278     /**
279      * Returns if the auto brightness has been applied
280      */
hasAppliedAutoBrightness()281     public boolean hasAppliedAutoBrightness() {
282         return mAppliedAutoBrightness;
283     }
284 
285     /**
286      * Used to adjust the state of this class when the automatic brightness value for the
287      * associated display is valid
288      */
289     @VisibleForTesting
adjustAutomaticBrightnessStateIfValid(float brightnessState)290     void adjustAutomaticBrightnessStateIfValid(float brightnessState) {
291         mAutoBrightnessAdjustmentReasonsFlags = isTemporaryAutoBrightnessAdjustmentApplied()
292                 ? BrightnessReason.ADJUSTMENT_AUTO_TEMP
293                 : BrightnessReason.ADJUSTMENT_AUTO;
294         float newAutoBrightnessAdjustment =
295                 (mAutomaticBrightnessController != null)
296                         ? mAutomaticBrightnessController.getAutomaticScreenBrightnessAdjustment()
297                         : 0.0f;
298         if (!Float.isNaN(newAutoBrightnessAdjustment)
299                 && mAutoBrightnessAdjustment != newAutoBrightnessAdjustment) {
300             // If the auto-brightness controller has decided to change the adjustment value
301             // used, make sure that's reflected in settings.
302             putAutoBrightnessAdjustmentSetting(newAutoBrightnessAdjustment);
303         } else {
304             mAutoBrightnessAdjustmentReasonsFlags = 0;
305         }
306     }
307 
308     /**
309      * Sets up the system to reset the short term model. Note that this will not reset the model
310      * right away, but ensures that the reset happens whenever the next brightness change happens
311      */
312     @VisibleForTesting
setShouldResetShortTermModel(boolean shouldResetShortTermModel)313     void setShouldResetShortTermModel(boolean shouldResetShortTermModel) {
314         mShouldResetShortTermModel = shouldResetShortTermModel;
315     }
316 
317     @VisibleForTesting
shouldResetShortTermModel()318     boolean shouldResetShortTermModel() {
319         return mShouldResetShortTermModel;
320     }
321 
322     @VisibleForTesting
getAutoBrightnessAdjustment()323     float getAutoBrightnessAdjustment() {
324         return mAutoBrightnessAdjustment;
325     }
326 
327     @VisibleForTesting
getPendingAutoBrightnessAdjustment()328     float getPendingAutoBrightnessAdjustment() {
329         return mPendingAutoBrightnessAdjustment;
330     }
331 
332     @VisibleForTesting
getTemporaryAutoBrightnessAdjustment()333     float getTemporaryAutoBrightnessAdjustment() {
334         return mTemporaryAutoBrightnessAdjustment;
335     }
336 
337     @VisibleForTesting
putAutoBrightnessAdjustmentSetting(float adjustment)338     void putAutoBrightnessAdjustmentSetting(float adjustment) {
339         if (mDisplayId == Display.DEFAULT_DISPLAY) {
340             mAutoBrightnessAdjustment = adjustment;
341             Settings.System.putFloatForUser(mContext.getContentResolver(),
342                     Settings.System.SCREEN_AUTO_BRIGHTNESS_ADJ, adjustment,
343                     UserHandle.USER_CURRENT);
344         }
345     }
346 
347     /**
348      * Sets if the auto-brightness is applied on the latest brightness change.
349      */
setAutoBrightnessApplied(boolean autoBrightnessApplied)350     public void setAutoBrightnessApplied(boolean autoBrightnessApplied) {
351         mAppliedAutoBrightness = autoBrightnessApplied;
352     }
353 
354     /**
355      * Accommodates the latest manual changes made by the user. Also updates {@link
356      * AutomaticBrightnessController} about the changes and configures it accordingly.
357      */
358     @VisibleForTesting
accommodateUserBrightnessChanges(boolean userSetBrightnessChanged, float lastUserSetScreenBrightness, int policy, BrightnessConfiguration brightnessConfiguration, int autoBrightnessState)359     void accommodateUserBrightnessChanges(boolean userSetBrightnessChanged,
360             float lastUserSetScreenBrightness, int policy,
361             BrightnessConfiguration brightnessConfiguration, int autoBrightnessState) {
362         // Update the pending auto-brightness adjustments if any. This typically checks and adjusts
363         // the state of the class if the user moves the brightness slider and has settled to a
364         // different value
365         processPendingAutoBrightnessAdjustments();
366         // Update the temporary auto-brightness adjustments if any. This typically checks and
367         // adjusts the state of this class if the user is in the process of moving the brightness
368         // slider, but hasn't settled to any value yet
369         float autoBrightnessAdjustment = updateTemporaryAutoBrightnessAdjustments();
370         mIsShortTermModelActive = false;
371         // Configure auto-brightness.
372         if (mAutomaticBrightnessController != null) {
373             // Accommodate user changes if any in the auto-brightness model
374             mAutomaticBrightnessController.configure(autoBrightnessState,
375                     brightnessConfiguration,
376                     lastUserSetScreenBrightness,
377                     userSetBrightnessChanged, autoBrightnessAdjustment,
378                     mAutoBrightnessAdjustmentChanged, policy, mShouldResetShortTermModel);
379             mShouldResetShortTermModel = false;
380             // We take note if the user brightness point is still being used in the current
381             // auto-brightness model.
382             mIsShortTermModelActive = mAutomaticBrightnessController.hasUserDataPoints();
383         }
384     }
385 
386     /**
387      * Evaluates if there are any temporary auto-brightness adjustments which is not applied yet.
388      * Temporary brightness adjustments happen when the user moves the brightness slider in the
389      * auto-brightness mode, but hasn't settled to a value yet
390      */
updateTemporaryAutoBrightnessAdjustments()391     private float updateTemporaryAutoBrightnessAdjustments() {
392         mAppliedTemporaryAutoBrightnessAdjustment =
393                 !Float.isNaN(mTemporaryAutoBrightnessAdjustment);
394         // We do not update the mAutoBrightnessAdjustment with mTemporaryAutoBrightnessAdjustment
395         // since we have not settled to a value yet
396         return mAppliedTemporaryAutoBrightnessAdjustment
397                 ? mTemporaryAutoBrightnessAdjustment : mAutoBrightnessAdjustment;
398     }
399 
400     /**
401      * Returns the auto-brightness adjustment that is set in the system setting.
402      */
getAutoBrightnessAdjustmentSetting()403     private float getAutoBrightnessAdjustmentSetting() {
404         final float adj = Settings.System.getFloatForUser(mContext.getContentResolver(),
405                 Settings.System.SCREEN_AUTO_BRIGHTNESS_ADJ, 0.0f, UserHandle.USER_CURRENT);
406         return Float.isNaN(adj) ? 0.0f : BrightnessUtils.clampBrightnessAdjustment(adj);
407     }
408 }
409