blob: 6d7dff5736fa95d06642db2fdd2bde14f81967c2 [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) {
Michael Wright639c8be2014-01-17 18:29:12 -0800325 updateAutoBrightness(false /*sendUpdate*/);
326 }
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 }
670 updateAutoBrightness(true);
671 }
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 }
700 updateAutoBrightness(true);
701 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
720 private void updateAutoBrightness(boolean sendUpdate) {
721 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
735 && newScreenAutoBrightness > mScreenDarkeningThreshold
736 && newScreenAutoBrightness < mScreenBrighteningThreshold) {
Dan Gittika5a2d632019-01-09 14:25:29 +0000737 if (mLoggingEnabled) {
Dan Gittiked958e92018-11-13 14:58:20 +0000738 Slog.d(TAG, "ignoring newScreenAutoBrightness: " + mScreenDarkeningThreshold
739 + " < " + newScreenAutoBrightness + " < " + mScreenBrighteningThreshold);
740 }
741 return;
742 }
743
Michael Wright639c8be2014-01-17 18:29:12 -0800744 if (mScreenAutoBrightness != newScreenAutoBrightness) {
Dan Gittika5a2d632019-01-09 14:25:29 +0000745 if (mLoggingEnabled) {
Dan Gittikc5d32912018-02-22 13:53:47 +0000746 Slog.d(TAG, "updateAutoBrightness: " +
Dan Gittik57d6f112018-03-27 18:14:22 +0100747 "mScreenAutoBrightness=" + mScreenAutoBrightness + ", " +
748 "newScreenAutoBrightness=" + newScreenAutoBrightness);
Michael Wright639c8be2014-01-17 18:29:12 -0800749 }
750
751 mScreenAutoBrightness = newScreenAutoBrightness;
Dan Gittiked958e92018-11-13 14:58:20 +0000752 mScreenBrighteningThreshold =
753 mScreenBrightnessThresholds.getBrighteningThreshold(newScreenAutoBrightness);
754 mScreenDarkeningThreshold =
755 mScreenBrightnessThresholds.getDarkeningThreshold(newScreenAutoBrightness);
756
Michael Wright639c8be2014-01-17 18:29:12 -0800757 if (sendUpdate) {
758 mCallbacks.updateBrightness();
759 }
760 }
761 }
762
763 private int clampScreenBrightness(int value) {
764 return MathUtils.constrain(value,
765 mScreenBrightnessRangeMinimum, mScreenBrightnessRangeMaximum);
766 }
767
Jeff Browna576b4d2015-04-23 19:58:06 -0700768 private void prepareBrightnessAdjustmentSample() {
769 if (!mBrightnessAdjustmentSamplePending) {
770 mBrightnessAdjustmentSamplePending = true;
Jeff Browna576b4d2015-04-23 19:58:06 -0700771 mBrightnessAdjustmentSampleOldLux = mAmbientLuxValid ? mAmbientLux : -1;
772 mBrightnessAdjustmentSampleOldBrightness = mScreenAutoBrightness;
Jeff Browna576b4d2015-04-23 19:58:06 -0700773 } else {
774 mHandler.removeMessages(MSG_BRIGHTNESS_ADJUSTMENT_SAMPLE);
775 }
776
777 mHandler.sendEmptyMessageDelayed(MSG_BRIGHTNESS_ADJUSTMENT_SAMPLE,
778 BRIGHTNESS_ADJUSTMENT_SAMPLE_DEBOUNCE_MILLIS);
779 }
780
Sudheer Shankab3f60652019-01-04 20:30:14 +0000781 private void cancelBrightnessAdjustmentSample() {
782 if (mBrightnessAdjustmentSamplePending) {
783 mBrightnessAdjustmentSamplePending = false;
784 mHandler.removeMessages(MSG_BRIGHTNESS_ADJUSTMENT_SAMPLE);
785 }
786 }
787
Jeff Browna576b4d2015-04-23 19:58:06 -0700788 private void collectBrightnessAdjustmentSample() {
789 if (mBrightnessAdjustmentSamplePending) {
790 mBrightnessAdjustmentSamplePending = false;
791 if (mAmbientLuxValid && mScreenAutoBrightness >= 0) {
Dan Gittika5a2d632019-01-09 14:25:29 +0000792 if (mLoggingEnabled) {
Dan Gittikc5d32912018-02-22 13:53:47 +0000793 Slog.d(TAG, "Auto-brightness adjustment changed by user: " +
Dan Gittik57d6f112018-03-27 18:14:22 +0100794 "lux=" + mAmbientLux + ", " +
795 "brightness=" + mScreenAutoBrightness + ", " +
796 "ring=" + mAmbientLightRingBuffer);
Jeff Browna576b4d2015-04-23 19:58:06 -0700797 }
798
799 EventLog.writeEvent(EventLogTags.AUTO_BRIGHTNESS_ADJ,
Jeff Browna576b4d2015-04-23 19:58:06 -0700800 mBrightnessAdjustmentSampleOldLux,
801 mBrightnessAdjustmentSampleOldBrightness,
Jeff Browna576b4d2015-04-23 19:58:06 -0700802 mAmbientLux,
Dan Gittik57d6f112018-03-27 18:14:22 +0100803 mScreenAutoBrightness);
Jeff Browna576b4d2015-04-23 19:58:06 -0700804 }
805 }
806 }
807
Dan Gittika5a2d632019-01-09 14:25:29 +0000808 // Register a TaskStackListener to call back to us onTaskStackChanged, so we can update the
809 // foreground app's package name and category and correct the brightness accordingly.
810 private void registerForegroundAppUpdater() {
811 try {
812 mActivityTaskManager.registerTaskStackListener(mTaskStackListener);
813 // This will not get called until the foreground app changes for the first time, so
814 // call it explicitly to get the current foreground app's info.
815 updateForegroundApp();
816 } catch (RemoteException e) {
817 if (mLoggingEnabled) {
818 Slog.e(TAG, "Failed to register foreground app updater: " + e);
819 }
820 // Nothing to do.
821 }
822 }
823
824 private void unregisterForegroundAppUpdater() {
825 try {
826 mActivityTaskManager.unregisterTaskStackListener(mTaskStackListener);
827 } catch (RemoteException e) {
828 // Nothing to do.
829 }
830 mForegroundAppPackageName = null;
831 mForegroundAppCategory = ApplicationInfo.CATEGORY_UNDEFINED;
832 }
833
834 // Set the foreground app's package name and category, so brightness can be corrected per app.
835 private void updateForegroundApp() {
836 if (mLoggingEnabled) {
837 Slog.d(TAG, "Attempting to update foreground app");
838 }
839 // The ActivityTaskManager's lock tends to get contended, so this is done in a background
840 // thread and applied via this thread's handler synchronously.
841 BackgroundThread.getHandler().post(new Runnable() {
842 public void run() {
843 try {
844 // The foreground app is the top activity of the focused tasks stack.
845 final StackInfo info = mActivityTaskManager.getFocusedStackInfo();
846 if (info == null || info.topActivity == null) {
847 return;
848 }
849 final String packageName = info.topActivity.getPackageName();
850 // If the app didn't change, there's nothing to do. Otherwise, we have to
851 // update the category and re-apply the brightness correction.
852 if (mForegroundAppPackageName != null
853 && mForegroundAppPackageName.equals(packageName)) {
854 return;
855 }
856 mPendingForegroundAppPackageName = packageName;
857 mPendingForegroundAppCategory = ApplicationInfo.CATEGORY_UNDEFINED;
858 try {
859 ApplicationInfo app = mPackageManager.getApplicationInfo(packageName,
860 PackageManager.MATCH_ANY_USER);
861 mPendingForegroundAppCategory = app.category;
862 } catch (PackageManager.NameNotFoundException e) {
863 // Nothing to do
864 }
865 mHandler.sendEmptyMessage(MSG_UPDATE_FOREGROUND_APP_SYNC);
866 } catch (RemoteException e) {
867 // Nothing to do
868 }
869 }
870 });
871 }
872
873 private void updateForegroundAppSync() {
874 if (mLoggingEnabled) {
875 Slog.d(TAG, "Updating foreground app: packageName=" + mPendingForegroundAppPackageName
876 + ", category=" + mPendingForegroundAppCategory);
877 }
878 mForegroundAppPackageName = mPendingForegroundAppPackageName;
879 mPendingForegroundAppPackageName = null;
880 mForegroundAppCategory = mPendingForegroundAppCategory;
881 mPendingForegroundAppCategory = ApplicationInfo.CATEGORY_UNDEFINED;
882 updateAutoBrightness(true /* sendUpdate */);
883 }
884
Michael Wright639c8be2014-01-17 18:29:12 -0800885 private final class AutomaticBrightnessHandler extends Handler {
886 public AutomaticBrightnessHandler(Looper looper) {
887 super(looper, null, true /*async*/);
888 }
889
890 @Override
891 public void handleMessage(Message msg) {
892 switch (msg.what) {
893 case MSG_UPDATE_AMBIENT_LUX:
894 updateAmbientLux();
895 break;
Jeff Browna576b4d2015-04-23 19:58:06 -0700896
897 case MSG_BRIGHTNESS_ADJUSTMENT_SAMPLE:
898 collectBrightnessAdjustmentSample();
899 break;
Michael Wrightd8460232018-01-16 18:04:59 +0000900
Dan Gittikc5d32912018-02-22 13:53:47 +0000901 case MSG_INVALIDATE_SHORT_TERM_MODEL:
902 invalidateShortTermModel();
Michael Wrightd8460232018-01-16 18:04:59 +0000903 break;
Dan Gittika5a2d632019-01-09 14:25:29 +0000904
905 case MSG_UPDATE_FOREGROUND_APP:
906 updateForegroundApp();
907 break;
908
909 case MSG_UPDATE_FOREGROUND_APP_SYNC:
910 updateForegroundAppSync();
911 break;
Michael Wright639c8be2014-01-17 18:29:12 -0800912 }
913 }
914 }
915
916 private final SensorEventListener mLightSensorListener = new SensorEventListener() {
917 @Override
918 public void onSensorChanged(SensorEvent event) {
919 if (mLightSensorEnabled) {
920 final long time = SystemClock.uptimeMillis();
921 final float lux = event.values[0];
922 handleLightSensorEvent(time, lux);
923 }
924 }
925
926 @Override
927 public void onAccuracyChanged(Sensor sensor, int accuracy) {
928 // Not used.
929 }
930 };
931
Dan Gittika5a2d632019-01-09 14:25:29 +0000932 // Call back whenever the tasks stack changes, which includes tasks being created, removed, and
933 // moving to top.
934 class TaskStackListenerImpl extends TaskStackListener {
935 @Override
936 public void onTaskStackChanged() {
937 mHandler.sendEmptyMessage(MSG_UPDATE_FOREGROUND_APP);
938 }
939 }
940
Michael Wright639c8be2014-01-17 18:29:12 -0800941 /** Callbacks to request updates to the display's power state. */
942 interface Callbacks {
943 void updateBrightness();
944 }
945
Michael Wright0a933142017-08-16 20:38:21 +0100946 /**
947 * A ring buffer of ambient light measurements sorted by time.
948 *
949 * Each entry consists of a timestamp and a lux measurement, and the overall buffer is sorted
950 * from oldest to newest.
951 */
Michael Wright103fb782016-04-22 01:03:09 -0400952 private static final class AmbientLightRingBuffer {
Michael Wright639c8be2014-01-17 18:29:12 -0800953 // Proportional extra capacity of the buffer beyond the expected number of light samples
954 // in the horizon
955 private static final float BUFFER_SLACK = 1.5f;
Michael Wright639c8be2014-01-17 18:29:12 -0800956 private float[] mRingLux;
957 private long[] mRingTime;
958 private int mCapacity;
959
960 // The first valid element and the next open slot.
961 // Note that if mCount is zero then there are no valid elements.
962 private int mStart;
963 private int mEnd;
964 private int mCount;
965
Zoran Jovanovic6fc42f52015-12-10 17:01:16 +0100966 public AmbientLightRingBuffer(long lightSensorRate, int ambientLightHorizon) {
967 mCapacity = (int) Math.ceil(ambientLightHorizon * BUFFER_SLACK / lightSensorRate);
Michael Wright639c8be2014-01-17 18:29:12 -0800968 mRingLux = new float[mCapacity];
969 mRingTime = new long[mCapacity];
970 }
971
972 public float getLux(int index) {
973 return mRingLux[offsetOf(index)];
974 }
975
976 public long getTime(int index) {
977 return mRingTime[offsetOf(index)];
978 }
979
980 public void push(long time, float lux) {
981 int next = mEnd;
982 if (mCount == mCapacity) {
983 int newSize = mCapacity * 2;
984
985 float[] newRingLux = new float[newSize];
986 long[] newRingTime = new long[newSize];
987 int length = mCapacity - mStart;
988 System.arraycopy(mRingLux, mStart, newRingLux, 0, length);
989 System.arraycopy(mRingTime, mStart, newRingTime, 0, length);
990 if (mStart != 0) {
991 System.arraycopy(mRingLux, 0, newRingLux, length, mStart);
992 System.arraycopy(mRingTime, 0, newRingTime, length, mStart);
993 }
994 mRingLux = newRingLux;
995 mRingTime = newRingTime;
996
997 next = mCapacity;
998 mCapacity = newSize;
999 mStart = 0;
1000 }
1001 mRingTime[next] = time;
1002 mRingLux[next] = lux;
1003 mEnd = next + 1;
1004 if (mEnd == mCapacity) {
1005 mEnd = 0;
1006 }
1007 mCount++;
1008 }
1009
1010 public void prune(long horizon) {
1011 if (mCount == 0) {
1012 return;
1013 }
1014
1015 while (mCount > 1) {
1016 int next = mStart + 1;
1017 if (next >= mCapacity) {
1018 next -= mCapacity;
1019 }
1020 if (mRingTime[next] > horizon) {
1021 // Some light sensors only produce data upon a change in the ambient light
1022 // levels, so we need to consider the previous measurement as the ambient light
1023 // level for all points in time up until we receive a new measurement. Thus, we
1024 // always want to keep the youngest element that would be removed from the
1025 // buffer and just set its measurement time to the horizon time since at that
1026 // point it is the ambient light level, and to remove it would be to drop a
1027 // valid data point within our horizon.
1028 break;
1029 }
1030 mStart = next;
1031 mCount -= 1;
1032 }
1033
1034 if (mRingTime[mStart] < horizon) {
1035 mRingTime[mStart] = horizon;
1036 }
1037 }
1038
1039 public int size() {
1040 return mCount;
1041 }
1042
Michael Wright639c8be2014-01-17 18:29:12 -08001043 public void clear() {
1044 mStart = 0;
1045 mEnd = 0;
1046 mCount = 0;
1047 }
1048
1049 @Override
1050 public String toString() {
Jeff Browna576b4d2015-04-23 19:58:06 -07001051 StringBuffer buf = new StringBuffer();
1052 buf.append('[');
1053 for (int i = 0; i < mCount; i++) {
1054 final long next = i + 1 < mCount ? getTime(i + 1) : SystemClock.uptimeMillis();
1055 if (i != 0) {
1056 buf.append(", ");
1057 }
1058 buf.append(getLux(i));
1059 buf.append(" / ");
1060 buf.append(next - getTime(i));
1061 buf.append("ms");
Michael Wright639c8be2014-01-17 18:29:12 -08001062 }
Jeff Browna576b4d2015-04-23 19:58:06 -07001063 buf.append(']');
1064 return buf.toString();
Michael Wright639c8be2014-01-17 18:29:12 -08001065 }
1066
1067 private int offsetOf(int index) {
1068 if (index >= mCount || index < 0) {
1069 throw new ArrayIndexOutOfBoundsException(index);
1070 }
1071 index += mStart;
1072 if (index >= mCapacity) {
1073 index -= mCapacity;
1074 }
1075 return index;
1076 }
1077 }
1078}