blob: c99774a41f104cd81fb1c522aa583cbedcc8ab95 [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
Santos Cordon64a86272019-11-28 11:24:21 +000044import com.android.internal.annotations.VisibleForTesting;
Dan Gittika5a2d632019-01-09 14:25:29 +000045import com.android.internal.os.BackgroundThread;
Dan Gittiked958e92018-11-13 14:58:20 +000046import com.android.server.EventLogTags;
47
Michael Wright639c8be2014-01-17 18:29:12 -080048import java.io.PrintWriter;
Michael Wright639c8be2014-01-17 18:29:12 -080049
50class AutomaticBrightnessController {
51 private static final String TAG = "AutomaticBrightnessController";
52
Michael Wright639c8be2014-01-17 18:29:12 -080053 private static final boolean DEBUG_PRETEND_LIGHT_SENSOR_ABSENT = false;
54
Michael Wright639c8be2014-01-17 18:29:12 -080055 // How long the current sensor reading is assumed to be valid beyond the current time.
56 // This provides a bit of prediction, as well as ensures that the weight for the last sample is
57 // non-zero, which in turn ensures that the total weight is non-zero.
58 private static final long AMBIENT_LIGHT_PREDICTION_TIME_MILLIS = 100;
59
Jeff Browna576b4d2015-04-23 19:58:06 -070060 // Debounce for sampling user-initiated changes in display brightness to ensure
61 // the user is satisfied with the result before storing the sample.
62 private static final int BRIGHTNESS_ADJUSTMENT_SAMPLE_DEBOUNCE_MILLIS = 10000;
63
Michael Wright639c8be2014-01-17 18:29:12 -080064 private static final int MSG_UPDATE_AMBIENT_LUX = 1;
Jeff Browna576b4d2015-04-23 19:58:06 -070065 private static final int MSG_BRIGHTNESS_ADJUSTMENT_SAMPLE = 2;
Dan Gittikc5d32912018-02-22 13:53:47 +000066 private static final int MSG_INVALIDATE_SHORT_TERM_MODEL = 3;
Dan Gittika5a2d632019-01-09 14:25:29 +000067 private static final int MSG_UPDATE_FOREGROUND_APP = 4;
68 private static final int MSG_UPDATE_FOREGROUND_APP_SYNC = 5;
Michael Wright639c8be2014-01-17 18:29:12 -080069
Michael Wright0a933142017-08-16 20:38:21 +010070 // Length of the ambient light horizon used to calculate the long term estimate of ambient
71 // light.
72 private static final int AMBIENT_LIGHT_LONG_HORIZON_MILLIS = 10000;
73
74 // Length of the ambient light horizon used to calculate short-term estimate of ambient light.
75 private static final int AMBIENT_LIGHT_SHORT_HORIZON_MILLIS = 2000;
76
Julius D'souza428aed02016-08-07 19:08:30 -070077 // Callbacks for requesting updates to the display's power state
Michael Wright639c8be2014-01-17 18:29:12 -080078 private final Callbacks mCallbacks;
79
80 // The sensor manager.
81 private final SensorManager mSensorManager;
82
83 // The light sensor, or null if not available or needed.
84 private final Sensor mLightSensor;
85
Michael Wrighteef0e132017-11-21 17:57:52 +000086 // The mapper to translate ambient lux to screen brightness in the range [0, 1.0].
87 private final BrightnessMappingStrategy mBrightnessMapper;
Michael Wright639c8be2014-01-17 18:29:12 -080088
89 // The minimum and maximum screen brightnesses.
90 private final int mScreenBrightnessRangeMinimum;
91 private final int mScreenBrightnessRangeMaximum;
Michael Wright2155bc22018-05-01 00:38:32 +010092
93 // How much to scale doze brightness by (should be (0, 1.0]).
Filip Gruszczynskia15aa7d2014-10-28 14:12:40 -070094 private final float mDozeScaleFactor;
Michael Wright639c8be2014-01-17 18:29:12 -080095
Julius D'souza5d717092016-10-24 19:26:45 -070096 // Initial light sensor event rate in milliseconds.
97 private final int mInitialLightSensorRate;
98
99 // Steady-state light sensor event rate in milliseconds.
100 private final int mNormalLightSensorRate;
101
102 // The current light sensor event rate in milliseconds.
103 private int mCurrentLightSensorRate;
Filip Gruszczynskid81ecd12015-02-06 12:38:47 -0800104
105 // Stability requirements in milliseconds for accepting a new brightness level. This is used
106 // for debouncing the light sensor. Different constants are used to debounce the light sensor
107 // when adapting to brighter or darker environments. This parameter controls how quickly
108 // brightness changes occur in response to an observed change in light level that exceeds the
109 // hysteresis threshold.
110 private final long mBrighteningLightDebounceConfig;
111 private final long mDarkeningLightDebounceConfig;
112
113 // If true immediately after the screen is turned on the controller will try to adjust the
114 // brightness based on the current sensor reads. If false, the controller will collect more data
115 // and only then decide whether to change brightness.
116 private final boolean mResetAmbientLuxAfterWarmUpConfig;
117
Zoran Jovanovic6fc42f52015-12-10 17:01:16 +0100118 // Period of time in which to consider light samples in milliseconds.
119 private final int mAmbientLightHorizon;
120
121 // The intercept used for the weighting calculation. This is used in order to keep all possible
122 // weighting values positive.
123 private final int mWeightingIntercept;
124
Michael Wright2155bc22018-05-01 00:38:32 +0100125 // Configuration object for determining thresholds to change brightness dynamically
Dan Gittiked958e92018-11-13 14:58:20 +0000126 private final HysteresisLevels mAmbientBrightnessThresholds;
127 private final HysteresisLevels mScreenBrightnessThresholds;
Julius D'souza428aed02016-08-07 19:08:30 -0700128
Dan Gittika5a2d632019-01-09 14:25:29 +0000129 private boolean mLoggingEnabled;
130
Michael Wright639c8be2014-01-17 18:29:12 -0800131 // Amount of time to delay auto-brightness after screen on while waiting for
132 // the light sensor to warm-up in milliseconds.
133 // May be 0 if no warm-up is required.
134 private int mLightSensorWarmUpTimeConfig;
135
136 // Set to true if the light sensor is enabled.
137 private boolean mLightSensorEnabled;
138
139 // The time when the light sensor was enabled.
140 private long mLightSensorEnableTime;
141
142 // The currently accepted nominal ambient light level.
143 private float mAmbientLux;
144
145 // True if mAmbientLux holds a valid value.
146 private boolean mAmbientLuxValid;
147
148 // The ambient light level threshold at which to brighten or darken the screen.
Dan Gittiked958e92018-11-13 14:58:20 +0000149 private float mAmbientBrighteningThreshold;
150 private float mAmbientDarkeningThreshold;
151
152 // The screen brightness threshold at which to brighten or darken the screen.
153 private float mScreenBrighteningThreshold;
154 private float mScreenDarkeningThreshold;
Michael Wright639c8be2014-01-17 18:29:12 -0800155
156 // The most recent light sample.
157 private float mLastObservedLux;
158
159 // The time of the most light recent sample.
160 private long mLastObservedLuxTime;
161
162 // The number of light samples collected since the light sensor was enabled.
163 private int mRecentLightSamples;
164
165 // A ring buffer containing all of the recent ambient light sensor readings.
166 private AmbientLightRingBuffer mAmbientLightRingBuffer;
167
168 // The handler
169 private AutomaticBrightnessHandler mHandler;
170
171 // The screen brightness level that has been chosen by the auto-brightness
172 // algorithm. The actual brightness should ramp towards this value.
173 // We preserve this value even when we stop using the light sensor so
174 // that we can quickly revert to the previous auto-brightness level
175 // while the light sensor warms up.
176 // Use -1 if there is no current auto-brightness value available.
177 private int mScreenAutoBrightness = -1;
178
Michael Wrightd8460232018-01-16 18:04:59 +0000179 // The current display policy. This is useful, for example, for knowing when we're dozing,
180 // where the light sensor may not be available.
181 private int mDisplayPolicy = DisplayPowerRequest.POLICY_OFF;
Filip Gruszczynskia15aa7d2014-10-28 14:12:40 -0700182
Jeff Browna576b4d2015-04-23 19:58:06 -0700183 // True if we are collecting a brightness adjustment sample, along with some data
184 // for the initial state of the sample.
185 private boolean mBrightnessAdjustmentSamplePending;
Jeff Browna576b4d2015-04-23 19:58:06 -0700186 private float mBrightnessAdjustmentSampleOldLux;
187 private int mBrightnessAdjustmentSampleOldBrightness;
Jeff Browna576b4d2015-04-23 19:58:06 -0700188
Dan Gittikc5d32912018-02-22 13:53:47 +0000189 // When the short term model is invalidated, we don't necessarily reset it (i.e. clear the
190 // user's adjustment) immediately, but wait for a drastic enough change in the ambient light.
191 // The anchor determines what were the light levels when the user has set her preference, and
192 // we use a relative threshold to determine when to revert to the OEM curve.
193 private boolean mShortTermModelValid;
194 private float mShortTermModelAnchor;
Dan Gittikc5d32912018-02-22 13:53:47 +0000195
Dan Gittika5a2d632019-01-09 14:25:29 +0000196 // Context-sensitive brightness configurations require keeping track of the foreground app's
197 // package name and category, which is done by registering a TaskStackListener to call back to
198 // us onTaskStackChanged, and then using the ActivityTaskManager to get the foreground app's
199 // package namd and PackageManager to get its category (so might as well cache them).
200 private String mForegroundAppPackageName;
201 private String mPendingForegroundAppPackageName;
202 private @ApplicationInfo.Category int mForegroundAppCategory;
203 private @ApplicationInfo.Category int mPendingForegroundAppCategory;
204 private TaskStackListenerImpl mTaskStackListener;
205 private IActivityTaskManager mActivityTaskManager;
206 private PackageManager mPackageManager;
207
Santos Cordon64a86272019-11-28 11:24:21 +0000208 private final Injector mInjector;
209
210 AutomaticBrightnessController(Callbacks callbacks, Looper looper,
Michael Wrighte02db662019-03-08 21:24:36 +0000211 SensorManager sensorManager, Sensor lightSensor, BrightnessMappingStrategy mapper,
Dan Gittik57d6f112018-03-27 18:14:22 +0100212 int lightSensorWarmUpTime, int brightnessMin, int brightnessMax, float dozeScaleFactor,
Julius D'souza5d717092016-10-24 19:26:45 -0700213 int lightSensorRate, int initialLightSensorRate, long brighteningLightDebounceConfig,
Zoran Jovanovic6fc42f52015-12-10 17:01:16 +0100214 long darkeningLightDebounceConfig, boolean resetAmbientLuxAfterWarmUpConfig,
Dan Gittiked958e92018-11-13 14:58:20 +0000215 HysteresisLevels ambientBrightnessThresholds,
Kenny Guyb29fdf12019-12-04 12:57:04 +0000216 HysteresisLevels screenBrightnessThresholds,
Dan Gittika5a2d632019-01-09 14:25:29 +0000217 PackageManager packageManager) {
Santos Cordon64a86272019-11-28 11:24:21 +0000218 this(new Injector(), callbacks, looper, sensorManager, lightSensor, mapper,
219 lightSensorWarmUpTime, brightnessMin, brightnessMax, dozeScaleFactor,
220 lightSensorRate, initialLightSensorRate, brighteningLightDebounceConfig,
221 darkeningLightDebounceConfig, resetAmbientLuxAfterWarmUpConfig,
Kenny Guyb29fdf12019-12-04 12:57:04 +0000222 ambientBrightnessThresholds, screenBrightnessThresholds, packageManager);
Santos Cordon64a86272019-11-28 11:24:21 +0000223 }
224
225 @VisibleForTesting
226 AutomaticBrightnessController(Injector injector, Callbacks callbacks, Looper looper,
227 SensorManager sensorManager, Sensor lightSensor, BrightnessMappingStrategy mapper,
228 int lightSensorWarmUpTime, int brightnessMin, int brightnessMax, float dozeScaleFactor,
229 int lightSensorRate, int initialLightSensorRate, long brighteningLightDebounceConfig,
230 long darkeningLightDebounceConfig, boolean resetAmbientLuxAfterWarmUpConfig,
231 HysteresisLevels ambientBrightnessThresholds,
Kenny Guyb29fdf12019-12-04 12:57:04 +0000232 HysteresisLevels screenBrightnessThresholds,
Santos Cordon64a86272019-11-28 11:24:21 +0000233 PackageManager packageManager) {
234 mInjector = injector;
Michael Wright639c8be2014-01-17 18:29:12 -0800235 mCallbacks = callbacks;
Michael Wright639c8be2014-01-17 18:29:12 -0800236 mSensorManager = sensorManager;
Michael Wrighteef0e132017-11-21 17:57:52 +0000237 mBrightnessMapper = mapper;
Michael Wright639c8be2014-01-17 18:29:12 -0800238 mScreenBrightnessRangeMinimum = brightnessMin;
239 mScreenBrightnessRangeMaximum = brightnessMax;
240 mLightSensorWarmUpTimeConfig = lightSensorWarmUpTime;
Filip Gruszczynskia15aa7d2014-10-28 14:12:40 -0700241 mDozeScaleFactor = dozeScaleFactor;
Julius D'souza5d717092016-10-24 19:26:45 -0700242 mNormalLightSensorRate = lightSensorRate;
243 mInitialLightSensorRate = initialLightSensorRate;
244 mCurrentLightSensorRate = -1;
Filip Gruszczynskid81ecd12015-02-06 12:38:47 -0800245 mBrighteningLightDebounceConfig = brighteningLightDebounceConfig;
246 mDarkeningLightDebounceConfig = darkeningLightDebounceConfig;
247 mResetAmbientLuxAfterWarmUpConfig = resetAmbientLuxAfterWarmUpConfig;
Michael Wright2155bc22018-05-01 00:38:32 +0100248 mAmbientLightHorizon = AMBIENT_LIGHT_LONG_HORIZON_MILLIS;
249 mWeightingIntercept = AMBIENT_LIGHT_LONG_HORIZON_MILLIS;
Dan Gittiked958e92018-11-13 14:58:20 +0000250 mAmbientBrightnessThresholds = ambientBrightnessThresholds;
251 mScreenBrightnessThresholds = screenBrightnessThresholds;
Dan Gittikc5d32912018-02-22 13:53:47 +0000252 mShortTermModelValid = true;
253 mShortTermModelAnchor = -1;
Michael Wright639c8be2014-01-17 18:29:12 -0800254
255 mHandler = new AutomaticBrightnessHandler(looper);
Michael Wright103fb782016-04-22 01:03:09 -0400256 mAmbientLightRingBuffer =
Julius D'souza5d717092016-10-24 19:26:45 -0700257 new AmbientLightRingBuffer(mNormalLightSensorRate, mAmbientLightHorizon);
Michael Wright639c8be2014-01-17 18:29:12 -0800258
259 if (!DEBUG_PRETEND_LIGHT_SENSOR_ABSENT) {
Michael Wrighte02db662019-03-08 21:24:36 +0000260 mLightSensor = lightSensor;
Michael Wright639c8be2014-01-17 18:29:12 -0800261 }
Dan Gittika5a2d632019-01-09 14:25:29 +0000262
263 mActivityTaskManager = ActivityTaskManager.getService();
264 mPackageManager = packageManager;
265 mTaskStackListener = new TaskStackListenerImpl();
266 mForegroundAppPackageName = null;
267 mPendingForegroundAppPackageName = null;
268 mForegroundAppCategory = ApplicationInfo.CATEGORY_UNDEFINED;
269 mPendingForegroundAppCategory = ApplicationInfo.CATEGORY_UNDEFINED;
270 }
271
272 /**
273 * Enable/disable logging.
274 *
275 * @param loggingEnabled
276 * Whether logging should be on/off.
277 *
278 * @return Whether the method succeeded or not.
279 */
280 public boolean setLoggingEnabled(boolean loggingEnabled) {
281 if (mLoggingEnabled == loggingEnabled) {
282 return false;
283 }
284 mBrightnessMapper.setLoggingEnabled(loggingEnabled);
285 mLoggingEnabled = loggingEnabled;
286 return true;
Michael Wright639c8be2014-01-17 18:29:12 -0800287 }
288
289 public int getAutomaticScreenBrightness() {
Dan Gittik58784422018-04-05 12:30:38 +0100290 if (!mAmbientLuxValid) {
291 return -1;
292 }
Michael Wrightd8460232018-01-16 18:04:59 +0000293 if (mDisplayPolicy == DisplayPowerRequest.POLICY_DOZE) {
Filip Gruszczynskia15aa7d2014-10-28 14:12:40 -0700294 return (int) (mScreenAutoBrightness * mDozeScaleFactor);
295 }
Michael Wright639c8be2014-01-17 18:29:12 -0800296 return mScreenAutoBrightness;
297 }
298
Kenny Guyb54d40b2019-02-28 12:49:53 +0000299 public boolean hasValidAmbientLux() {
300 return mAmbientLuxValid;
301 }
302
Michael Wright617564f2018-01-25 22:20:54 +0000303 public float getAutomaticScreenBrightnessAdjustment() {
Dan Gittik57d6f112018-03-27 18:14:22 +0100304 return mBrightnessMapper.getAutoBrightnessAdjustment();
Michael Wright617564f2018-01-25 22:20:54 +0000305 }
306
Michael Wrighteef0e132017-11-21 17:57:52 +0000307 public void configure(boolean enable, @Nullable BrightnessConfiguration configuration,
Michael Wright617564f2018-01-25 22:20:54 +0000308 float brightness, boolean userChangedBrightness, float adjustment,
309 boolean userChangedAutoBrightnessAdjustment, int displayPolicy) {
Filip Gruszczynskia15aa7d2014-10-28 14:12:40 -0700310 // While dozing, the application processor may be suspended which will prevent us from
311 // receiving new information from the light sensor. On some devices, we may be able to
312 // switch to a wake-up light sensor instead but for now we will simply disable the sensor
313 // and hold onto the last computed screen auto brightness. We save the dozing flag for
314 // debugging purposes.
Michael Wrightd8460232018-01-16 18:04:59 +0000315 boolean dozing = (displayPolicy == DisplayPowerRequest.POLICY_DOZE);
Michael Wrighteef0e132017-11-21 17:57:52 +0000316 boolean changed = setBrightnessConfiguration(configuration);
Michael Wrightd8460232018-01-16 18:04:59 +0000317 changed |= setDisplayPolicy(displayPolicy);
Dan Gittik57d6f112018-03-27 18:14:22 +0100318 if (userChangedAutoBrightnessAdjustment) {
319 changed |= setAutoBrightnessAdjustment(adjustment);
320 }
Michael Wright617564f2018-01-25 22:20:54 +0000321 if (userChangedBrightness && enable) {
322 // Update the brightness curve with the new user control point. It's critical this
323 // happens after we update the autobrightness adjustment since it may reset it.
Michael Wrightd8460232018-01-16 18:04:59 +0000324 changed |= setScreenBrightnessByUser(brightness);
Michael Wright617564f2018-01-25 22:20:54 +0000325 }
326 final boolean userInitiatedChange =
327 userChangedBrightness || userChangedAutoBrightnessAdjustment;
328 if (userInitiatedChange && enable && !dozing) {
Soroosh Mariooryada8edffd2017-03-22 17:08:26 -0700329 prepareBrightnessAdjustmentSample();
330 }
Michael Wrightd8460232018-01-16 18:04:59 +0000331 changed |= setLightSensorEnabled(enable && !dozing);
Jeff Brown970d4132014-07-19 11:33:47 -0700332 if (changed) {
Santos Cordon4acbedb2019-06-07 17:20:41 +0100333 updateAutoBrightness(false /*sendUpdate*/, userInitiatedChange);
Michael Wright639c8be2014-01-17 18:29:12 -0800334 }
335 }
336
Kenny Guy53d06612018-01-30 14:19:13 +0000337 public boolean hasUserDataPoints() {
338 return mBrightnessMapper.hasUserDataPoints();
339 }
340
341 public boolean isDefaultConfig() {
342 return mBrightnessMapper.isDefaultConfig();
343 }
344
Kenny Guy6d1009f2018-03-14 14:28:23 +0000345 public BrightnessConfiguration getDefaultConfig() {
346 return mBrightnessMapper.getDefaultConfig();
347 }
348
Michael Wrightd8460232018-01-16 18:04:59 +0000349 private boolean setDisplayPolicy(int policy) {
350 if (mDisplayPolicy == policy) {
351 return false;
352 }
353 final int oldPolicy = mDisplayPolicy;
354 mDisplayPolicy = policy;
Dan Gittika5a2d632019-01-09 14:25:29 +0000355 if (mLoggingEnabled) {
Dan Gittikc5d32912018-02-22 13:53:47 +0000356 Slog.d(TAG, "Display policy transitioning from " + oldPolicy + " to " + policy);
Michael Wrightd8460232018-01-16 18:04:59 +0000357 }
358 if (!isInteractivePolicy(policy) && isInteractivePolicy(oldPolicy)) {
Dan Gittikc5d32912018-02-22 13:53:47 +0000359 mHandler.sendEmptyMessageDelayed(MSG_INVALIDATE_SHORT_TERM_MODEL,
Kenny Guyb29fdf12019-12-04 12:57:04 +0000360 mBrightnessMapper.getShortTermModelTimeout());
Michael Wrightd8460232018-01-16 18:04:59 +0000361 } else if (isInteractivePolicy(policy) && !isInteractivePolicy(oldPolicy)) {
Dan Gittikc5d32912018-02-22 13:53:47 +0000362 mHandler.removeMessages(MSG_INVALIDATE_SHORT_TERM_MODEL);
Michael Wrightd8460232018-01-16 18:04:59 +0000363 }
364 return true;
365 }
366
367 private static boolean isInteractivePolicy(int policy) {
368 return policy == DisplayPowerRequest.POLICY_BRIGHT
369 || policy == DisplayPowerRequest.POLICY_DIM
370 || policy == DisplayPowerRequest.POLICY_VR;
371 }
372
373 private boolean setScreenBrightnessByUser(float brightness) {
374 if (!mAmbientLuxValid) {
375 // If we don't have a valid ambient lux then we don't have a valid brightness anyways,
376 // and we can't use this data to add a new control point to the short-term model.
377 return false;
378 }
379 mBrightnessMapper.addUserDataPoint(mAmbientLux, brightness);
Dan Gittikc5d32912018-02-22 13:53:47 +0000380 mShortTermModelValid = true;
381 mShortTermModelAnchor = mAmbientLux;
Dan Gittika5a2d632019-01-09 14:25:29 +0000382 if (mLoggingEnabled) {
Dan Gittikc5d32912018-02-22 13:53:47 +0000383 Slog.d(TAG, "ShortTermModel: anchor=" + mShortTermModelAnchor);
384 }
Michael Wrightd8460232018-01-16 18:04:59 +0000385 return true;
386 }
387
Dan Gittikc1352252018-04-27 17:48:31 +0100388 public void resetShortTermModel() {
Michael Wrightd8460232018-01-16 18:04:59 +0000389 mBrightnessMapper.clearUserDataPoints();
Dan Gittikc5d32912018-02-22 13:53:47 +0000390 mShortTermModelValid = true;
391 mShortTermModelAnchor = -1;
392 }
393
394 private void invalidateShortTermModel() {
Dan Gittika5a2d632019-01-09 14:25:29 +0000395 if (mLoggingEnabled) {
Dan Gittikc5d32912018-02-22 13:53:47 +0000396 Slog.d(TAG, "ShortTermModel: invalidate user data");
397 }
398 mShortTermModelValid = false;
Michael Wrightd8460232018-01-16 18:04:59 +0000399 }
400
Michael Wrighteef0e132017-11-21 17:57:52 +0000401 public boolean setBrightnessConfiguration(BrightnessConfiguration configuration) {
Michael Wrightb8f4f772018-05-01 18:28:58 +0100402 if (mBrightnessMapper.setBrightnessConfiguration(configuration)) {
403 resetShortTermModel();
404 return true;
405 }
406 return false;
Michael Wrighteef0e132017-11-21 17:57:52 +0000407 }
408
Michael Wright639c8be2014-01-17 18:29:12 -0800409 public void dump(PrintWriter pw) {
410 pw.println();
411 pw.println("Automatic Brightness Controller Configuration:");
Michael Wright639c8be2014-01-17 18:29:12 -0800412 pw.println(" mScreenBrightnessRangeMinimum=" + mScreenBrightnessRangeMinimum);
413 pw.println(" mScreenBrightnessRangeMaximum=" + mScreenBrightnessRangeMaximum);
Michael Wright2155bc22018-05-01 00:38:32 +0100414 pw.println(" mDozeScaleFactor=" + mDozeScaleFactor);
415 pw.println(" mInitialLightSensorRate=" + mInitialLightSensorRate);
416 pw.println(" mNormalLightSensorRate=" + mNormalLightSensorRate);
Michael Wright639c8be2014-01-17 18:29:12 -0800417 pw.println(" mLightSensorWarmUpTimeConfig=" + mLightSensorWarmUpTimeConfig);
Filip Gruszczynskid81ecd12015-02-06 12:38:47 -0800418 pw.println(" mBrighteningLightDebounceConfig=" + mBrighteningLightDebounceConfig);
419 pw.println(" mDarkeningLightDebounceConfig=" + mDarkeningLightDebounceConfig);
420 pw.println(" mResetAmbientLuxAfterWarmUpConfig=" + mResetAmbientLuxAfterWarmUpConfig);
Michael Wright2155bc22018-05-01 00:38:32 +0100421 pw.println(" mAmbientLightHorizon=" + mAmbientLightHorizon);
422 pw.println(" mWeightingIntercept=" + mWeightingIntercept);
Michael Wright639c8be2014-01-17 18:29:12 -0800423
424 pw.println();
425 pw.println("Automatic Brightness Controller State:");
426 pw.println(" mLightSensor=" + mLightSensor);
Michael Wright639c8be2014-01-17 18:29:12 -0800427 pw.println(" mLightSensorEnabled=" + mLightSensorEnabled);
428 pw.println(" mLightSensorEnableTime=" + TimeUtils.formatUptime(mLightSensorEnableTime));
Michael Wright2155bc22018-05-01 00:38:32 +0100429 pw.println(" mCurrentLightSensorRate=" + mCurrentLightSensorRate);
Michael Wright639c8be2014-01-17 18:29:12 -0800430 pw.println(" mAmbientLux=" + mAmbientLux);
Dan Gittik58784422018-04-05 12:30:38 +0100431 pw.println(" mAmbientLuxValid=" + mAmbientLuxValid);
Dan Gittiked958e92018-11-13 14:58:20 +0000432 pw.println(" mAmbientBrighteningThreshold=" + mAmbientBrighteningThreshold);
433 pw.println(" mAmbientDarkeningThreshold=" + mAmbientDarkeningThreshold);
434 pw.println(" mScreenBrighteningThreshold=" + mScreenBrighteningThreshold);
435 pw.println(" mScreenDarkeningThreshold=" + mScreenDarkeningThreshold);
Michael Wright639c8be2014-01-17 18:29:12 -0800436 pw.println(" mLastObservedLux=" + mLastObservedLux);
437 pw.println(" mLastObservedLuxTime=" + TimeUtils.formatUptime(mLastObservedLuxTime));
438 pw.println(" mRecentLightSamples=" + mRecentLightSamples);
439 pw.println(" mAmbientLightRingBuffer=" + mAmbientLightRingBuffer);
440 pw.println(" mScreenAutoBrightness=" + mScreenAutoBrightness);
Michael Wright2155bc22018-05-01 00:38:32 +0100441 pw.println(" mDisplayPolicy=" + DisplayPowerRequest.policyToString(mDisplayPolicy));
Kenny Guyb29fdf12019-12-04 12:57:04 +0000442 pw.println(" mShortTermModelTimeout=" + mBrightnessMapper.getShortTermModelTimeout());
Dan Gittikc5d32912018-02-22 13:53:47 +0000443 pw.println(" mShortTermModelAnchor=" + mShortTermModelAnchor);
Michael Wright2155bc22018-05-01 00:38:32 +0100444 pw.println(" mShortTermModelValid=" + mShortTermModelValid);
445 pw.println(" mBrightnessAdjustmentSamplePending=" + mBrightnessAdjustmentSamplePending);
446 pw.println(" mBrightnessAdjustmentSampleOldLux=" + mBrightnessAdjustmentSampleOldLux);
447 pw.println(" mBrightnessAdjustmentSampleOldBrightness="
448 + mBrightnessAdjustmentSampleOldBrightness);
Dan Gittika5a2d632019-01-09 14:25:29 +0000449 pw.println(" mForegroundAppPackageName=" + mForegroundAppPackageName);
450 pw.println(" mPendingForegroundAppPackageName=" + mPendingForegroundAppPackageName);
451 pw.println(" mForegroundAppCategory=" + mForegroundAppCategory);
452 pw.println(" mPendingForegroundAppCategory=" + mPendingForegroundAppCategory);
Michael Wrighteef0e132017-11-21 17:57:52 +0000453
454 pw.println();
455 mBrightnessMapper.dump(pw);
Michael Wright2155bc22018-05-01 00:38:32 +0100456
457 pw.println();
Dan Gittiked958e92018-11-13 14:58:20 +0000458 mAmbientBrightnessThresholds.dump(pw);
459 mScreenBrightnessThresholds.dump(pw);
Michael Wright639c8be2014-01-17 18:29:12 -0800460 }
461
462 private boolean setLightSensorEnabled(boolean enable) {
463 if (enable) {
464 if (!mLightSensorEnabled) {
465 mLightSensorEnabled = true;
466 mLightSensorEnableTime = SystemClock.uptimeMillis();
Julius D'souza5d717092016-10-24 19:26:45 -0700467 mCurrentLightSensorRate = mInitialLightSensorRate;
Dan Gittika5a2d632019-01-09 14:25:29 +0000468 registerForegroundAppUpdater();
Michael Wright639c8be2014-01-17 18:29:12 -0800469 mSensorManager.registerListener(mLightSensorListener, mLightSensor,
Julius D'souza5d717092016-10-24 19:26:45 -0700470 mCurrentLightSensorRate * 1000, mHandler);
Michael Wright639c8be2014-01-17 18:29:12 -0800471 return true;
472 }
Dan Gittikc5d32912018-02-22 13:53:47 +0000473 } else if (mLightSensorEnabled) {
474 mLightSensorEnabled = false;
475 mAmbientLuxValid = !mResetAmbientLuxAfterWarmUpConfig;
Dan Gittikf387dd72018-07-13 15:10:39 +0100476 mScreenAutoBrightness = -1;
Dan Gittikc5d32912018-02-22 13:53:47 +0000477 mRecentLightSamples = 0;
478 mAmbientLightRingBuffer.clear();
479 mCurrentLightSensorRate = -1;
480 mHandler.removeMessages(MSG_UPDATE_AMBIENT_LUX);
Dan Gittika5a2d632019-01-09 14:25:29 +0000481 unregisterForegroundAppUpdater();
Dan Gittikc5d32912018-02-22 13:53:47 +0000482 mSensorManager.unregisterListener(mLightSensorListener);
Michael Wright639c8be2014-01-17 18:29:12 -0800483 }
484 return false;
485 }
486
487 private void handleLightSensorEvent(long time, float lux) {
Michael Wrightb0a1d3d2017-09-22 15:05:02 +0100488 Trace.traceCounter(Trace.TRACE_TAG_POWER, "ALS", (int) lux);
Michael Wright639c8be2014-01-17 18:29:12 -0800489 mHandler.removeMessages(MSG_UPDATE_AMBIENT_LUX);
490
Julius D'souza5d717092016-10-24 19:26:45 -0700491 if (mAmbientLightRingBuffer.size() == 0) {
492 // switch to using the steady-state sample rate after grabbing the initial light sample
493 adjustLightSensorRate(mNormalLightSensorRate);
494 }
Michael Wright639c8be2014-01-17 18:29:12 -0800495 applyLightSensorMeasurement(time, lux);
496 updateAmbientLux(time);
497 }
498
499 private void applyLightSensorMeasurement(long time, float lux) {
500 mRecentLightSamples++;
Zoran Jovanovic6fc42f52015-12-10 17:01:16 +0100501 mAmbientLightRingBuffer.prune(time - mAmbientLightHorizon);
Michael Wright639c8be2014-01-17 18:29:12 -0800502 mAmbientLightRingBuffer.push(time, lux);
503
504 // Remember this sample value.
505 mLastObservedLux = lux;
506 mLastObservedLuxTime = time;
507 }
508
Julius D'souza5d717092016-10-24 19:26:45 -0700509 private void adjustLightSensorRate(int lightSensorRate) {
510 // if the light sensor rate changed, update the sensor listener
511 if (lightSensorRate != mCurrentLightSensorRate) {
Dan Gittika5a2d632019-01-09 14:25:29 +0000512 if (mLoggingEnabled) {
Dan Gittikc5d32912018-02-22 13:53:47 +0000513 Slog.d(TAG, "adjustLightSensorRate: " +
Dan Gittik57d6f112018-03-27 18:14:22 +0100514 "previousRate=" + mCurrentLightSensorRate + ", " +
515 "currentRate=" + lightSensorRate);
Julius D'souza5d717092016-10-24 19:26:45 -0700516 }
517 mCurrentLightSensorRate = lightSensorRate;
518 mSensorManager.unregisterListener(mLightSensorListener);
519 mSensorManager.registerListener(mLightSensorListener, mLightSensor,
520 lightSensorRate * 1000, mHandler);
521 }
522 }
523
Dan Gittik57d6f112018-03-27 18:14:22 +0100524 private boolean setAutoBrightnessAdjustment(float adjustment) {
525 return mBrightnessMapper.setAutoBrightnessAdjustment(adjustment);
Michael Wright639c8be2014-01-17 18:29:12 -0800526 }
527
528 private void setAmbientLux(float lux) {
Dan Gittika5a2d632019-01-09 14:25:29 +0000529 if (mLoggingEnabled) {
Michael Wright0a933142017-08-16 20:38:21 +0100530 Slog.d(TAG, "setAmbientLux(" + lux + ")");
531 }
Michael Wrightd8460232018-01-16 18:04:59 +0000532 if (lux < 0) {
Dan Gittikc5d32912018-02-22 13:53:47 +0000533 Slog.w(TAG, "Ambient lux was negative, ignoring and setting to 0");
Michael Wrightd8460232018-01-16 18:04:59 +0000534 lux = 0;
535 }
Michael Wright639c8be2014-01-17 18:29:12 -0800536 mAmbientLux = lux;
Dan Gittiked958e92018-11-13 14:58:20 +0000537 mAmbientBrighteningThreshold = mAmbientBrightnessThresholds.getBrighteningThreshold(lux);
538 mAmbientDarkeningThreshold = mAmbientBrightnessThresholds.getDarkeningThreshold(lux);
Dan Gittikc5d32912018-02-22 13:53:47 +0000539
540 // If the short term model was invalidated and the change is drastic enough, reset it.
541 if (!mShortTermModelValid && mShortTermModelAnchor != -1) {
Kenny Guyb29fdf12019-12-04 12:57:04 +0000542 if (mBrightnessMapper.shouldResetShortTermModel(mAmbientLux, mShortTermModelAnchor)) {
Dan Gittikc5d32912018-02-22 13:53:47 +0000543 resetShortTermModel();
Kenny Guyb29fdf12019-12-04 12:57:04 +0000544 } else {
545 mShortTermModelValid = true;
Dan Gittikc5d32912018-02-22 13:53:47 +0000546 }
547 }
Michael Wright639c8be2014-01-17 18:29:12 -0800548 }
549
Michael Wright0a933142017-08-16 20:38:21 +0100550 private float calculateAmbientLux(long now, long horizon) {
Dan Gittika5a2d632019-01-09 14:25:29 +0000551 if (mLoggingEnabled) {
Michael Wright0a933142017-08-16 20:38:21 +0100552 Slog.d(TAG, "calculateAmbientLux(" + now + ", " + horizon + ")");
553 }
Michael Wright639c8be2014-01-17 18:29:12 -0800554 final int N = mAmbientLightRingBuffer.size();
555 if (N == 0) {
556 Slog.e(TAG, "calculateAmbientLux: No ambient light readings available");
557 return -1;
558 }
Michael Wright0a933142017-08-16 20:38:21 +0100559
560 // Find the first measurement that is just outside of the horizon.
561 int endIndex = 0;
562 final long horizonStartTime = now - horizon;
563 for (int i = 0; i < N-1; i++) {
564 if (mAmbientLightRingBuffer.getTime(i + 1) <= horizonStartTime) {
565 endIndex++;
566 } else {
567 break;
568 }
569 }
Dan Gittika5a2d632019-01-09 14:25:29 +0000570 if (mLoggingEnabled) {
Dan Gittik57d6f112018-03-27 18:14:22 +0100571 Slog.d(TAG, "calculateAmbientLux: selected endIndex=" + endIndex + ", point=(" +
572 mAmbientLightRingBuffer.getTime(endIndex) + ", " +
573 mAmbientLightRingBuffer.getLux(endIndex) + ")");
Michael Wright0a933142017-08-16 20:38:21 +0100574 }
Michael Wright639c8be2014-01-17 18:29:12 -0800575 float sum = 0;
576 float totalWeight = 0;
577 long endTime = AMBIENT_LIGHT_PREDICTION_TIME_MILLIS;
Michael Wright0a933142017-08-16 20:38:21 +0100578 for (int i = N - 1; i >= endIndex; i--) {
579 long eventTime = mAmbientLightRingBuffer.getTime(i);
580 if (i == endIndex && eventTime < horizonStartTime) {
581 // If we're at the final value, make sure we only consider the part of the sample
582 // within our desired horizon.
583 eventTime = horizonStartTime;
584 }
585 final long startTime = eventTime - now;
Michael Wright639c8be2014-01-17 18:29:12 -0800586 float weight = calculateWeight(startTime, endTime);
587 float lux = mAmbientLightRingBuffer.getLux(i);
Dan Gittika5a2d632019-01-09 14:25:29 +0000588 if (mLoggingEnabled) {
Dan Gittikc5d32912018-02-22 13:53:47 +0000589 Slog.d(TAG, "calculateAmbientLux: [" + startTime + ", " + endTime + "]: " +
Dan Gittik57d6f112018-03-27 18:14:22 +0100590 "lux=" + lux + ", " +
591 "weight=" + weight);
Michael Wright639c8be2014-01-17 18:29:12 -0800592 }
593 totalWeight += weight;
Dan Gittikc5d32912018-02-22 13:53:47 +0000594 sum += lux * weight;
Michael Wright639c8be2014-01-17 18:29:12 -0800595 endTime = startTime;
596 }
Dan Gittika5a2d632019-01-09 14:25:29 +0000597 if (mLoggingEnabled) {
Dan Gittikc5d32912018-02-22 13:53:47 +0000598 Slog.d(TAG, "calculateAmbientLux: " +
Dan Gittik57d6f112018-03-27 18:14:22 +0100599 "totalWeight=" + totalWeight + ", " +
600 "newAmbientLux=" + (sum / totalWeight));
Michael Wright639c8be2014-01-17 18:29:12 -0800601 }
602 return sum / totalWeight;
603 }
604
Zoran Jovanovic6fc42f52015-12-10 17:01:16 +0100605 private float calculateWeight(long startDelta, long endDelta) {
Michael Wright639c8be2014-01-17 18:29:12 -0800606 return weightIntegral(endDelta) - weightIntegral(startDelta);
607 }
608
Zoran Jovanovic6fc42f52015-12-10 17:01:16 +0100609 // Evaluates the integral of y = x + mWeightingIntercept. This is always positive for the
Michael Wright639c8be2014-01-17 18:29:12 -0800610 // horizon we're looking at and provides a non-linear weighting for light samples.
Zoran Jovanovic6fc42f52015-12-10 17:01:16 +0100611 private float weightIntegral(long x) {
612 return x * (x * 0.5f + mWeightingIntercept);
Michael Wright639c8be2014-01-17 18:29:12 -0800613 }
614
615 private long nextAmbientLightBrighteningTransition(long time) {
616 final int N = mAmbientLightRingBuffer.size();
617 long earliestValidTime = time;
618 for (int i = N - 1; i >= 0; i--) {
Dan Gittiked958e92018-11-13 14:58:20 +0000619 if (mAmbientLightRingBuffer.getLux(i) <= mAmbientBrighteningThreshold) {
Michael Wright639c8be2014-01-17 18:29:12 -0800620 break;
621 }
622 earliestValidTime = mAmbientLightRingBuffer.getTime(i);
623 }
Filip Gruszczynskid81ecd12015-02-06 12:38:47 -0800624 return earliestValidTime + mBrighteningLightDebounceConfig;
Michael Wright639c8be2014-01-17 18:29:12 -0800625 }
626
627 private long nextAmbientLightDarkeningTransition(long time) {
628 final int N = mAmbientLightRingBuffer.size();
629 long earliestValidTime = time;
630 for (int i = N - 1; i >= 0; i--) {
Dan Gittiked958e92018-11-13 14:58:20 +0000631 if (mAmbientLightRingBuffer.getLux(i) >= mAmbientDarkeningThreshold) {
Michael Wright639c8be2014-01-17 18:29:12 -0800632 break;
633 }
634 earliestValidTime = mAmbientLightRingBuffer.getTime(i);
635 }
Filip Gruszczynskid81ecd12015-02-06 12:38:47 -0800636 return earliestValidTime + mDarkeningLightDebounceConfig;
Michael Wright639c8be2014-01-17 18:29:12 -0800637 }
638
639 private void updateAmbientLux() {
640 long time = SystemClock.uptimeMillis();
Zoran Jovanovic6fc42f52015-12-10 17:01:16 +0100641 mAmbientLightRingBuffer.prune(time - mAmbientLightHorizon);
Michael Wright639c8be2014-01-17 18:29:12 -0800642 updateAmbientLux(time);
643 }
644
645 private void updateAmbientLux(long time) {
646 // If the light sensor was just turned on then immediately update our initial
647 // estimate of the current ambient light level.
648 if (!mAmbientLuxValid) {
649 final long timeWhenSensorWarmedUp =
650 mLightSensorWarmUpTimeConfig + mLightSensorEnableTime;
651 if (time < timeWhenSensorWarmedUp) {
Dan Gittika5a2d632019-01-09 14:25:29 +0000652 if (mLoggingEnabled) {
Kenny Guyb54d40b2019-02-28 12:49:53 +0000653 Slog.d(TAG, "updateAmbientLux: Sensor not ready yet: "
654 + "time=" + time + ", "
655 + "timeWhenSensorWarmedUp=" + timeWhenSensorWarmedUp);
Michael Wright639c8be2014-01-17 18:29:12 -0800656 }
657 mHandler.sendEmptyMessageAtTime(MSG_UPDATE_AMBIENT_LUX,
658 timeWhenSensorWarmedUp);
659 return;
660 }
Michael Wright0a933142017-08-16 20:38:21 +0100661 setAmbientLux(calculateAmbientLux(time, AMBIENT_LIGHT_SHORT_HORIZON_MILLIS));
Michael Wright639c8be2014-01-17 18:29:12 -0800662 mAmbientLuxValid = true;
Dan Gittika5a2d632019-01-09 14:25:29 +0000663 if (mLoggingEnabled) {
Dan Gittikc5d32912018-02-22 13:53:47 +0000664 Slog.d(TAG, "updateAmbientLux: Initializing: " +
665 "mAmbientLightRingBuffer=" + mAmbientLightRingBuffer + ", " +
666 "mAmbientLux=" + mAmbientLux);
Michael Wright639c8be2014-01-17 18:29:12 -0800667 }
Santos Cordon4acbedb2019-06-07 17:20:41 +0100668 updateAutoBrightness(true /* sendUpdate */, false /* isManuallySet */);
Michael Wright639c8be2014-01-17 18:29:12 -0800669 }
670
671 long nextBrightenTransition = nextAmbientLightBrighteningTransition(time);
672 long nextDarkenTransition = nextAmbientLightDarkeningTransition(time);
Michael Wright0a933142017-08-16 20:38:21 +0100673 // Essentially, we calculate both a slow ambient lux, to ensure there's a true long-term
674 // change in lighting conditions, and a fast ambient lux to determine what the new
675 // brightness situation is since the slow lux can be quite slow to converge.
676 //
677 // Note that both values need to be checked for sufficient change before updating the
678 // proposed ambient light value since the slow value might be sufficiently far enough away
679 // from the fast value to cause a recalculation while its actually just converging on
680 // the fast value still.
681 float slowAmbientLux = calculateAmbientLux(time, AMBIENT_LIGHT_LONG_HORIZON_MILLIS);
682 float fastAmbientLux = calculateAmbientLux(time, AMBIENT_LIGHT_SHORT_HORIZON_MILLIS);
Michael Wright639c8be2014-01-17 18:29:12 -0800683
Dan Gittiked958e92018-11-13 14:58:20 +0000684 if ((slowAmbientLux >= mAmbientBrighteningThreshold
685 && fastAmbientLux >= mAmbientBrighteningThreshold
686 && nextBrightenTransition <= time)
687 || (slowAmbientLux <= mAmbientDarkeningThreshold
688 && fastAmbientLux <= mAmbientDarkeningThreshold
689 && nextDarkenTransition <= time)) {
Michael Wright0a933142017-08-16 20:38:21 +0100690 setAmbientLux(fastAmbientLux);
Dan Gittika5a2d632019-01-09 14:25:29 +0000691 if (mLoggingEnabled) {
Dan Gittiked958e92018-11-13 14:58:20 +0000692 Slog.d(TAG, "updateAmbientLux: "
693 + ((fastAmbientLux > mAmbientLux) ? "Brightened" : "Darkened") + ": "
Dan Gittika5a2d632019-01-09 14:25:29 +0000694 + "mBrighteningLuxThreshold=" + mAmbientBrighteningThreshold + ", "
Dan Gittiked958e92018-11-13 14:58:20 +0000695 + "mAmbientLightRingBuffer=" + mAmbientLightRingBuffer + ", "
696 + "mAmbientLux=" + mAmbientLux);
Michael Wright639c8be2014-01-17 18:29:12 -0800697 }
Santos Cordon4acbedb2019-06-07 17:20:41 +0100698 updateAutoBrightness(true /* sendUpdate */, false /* isManuallySet */);
Michael Wright639c8be2014-01-17 18:29:12 -0800699 nextBrightenTransition = nextAmbientLightBrighteningTransition(time);
700 nextDarkenTransition = nextAmbientLightDarkeningTransition(time);
701 }
702 long nextTransitionTime = Math.min(nextDarkenTransition, nextBrightenTransition);
703 // If one of the transitions is ready to occur, but the total weighted ambient lux doesn't
704 // exceed the necessary threshold, then it's possible we'll get a transition time prior to
705 // now. Rather than continually checking to see whether the weighted lux exceeds the
706 // threshold, schedule an update for when we'd normally expect another light sample, which
707 // should be enough time to decide whether we should actually transition to the new
708 // weighted ambient lux or not.
709 nextTransitionTime =
Julius D'souza5d717092016-10-24 19:26:45 -0700710 nextTransitionTime > time ? nextTransitionTime : time + mNormalLightSensorRate;
Dan Gittika5a2d632019-01-09 14:25:29 +0000711 if (mLoggingEnabled) {
Dan Gittikc5d32912018-02-22 13:53:47 +0000712 Slog.d(TAG, "updateAmbientLux: Scheduling ambient lux update for " +
Dan Gittik57d6f112018-03-27 18:14:22 +0100713 nextTransitionTime + TimeUtils.formatUptime(nextTransitionTime));
Michael Wright639c8be2014-01-17 18:29:12 -0800714 }
715 mHandler.sendEmptyMessageAtTime(MSG_UPDATE_AMBIENT_LUX, nextTransitionTime);
716 }
717
Santos Cordon4acbedb2019-06-07 17:20:41 +0100718 private void updateAutoBrightness(boolean sendUpdate, boolean isManuallySet) {
Michael Wright639c8be2014-01-17 18:29:12 -0800719 if (!mAmbientLuxValid) {
720 return;
721 }
722
Dan Gittika5a2d632019-01-09 14:25:29 +0000723 float value = mBrightnessMapper.getBrightness(mAmbientLux, mForegroundAppPackageName,
724 mForegroundAppCategory);
Michael Wright639c8be2014-01-17 18:29:12 -0800725
Santos Cordon64a86272019-11-28 11:24:21 +0000726 int newScreenAutoBrightness = Math.round(clampScreenBrightness(
727 value * PowerManager.BRIGHTNESS_ON));
Dan Gittiked958e92018-11-13 14:58:20 +0000728
729 // If screenAutoBrightness is set, we should have screen{Brightening,Darkening}Threshold,
730 // in which case we ignore the new screen brightness if it doesn't differ enough from the
731 // previous one.
732 if (mScreenAutoBrightness != -1
Santos Cordon4acbedb2019-06-07 17:20:41 +0100733 && !isManuallySet
Dan Gittiked958e92018-11-13 14:58:20 +0000734 && newScreenAutoBrightness > mScreenDarkeningThreshold
735 && newScreenAutoBrightness < mScreenBrighteningThreshold) {
Dan Gittika5a2d632019-01-09 14:25:29 +0000736 if (mLoggingEnabled) {
Dan Gittiked958e92018-11-13 14:58:20 +0000737 Slog.d(TAG, "ignoring newScreenAutoBrightness: " + mScreenDarkeningThreshold
738 + " < " + newScreenAutoBrightness + " < " + mScreenBrighteningThreshold);
739 }
740 return;
741 }
742
Michael Wright639c8be2014-01-17 18:29:12 -0800743 if (mScreenAutoBrightness != newScreenAutoBrightness) {
Dan Gittika5a2d632019-01-09 14:25:29 +0000744 if (mLoggingEnabled) {
Dan Gittikc5d32912018-02-22 13:53:47 +0000745 Slog.d(TAG, "updateAutoBrightness: " +
Dan Gittik57d6f112018-03-27 18:14:22 +0100746 "mScreenAutoBrightness=" + mScreenAutoBrightness + ", " +
747 "newScreenAutoBrightness=" + newScreenAutoBrightness);
Michael Wright639c8be2014-01-17 18:29:12 -0800748 }
749
750 mScreenAutoBrightness = newScreenAutoBrightness;
Santos Cordon64a86272019-11-28 11:24:21 +0000751 mScreenBrighteningThreshold = clampScreenBrightness(
752 mScreenBrightnessThresholds.getBrighteningThreshold(newScreenAutoBrightness));
753 mScreenDarkeningThreshold = clampScreenBrightness(
754 mScreenBrightnessThresholds.getDarkeningThreshold(newScreenAutoBrightness));
Dan Gittiked958e92018-11-13 14:58:20 +0000755
Michael Wright639c8be2014-01-17 18:29:12 -0800756 if (sendUpdate) {
757 mCallbacks.updateBrightness();
758 }
759 }
760 }
761
Santos Cordon64a86272019-11-28 11:24:21 +0000762 private float clampScreenBrightness(float value) {
Michael Wright639c8be2014-01-17 18:29:12 -0800763 return MathUtils.constrain(value,
764 mScreenBrightnessRangeMinimum, mScreenBrightnessRangeMaximum);
765 }
766
Jeff Browna576b4d2015-04-23 19:58:06 -0700767 private void prepareBrightnessAdjustmentSample() {
768 if (!mBrightnessAdjustmentSamplePending) {
769 mBrightnessAdjustmentSamplePending = true;
Jeff Browna576b4d2015-04-23 19:58:06 -0700770 mBrightnessAdjustmentSampleOldLux = mAmbientLuxValid ? mAmbientLux : -1;
771 mBrightnessAdjustmentSampleOldBrightness = mScreenAutoBrightness;
Jeff Browna576b4d2015-04-23 19:58:06 -0700772 } else {
773 mHandler.removeMessages(MSG_BRIGHTNESS_ADJUSTMENT_SAMPLE);
774 }
775
776 mHandler.sendEmptyMessageDelayed(MSG_BRIGHTNESS_ADJUSTMENT_SAMPLE,
777 BRIGHTNESS_ADJUSTMENT_SAMPLE_DEBOUNCE_MILLIS);
778 }
779
Sudheer Shankab3f60652019-01-04 20:30:14 +0000780 private void cancelBrightnessAdjustmentSample() {
781 if (mBrightnessAdjustmentSamplePending) {
782 mBrightnessAdjustmentSamplePending = false;
783 mHandler.removeMessages(MSG_BRIGHTNESS_ADJUSTMENT_SAMPLE);
784 }
785 }
786
Jeff Browna576b4d2015-04-23 19:58:06 -0700787 private void collectBrightnessAdjustmentSample() {
788 if (mBrightnessAdjustmentSamplePending) {
789 mBrightnessAdjustmentSamplePending = false;
790 if (mAmbientLuxValid && mScreenAutoBrightness >= 0) {
Dan Gittika5a2d632019-01-09 14:25:29 +0000791 if (mLoggingEnabled) {
Dan Gittikc5d32912018-02-22 13:53:47 +0000792 Slog.d(TAG, "Auto-brightness adjustment changed by user: " +
Dan Gittik57d6f112018-03-27 18:14:22 +0100793 "lux=" + mAmbientLux + ", " +
794 "brightness=" + mScreenAutoBrightness + ", " +
795 "ring=" + mAmbientLightRingBuffer);
Jeff Browna576b4d2015-04-23 19:58:06 -0700796 }
797
798 EventLog.writeEvent(EventLogTags.AUTO_BRIGHTNESS_ADJ,
Jeff Browna576b4d2015-04-23 19:58:06 -0700799 mBrightnessAdjustmentSampleOldLux,
800 mBrightnessAdjustmentSampleOldBrightness,
Jeff Browna576b4d2015-04-23 19:58:06 -0700801 mAmbientLux,
Dan Gittik57d6f112018-03-27 18:14:22 +0100802 mScreenAutoBrightness);
Jeff Browna576b4d2015-04-23 19:58:06 -0700803 }
804 }
805 }
806
Dan Gittika5a2d632019-01-09 14:25:29 +0000807 // Register a TaskStackListener to call back to us onTaskStackChanged, so we can update the
808 // foreground app's package name and category and correct the brightness accordingly.
809 private void registerForegroundAppUpdater() {
810 try {
811 mActivityTaskManager.registerTaskStackListener(mTaskStackListener);
812 // This will not get called until the foreground app changes for the first time, so
813 // call it explicitly to get the current foreground app's info.
814 updateForegroundApp();
815 } catch (RemoteException e) {
816 if (mLoggingEnabled) {
817 Slog.e(TAG, "Failed to register foreground app updater: " + e);
818 }
819 // Nothing to do.
820 }
821 }
822
823 private void unregisterForegroundAppUpdater() {
824 try {
825 mActivityTaskManager.unregisterTaskStackListener(mTaskStackListener);
826 } catch (RemoteException e) {
827 // Nothing to do.
828 }
829 mForegroundAppPackageName = null;
830 mForegroundAppCategory = ApplicationInfo.CATEGORY_UNDEFINED;
831 }
832
833 // Set the foreground app's package name and category, so brightness can be corrected per app.
834 private void updateForegroundApp() {
835 if (mLoggingEnabled) {
836 Slog.d(TAG, "Attempting to update foreground app");
837 }
838 // The ActivityTaskManager's lock tends to get contended, so this is done in a background
839 // thread and applied via this thread's handler synchronously.
Santos Cordon64a86272019-11-28 11:24:21 +0000840 mInjector.getBackgroundThreadHandler().post(new Runnable() {
Dan Gittika5a2d632019-01-09 14:25:29 +0000841 public void run() {
842 try {
843 // The foreground app is the top activity of the focused tasks stack.
844 final StackInfo info = mActivityTaskManager.getFocusedStackInfo();
845 if (info == null || info.topActivity == null) {
846 return;
847 }
848 final String packageName = info.topActivity.getPackageName();
849 // If the app didn't change, there's nothing to do. Otherwise, we have to
850 // update the category and re-apply the brightness correction.
851 if (mForegroundAppPackageName != null
852 && mForegroundAppPackageName.equals(packageName)) {
853 return;
854 }
855 mPendingForegroundAppPackageName = packageName;
856 mPendingForegroundAppCategory = ApplicationInfo.CATEGORY_UNDEFINED;
857 try {
858 ApplicationInfo app = mPackageManager.getApplicationInfo(packageName,
859 PackageManager.MATCH_ANY_USER);
860 mPendingForegroundAppCategory = app.category;
861 } catch (PackageManager.NameNotFoundException e) {
862 // Nothing to do
863 }
864 mHandler.sendEmptyMessage(MSG_UPDATE_FOREGROUND_APP_SYNC);
865 } catch (RemoteException e) {
866 // Nothing to do
867 }
868 }
869 });
870 }
871
872 private void updateForegroundAppSync() {
873 if (mLoggingEnabled) {
874 Slog.d(TAG, "Updating foreground app: packageName=" + mPendingForegroundAppPackageName
875 + ", category=" + mPendingForegroundAppCategory);
876 }
877 mForegroundAppPackageName = mPendingForegroundAppPackageName;
878 mPendingForegroundAppPackageName = null;
879 mForegroundAppCategory = mPendingForegroundAppCategory;
880 mPendingForegroundAppCategory = ApplicationInfo.CATEGORY_UNDEFINED;
Santos Cordon4acbedb2019-06-07 17:20:41 +0100881 updateAutoBrightness(true /* sendUpdate */, false /* isManuallySet */);
Dan Gittika5a2d632019-01-09 14:25:29 +0000882 }
883
Michael Wright639c8be2014-01-17 18:29:12 -0800884 private final class AutomaticBrightnessHandler extends Handler {
885 public AutomaticBrightnessHandler(Looper looper) {
886 super(looper, null, true /*async*/);
887 }
888
889 @Override
890 public void handleMessage(Message msg) {
891 switch (msg.what) {
892 case MSG_UPDATE_AMBIENT_LUX:
893 updateAmbientLux();
894 break;
Jeff Browna576b4d2015-04-23 19:58:06 -0700895
896 case MSG_BRIGHTNESS_ADJUSTMENT_SAMPLE:
897 collectBrightnessAdjustmentSample();
898 break;
Michael Wrightd8460232018-01-16 18:04:59 +0000899
Dan Gittikc5d32912018-02-22 13:53:47 +0000900 case MSG_INVALIDATE_SHORT_TERM_MODEL:
901 invalidateShortTermModel();
Michael Wrightd8460232018-01-16 18:04:59 +0000902 break;
Dan Gittika5a2d632019-01-09 14:25:29 +0000903
904 case MSG_UPDATE_FOREGROUND_APP:
905 updateForegroundApp();
906 break;
907
908 case MSG_UPDATE_FOREGROUND_APP_SYNC:
909 updateForegroundAppSync();
910 break;
Michael Wright639c8be2014-01-17 18:29:12 -0800911 }
912 }
913 }
914
915 private final SensorEventListener mLightSensorListener = new SensorEventListener() {
916 @Override
917 public void onSensorChanged(SensorEvent event) {
918 if (mLightSensorEnabled) {
919 final long time = SystemClock.uptimeMillis();
920 final float lux = event.values[0];
921 handleLightSensorEvent(time, lux);
922 }
923 }
924
925 @Override
926 public void onAccuracyChanged(Sensor sensor, int accuracy) {
927 // Not used.
928 }
929 };
930
Dan Gittika5a2d632019-01-09 14:25:29 +0000931 // Call back whenever the tasks stack changes, which includes tasks being created, removed, and
932 // moving to top.
933 class TaskStackListenerImpl extends TaskStackListener {
934 @Override
935 public void onTaskStackChanged() {
936 mHandler.sendEmptyMessage(MSG_UPDATE_FOREGROUND_APP);
937 }
938 }
939
Michael Wright639c8be2014-01-17 18:29:12 -0800940 /** Callbacks to request updates to the display's power state. */
941 interface Callbacks {
942 void updateBrightness();
943 }
944
Michael Wright0a933142017-08-16 20:38:21 +0100945 /**
946 * A ring buffer of ambient light measurements sorted by time.
947 *
948 * Each entry consists of a timestamp and a lux measurement, and the overall buffer is sorted
949 * from oldest to newest.
950 */
Michael Wright103fb782016-04-22 01:03:09 -0400951 private static final class AmbientLightRingBuffer {
Michael Wright639c8be2014-01-17 18:29:12 -0800952 // Proportional extra capacity of the buffer beyond the expected number of light samples
953 // in the horizon
954 private static final float BUFFER_SLACK = 1.5f;
Michael Wright639c8be2014-01-17 18:29:12 -0800955 private float[] mRingLux;
956 private long[] mRingTime;
957 private int mCapacity;
958
959 // The first valid element and the next open slot.
960 // Note that if mCount is zero then there are no valid elements.
961 private int mStart;
962 private int mEnd;
963 private int mCount;
964
Zoran Jovanovic6fc42f52015-12-10 17:01:16 +0100965 public AmbientLightRingBuffer(long lightSensorRate, int ambientLightHorizon) {
Santos Cordon64a86272019-11-28 11:24:21 +0000966 if (lightSensorRate <= 0) {
967 throw new IllegalArgumentException("lightSensorRate must be above 0");
968 }
Zoran Jovanovic6fc42f52015-12-10 17:01:16 +0100969 mCapacity = (int) Math.ceil(ambientLightHorizon * BUFFER_SLACK / lightSensorRate);
Michael Wright639c8be2014-01-17 18:29:12 -0800970 mRingLux = new float[mCapacity];
971 mRingTime = new long[mCapacity];
972 }
973
974 public float getLux(int index) {
975 return mRingLux[offsetOf(index)];
976 }
977
978 public long getTime(int index) {
979 return mRingTime[offsetOf(index)];
980 }
981
982 public void push(long time, float lux) {
983 int next = mEnd;
984 if (mCount == mCapacity) {
985 int newSize = mCapacity * 2;
986
987 float[] newRingLux = new float[newSize];
988 long[] newRingTime = new long[newSize];
989 int length = mCapacity - mStart;
990 System.arraycopy(mRingLux, mStart, newRingLux, 0, length);
991 System.arraycopy(mRingTime, mStart, newRingTime, 0, length);
992 if (mStart != 0) {
993 System.arraycopy(mRingLux, 0, newRingLux, length, mStart);
994 System.arraycopy(mRingTime, 0, newRingTime, length, mStart);
995 }
996 mRingLux = newRingLux;
997 mRingTime = newRingTime;
998
999 next = mCapacity;
1000 mCapacity = newSize;
1001 mStart = 0;
1002 }
1003 mRingTime[next] = time;
1004 mRingLux[next] = lux;
1005 mEnd = next + 1;
1006 if (mEnd == mCapacity) {
1007 mEnd = 0;
1008 }
1009 mCount++;
1010 }
1011
1012 public void prune(long horizon) {
1013 if (mCount == 0) {
1014 return;
1015 }
1016
1017 while (mCount > 1) {
1018 int next = mStart + 1;
1019 if (next >= mCapacity) {
1020 next -= mCapacity;
1021 }
1022 if (mRingTime[next] > horizon) {
1023 // Some light sensors only produce data upon a change in the ambient light
1024 // levels, so we need to consider the previous measurement as the ambient light
1025 // level for all points in time up until we receive a new measurement. Thus, we
1026 // always want to keep the youngest element that would be removed from the
1027 // buffer and just set its measurement time to the horizon time since at that
1028 // point it is the ambient light level, and to remove it would be to drop a
1029 // valid data point within our horizon.
1030 break;
1031 }
1032 mStart = next;
1033 mCount -= 1;
1034 }
1035
1036 if (mRingTime[mStart] < horizon) {
1037 mRingTime[mStart] = horizon;
1038 }
1039 }
1040
1041 public int size() {
1042 return mCount;
1043 }
1044
Michael Wright639c8be2014-01-17 18:29:12 -08001045 public void clear() {
1046 mStart = 0;
1047 mEnd = 0;
1048 mCount = 0;
1049 }
1050
1051 @Override
1052 public String toString() {
Jeff Browna576b4d2015-04-23 19:58:06 -07001053 StringBuffer buf = new StringBuffer();
1054 buf.append('[');
1055 for (int i = 0; i < mCount; i++) {
1056 final long next = i + 1 < mCount ? getTime(i + 1) : SystemClock.uptimeMillis();
1057 if (i != 0) {
1058 buf.append(", ");
1059 }
1060 buf.append(getLux(i));
1061 buf.append(" / ");
1062 buf.append(next - getTime(i));
1063 buf.append("ms");
Michael Wright639c8be2014-01-17 18:29:12 -08001064 }
Jeff Browna576b4d2015-04-23 19:58:06 -07001065 buf.append(']');
1066 return buf.toString();
Michael Wright639c8be2014-01-17 18:29:12 -08001067 }
1068
1069 private int offsetOf(int index) {
1070 if (index >= mCount || index < 0) {
1071 throw new ArrayIndexOutOfBoundsException(index);
1072 }
1073 index += mStart;
1074 if (index >= mCapacity) {
1075 index -= mCapacity;
1076 }
1077 return index;
1078 }
1079 }
Santos Cordon64a86272019-11-28 11:24:21 +00001080
1081 public static class Injector {
1082 public Handler getBackgroundThreadHandler() {
1083 return BackgroundThread.getHandler();
1084 }
1085 }
Michael Wright639c8be2014-01-17 18:29:12 -08001086}