blob: 31632dc007a51ece71535844e14582851a7db1b7 [file] [log] [blame]
Michael Wright639c8be2014-01-17 18:29:12 -08001/*
2 * Copyright (C) 2014 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
Jeff Brown131206b2014-04-08 17:27:14 -070017package com.android.server.display;
Michael Wright639c8be2014-01-17 18:29:12 -080018
Justin Klaassen908b86c2016-08-08 09:18:42 -070019import android.annotation.Nullable;
Dan Gittika5a2d632019-01-09 14:25:29 +000020import android.app.ActivityManager.StackInfo;
21import android.app.ActivityTaskManager;
22import android.app.IActivityTaskManager;
23import android.app.TaskStackListener;
24import android.content.pm.ApplicationInfo;
25import android.content.pm.PackageManager;
Michael Wright639c8be2014-01-17 18:29:12 -080026import android.hardware.Sensor;
27import android.hardware.SensorEvent;
28import android.hardware.SensorEventListener;
29import android.hardware.SensorManager;
Michael Wrighteef0e132017-11-21 17:57:52 +000030import android.hardware.display.BrightnessConfiguration;
Michael Wrightd8460232018-01-16 18:04:59 +000031import android.hardware.display.DisplayManagerInternal.DisplayPowerRequest;
Michael Wright639c8be2014-01-17 18:29:12 -080032import android.os.Handler;
33import android.os.Looper;
34import android.os.Message;
35import android.os.PowerManager;
Dan Gittika5a2d632019-01-09 14:25:29 +000036import android.os.RemoteException;
Michael Wright639c8be2014-01-17 18:29:12 -080037import android.os.SystemClock;
Michael Wrightb0a1d3d2017-09-22 15:05:02 +010038import android.os.Trace;
Jeff Browna576b4d2015-04-23 19:58:06 -070039import android.util.EventLog;
Michael Wright639c8be2014-01-17 18:29:12 -080040import android.util.MathUtils;
Michael Wright639c8be2014-01-17 18:29:12 -080041import android.util.Slog;
42import android.util.TimeUtils;
43
Dan Gittika5a2d632019-01-09 14:25:29 +000044import com.android.internal.os.BackgroundThread;
Dan Gittiked958e92018-11-13 14:58:20 +000045import com.android.server.EventLogTags;
46
Michael Wright639c8be2014-01-17 18:29:12 -080047import java.io.PrintWriter;
Michael Wright639c8be2014-01-17 18:29:12 -080048
49class AutomaticBrightnessController {
50 private static final String TAG = "AutomaticBrightnessController";
51
Michael Wright639c8be2014-01-17 18:29:12 -080052 private static final boolean DEBUG_PRETEND_LIGHT_SENSOR_ABSENT = false;
53
54 // If true, enables the use of the screen auto-brightness adjustment setting.
Adrian Roosdaf7d412014-05-13 14:55:09 +020055 private static final boolean USE_SCREEN_AUTO_BRIGHTNESS_ADJUSTMENT = true;
Michael Wright639c8be2014-01-17 18:29:12 -080056
Michael Wright639c8be2014-01-17 18:29:12 -080057 // How long the current sensor reading is assumed to be valid beyond the current time.
58 // This provides a bit of prediction, as well as ensures that the weight for the last sample is
59 // non-zero, which in turn ensures that the total weight is non-zero.
60 private static final long AMBIENT_LIGHT_PREDICTION_TIME_MILLIS = 100;
61
Jeff Browna576b4d2015-04-23 19:58:06 -070062 // Debounce for sampling user-initiated changes in display brightness to ensure
63 // the user is satisfied with the result before storing the sample.
64 private static final int BRIGHTNESS_ADJUSTMENT_SAMPLE_DEBOUNCE_MILLIS = 10000;
65
Michael Wright639c8be2014-01-17 18:29:12 -080066 private static final int MSG_UPDATE_AMBIENT_LUX = 1;
Jeff Browna576b4d2015-04-23 19:58:06 -070067 private static final int MSG_BRIGHTNESS_ADJUSTMENT_SAMPLE = 2;
Dan Gittikc5d32912018-02-22 13:53:47 +000068 private static final int MSG_INVALIDATE_SHORT_TERM_MODEL = 3;
Dan Gittika5a2d632019-01-09 14:25:29 +000069 private static final int MSG_UPDATE_FOREGROUND_APP = 4;
70 private static final int MSG_UPDATE_FOREGROUND_APP_SYNC = 5;
Michael Wright639c8be2014-01-17 18:29:12 -080071
Michael Wright0a933142017-08-16 20:38:21 +010072 // Length of the ambient light horizon used to calculate the long term estimate of ambient
73 // light.
74 private static final int AMBIENT_LIGHT_LONG_HORIZON_MILLIS = 10000;
75
76 // Length of the ambient light horizon used to calculate short-term estimate of ambient light.
77 private static final int AMBIENT_LIGHT_SHORT_HORIZON_MILLIS = 2000;
78
Julius D'souza428aed02016-08-07 19:08:30 -070079 // Callbacks for requesting updates to the display's power state
Michael Wright639c8be2014-01-17 18:29:12 -080080 private final Callbacks mCallbacks;
81
82 // The sensor manager.
83 private final SensorManager mSensorManager;
84
85 // The light sensor, or null if not available or needed.
86 private final Sensor mLightSensor;
87
Michael Wrighteef0e132017-11-21 17:57:52 +000088 // The mapper to translate ambient lux to screen brightness in the range [0, 1.0].
89 private final BrightnessMappingStrategy mBrightnessMapper;
Michael Wright639c8be2014-01-17 18:29:12 -080090
91 // The minimum and maximum screen brightnesses.
92 private final int mScreenBrightnessRangeMinimum;
93 private final int mScreenBrightnessRangeMaximum;
Michael Wright2155bc22018-05-01 00:38:32 +010094
95 // How much to scale doze brightness by (should be (0, 1.0]).
Filip Gruszczynskia15aa7d2014-10-28 14:12:40 -070096 private final float mDozeScaleFactor;
Michael Wright639c8be2014-01-17 18:29:12 -080097
Julius D'souza5d717092016-10-24 19:26:45 -070098 // Initial light sensor event rate in milliseconds.
99 private final int mInitialLightSensorRate;
100
101 // Steady-state light sensor event rate in milliseconds.
102 private final int mNormalLightSensorRate;
103
104 // The current light sensor event rate in milliseconds.
105 private int mCurrentLightSensorRate;
Filip Gruszczynskid81ecd12015-02-06 12:38:47 -0800106
107 // Stability requirements in milliseconds for accepting a new brightness level. This is used
108 // for debouncing the light sensor. Different constants are used to debounce the light sensor
109 // when adapting to brighter or darker environments. This parameter controls how quickly
110 // brightness changes occur in response to an observed change in light level that exceeds the
111 // hysteresis threshold.
112 private final long mBrighteningLightDebounceConfig;
113 private final long mDarkeningLightDebounceConfig;
114
115 // If true immediately after the screen is turned on the controller will try to adjust the
116 // brightness based on the current sensor reads. If false, the controller will collect more data
117 // and only then decide whether to change brightness.
118 private final boolean mResetAmbientLuxAfterWarmUpConfig;
119
Zoran Jovanovic6fc42f52015-12-10 17:01:16 +0100120 // Period of time in which to consider light samples in milliseconds.
121 private final int mAmbientLightHorizon;
122
123 // The intercept used for the weighting calculation. This is used in order to keep all possible
124 // weighting values positive.
125 private final int mWeightingIntercept;
126
Michael Wright2155bc22018-05-01 00:38:32 +0100127 // Configuration object for determining thresholds to change brightness dynamically
Dan Gittiked958e92018-11-13 14:58:20 +0000128 private final HysteresisLevels mAmbientBrightnessThresholds;
129 private final HysteresisLevels mScreenBrightnessThresholds;
Julius D'souza428aed02016-08-07 19:08:30 -0700130
Dan Gittika5a2d632019-01-09 14:25:29 +0000131 private boolean mLoggingEnabled;
132
Dan Gittik825cc072018-12-17 14:24:48 +0000133 // Timeout after which we remove the effects any user interactions might've had on the
134 // brightness mapping. This timeout doesn't start until we transition to a non-interactive
135 // display policy so that we don't reset while users are using their devices, but also so that
136 // we don't erroneously keep the short-term model if the device is dozing but the display is
137 // fully on.
138 private long mShortTermModelTimeout;
139
Michael Wright639c8be2014-01-17 18:29:12 -0800140 // Amount of time to delay auto-brightness after screen on while waiting for
141 // the light sensor to warm-up in milliseconds.
142 // May be 0 if no warm-up is required.
143 private int mLightSensorWarmUpTimeConfig;
144
145 // Set to true if the light sensor is enabled.
146 private boolean mLightSensorEnabled;
147
148 // The time when the light sensor was enabled.
149 private long mLightSensorEnableTime;
150
151 // The currently accepted nominal ambient light level.
152 private float mAmbientLux;
153
154 // True if mAmbientLux holds a valid value.
155 private boolean mAmbientLuxValid;
156
157 // The ambient light level threshold at which to brighten or darken the screen.
Dan Gittiked958e92018-11-13 14:58:20 +0000158 private float mAmbientBrighteningThreshold;
159 private float mAmbientDarkeningThreshold;
160
161 // The screen brightness threshold at which to brighten or darken the screen.
162 private float mScreenBrighteningThreshold;
163 private float mScreenDarkeningThreshold;
Michael Wright639c8be2014-01-17 18:29:12 -0800164
165 // The most recent light sample.
166 private float mLastObservedLux;
167
168 // The time of the most light recent sample.
169 private long mLastObservedLuxTime;
170
171 // The number of light samples collected since the light sensor was enabled.
172 private int mRecentLightSamples;
173
174 // A ring buffer containing all of the recent ambient light sensor readings.
175 private AmbientLightRingBuffer mAmbientLightRingBuffer;
176
177 // The handler
178 private AutomaticBrightnessHandler mHandler;
179
180 // The screen brightness level that has been chosen by the auto-brightness
181 // algorithm. The actual brightness should ramp towards this value.
182 // We preserve this value even when we stop using the light sensor so
183 // that we can quickly revert to the previous auto-brightness level
184 // while the light sensor warms up.
185 // Use -1 if there is no current auto-brightness value available.
186 private int mScreenAutoBrightness = -1;
187
Michael Wrightd8460232018-01-16 18:04:59 +0000188 // The current display policy. This is useful, for example, for knowing when we're dozing,
189 // where the light sensor may not be available.
190 private int mDisplayPolicy = DisplayPowerRequest.POLICY_OFF;
Filip Gruszczynskia15aa7d2014-10-28 14:12:40 -0700191
Jeff Browna576b4d2015-04-23 19:58:06 -0700192 // True if we are collecting a brightness adjustment sample, along with some data
193 // for the initial state of the sample.
194 private boolean mBrightnessAdjustmentSamplePending;
Jeff Browna576b4d2015-04-23 19:58:06 -0700195 private float mBrightnessAdjustmentSampleOldLux;
196 private int mBrightnessAdjustmentSampleOldBrightness;
Jeff Browna576b4d2015-04-23 19:58:06 -0700197
Dan Gittikc5d32912018-02-22 13:53:47 +0000198 // When the short term model is invalidated, we don't necessarily reset it (i.e. clear the
199 // user's adjustment) immediately, but wait for a drastic enough change in the ambient light.
200 // The anchor determines what were the light levels when the user has set her preference, and
201 // we use a relative threshold to determine when to revert to the OEM curve.
202 private boolean mShortTermModelValid;
203 private float mShortTermModelAnchor;
204 private float SHORT_TERM_MODEL_THRESHOLD_RATIO = 0.6f;
205
Dan Gittika5a2d632019-01-09 14:25:29 +0000206 // Context-sensitive brightness configurations require keeping track of the foreground app's
207 // package name and category, which is done by registering a TaskStackListener to call back to
208 // us onTaskStackChanged, and then using the ActivityTaskManager to get the foreground app's
209 // package namd and PackageManager to get its category (so might as well cache them).
210 private String mForegroundAppPackageName;
211 private String mPendingForegroundAppPackageName;
212 private @ApplicationInfo.Category int mForegroundAppCategory;
213 private @ApplicationInfo.Category int mPendingForegroundAppCategory;
214 private TaskStackListenerImpl mTaskStackListener;
215 private IActivityTaskManager mActivityTaskManager;
216 private PackageManager mPackageManager;
217
Michael Wright639c8be2014-01-17 18:29:12 -0800218 public AutomaticBrightnessController(Callbacks callbacks, Looper looper,
Michael Wrighte02db662019-03-08 21:24:36 +0000219 SensorManager sensorManager, Sensor lightSensor, BrightnessMappingStrategy mapper,
Dan Gittik57d6f112018-03-27 18:14:22 +0100220 int lightSensorWarmUpTime, int brightnessMin, int brightnessMax, float dozeScaleFactor,
Julius D'souza5d717092016-10-24 19:26:45 -0700221 int lightSensorRate, int initialLightSensorRate, long brighteningLightDebounceConfig,
Zoran Jovanovic6fc42f52015-12-10 17:01:16 +0100222 long darkeningLightDebounceConfig, boolean resetAmbientLuxAfterWarmUpConfig,
Dan Gittiked958e92018-11-13 14:58:20 +0000223 HysteresisLevels ambientBrightnessThresholds,
Dan Gittika5a2d632019-01-09 14:25:29 +0000224 HysteresisLevels screenBrightnessThresholds, long shortTermModelTimeout,
225 PackageManager packageManager) {
Michael Wright639c8be2014-01-17 18:29:12 -0800226 mCallbacks = callbacks;
Michael Wright639c8be2014-01-17 18:29:12 -0800227 mSensorManager = sensorManager;
Michael Wrighteef0e132017-11-21 17:57:52 +0000228 mBrightnessMapper = mapper;
Michael Wright639c8be2014-01-17 18:29:12 -0800229 mScreenBrightnessRangeMinimum = brightnessMin;
230 mScreenBrightnessRangeMaximum = brightnessMax;
231 mLightSensorWarmUpTimeConfig = lightSensorWarmUpTime;
Filip Gruszczynskia15aa7d2014-10-28 14:12:40 -0700232 mDozeScaleFactor = dozeScaleFactor;
Julius D'souza5d717092016-10-24 19:26:45 -0700233 mNormalLightSensorRate = lightSensorRate;
234 mInitialLightSensorRate = initialLightSensorRate;
235 mCurrentLightSensorRate = -1;
Filip Gruszczynskid81ecd12015-02-06 12:38:47 -0800236 mBrighteningLightDebounceConfig = brighteningLightDebounceConfig;
237 mDarkeningLightDebounceConfig = darkeningLightDebounceConfig;
238 mResetAmbientLuxAfterWarmUpConfig = resetAmbientLuxAfterWarmUpConfig;
Michael Wright2155bc22018-05-01 00:38:32 +0100239 mAmbientLightHorizon = AMBIENT_LIGHT_LONG_HORIZON_MILLIS;
240 mWeightingIntercept = AMBIENT_LIGHT_LONG_HORIZON_MILLIS;
Dan Gittiked958e92018-11-13 14:58:20 +0000241 mAmbientBrightnessThresholds = ambientBrightnessThresholds;
242 mScreenBrightnessThresholds = screenBrightnessThresholds;
Dan Gittik825cc072018-12-17 14:24:48 +0000243 mShortTermModelTimeout = shortTermModelTimeout;
Dan Gittikc5d32912018-02-22 13:53:47 +0000244 mShortTermModelValid = true;
245 mShortTermModelAnchor = -1;
Michael Wright639c8be2014-01-17 18:29:12 -0800246
247 mHandler = new AutomaticBrightnessHandler(looper);
Michael Wright103fb782016-04-22 01:03:09 -0400248 mAmbientLightRingBuffer =
Julius D'souza5d717092016-10-24 19:26:45 -0700249 new AmbientLightRingBuffer(mNormalLightSensorRate, mAmbientLightHorizon);
Michael Wright639c8be2014-01-17 18:29:12 -0800250
251 if (!DEBUG_PRETEND_LIGHT_SENSOR_ABSENT) {
Michael Wrighte02db662019-03-08 21:24:36 +0000252 mLightSensor = lightSensor;
Michael Wright639c8be2014-01-17 18:29:12 -0800253 }
Dan Gittika5a2d632019-01-09 14:25:29 +0000254
255 mActivityTaskManager = ActivityTaskManager.getService();
256 mPackageManager = packageManager;
257 mTaskStackListener = new TaskStackListenerImpl();
258 mForegroundAppPackageName = null;
259 mPendingForegroundAppPackageName = null;
260 mForegroundAppCategory = ApplicationInfo.CATEGORY_UNDEFINED;
261 mPendingForegroundAppCategory = ApplicationInfo.CATEGORY_UNDEFINED;
262 }
263
264 /**
265 * Enable/disable logging.
266 *
267 * @param loggingEnabled
268 * Whether logging should be on/off.
269 *
270 * @return Whether the method succeeded or not.
271 */
272 public boolean setLoggingEnabled(boolean loggingEnabled) {
273 if (mLoggingEnabled == loggingEnabled) {
274 return false;
275 }
276 mBrightnessMapper.setLoggingEnabled(loggingEnabled);
277 mLoggingEnabled = loggingEnabled;
278 return true;
Michael Wright639c8be2014-01-17 18:29:12 -0800279 }
280
281 public int getAutomaticScreenBrightness() {
Dan Gittik58784422018-04-05 12:30:38 +0100282 if (!mAmbientLuxValid) {
283 return -1;
284 }
Michael Wrightd8460232018-01-16 18:04:59 +0000285 if (mDisplayPolicy == DisplayPowerRequest.POLICY_DOZE) {
Filip Gruszczynskia15aa7d2014-10-28 14:12:40 -0700286 return (int) (mScreenAutoBrightness * mDozeScaleFactor);
287 }
Michael Wright639c8be2014-01-17 18:29:12 -0800288 return mScreenAutoBrightness;
289 }
290
Kenny Guyb54d40b2019-02-28 12:49:53 +0000291 public boolean hasValidAmbientLux() {
292 return mAmbientLuxValid;
293 }
294
Michael Wright617564f2018-01-25 22:20:54 +0000295 public float getAutomaticScreenBrightnessAdjustment() {
Dan Gittik57d6f112018-03-27 18:14:22 +0100296 return mBrightnessMapper.getAutoBrightnessAdjustment();
Michael Wright617564f2018-01-25 22:20:54 +0000297 }
298
Michael Wrighteef0e132017-11-21 17:57:52 +0000299 public void configure(boolean enable, @Nullable BrightnessConfiguration configuration,
Michael Wright617564f2018-01-25 22:20:54 +0000300 float brightness, boolean userChangedBrightness, float adjustment,
301 boolean userChangedAutoBrightnessAdjustment, int displayPolicy) {
Filip Gruszczynskia15aa7d2014-10-28 14:12:40 -0700302 // While dozing, the application processor may be suspended which will prevent us from
303 // receiving new information from the light sensor. On some devices, we may be able to
304 // switch to a wake-up light sensor instead but for now we will simply disable the sensor
305 // and hold onto the last computed screen auto brightness. We save the dozing flag for
306 // debugging purposes.
Michael Wrightd8460232018-01-16 18:04:59 +0000307 boolean dozing = (displayPolicy == DisplayPowerRequest.POLICY_DOZE);
Michael Wrighteef0e132017-11-21 17:57:52 +0000308 boolean changed = setBrightnessConfiguration(configuration);
Michael Wrightd8460232018-01-16 18:04:59 +0000309 changed |= setDisplayPolicy(displayPolicy);
Dan Gittik57d6f112018-03-27 18:14:22 +0100310 if (userChangedAutoBrightnessAdjustment) {
311 changed |= setAutoBrightnessAdjustment(adjustment);
312 }
Michael Wright617564f2018-01-25 22:20:54 +0000313 if (userChangedBrightness && enable) {
314 // Update the brightness curve with the new user control point. It's critical this
315 // happens after we update the autobrightness adjustment since it may reset it.
Michael Wrightd8460232018-01-16 18:04:59 +0000316 changed |= setScreenBrightnessByUser(brightness);
Michael Wright617564f2018-01-25 22:20:54 +0000317 }
318 final boolean userInitiatedChange =
319 userChangedBrightness || userChangedAutoBrightnessAdjustment;
320 if (userInitiatedChange && enable && !dozing) {
Soroosh Mariooryada8edffd2017-03-22 17:08:26 -0700321 prepareBrightnessAdjustmentSample();
322 }
Michael Wrightd8460232018-01-16 18:04:59 +0000323 changed |= setLightSensorEnabled(enable && !dozing);
Jeff Brown970d4132014-07-19 11:33:47 -0700324 if (changed) {
Santos Cordon4acbedb2019-06-07 17:20:41 +0100325 updateAutoBrightness(false /*sendUpdate*/, userInitiatedChange);
Michael Wright639c8be2014-01-17 18:29:12 -0800326 }
327 }
328
Kenny Guy53d06612018-01-30 14:19:13 +0000329 public boolean hasUserDataPoints() {
330 return mBrightnessMapper.hasUserDataPoints();
331 }
332
333 public boolean isDefaultConfig() {
334 return mBrightnessMapper.isDefaultConfig();
335 }
336
Kenny Guy6d1009f2018-03-14 14:28:23 +0000337 public BrightnessConfiguration getDefaultConfig() {
338 return mBrightnessMapper.getDefaultConfig();
339 }
340
Michael Wrightd8460232018-01-16 18:04:59 +0000341 private boolean setDisplayPolicy(int policy) {
342 if (mDisplayPolicy == policy) {
343 return false;
344 }
345 final int oldPolicy = mDisplayPolicy;
346 mDisplayPolicy = policy;
Dan Gittika5a2d632019-01-09 14:25:29 +0000347 if (mLoggingEnabled) {
Dan Gittikc5d32912018-02-22 13:53:47 +0000348 Slog.d(TAG, "Display policy transitioning from " + oldPolicy + " to " + policy);
Michael Wrightd8460232018-01-16 18:04:59 +0000349 }
350 if (!isInteractivePolicy(policy) && isInteractivePolicy(oldPolicy)) {
Dan Gittikc5d32912018-02-22 13:53:47 +0000351 mHandler.sendEmptyMessageDelayed(MSG_INVALIDATE_SHORT_TERM_MODEL,
Dan Gittik825cc072018-12-17 14:24:48 +0000352 mShortTermModelTimeout);
Michael Wrightd8460232018-01-16 18:04:59 +0000353 } else if (isInteractivePolicy(policy) && !isInteractivePolicy(oldPolicy)) {
Dan Gittikc5d32912018-02-22 13:53:47 +0000354 mHandler.removeMessages(MSG_INVALIDATE_SHORT_TERM_MODEL);
Michael Wrightd8460232018-01-16 18:04:59 +0000355 }
356 return true;
357 }
358
359 private static boolean isInteractivePolicy(int policy) {
360 return policy == DisplayPowerRequest.POLICY_BRIGHT
361 || policy == DisplayPowerRequest.POLICY_DIM
362 || policy == DisplayPowerRequest.POLICY_VR;
363 }
364
365 private boolean setScreenBrightnessByUser(float brightness) {
366 if (!mAmbientLuxValid) {
367 // If we don't have a valid ambient lux then we don't have a valid brightness anyways,
368 // and we can't use this data to add a new control point to the short-term model.
369 return false;
370 }
371 mBrightnessMapper.addUserDataPoint(mAmbientLux, brightness);
Dan Gittikc5d32912018-02-22 13:53:47 +0000372 mShortTermModelValid = true;
373 mShortTermModelAnchor = mAmbientLux;
Dan Gittika5a2d632019-01-09 14:25:29 +0000374 if (mLoggingEnabled) {
Dan Gittikc5d32912018-02-22 13:53:47 +0000375 Slog.d(TAG, "ShortTermModel: anchor=" + mShortTermModelAnchor);
376 }
Michael Wrightd8460232018-01-16 18:04:59 +0000377 return true;
378 }
379
Dan Gittikc1352252018-04-27 17:48:31 +0100380 public void resetShortTermModel() {
Michael Wrightd8460232018-01-16 18:04:59 +0000381 mBrightnessMapper.clearUserDataPoints();
Dan Gittikc5d32912018-02-22 13:53:47 +0000382 mShortTermModelValid = true;
383 mShortTermModelAnchor = -1;
384 }
385
386 private void invalidateShortTermModel() {
Dan Gittika5a2d632019-01-09 14:25:29 +0000387 if (mLoggingEnabled) {
Dan Gittikc5d32912018-02-22 13:53:47 +0000388 Slog.d(TAG, "ShortTermModel: invalidate user data");
389 }
390 mShortTermModelValid = false;
Michael Wrightd8460232018-01-16 18:04:59 +0000391 }
392
Michael Wrighteef0e132017-11-21 17:57:52 +0000393 public boolean setBrightnessConfiguration(BrightnessConfiguration configuration) {
Michael Wrightb8f4f772018-05-01 18:28:58 +0100394 if (mBrightnessMapper.setBrightnessConfiguration(configuration)) {
395 resetShortTermModel();
396 return true;
397 }
398 return false;
Michael Wrighteef0e132017-11-21 17:57:52 +0000399 }
400
Michael Wright639c8be2014-01-17 18:29:12 -0800401 public void dump(PrintWriter pw) {
402 pw.println();
403 pw.println("Automatic Brightness Controller Configuration:");
Michael Wright639c8be2014-01-17 18:29:12 -0800404 pw.println(" mScreenBrightnessRangeMinimum=" + mScreenBrightnessRangeMinimum);
405 pw.println(" mScreenBrightnessRangeMaximum=" + mScreenBrightnessRangeMaximum);
Michael Wright2155bc22018-05-01 00:38:32 +0100406 pw.println(" mDozeScaleFactor=" + mDozeScaleFactor);
407 pw.println(" mInitialLightSensorRate=" + mInitialLightSensorRate);
408 pw.println(" mNormalLightSensorRate=" + mNormalLightSensorRate);
Michael Wright639c8be2014-01-17 18:29:12 -0800409 pw.println(" mLightSensorWarmUpTimeConfig=" + mLightSensorWarmUpTimeConfig);
Filip Gruszczynskid81ecd12015-02-06 12:38:47 -0800410 pw.println(" mBrighteningLightDebounceConfig=" + mBrighteningLightDebounceConfig);
411 pw.println(" mDarkeningLightDebounceConfig=" + mDarkeningLightDebounceConfig);
412 pw.println(" mResetAmbientLuxAfterWarmUpConfig=" + mResetAmbientLuxAfterWarmUpConfig);
Michael Wright2155bc22018-05-01 00:38:32 +0100413 pw.println(" mAmbientLightHorizon=" + mAmbientLightHorizon);
414 pw.println(" mWeightingIntercept=" + mWeightingIntercept);
Michael Wright639c8be2014-01-17 18:29:12 -0800415
416 pw.println();
417 pw.println("Automatic Brightness Controller State:");
418 pw.println(" mLightSensor=" + mLightSensor);
Michael Wright639c8be2014-01-17 18:29:12 -0800419 pw.println(" mLightSensorEnabled=" + mLightSensorEnabled);
420 pw.println(" mLightSensorEnableTime=" + TimeUtils.formatUptime(mLightSensorEnableTime));
Michael Wright2155bc22018-05-01 00:38:32 +0100421 pw.println(" mCurrentLightSensorRate=" + mCurrentLightSensorRate);
Michael Wright639c8be2014-01-17 18:29:12 -0800422 pw.println(" mAmbientLux=" + mAmbientLux);
Dan Gittik58784422018-04-05 12:30:38 +0100423 pw.println(" mAmbientLuxValid=" + mAmbientLuxValid);
Dan Gittiked958e92018-11-13 14:58:20 +0000424 pw.println(" mAmbientBrighteningThreshold=" + mAmbientBrighteningThreshold);
425 pw.println(" mAmbientDarkeningThreshold=" + mAmbientDarkeningThreshold);
426 pw.println(" mScreenBrighteningThreshold=" + mScreenBrighteningThreshold);
427 pw.println(" mScreenDarkeningThreshold=" + mScreenDarkeningThreshold);
Michael Wright639c8be2014-01-17 18:29:12 -0800428 pw.println(" mLastObservedLux=" + mLastObservedLux);
429 pw.println(" mLastObservedLuxTime=" + TimeUtils.formatUptime(mLastObservedLuxTime));
430 pw.println(" mRecentLightSamples=" + mRecentLightSamples);
431 pw.println(" mAmbientLightRingBuffer=" + mAmbientLightRingBuffer);
432 pw.println(" mScreenAutoBrightness=" + mScreenAutoBrightness);
Michael Wright2155bc22018-05-01 00:38:32 +0100433 pw.println(" mDisplayPolicy=" + DisplayPowerRequest.policyToString(mDisplayPolicy));
Dan Gittik825cc072018-12-17 14:24:48 +0000434 pw.println(" mShortTermModelTimeout=" + mShortTermModelTimeout);
Dan Gittikc5d32912018-02-22 13:53:47 +0000435 pw.println(" mShortTermModelAnchor=" + mShortTermModelAnchor);
Michael Wright2155bc22018-05-01 00:38:32 +0100436 pw.println(" mShortTermModelValid=" + mShortTermModelValid);
437 pw.println(" mBrightnessAdjustmentSamplePending=" + mBrightnessAdjustmentSamplePending);
438 pw.println(" mBrightnessAdjustmentSampleOldLux=" + mBrightnessAdjustmentSampleOldLux);
439 pw.println(" mBrightnessAdjustmentSampleOldBrightness="
440 + mBrightnessAdjustmentSampleOldBrightness);
Dan Gittika5a2d632019-01-09 14:25:29 +0000441 pw.println(" mForegroundAppPackageName=" + mForegroundAppPackageName);
442 pw.println(" mPendingForegroundAppPackageName=" + mPendingForegroundAppPackageName);
443 pw.println(" mForegroundAppCategory=" + mForegroundAppCategory);
444 pw.println(" mPendingForegroundAppCategory=" + mPendingForegroundAppCategory);
Michael Wrighteef0e132017-11-21 17:57:52 +0000445
446 pw.println();
447 mBrightnessMapper.dump(pw);
Michael Wright2155bc22018-05-01 00:38:32 +0100448
449 pw.println();
Dan Gittiked958e92018-11-13 14:58:20 +0000450 mAmbientBrightnessThresholds.dump(pw);
451 mScreenBrightnessThresholds.dump(pw);
Michael Wright639c8be2014-01-17 18:29:12 -0800452 }
453
454 private boolean setLightSensorEnabled(boolean enable) {
455 if (enable) {
456 if (!mLightSensorEnabled) {
457 mLightSensorEnabled = true;
458 mLightSensorEnableTime = SystemClock.uptimeMillis();
Julius D'souza5d717092016-10-24 19:26:45 -0700459 mCurrentLightSensorRate = mInitialLightSensorRate;
Dan Gittika5a2d632019-01-09 14:25:29 +0000460 registerForegroundAppUpdater();
Michael Wright639c8be2014-01-17 18:29:12 -0800461 mSensorManager.registerListener(mLightSensorListener, mLightSensor,
Julius D'souza5d717092016-10-24 19:26:45 -0700462 mCurrentLightSensorRate * 1000, mHandler);
Michael Wright639c8be2014-01-17 18:29:12 -0800463 return true;
464 }
Dan Gittikc5d32912018-02-22 13:53:47 +0000465 } else if (mLightSensorEnabled) {
466 mLightSensorEnabled = false;
467 mAmbientLuxValid = !mResetAmbientLuxAfterWarmUpConfig;
Dan Gittikf387dd72018-07-13 15:10:39 +0100468 mScreenAutoBrightness = -1;
Dan Gittikc5d32912018-02-22 13:53:47 +0000469 mRecentLightSamples = 0;
470 mAmbientLightRingBuffer.clear();
471 mCurrentLightSensorRate = -1;
472 mHandler.removeMessages(MSG_UPDATE_AMBIENT_LUX);
Dan Gittika5a2d632019-01-09 14:25:29 +0000473 unregisterForegroundAppUpdater();
Dan Gittikc5d32912018-02-22 13:53:47 +0000474 mSensorManager.unregisterListener(mLightSensorListener);
Michael Wright639c8be2014-01-17 18:29:12 -0800475 }
476 return false;
477 }
478
479 private void handleLightSensorEvent(long time, float lux) {
Michael Wrightb0a1d3d2017-09-22 15:05:02 +0100480 Trace.traceCounter(Trace.TRACE_TAG_POWER, "ALS", (int) lux);
Michael Wright639c8be2014-01-17 18:29:12 -0800481 mHandler.removeMessages(MSG_UPDATE_AMBIENT_LUX);
482
Julius D'souza5d717092016-10-24 19:26:45 -0700483 if (mAmbientLightRingBuffer.size() == 0) {
484 // switch to using the steady-state sample rate after grabbing the initial light sample
485 adjustLightSensorRate(mNormalLightSensorRate);
486 }
Michael Wright639c8be2014-01-17 18:29:12 -0800487 applyLightSensorMeasurement(time, lux);
488 updateAmbientLux(time);
489 }
490
491 private void applyLightSensorMeasurement(long time, float lux) {
492 mRecentLightSamples++;
Zoran Jovanovic6fc42f52015-12-10 17:01:16 +0100493 mAmbientLightRingBuffer.prune(time - mAmbientLightHorizon);
Michael Wright639c8be2014-01-17 18:29:12 -0800494 mAmbientLightRingBuffer.push(time, lux);
495
496 // Remember this sample value.
497 mLastObservedLux = lux;
498 mLastObservedLuxTime = time;
499 }
500
Julius D'souza5d717092016-10-24 19:26:45 -0700501 private void adjustLightSensorRate(int lightSensorRate) {
502 // if the light sensor rate changed, update the sensor listener
503 if (lightSensorRate != mCurrentLightSensorRate) {
Dan Gittika5a2d632019-01-09 14:25:29 +0000504 if (mLoggingEnabled) {
Dan Gittikc5d32912018-02-22 13:53:47 +0000505 Slog.d(TAG, "adjustLightSensorRate: " +
Dan Gittik57d6f112018-03-27 18:14:22 +0100506 "previousRate=" + mCurrentLightSensorRate + ", " +
507 "currentRate=" + lightSensorRate);
Julius D'souza5d717092016-10-24 19:26:45 -0700508 }
509 mCurrentLightSensorRate = lightSensorRate;
510 mSensorManager.unregisterListener(mLightSensorListener);
511 mSensorManager.registerListener(mLightSensorListener, mLightSensor,
512 lightSensorRate * 1000, mHandler);
513 }
514 }
515
Dan Gittik57d6f112018-03-27 18:14:22 +0100516 private boolean setAutoBrightnessAdjustment(float adjustment) {
517 return mBrightnessMapper.setAutoBrightnessAdjustment(adjustment);
Michael Wright639c8be2014-01-17 18:29:12 -0800518 }
519
520 private void setAmbientLux(float lux) {
Dan Gittika5a2d632019-01-09 14:25:29 +0000521 if (mLoggingEnabled) {
Michael Wright0a933142017-08-16 20:38:21 +0100522 Slog.d(TAG, "setAmbientLux(" + lux + ")");
523 }
Michael Wrightd8460232018-01-16 18:04:59 +0000524 if (lux < 0) {
Dan Gittikc5d32912018-02-22 13:53:47 +0000525 Slog.w(TAG, "Ambient lux was negative, ignoring and setting to 0");
Michael Wrightd8460232018-01-16 18:04:59 +0000526 lux = 0;
527 }
Michael Wright639c8be2014-01-17 18:29:12 -0800528 mAmbientLux = lux;
Dan Gittiked958e92018-11-13 14:58:20 +0000529 mAmbientBrighteningThreshold = mAmbientBrightnessThresholds.getBrighteningThreshold(lux);
530 mAmbientDarkeningThreshold = mAmbientBrightnessThresholds.getDarkeningThreshold(lux);
Dan Gittikc5d32912018-02-22 13:53:47 +0000531
532 // If the short term model was invalidated and the change is drastic enough, reset it.
533 if (!mShortTermModelValid && mShortTermModelAnchor != -1) {
534 final float minAmbientLux =
535 mShortTermModelAnchor - mShortTermModelAnchor * SHORT_TERM_MODEL_THRESHOLD_RATIO;
536 final float maxAmbientLux =
537 mShortTermModelAnchor + mShortTermModelAnchor * SHORT_TERM_MODEL_THRESHOLD_RATIO;
538 if (minAmbientLux < mAmbientLux && mAmbientLux < maxAmbientLux) {
Dan Gittika5a2d632019-01-09 14:25:29 +0000539 if (mLoggingEnabled) {
Dan Gittik57d6f112018-03-27 18:14:22 +0100540 Slog.d(TAG, "ShortTermModel: re-validate user data, ambient lux is " +
541 minAmbientLux + " < " + mAmbientLux + " < " + maxAmbientLux);
542 }
Dan Gittikc5d32912018-02-22 13:53:47 +0000543 mShortTermModelValid = true;
544 } else {
545 Slog.d(TAG, "ShortTermModel: reset data, ambient lux is " + mAmbientLux +
Dan Gittik57d6f112018-03-27 18:14:22 +0100546 "(" + minAmbientLux + ", " + maxAmbientLux + ")");
Dan Gittikc5d32912018-02-22 13:53:47 +0000547 resetShortTermModel();
548 }
549 }
Michael Wright639c8be2014-01-17 18:29:12 -0800550 }
551
Michael Wright0a933142017-08-16 20:38:21 +0100552 private float calculateAmbientLux(long now, long horizon) {
Dan Gittika5a2d632019-01-09 14:25:29 +0000553 if (mLoggingEnabled) {
Michael Wright0a933142017-08-16 20:38:21 +0100554 Slog.d(TAG, "calculateAmbientLux(" + now + ", " + horizon + ")");
555 }
Michael Wright639c8be2014-01-17 18:29:12 -0800556 final int N = mAmbientLightRingBuffer.size();
557 if (N == 0) {
558 Slog.e(TAG, "calculateAmbientLux: No ambient light readings available");
559 return -1;
560 }
Michael Wright0a933142017-08-16 20:38:21 +0100561
562 // Find the first measurement that is just outside of the horizon.
563 int endIndex = 0;
564 final long horizonStartTime = now - horizon;
565 for (int i = 0; i < N-1; i++) {
566 if (mAmbientLightRingBuffer.getTime(i + 1) <= horizonStartTime) {
567 endIndex++;
568 } else {
569 break;
570 }
571 }
Dan Gittika5a2d632019-01-09 14:25:29 +0000572 if (mLoggingEnabled) {
Dan Gittik57d6f112018-03-27 18:14:22 +0100573 Slog.d(TAG, "calculateAmbientLux: selected endIndex=" + endIndex + ", point=(" +
574 mAmbientLightRingBuffer.getTime(endIndex) + ", " +
575 mAmbientLightRingBuffer.getLux(endIndex) + ")");
Michael Wright0a933142017-08-16 20:38:21 +0100576 }
Michael Wright639c8be2014-01-17 18:29:12 -0800577 float sum = 0;
578 float totalWeight = 0;
579 long endTime = AMBIENT_LIGHT_PREDICTION_TIME_MILLIS;
Michael Wright0a933142017-08-16 20:38:21 +0100580 for (int i = N - 1; i >= endIndex; i--) {
581 long eventTime = mAmbientLightRingBuffer.getTime(i);
582 if (i == endIndex && eventTime < horizonStartTime) {
583 // If we're at the final value, make sure we only consider the part of the sample
584 // within our desired horizon.
585 eventTime = horizonStartTime;
586 }
587 final long startTime = eventTime - now;
Michael Wright639c8be2014-01-17 18:29:12 -0800588 float weight = calculateWeight(startTime, endTime);
589 float lux = mAmbientLightRingBuffer.getLux(i);
Dan Gittika5a2d632019-01-09 14:25:29 +0000590 if (mLoggingEnabled) {
Dan Gittikc5d32912018-02-22 13:53:47 +0000591 Slog.d(TAG, "calculateAmbientLux: [" + startTime + ", " + endTime + "]: " +
Dan Gittik57d6f112018-03-27 18:14:22 +0100592 "lux=" + lux + ", " +
593 "weight=" + weight);
Michael Wright639c8be2014-01-17 18:29:12 -0800594 }
595 totalWeight += weight;
Dan Gittikc5d32912018-02-22 13:53:47 +0000596 sum += lux * weight;
Michael Wright639c8be2014-01-17 18:29:12 -0800597 endTime = startTime;
598 }
Dan Gittika5a2d632019-01-09 14:25:29 +0000599 if (mLoggingEnabled) {
Dan Gittikc5d32912018-02-22 13:53:47 +0000600 Slog.d(TAG, "calculateAmbientLux: " +
Dan Gittik57d6f112018-03-27 18:14:22 +0100601 "totalWeight=" + totalWeight + ", " +
602 "newAmbientLux=" + (sum / totalWeight));
Michael Wright639c8be2014-01-17 18:29:12 -0800603 }
604 return sum / totalWeight;
605 }
606
Zoran Jovanovic6fc42f52015-12-10 17:01:16 +0100607 private float calculateWeight(long startDelta, long endDelta) {
Michael Wright639c8be2014-01-17 18:29:12 -0800608 return weightIntegral(endDelta) - weightIntegral(startDelta);
609 }
610
Zoran Jovanovic6fc42f52015-12-10 17:01:16 +0100611 // Evaluates the integral of y = x + mWeightingIntercept. This is always positive for the
Michael Wright639c8be2014-01-17 18:29:12 -0800612 // horizon we're looking at and provides a non-linear weighting for light samples.
Zoran Jovanovic6fc42f52015-12-10 17:01:16 +0100613 private float weightIntegral(long x) {
614 return x * (x * 0.5f + mWeightingIntercept);
Michael Wright639c8be2014-01-17 18:29:12 -0800615 }
616
617 private long nextAmbientLightBrighteningTransition(long time) {
618 final int N = mAmbientLightRingBuffer.size();
619 long earliestValidTime = time;
620 for (int i = N - 1; i >= 0; i--) {
Dan Gittiked958e92018-11-13 14:58:20 +0000621 if (mAmbientLightRingBuffer.getLux(i) <= mAmbientBrighteningThreshold) {
Michael Wright639c8be2014-01-17 18:29:12 -0800622 break;
623 }
624 earliestValidTime = mAmbientLightRingBuffer.getTime(i);
625 }
Filip Gruszczynskid81ecd12015-02-06 12:38:47 -0800626 return earliestValidTime + mBrighteningLightDebounceConfig;
Michael Wright639c8be2014-01-17 18:29:12 -0800627 }
628
629 private long nextAmbientLightDarkeningTransition(long time) {
630 final int N = mAmbientLightRingBuffer.size();
631 long earliestValidTime = time;
632 for (int i = N - 1; i >= 0; i--) {
Dan Gittiked958e92018-11-13 14:58:20 +0000633 if (mAmbientLightRingBuffer.getLux(i) >= mAmbientDarkeningThreshold) {
Michael Wright639c8be2014-01-17 18:29:12 -0800634 break;
635 }
636 earliestValidTime = mAmbientLightRingBuffer.getTime(i);
637 }
Filip Gruszczynskid81ecd12015-02-06 12:38:47 -0800638 return earliestValidTime + mDarkeningLightDebounceConfig;
Michael Wright639c8be2014-01-17 18:29:12 -0800639 }
640
641 private void updateAmbientLux() {
642 long time = SystemClock.uptimeMillis();
Zoran Jovanovic6fc42f52015-12-10 17:01:16 +0100643 mAmbientLightRingBuffer.prune(time - mAmbientLightHorizon);
Michael Wright639c8be2014-01-17 18:29:12 -0800644 updateAmbientLux(time);
645 }
646
647 private void updateAmbientLux(long time) {
648 // If the light sensor was just turned on then immediately update our initial
649 // estimate of the current ambient light level.
650 if (!mAmbientLuxValid) {
651 final long timeWhenSensorWarmedUp =
652 mLightSensorWarmUpTimeConfig + mLightSensorEnableTime;
653 if (time < timeWhenSensorWarmedUp) {
Dan Gittika5a2d632019-01-09 14:25:29 +0000654 if (mLoggingEnabled) {
Kenny Guyb54d40b2019-02-28 12:49:53 +0000655 Slog.d(TAG, "updateAmbientLux: Sensor not ready yet: "
656 + "time=" + time + ", "
657 + "timeWhenSensorWarmedUp=" + timeWhenSensorWarmedUp);
Michael Wright639c8be2014-01-17 18:29:12 -0800658 }
659 mHandler.sendEmptyMessageAtTime(MSG_UPDATE_AMBIENT_LUX,
660 timeWhenSensorWarmedUp);
661 return;
662 }
Michael Wright0a933142017-08-16 20:38:21 +0100663 setAmbientLux(calculateAmbientLux(time, AMBIENT_LIGHT_SHORT_HORIZON_MILLIS));
Michael Wright639c8be2014-01-17 18:29:12 -0800664 mAmbientLuxValid = true;
Dan Gittika5a2d632019-01-09 14:25:29 +0000665 if (mLoggingEnabled) {
Dan Gittikc5d32912018-02-22 13:53:47 +0000666 Slog.d(TAG, "updateAmbientLux: Initializing: " +
667 "mAmbientLightRingBuffer=" + mAmbientLightRingBuffer + ", " +
668 "mAmbientLux=" + mAmbientLux);
Michael Wright639c8be2014-01-17 18:29:12 -0800669 }
Santos Cordon4acbedb2019-06-07 17:20:41 +0100670 updateAutoBrightness(true /* sendUpdate */, false /* isManuallySet */);
Michael Wright639c8be2014-01-17 18:29:12 -0800671 }
672
673 long nextBrightenTransition = nextAmbientLightBrighteningTransition(time);
674 long nextDarkenTransition = nextAmbientLightDarkeningTransition(time);
Michael Wright0a933142017-08-16 20:38:21 +0100675 // Essentially, we calculate both a slow ambient lux, to ensure there's a true long-term
676 // change in lighting conditions, and a fast ambient lux to determine what the new
677 // brightness situation is since the slow lux can be quite slow to converge.
678 //
679 // Note that both values need to be checked for sufficient change before updating the
680 // proposed ambient light value since the slow value might be sufficiently far enough away
681 // from the fast value to cause a recalculation while its actually just converging on
682 // the fast value still.
683 float slowAmbientLux = calculateAmbientLux(time, AMBIENT_LIGHT_LONG_HORIZON_MILLIS);
684 float fastAmbientLux = calculateAmbientLux(time, AMBIENT_LIGHT_SHORT_HORIZON_MILLIS);
Michael Wright639c8be2014-01-17 18:29:12 -0800685
Dan Gittiked958e92018-11-13 14:58:20 +0000686 if ((slowAmbientLux >= mAmbientBrighteningThreshold
687 && fastAmbientLux >= mAmbientBrighteningThreshold
688 && nextBrightenTransition <= time)
689 || (slowAmbientLux <= mAmbientDarkeningThreshold
690 && fastAmbientLux <= mAmbientDarkeningThreshold
691 && nextDarkenTransition <= time)) {
Michael Wright0a933142017-08-16 20:38:21 +0100692 setAmbientLux(fastAmbientLux);
Dan Gittika5a2d632019-01-09 14:25:29 +0000693 if (mLoggingEnabled) {
Dan Gittiked958e92018-11-13 14:58:20 +0000694 Slog.d(TAG, "updateAmbientLux: "
695 + ((fastAmbientLux > mAmbientLux) ? "Brightened" : "Darkened") + ": "
Dan Gittika5a2d632019-01-09 14:25:29 +0000696 + "mBrighteningLuxThreshold=" + mAmbientBrighteningThreshold + ", "
Dan Gittiked958e92018-11-13 14:58:20 +0000697 + "mAmbientLightRingBuffer=" + mAmbientLightRingBuffer + ", "
698 + "mAmbientLux=" + mAmbientLux);
Michael Wright639c8be2014-01-17 18:29:12 -0800699 }
Santos Cordon4acbedb2019-06-07 17:20:41 +0100700 updateAutoBrightness(true /* sendUpdate */, false /* isManuallySet */);
Michael Wright639c8be2014-01-17 18:29:12 -0800701 nextBrightenTransition = nextAmbientLightBrighteningTransition(time);
702 nextDarkenTransition = nextAmbientLightDarkeningTransition(time);
703 }
704 long nextTransitionTime = Math.min(nextDarkenTransition, nextBrightenTransition);
705 // If one of the transitions is ready to occur, but the total weighted ambient lux doesn't
706 // exceed the necessary threshold, then it's possible we'll get a transition time prior to
707 // now. Rather than continually checking to see whether the weighted lux exceeds the
708 // threshold, schedule an update for when we'd normally expect another light sample, which
709 // should be enough time to decide whether we should actually transition to the new
710 // weighted ambient lux or not.
711 nextTransitionTime =
Julius D'souza5d717092016-10-24 19:26:45 -0700712 nextTransitionTime > time ? nextTransitionTime : time + mNormalLightSensorRate;
Dan Gittika5a2d632019-01-09 14:25:29 +0000713 if (mLoggingEnabled) {
Dan Gittikc5d32912018-02-22 13:53:47 +0000714 Slog.d(TAG, "updateAmbientLux: Scheduling ambient lux update for " +
Dan Gittik57d6f112018-03-27 18:14:22 +0100715 nextTransitionTime + TimeUtils.formatUptime(nextTransitionTime));
Michael Wright639c8be2014-01-17 18:29:12 -0800716 }
717 mHandler.sendEmptyMessageAtTime(MSG_UPDATE_AMBIENT_LUX, nextTransitionTime);
718 }
719
Santos Cordon4acbedb2019-06-07 17:20:41 +0100720 private void updateAutoBrightness(boolean sendUpdate, boolean isManuallySet) {
Michael Wright639c8be2014-01-17 18:29:12 -0800721 if (!mAmbientLuxValid) {
722 return;
723 }
724
Dan Gittika5a2d632019-01-09 14:25:29 +0000725 float value = mBrightnessMapper.getBrightness(mAmbientLux, mForegroundAppPackageName,
726 mForegroundAppCategory);
Michael Wright639c8be2014-01-17 18:29:12 -0800727
728 int newScreenAutoBrightness =
Jeff Browna576b4d2015-04-23 19:58:06 -0700729 clampScreenBrightness(Math.round(value * PowerManager.BRIGHTNESS_ON));
Dan Gittiked958e92018-11-13 14:58:20 +0000730
731 // If screenAutoBrightness is set, we should have screen{Brightening,Darkening}Threshold,
732 // in which case we ignore the new screen brightness if it doesn't differ enough from the
733 // previous one.
734 if (mScreenAutoBrightness != -1
Santos Cordon4acbedb2019-06-07 17:20:41 +0100735 && !isManuallySet
Dan Gittiked958e92018-11-13 14:58:20 +0000736 && newScreenAutoBrightness > mScreenDarkeningThreshold
737 && newScreenAutoBrightness < mScreenBrighteningThreshold) {
Dan Gittika5a2d632019-01-09 14:25:29 +0000738 if (mLoggingEnabled) {
Dan Gittiked958e92018-11-13 14:58:20 +0000739 Slog.d(TAG, "ignoring newScreenAutoBrightness: " + mScreenDarkeningThreshold
740 + " < " + newScreenAutoBrightness + " < " + mScreenBrighteningThreshold);
741 }
742 return;
743 }
744
Michael Wright639c8be2014-01-17 18:29:12 -0800745 if (mScreenAutoBrightness != newScreenAutoBrightness) {
Dan Gittika5a2d632019-01-09 14:25:29 +0000746 if (mLoggingEnabled) {
Dan Gittikc5d32912018-02-22 13:53:47 +0000747 Slog.d(TAG, "updateAutoBrightness: " +
Dan Gittik57d6f112018-03-27 18:14:22 +0100748 "mScreenAutoBrightness=" + mScreenAutoBrightness + ", " +
749 "newScreenAutoBrightness=" + newScreenAutoBrightness);
Michael Wright639c8be2014-01-17 18:29:12 -0800750 }
751
752 mScreenAutoBrightness = newScreenAutoBrightness;
Dan Gittiked958e92018-11-13 14:58:20 +0000753 mScreenBrighteningThreshold =
754 mScreenBrightnessThresholds.getBrighteningThreshold(newScreenAutoBrightness);
755 mScreenDarkeningThreshold =
756 mScreenBrightnessThresholds.getDarkeningThreshold(newScreenAutoBrightness);
757
Michael Wright639c8be2014-01-17 18:29:12 -0800758 if (sendUpdate) {
759 mCallbacks.updateBrightness();
760 }
761 }
762 }
763
764 private int clampScreenBrightness(int value) {
765 return MathUtils.constrain(value,
766 mScreenBrightnessRangeMinimum, mScreenBrightnessRangeMaximum);
767 }
768
Jeff Browna576b4d2015-04-23 19:58:06 -0700769 private void prepareBrightnessAdjustmentSample() {
770 if (!mBrightnessAdjustmentSamplePending) {
771 mBrightnessAdjustmentSamplePending = true;
Jeff Browna576b4d2015-04-23 19:58:06 -0700772 mBrightnessAdjustmentSampleOldLux = mAmbientLuxValid ? mAmbientLux : -1;
773 mBrightnessAdjustmentSampleOldBrightness = mScreenAutoBrightness;
Jeff Browna576b4d2015-04-23 19:58:06 -0700774 } else {
775 mHandler.removeMessages(MSG_BRIGHTNESS_ADJUSTMENT_SAMPLE);
776 }
777
778 mHandler.sendEmptyMessageDelayed(MSG_BRIGHTNESS_ADJUSTMENT_SAMPLE,
779 BRIGHTNESS_ADJUSTMENT_SAMPLE_DEBOUNCE_MILLIS);
780 }
781
Sudheer Shankab3f60652019-01-04 20:30:14 +0000782 private void cancelBrightnessAdjustmentSample() {
783 if (mBrightnessAdjustmentSamplePending) {
784 mBrightnessAdjustmentSamplePending = false;
785 mHandler.removeMessages(MSG_BRIGHTNESS_ADJUSTMENT_SAMPLE);
786 }
787 }
788
Jeff Browna576b4d2015-04-23 19:58:06 -0700789 private void collectBrightnessAdjustmentSample() {
790 if (mBrightnessAdjustmentSamplePending) {
791 mBrightnessAdjustmentSamplePending = false;
792 if (mAmbientLuxValid && mScreenAutoBrightness >= 0) {
Dan Gittika5a2d632019-01-09 14:25:29 +0000793 if (mLoggingEnabled) {
Dan Gittikc5d32912018-02-22 13:53:47 +0000794 Slog.d(TAG, "Auto-brightness adjustment changed by user: " +
Dan Gittik57d6f112018-03-27 18:14:22 +0100795 "lux=" + mAmbientLux + ", " +
796 "brightness=" + mScreenAutoBrightness + ", " +
797 "ring=" + mAmbientLightRingBuffer);
Jeff Browna576b4d2015-04-23 19:58:06 -0700798 }
799
800 EventLog.writeEvent(EventLogTags.AUTO_BRIGHTNESS_ADJ,
Jeff Browna576b4d2015-04-23 19:58:06 -0700801 mBrightnessAdjustmentSampleOldLux,
802 mBrightnessAdjustmentSampleOldBrightness,
Jeff Browna576b4d2015-04-23 19:58:06 -0700803 mAmbientLux,
Dan Gittik57d6f112018-03-27 18:14:22 +0100804 mScreenAutoBrightness);
Jeff Browna576b4d2015-04-23 19:58:06 -0700805 }
806 }
807 }
808
Dan Gittika5a2d632019-01-09 14:25:29 +0000809 // Register a TaskStackListener to call back to us onTaskStackChanged, so we can update the
810 // foreground app's package name and category and correct the brightness accordingly.
811 private void registerForegroundAppUpdater() {
812 try {
813 mActivityTaskManager.registerTaskStackListener(mTaskStackListener);
814 // This will not get called until the foreground app changes for the first time, so
815 // call it explicitly to get the current foreground app's info.
816 updateForegroundApp();
817 } catch (RemoteException e) {
818 if (mLoggingEnabled) {
819 Slog.e(TAG, "Failed to register foreground app updater: " + e);
820 }
821 // Nothing to do.
822 }
823 }
824
825 private void unregisterForegroundAppUpdater() {
826 try {
827 mActivityTaskManager.unregisterTaskStackListener(mTaskStackListener);
828 } catch (RemoteException e) {
829 // Nothing to do.
830 }
831 mForegroundAppPackageName = null;
832 mForegroundAppCategory = ApplicationInfo.CATEGORY_UNDEFINED;
833 }
834
835 // Set the foreground app's package name and category, so brightness can be corrected per app.
836 private void updateForegroundApp() {
837 if (mLoggingEnabled) {
838 Slog.d(TAG, "Attempting to update foreground app");
839 }
840 // The ActivityTaskManager's lock tends to get contended, so this is done in a background
841 // thread and applied via this thread's handler synchronously.
842 BackgroundThread.getHandler().post(new Runnable() {
843 public void run() {
844 try {
845 // The foreground app is the top activity of the focused tasks stack.
846 final StackInfo info = mActivityTaskManager.getFocusedStackInfo();
847 if (info == null || info.topActivity == null) {
848 return;
849 }
850 final String packageName = info.topActivity.getPackageName();
851 // If the app didn't change, there's nothing to do. Otherwise, we have to
852 // update the category and re-apply the brightness correction.
853 if (mForegroundAppPackageName != null
854 && mForegroundAppPackageName.equals(packageName)) {
855 return;
856 }
857 mPendingForegroundAppPackageName = packageName;
858 mPendingForegroundAppCategory = ApplicationInfo.CATEGORY_UNDEFINED;
859 try {
860 ApplicationInfo app = mPackageManager.getApplicationInfo(packageName,
861 PackageManager.MATCH_ANY_USER);
862 mPendingForegroundAppCategory = app.category;
863 } catch (PackageManager.NameNotFoundException e) {
864 // Nothing to do
865 }
866 mHandler.sendEmptyMessage(MSG_UPDATE_FOREGROUND_APP_SYNC);
867 } catch (RemoteException e) {
868 // Nothing to do
869 }
870 }
871 });
872 }
873
874 private void updateForegroundAppSync() {
875 if (mLoggingEnabled) {
876 Slog.d(TAG, "Updating foreground app: packageName=" + mPendingForegroundAppPackageName
877 + ", category=" + mPendingForegroundAppCategory);
878 }
879 mForegroundAppPackageName = mPendingForegroundAppPackageName;
880 mPendingForegroundAppPackageName = null;
881 mForegroundAppCategory = mPendingForegroundAppCategory;
882 mPendingForegroundAppCategory = ApplicationInfo.CATEGORY_UNDEFINED;
Santos Cordon4acbedb2019-06-07 17:20:41 +0100883 updateAutoBrightness(true /* sendUpdate */, false /* isManuallySet */);
Dan Gittika5a2d632019-01-09 14:25:29 +0000884 }
885
Michael Wright639c8be2014-01-17 18:29:12 -0800886 private final class AutomaticBrightnessHandler extends Handler {
887 public AutomaticBrightnessHandler(Looper looper) {
888 super(looper, null, true /*async*/);
889 }
890
891 @Override
892 public void handleMessage(Message msg) {
893 switch (msg.what) {
894 case MSG_UPDATE_AMBIENT_LUX:
895 updateAmbientLux();
896 break;
Jeff Browna576b4d2015-04-23 19:58:06 -0700897
898 case MSG_BRIGHTNESS_ADJUSTMENT_SAMPLE:
899 collectBrightnessAdjustmentSample();
900 break;
Michael Wrightd8460232018-01-16 18:04:59 +0000901
Dan Gittikc5d32912018-02-22 13:53:47 +0000902 case MSG_INVALIDATE_SHORT_TERM_MODEL:
903 invalidateShortTermModel();
Michael Wrightd8460232018-01-16 18:04:59 +0000904 break;
Dan Gittika5a2d632019-01-09 14:25:29 +0000905
906 case MSG_UPDATE_FOREGROUND_APP:
907 updateForegroundApp();
908 break;
909
910 case MSG_UPDATE_FOREGROUND_APP_SYNC:
911 updateForegroundAppSync();
912 break;
Michael Wright639c8be2014-01-17 18:29:12 -0800913 }
914 }
915 }
916
917 private final SensorEventListener mLightSensorListener = new SensorEventListener() {
918 @Override
919 public void onSensorChanged(SensorEvent event) {
920 if (mLightSensorEnabled) {
921 final long time = SystemClock.uptimeMillis();
922 final float lux = event.values[0];
923 handleLightSensorEvent(time, lux);
924 }
925 }
926
927 @Override
928 public void onAccuracyChanged(Sensor sensor, int accuracy) {
929 // Not used.
930 }
931 };
932
Dan Gittika5a2d632019-01-09 14:25:29 +0000933 // Call back whenever the tasks stack changes, which includes tasks being created, removed, and
934 // moving to top.
935 class TaskStackListenerImpl extends TaskStackListener {
936 @Override
937 public void onTaskStackChanged() {
938 mHandler.sendEmptyMessage(MSG_UPDATE_FOREGROUND_APP);
939 }
940 }
941
Michael Wright639c8be2014-01-17 18:29:12 -0800942 /** Callbacks to request updates to the display's power state. */
943 interface Callbacks {
944 void updateBrightness();
945 }
946
Michael Wright0a933142017-08-16 20:38:21 +0100947 /**
948 * A ring buffer of ambient light measurements sorted by time.
949 *
950 * Each entry consists of a timestamp and a lux measurement, and the overall buffer is sorted
951 * from oldest to newest.
952 */
Michael Wright103fb782016-04-22 01:03:09 -0400953 private static final class AmbientLightRingBuffer {
Michael Wright639c8be2014-01-17 18:29:12 -0800954 // Proportional extra capacity of the buffer beyond the expected number of light samples
955 // in the horizon
956 private static final float BUFFER_SLACK = 1.5f;
Michael Wright639c8be2014-01-17 18:29:12 -0800957 private float[] mRingLux;
958 private long[] mRingTime;
959 private int mCapacity;
960
961 // The first valid element and the next open slot.
962 // Note that if mCount is zero then there are no valid elements.
963 private int mStart;
964 private int mEnd;
965 private int mCount;
966
Zoran Jovanovic6fc42f52015-12-10 17:01:16 +0100967 public AmbientLightRingBuffer(long lightSensorRate, int ambientLightHorizon) {
968 mCapacity = (int) Math.ceil(ambientLightHorizon * BUFFER_SLACK / lightSensorRate);
Michael Wright639c8be2014-01-17 18:29:12 -0800969 mRingLux = new float[mCapacity];
970 mRingTime = new long[mCapacity];
971 }
972
973 public float getLux(int index) {
974 return mRingLux[offsetOf(index)];
975 }
976
977 public long getTime(int index) {
978 return mRingTime[offsetOf(index)];
979 }
980
981 public void push(long time, float lux) {
982 int next = mEnd;
983 if (mCount == mCapacity) {
984 int newSize = mCapacity * 2;
985
986 float[] newRingLux = new float[newSize];
987 long[] newRingTime = new long[newSize];
988 int length = mCapacity - mStart;
989 System.arraycopy(mRingLux, mStart, newRingLux, 0, length);
990 System.arraycopy(mRingTime, mStart, newRingTime, 0, length);
991 if (mStart != 0) {
992 System.arraycopy(mRingLux, 0, newRingLux, length, mStart);
993 System.arraycopy(mRingTime, 0, newRingTime, length, mStart);
994 }
995 mRingLux = newRingLux;
996 mRingTime = newRingTime;
997
998 next = mCapacity;
999 mCapacity = newSize;
1000 mStart = 0;
1001 }
1002 mRingTime[next] = time;
1003 mRingLux[next] = lux;
1004 mEnd = next + 1;
1005 if (mEnd == mCapacity) {
1006 mEnd = 0;
1007 }
1008 mCount++;
1009 }
1010
1011 public void prune(long horizon) {
1012 if (mCount == 0) {
1013 return;
1014 }
1015
1016 while (mCount > 1) {
1017 int next = mStart + 1;
1018 if (next >= mCapacity) {
1019 next -= mCapacity;
1020 }
1021 if (mRingTime[next] > horizon) {
1022 // Some light sensors only produce data upon a change in the ambient light
1023 // levels, so we need to consider the previous measurement as the ambient light
1024 // level for all points in time up until we receive a new measurement. Thus, we
1025 // always want to keep the youngest element that would be removed from the
1026 // buffer and just set its measurement time to the horizon time since at that
1027 // point it is the ambient light level, and to remove it would be to drop a
1028 // valid data point within our horizon.
1029 break;
1030 }
1031 mStart = next;
1032 mCount -= 1;
1033 }
1034
1035 if (mRingTime[mStart] < horizon) {
1036 mRingTime[mStart] = horizon;
1037 }
1038 }
1039
1040 public int size() {
1041 return mCount;
1042 }
1043
Michael Wright639c8be2014-01-17 18:29:12 -08001044 public void clear() {
1045 mStart = 0;
1046 mEnd = 0;
1047 mCount = 0;
1048 }
1049
1050 @Override
1051 public String toString() {
Jeff Browna576b4d2015-04-23 19:58:06 -07001052 StringBuffer buf = new StringBuffer();
1053 buf.append('[');
1054 for (int i = 0; i < mCount; i++) {
1055 final long next = i + 1 < mCount ? getTime(i + 1) : SystemClock.uptimeMillis();
1056 if (i != 0) {
1057 buf.append(", ");
1058 }
1059 buf.append(getLux(i));
1060 buf.append(" / ");
1061 buf.append(next - getTime(i));
1062 buf.append("ms");
Michael Wright639c8be2014-01-17 18:29:12 -08001063 }
Jeff Browna576b4d2015-04-23 19:58:06 -07001064 buf.append(']');
1065 return buf.toString();
Michael Wright639c8be2014-01-17 18:29:12 -08001066 }
1067
1068 private int offsetOf(int index) {
1069 if (index >= mCount || index < 0) {
1070 throw new ArrayIndexOutOfBoundsException(index);
1071 }
1072 index += mStart;
1073 if (index >= mCapacity) {
1074 index -= mCapacity;
1075 }
1076 return index;
1077 }
1078 }
1079}