blob: d57431e6b58b95fb25999695e4866c47dbd79bb0 [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,
Dan Gittik57d6f112018-03-27 18:14:22 +0100219 SensorManager sensorManager, BrightnessMappingStrategy mapper,
220 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) {
252 mLightSensor = mSensorManager.getDefaultSensor(Sensor.TYPE_LIGHT);
253 }
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
Michael Wright617564f2018-01-25 22:20:54 +0000291 public float getAutomaticScreenBrightnessAdjustment() {
Dan Gittik57d6f112018-03-27 18:14:22 +0100292 return mBrightnessMapper.getAutoBrightnessAdjustment();
Michael Wright617564f2018-01-25 22:20:54 +0000293 }
294
Michael Wrighteef0e132017-11-21 17:57:52 +0000295 public void configure(boolean enable, @Nullable BrightnessConfiguration configuration,
Michael Wright617564f2018-01-25 22:20:54 +0000296 float brightness, boolean userChangedBrightness, float adjustment,
297 boolean userChangedAutoBrightnessAdjustment, int displayPolicy) {
Filip Gruszczynskia15aa7d2014-10-28 14:12:40 -0700298 // While dozing, the application processor may be suspended which will prevent us from
299 // receiving new information from the light sensor. On some devices, we may be able to
300 // switch to a wake-up light sensor instead but for now we will simply disable the sensor
301 // and hold onto the last computed screen auto brightness. We save the dozing flag for
302 // debugging purposes.
Michael Wrightd8460232018-01-16 18:04:59 +0000303 boolean dozing = (displayPolicy == DisplayPowerRequest.POLICY_DOZE);
Michael Wrighteef0e132017-11-21 17:57:52 +0000304 boolean changed = setBrightnessConfiguration(configuration);
Michael Wrightd8460232018-01-16 18:04:59 +0000305 changed |= setDisplayPolicy(displayPolicy);
Dan Gittik57d6f112018-03-27 18:14:22 +0100306 if (userChangedAutoBrightnessAdjustment) {
307 changed |= setAutoBrightnessAdjustment(adjustment);
308 }
Michael Wright617564f2018-01-25 22:20:54 +0000309 if (userChangedBrightness && enable) {
310 // Update the brightness curve with the new user control point. It's critical this
311 // happens after we update the autobrightness adjustment since it may reset it.
Michael Wrightd8460232018-01-16 18:04:59 +0000312 changed |= setScreenBrightnessByUser(brightness);
Michael Wright617564f2018-01-25 22:20:54 +0000313 }
314 final boolean userInitiatedChange =
315 userChangedBrightness || userChangedAutoBrightnessAdjustment;
316 if (userInitiatedChange && enable && !dozing) {
Soroosh Mariooryada8edffd2017-03-22 17:08:26 -0700317 prepareBrightnessAdjustmentSample();
318 }
Michael Wrightd8460232018-01-16 18:04:59 +0000319 changed |= setLightSensorEnabled(enable && !dozing);
Jeff Brown970d4132014-07-19 11:33:47 -0700320 if (changed) {
Michael Wright639c8be2014-01-17 18:29:12 -0800321 updateAutoBrightness(false /*sendUpdate*/);
322 }
323 }
324
Kenny Guy53d06612018-01-30 14:19:13 +0000325 public boolean hasUserDataPoints() {
326 return mBrightnessMapper.hasUserDataPoints();
327 }
328
329 public boolean isDefaultConfig() {
330 return mBrightnessMapper.isDefaultConfig();
331 }
332
Kenny Guy6d1009f2018-03-14 14:28:23 +0000333 public BrightnessConfiguration getDefaultConfig() {
334 return mBrightnessMapper.getDefaultConfig();
335 }
336
Michael Wrightd8460232018-01-16 18:04:59 +0000337 private boolean setDisplayPolicy(int policy) {
338 if (mDisplayPolicy == policy) {
339 return false;
340 }
341 final int oldPolicy = mDisplayPolicy;
342 mDisplayPolicy = policy;
Dan Gittika5a2d632019-01-09 14:25:29 +0000343 if (mLoggingEnabled) {
Dan Gittikc5d32912018-02-22 13:53:47 +0000344 Slog.d(TAG, "Display policy transitioning from " + oldPolicy + " to " + policy);
Michael Wrightd8460232018-01-16 18:04:59 +0000345 }
346 if (!isInteractivePolicy(policy) && isInteractivePolicy(oldPolicy)) {
Dan Gittikc5d32912018-02-22 13:53:47 +0000347 mHandler.sendEmptyMessageDelayed(MSG_INVALIDATE_SHORT_TERM_MODEL,
Dan Gittik825cc072018-12-17 14:24:48 +0000348 mShortTermModelTimeout);
Michael Wrightd8460232018-01-16 18:04:59 +0000349 } else if (isInteractivePolicy(policy) && !isInteractivePolicy(oldPolicy)) {
Dan Gittikc5d32912018-02-22 13:53:47 +0000350 mHandler.removeMessages(MSG_INVALIDATE_SHORT_TERM_MODEL);
Michael Wrightd8460232018-01-16 18:04:59 +0000351 }
352 return true;
353 }
354
355 private static boolean isInteractivePolicy(int policy) {
356 return policy == DisplayPowerRequest.POLICY_BRIGHT
357 || policy == DisplayPowerRequest.POLICY_DIM
358 || policy == DisplayPowerRequest.POLICY_VR;
359 }
360
361 private boolean setScreenBrightnessByUser(float brightness) {
362 if (!mAmbientLuxValid) {
363 // If we don't have a valid ambient lux then we don't have a valid brightness anyways,
364 // and we can't use this data to add a new control point to the short-term model.
365 return false;
366 }
367 mBrightnessMapper.addUserDataPoint(mAmbientLux, brightness);
Dan Gittikc5d32912018-02-22 13:53:47 +0000368 mShortTermModelValid = true;
369 mShortTermModelAnchor = mAmbientLux;
Dan Gittika5a2d632019-01-09 14:25:29 +0000370 if (mLoggingEnabled) {
Dan Gittikc5d32912018-02-22 13:53:47 +0000371 Slog.d(TAG, "ShortTermModel: anchor=" + mShortTermModelAnchor);
372 }
Michael Wrightd8460232018-01-16 18:04:59 +0000373 return true;
374 }
375
Dan Gittikc1352252018-04-27 17:48:31 +0100376 public void resetShortTermModel() {
Michael Wrightd8460232018-01-16 18:04:59 +0000377 mBrightnessMapper.clearUserDataPoints();
Dan Gittikc5d32912018-02-22 13:53:47 +0000378 mShortTermModelValid = true;
379 mShortTermModelAnchor = -1;
380 }
381
382 private void invalidateShortTermModel() {
Dan Gittika5a2d632019-01-09 14:25:29 +0000383 if (mLoggingEnabled) {
Dan Gittikc5d32912018-02-22 13:53:47 +0000384 Slog.d(TAG, "ShortTermModel: invalidate user data");
385 }
386 mShortTermModelValid = false;
Michael Wrightd8460232018-01-16 18:04:59 +0000387 }
388
Michael Wrighteef0e132017-11-21 17:57:52 +0000389 public boolean setBrightnessConfiguration(BrightnessConfiguration configuration) {
Michael Wrightb8f4f772018-05-01 18:28:58 +0100390 if (mBrightnessMapper.setBrightnessConfiguration(configuration)) {
391 resetShortTermModel();
392 return true;
393 }
394 return false;
Michael Wrighteef0e132017-11-21 17:57:52 +0000395 }
396
Michael Wright639c8be2014-01-17 18:29:12 -0800397 public void dump(PrintWriter pw) {
398 pw.println();
399 pw.println("Automatic Brightness Controller Configuration:");
Michael Wright639c8be2014-01-17 18:29:12 -0800400 pw.println(" mScreenBrightnessRangeMinimum=" + mScreenBrightnessRangeMinimum);
401 pw.println(" mScreenBrightnessRangeMaximum=" + mScreenBrightnessRangeMaximum);
Michael Wright2155bc22018-05-01 00:38:32 +0100402 pw.println(" mDozeScaleFactor=" + mDozeScaleFactor);
403 pw.println(" mInitialLightSensorRate=" + mInitialLightSensorRate);
404 pw.println(" mNormalLightSensorRate=" + mNormalLightSensorRate);
Michael Wright639c8be2014-01-17 18:29:12 -0800405 pw.println(" mLightSensorWarmUpTimeConfig=" + mLightSensorWarmUpTimeConfig);
Filip Gruszczynskid81ecd12015-02-06 12:38:47 -0800406 pw.println(" mBrighteningLightDebounceConfig=" + mBrighteningLightDebounceConfig);
407 pw.println(" mDarkeningLightDebounceConfig=" + mDarkeningLightDebounceConfig);
408 pw.println(" mResetAmbientLuxAfterWarmUpConfig=" + mResetAmbientLuxAfterWarmUpConfig);
Michael Wright2155bc22018-05-01 00:38:32 +0100409 pw.println(" mAmbientLightHorizon=" + mAmbientLightHorizon);
410 pw.println(" mWeightingIntercept=" + mWeightingIntercept);
Michael Wright639c8be2014-01-17 18:29:12 -0800411
412 pw.println();
413 pw.println("Automatic Brightness Controller State:");
414 pw.println(" mLightSensor=" + mLightSensor);
Michael Wright639c8be2014-01-17 18:29:12 -0800415 pw.println(" mLightSensorEnabled=" + mLightSensorEnabled);
416 pw.println(" mLightSensorEnableTime=" + TimeUtils.formatUptime(mLightSensorEnableTime));
Michael Wright2155bc22018-05-01 00:38:32 +0100417 pw.println(" mCurrentLightSensorRate=" + mCurrentLightSensorRate);
Michael Wright639c8be2014-01-17 18:29:12 -0800418 pw.println(" mAmbientLux=" + mAmbientLux);
Dan Gittik58784422018-04-05 12:30:38 +0100419 pw.println(" mAmbientLuxValid=" + mAmbientLuxValid);
Dan Gittiked958e92018-11-13 14:58:20 +0000420 pw.println(" mAmbientBrighteningThreshold=" + mAmbientBrighteningThreshold);
421 pw.println(" mAmbientDarkeningThreshold=" + mAmbientDarkeningThreshold);
422 pw.println(" mScreenBrighteningThreshold=" + mScreenBrighteningThreshold);
423 pw.println(" mScreenDarkeningThreshold=" + mScreenDarkeningThreshold);
Michael Wright639c8be2014-01-17 18:29:12 -0800424 pw.println(" mLastObservedLux=" + mLastObservedLux);
425 pw.println(" mLastObservedLuxTime=" + TimeUtils.formatUptime(mLastObservedLuxTime));
426 pw.println(" mRecentLightSamples=" + mRecentLightSamples);
427 pw.println(" mAmbientLightRingBuffer=" + mAmbientLightRingBuffer);
428 pw.println(" mScreenAutoBrightness=" + mScreenAutoBrightness);
Michael Wright2155bc22018-05-01 00:38:32 +0100429 pw.println(" mDisplayPolicy=" + DisplayPowerRequest.policyToString(mDisplayPolicy));
Dan Gittik825cc072018-12-17 14:24:48 +0000430 pw.println(" mShortTermModelTimeout=" + mShortTermModelTimeout);
Dan Gittikc5d32912018-02-22 13:53:47 +0000431 pw.println(" mShortTermModelAnchor=" + mShortTermModelAnchor);
Michael Wright2155bc22018-05-01 00:38:32 +0100432 pw.println(" mShortTermModelValid=" + mShortTermModelValid);
433 pw.println(" mBrightnessAdjustmentSamplePending=" + mBrightnessAdjustmentSamplePending);
434 pw.println(" mBrightnessAdjustmentSampleOldLux=" + mBrightnessAdjustmentSampleOldLux);
435 pw.println(" mBrightnessAdjustmentSampleOldBrightness="
436 + mBrightnessAdjustmentSampleOldBrightness);
Dan Gittika5a2d632019-01-09 14:25:29 +0000437 pw.println(" mForegroundAppPackageName=" + mForegroundAppPackageName);
438 pw.println(" mPendingForegroundAppPackageName=" + mPendingForegroundAppPackageName);
439 pw.println(" mForegroundAppCategory=" + mForegroundAppCategory);
440 pw.println(" mPendingForegroundAppCategory=" + mPendingForegroundAppCategory);
Michael Wrighteef0e132017-11-21 17:57:52 +0000441
442 pw.println();
443 mBrightnessMapper.dump(pw);
Michael Wright2155bc22018-05-01 00:38:32 +0100444
445 pw.println();
Dan Gittiked958e92018-11-13 14:58:20 +0000446 mAmbientBrightnessThresholds.dump(pw);
447 mScreenBrightnessThresholds.dump(pw);
Michael Wright639c8be2014-01-17 18:29:12 -0800448 }
449
450 private boolean setLightSensorEnabled(boolean enable) {
451 if (enable) {
452 if (!mLightSensorEnabled) {
453 mLightSensorEnabled = true;
454 mLightSensorEnableTime = SystemClock.uptimeMillis();
Julius D'souza5d717092016-10-24 19:26:45 -0700455 mCurrentLightSensorRate = mInitialLightSensorRate;
Dan Gittika5a2d632019-01-09 14:25:29 +0000456 registerForegroundAppUpdater();
Michael Wright639c8be2014-01-17 18:29:12 -0800457 mSensorManager.registerListener(mLightSensorListener, mLightSensor,
Julius D'souza5d717092016-10-24 19:26:45 -0700458 mCurrentLightSensorRate * 1000, mHandler);
Michael Wright639c8be2014-01-17 18:29:12 -0800459 return true;
460 }
Dan Gittikc5d32912018-02-22 13:53:47 +0000461 } else if (mLightSensorEnabled) {
462 mLightSensorEnabled = false;
463 mAmbientLuxValid = !mResetAmbientLuxAfterWarmUpConfig;
Dan Gittikf387dd72018-07-13 15:10:39 +0100464 mScreenAutoBrightness = -1;
Dan Gittikc5d32912018-02-22 13:53:47 +0000465 mRecentLightSamples = 0;
466 mAmbientLightRingBuffer.clear();
467 mCurrentLightSensorRate = -1;
468 mHandler.removeMessages(MSG_UPDATE_AMBIENT_LUX);
Dan Gittika5a2d632019-01-09 14:25:29 +0000469 unregisterForegroundAppUpdater();
Dan Gittikc5d32912018-02-22 13:53:47 +0000470 mSensorManager.unregisterListener(mLightSensorListener);
Michael Wright639c8be2014-01-17 18:29:12 -0800471 }
472 return false;
473 }
474
475 private void handleLightSensorEvent(long time, float lux) {
Michael Wrightb0a1d3d2017-09-22 15:05:02 +0100476 Trace.traceCounter(Trace.TRACE_TAG_POWER, "ALS", (int) lux);
Michael Wright639c8be2014-01-17 18:29:12 -0800477 mHandler.removeMessages(MSG_UPDATE_AMBIENT_LUX);
478
Julius D'souza5d717092016-10-24 19:26:45 -0700479 if (mAmbientLightRingBuffer.size() == 0) {
480 // switch to using the steady-state sample rate after grabbing the initial light sample
481 adjustLightSensorRate(mNormalLightSensorRate);
482 }
Michael Wright639c8be2014-01-17 18:29:12 -0800483 applyLightSensorMeasurement(time, lux);
484 updateAmbientLux(time);
485 }
486
487 private void applyLightSensorMeasurement(long time, float lux) {
488 mRecentLightSamples++;
Zoran Jovanovic6fc42f52015-12-10 17:01:16 +0100489 mAmbientLightRingBuffer.prune(time - mAmbientLightHorizon);
Michael Wright639c8be2014-01-17 18:29:12 -0800490 mAmbientLightRingBuffer.push(time, lux);
491
492 // Remember this sample value.
493 mLastObservedLux = lux;
494 mLastObservedLuxTime = time;
495 }
496
Julius D'souza5d717092016-10-24 19:26:45 -0700497 private void adjustLightSensorRate(int lightSensorRate) {
498 // if the light sensor rate changed, update the sensor listener
499 if (lightSensorRate != mCurrentLightSensorRate) {
Dan Gittika5a2d632019-01-09 14:25:29 +0000500 if (mLoggingEnabled) {
Dan Gittikc5d32912018-02-22 13:53:47 +0000501 Slog.d(TAG, "adjustLightSensorRate: " +
Dan Gittik57d6f112018-03-27 18:14:22 +0100502 "previousRate=" + mCurrentLightSensorRate + ", " +
503 "currentRate=" + lightSensorRate);
Julius D'souza5d717092016-10-24 19:26:45 -0700504 }
505 mCurrentLightSensorRate = lightSensorRate;
506 mSensorManager.unregisterListener(mLightSensorListener);
507 mSensorManager.registerListener(mLightSensorListener, mLightSensor,
508 lightSensorRate * 1000, mHandler);
509 }
510 }
511
Dan Gittik57d6f112018-03-27 18:14:22 +0100512 private boolean setAutoBrightnessAdjustment(float adjustment) {
513 return mBrightnessMapper.setAutoBrightnessAdjustment(adjustment);
Michael Wright639c8be2014-01-17 18:29:12 -0800514 }
515
516 private void setAmbientLux(float lux) {
Dan Gittika5a2d632019-01-09 14:25:29 +0000517 if (mLoggingEnabled) {
Michael Wright0a933142017-08-16 20:38:21 +0100518 Slog.d(TAG, "setAmbientLux(" + lux + ")");
519 }
Michael Wrightd8460232018-01-16 18:04:59 +0000520 if (lux < 0) {
Dan Gittikc5d32912018-02-22 13:53:47 +0000521 Slog.w(TAG, "Ambient lux was negative, ignoring and setting to 0");
Michael Wrightd8460232018-01-16 18:04:59 +0000522 lux = 0;
523 }
Michael Wright639c8be2014-01-17 18:29:12 -0800524 mAmbientLux = lux;
Dan Gittiked958e92018-11-13 14:58:20 +0000525 mAmbientBrighteningThreshold = mAmbientBrightnessThresholds.getBrighteningThreshold(lux);
526 mAmbientDarkeningThreshold = mAmbientBrightnessThresholds.getDarkeningThreshold(lux);
Dan Gittikc5d32912018-02-22 13:53:47 +0000527
528 // If the short term model was invalidated and the change is drastic enough, reset it.
529 if (!mShortTermModelValid && mShortTermModelAnchor != -1) {
530 final float minAmbientLux =
531 mShortTermModelAnchor - mShortTermModelAnchor * SHORT_TERM_MODEL_THRESHOLD_RATIO;
532 final float maxAmbientLux =
533 mShortTermModelAnchor + mShortTermModelAnchor * SHORT_TERM_MODEL_THRESHOLD_RATIO;
534 if (minAmbientLux < mAmbientLux && mAmbientLux < maxAmbientLux) {
Dan Gittika5a2d632019-01-09 14:25:29 +0000535 if (mLoggingEnabled) {
Dan Gittik57d6f112018-03-27 18:14:22 +0100536 Slog.d(TAG, "ShortTermModel: re-validate user data, ambient lux is " +
537 minAmbientLux + " < " + mAmbientLux + " < " + maxAmbientLux);
538 }
Dan Gittikc5d32912018-02-22 13:53:47 +0000539 mShortTermModelValid = true;
540 } else {
541 Slog.d(TAG, "ShortTermModel: reset data, ambient lux is " + mAmbientLux +
Dan Gittik57d6f112018-03-27 18:14:22 +0100542 "(" + minAmbientLux + ", " + maxAmbientLux + ")");
Dan Gittikc5d32912018-02-22 13:53:47 +0000543 resetShortTermModel();
544 }
545 }
Michael Wright639c8be2014-01-17 18:29:12 -0800546 }
547
Michael Wright0a933142017-08-16 20:38:21 +0100548 private float calculateAmbientLux(long now, long horizon) {
Dan Gittika5a2d632019-01-09 14:25:29 +0000549 if (mLoggingEnabled) {
Michael Wright0a933142017-08-16 20:38:21 +0100550 Slog.d(TAG, "calculateAmbientLux(" + now + ", " + horizon + ")");
551 }
Michael Wright639c8be2014-01-17 18:29:12 -0800552 final int N = mAmbientLightRingBuffer.size();
553 if (N == 0) {
554 Slog.e(TAG, "calculateAmbientLux: No ambient light readings available");
555 return -1;
556 }
Michael Wright0a933142017-08-16 20:38:21 +0100557
558 // Find the first measurement that is just outside of the horizon.
559 int endIndex = 0;
560 final long horizonStartTime = now - horizon;
561 for (int i = 0; i < N-1; i++) {
562 if (mAmbientLightRingBuffer.getTime(i + 1) <= horizonStartTime) {
563 endIndex++;
564 } else {
565 break;
566 }
567 }
Dan Gittika5a2d632019-01-09 14:25:29 +0000568 if (mLoggingEnabled) {
Dan Gittik57d6f112018-03-27 18:14:22 +0100569 Slog.d(TAG, "calculateAmbientLux: selected endIndex=" + endIndex + ", point=(" +
570 mAmbientLightRingBuffer.getTime(endIndex) + ", " +
571 mAmbientLightRingBuffer.getLux(endIndex) + ")");
Michael Wright0a933142017-08-16 20:38:21 +0100572 }
Michael Wright639c8be2014-01-17 18:29:12 -0800573 float sum = 0;
574 float totalWeight = 0;
575 long endTime = AMBIENT_LIGHT_PREDICTION_TIME_MILLIS;
Michael Wright0a933142017-08-16 20:38:21 +0100576 for (int i = N - 1; i >= endIndex; i--) {
577 long eventTime = mAmbientLightRingBuffer.getTime(i);
578 if (i == endIndex && eventTime < horizonStartTime) {
579 // If we're at the final value, make sure we only consider the part of the sample
580 // within our desired horizon.
581 eventTime = horizonStartTime;
582 }
583 final long startTime = eventTime - now;
Michael Wright639c8be2014-01-17 18:29:12 -0800584 float weight = calculateWeight(startTime, endTime);
585 float lux = mAmbientLightRingBuffer.getLux(i);
Dan Gittika5a2d632019-01-09 14:25:29 +0000586 if (mLoggingEnabled) {
Dan Gittikc5d32912018-02-22 13:53:47 +0000587 Slog.d(TAG, "calculateAmbientLux: [" + startTime + ", " + endTime + "]: " +
Dan Gittik57d6f112018-03-27 18:14:22 +0100588 "lux=" + lux + ", " +
589 "weight=" + weight);
Michael Wright639c8be2014-01-17 18:29:12 -0800590 }
591 totalWeight += weight;
Dan Gittikc5d32912018-02-22 13:53:47 +0000592 sum += lux * weight;
Michael Wright639c8be2014-01-17 18:29:12 -0800593 endTime = startTime;
594 }
Dan Gittika5a2d632019-01-09 14:25:29 +0000595 if (mLoggingEnabled) {
Dan Gittikc5d32912018-02-22 13:53:47 +0000596 Slog.d(TAG, "calculateAmbientLux: " +
Dan Gittik57d6f112018-03-27 18:14:22 +0100597 "totalWeight=" + totalWeight + ", " +
598 "newAmbientLux=" + (sum / totalWeight));
Michael Wright639c8be2014-01-17 18:29:12 -0800599 }
600 return sum / totalWeight;
601 }
602
Zoran Jovanovic6fc42f52015-12-10 17:01:16 +0100603 private float calculateWeight(long startDelta, long endDelta) {
Michael Wright639c8be2014-01-17 18:29:12 -0800604 return weightIntegral(endDelta) - weightIntegral(startDelta);
605 }
606
Zoran Jovanovic6fc42f52015-12-10 17:01:16 +0100607 // Evaluates the integral of y = x + mWeightingIntercept. This is always positive for the
Michael Wright639c8be2014-01-17 18:29:12 -0800608 // horizon we're looking at and provides a non-linear weighting for light samples.
Zoran Jovanovic6fc42f52015-12-10 17:01:16 +0100609 private float weightIntegral(long x) {
610 return x * (x * 0.5f + mWeightingIntercept);
Michael Wright639c8be2014-01-17 18:29:12 -0800611 }
612
613 private long nextAmbientLightBrighteningTransition(long time) {
614 final int N = mAmbientLightRingBuffer.size();
615 long earliestValidTime = time;
616 for (int i = N - 1; i >= 0; i--) {
Dan Gittiked958e92018-11-13 14:58:20 +0000617 if (mAmbientLightRingBuffer.getLux(i) <= mAmbientBrighteningThreshold) {
Michael Wright639c8be2014-01-17 18:29:12 -0800618 break;
619 }
620 earliestValidTime = mAmbientLightRingBuffer.getTime(i);
621 }
Filip Gruszczynskid81ecd12015-02-06 12:38:47 -0800622 return earliestValidTime + mBrighteningLightDebounceConfig;
Michael Wright639c8be2014-01-17 18:29:12 -0800623 }
624
625 private long nextAmbientLightDarkeningTransition(long time) {
626 final int N = mAmbientLightRingBuffer.size();
627 long earliestValidTime = time;
628 for (int i = N - 1; i >= 0; i--) {
Dan Gittiked958e92018-11-13 14:58:20 +0000629 if (mAmbientLightRingBuffer.getLux(i) >= mAmbientDarkeningThreshold) {
Michael Wright639c8be2014-01-17 18:29:12 -0800630 break;
631 }
632 earliestValidTime = mAmbientLightRingBuffer.getTime(i);
633 }
Filip Gruszczynskid81ecd12015-02-06 12:38:47 -0800634 return earliestValidTime + mDarkeningLightDebounceConfig;
Michael Wright639c8be2014-01-17 18:29:12 -0800635 }
636
637 private void updateAmbientLux() {
638 long time = SystemClock.uptimeMillis();
Zoran Jovanovic6fc42f52015-12-10 17:01:16 +0100639 mAmbientLightRingBuffer.prune(time - mAmbientLightHorizon);
Michael Wright639c8be2014-01-17 18:29:12 -0800640 updateAmbientLux(time);
641 }
642
643 private void updateAmbientLux(long time) {
644 // If the light sensor was just turned on then immediately update our initial
645 // estimate of the current ambient light level.
646 if (!mAmbientLuxValid) {
647 final long timeWhenSensorWarmedUp =
648 mLightSensorWarmUpTimeConfig + mLightSensorEnableTime;
649 if (time < timeWhenSensorWarmedUp) {
Dan Gittika5a2d632019-01-09 14:25:29 +0000650 if (mLoggingEnabled) {
Dan Gittikc5d32912018-02-22 13:53:47 +0000651 Slog.d(TAG, "updateAmbientLux: Sensor not ready yet: " +
Dan Gittik57d6f112018-03-27 18:14:22 +0100652 "time=" + time + ", " +
653 "timeWhenSensorWarmedUp=" + timeWhenSensorWarmedUp);
Michael Wright639c8be2014-01-17 18:29:12 -0800654 }
655 mHandler.sendEmptyMessageAtTime(MSG_UPDATE_AMBIENT_LUX,
656 timeWhenSensorWarmedUp);
657 return;
658 }
Michael Wright0a933142017-08-16 20:38:21 +0100659 setAmbientLux(calculateAmbientLux(time, AMBIENT_LIGHT_SHORT_HORIZON_MILLIS));
Michael Wright639c8be2014-01-17 18:29:12 -0800660 mAmbientLuxValid = true;
Dan Gittika5a2d632019-01-09 14:25:29 +0000661 if (mLoggingEnabled) {
Dan Gittikc5d32912018-02-22 13:53:47 +0000662 Slog.d(TAG, "updateAmbientLux: Initializing: " +
663 "mAmbientLightRingBuffer=" + mAmbientLightRingBuffer + ", " +
664 "mAmbientLux=" + mAmbientLux);
Michael Wright639c8be2014-01-17 18:29:12 -0800665 }
666 updateAutoBrightness(true);
667 }
668
669 long nextBrightenTransition = nextAmbientLightBrighteningTransition(time);
670 long nextDarkenTransition = nextAmbientLightDarkeningTransition(time);
Michael Wright0a933142017-08-16 20:38:21 +0100671 // Essentially, we calculate both a slow ambient lux, to ensure there's a true long-term
672 // change in lighting conditions, and a fast ambient lux to determine what the new
673 // brightness situation is since the slow lux can be quite slow to converge.
674 //
675 // Note that both values need to be checked for sufficient change before updating the
676 // proposed ambient light value since the slow value might be sufficiently far enough away
677 // from the fast value to cause a recalculation while its actually just converging on
678 // the fast value still.
679 float slowAmbientLux = calculateAmbientLux(time, AMBIENT_LIGHT_LONG_HORIZON_MILLIS);
680 float fastAmbientLux = calculateAmbientLux(time, AMBIENT_LIGHT_SHORT_HORIZON_MILLIS);
Michael Wright639c8be2014-01-17 18:29:12 -0800681
Dan Gittiked958e92018-11-13 14:58:20 +0000682 if ((slowAmbientLux >= mAmbientBrighteningThreshold
683 && fastAmbientLux >= mAmbientBrighteningThreshold
684 && nextBrightenTransition <= time)
685 || (slowAmbientLux <= mAmbientDarkeningThreshold
686 && fastAmbientLux <= mAmbientDarkeningThreshold
687 && nextDarkenTransition <= time)) {
Michael Wright0a933142017-08-16 20:38:21 +0100688 setAmbientLux(fastAmbientLux);
Dan Gittika5a2d632019-01-09 14:25:29 +0000689 if (mLoggingEnabled) {
Dan Gittiked958e92018-11-13 14:58:20 +0000690 Slog.d(TAG, "updateAmbientLux: "
691 + ((fastAmbientLux > mAmbientLux) ? "Brightened" : "Darkened") + ": "
Dan Gittika5a2d632019-01-09 14:25:29 +0000692 + "mBrighteningLuxThreshold=" + mAmbientBrighteningThreshold + ", "
Dan Gittiked958e92018-11-13 14:58:20 +0000693 + "mAmbientLightRingBuffer=" + mAmbientLightRingBuffer + ", "
694 + "mAmbientLux=" + mAmbientLux);
Michael Wright639c8be2014-01-17 18:29:12 -0800695 }
696 updateAutoBrightness(true);
697 nextBrightenTransition = nextAmbientLightBrighteningTransition(time);
698 nextDarkenTransition = nextAmbientLightDarkeningTransition(time);
699 }
700 long nextTransitionTime = Math.min(nextDarkenTransition, nextBrightenTransition);
701 // If one of the transitions is ready to occur, but the total weighted ambient lux doesn't
702 // exceed the necessary threshold, then it's possible we'll get a transition time prior to
703 // now. Rather than continually checking to see whether the weighted lux exceeds the
704 // threshold, schedule an update for when we'd normally expect another light sample, which
705 // should be enough time to decide whether we should actually transition to the new
706 // weighted ambient lux or not.
707 nextTransitionTime =
Julius D'souza5d717092016-10-24 19:26:45 -0700708 nextTransitionTime > time ? nextTransitionTime : time + mNormalLightSensorRate;
Dan Gittika5a2d632019-01-09 14:25:29 +0000709 if (mLoggingEnabled) {
Dan Gittikc5d32912018-02-22 13:53:47 +0000710 Slog.d(TAG, "updateAmbientLux: Scheduling ambient lux update for " +
Dan Gittik57d6f112018-03-27 18:14:22 +0100711 nextTransitionTime + TimeUtils.formatUptime(nextTransitionTime));
Michael Wright639c8be2014-01-17 18:29:12 -0800712 }
713 mHandler.sendEmptyMessageAtTime(MSG_UPDATE_AMBIENT_LUX, nextTransitionTime);
714 }
715
716 private void updateAutoBrightness(boolean sendUpdate) {
717 if (!mAmbientLuxValid) {
718 return;
719 }
720
Dan Gittika5a2d632019-01-09 14:25:29 +0000721 float value = mBrightnessMapper.getBrightness(mAmbientLux, mForegroundAppPackageName,
722 mForegroundAppCategory);
Michael Wright639c8be2014-01-17 18:29:12 -0800723
724 int newScreenAutoBrightness =
Jeff Browna576b4d2015-04-23 19:58:06 -0700725 clampScreenBrightness(Math.round(value * PowerManager.BRIGHTNESS_ON));
Dan Gittiked958e92018-11-13 14:58:20 +0000726
727 // If screenAutoBrightness is set, we should have screen{Brightening,Darkening}Threshold,
728 // in which case we ignore the new screen brightness if it doesn't differ enough from the
729 // previous one.
730 if (mScreenAutoBrightness != -1
731 && newScreenAutoBrightness > mScreenDarkeningThreshold
732 && newScreenAutoBrightness < mScreenBrighteningThreshold) {
Dan Gittika5a2d632019-01-09 14:25:29 +0000733 if (mLoggingEnabled) {
Dan Gittiked958e92018-11-13 14:58:20 +0000734 Slog.d(TAG, "ignoring newScreenAutoBrightness: " + mScreenDarkeningThreshold
735 + " < " + newScreenAutoBrightness + " < " + mScreenBrighteningThreshold);
736 }
737 return;
738 }
739
Michael Wright639c8be2014-01-17 18:29:12 -0800740 if (mScreenAutoBrightness != newScreenAutoBrightness) {
Dan Gittika5a2d632019-01-09 14:25:29 +0000741 if (mLoggingEnabled) {
Dan Gittikc5d32912018-02-22 13:53:47 +0000742 Slog.d(TAG, "updateAutoBrightness: " +
Dan Gittik57d6f112018-03-27 18:14:22 +0100743 "mScreenAutoBrightness=" + mScreenAutoBrightness + ", " +
744 "newScreenAutoBrightness=" + newScreenAutoBrightness);
Michael Wright639c8be2014-01-17 18:29:12 -0800745 }
746
747 mScreenAutoBrightness = newScreenAutoBrightness;
Dan Gittiked958e92018-11-13 14:58:20 +0000748 mScreenBrighteningThreshold =
749 mScreenBrightnessThresholds.getBrighteningThreshold(newScreenAutoBrightness);
750 mScreenDarkeningThreshold =
751 mScreenBrightnessThresholds.getDarkeningThreshold(newScreenAutoBrightness);
752
Michael Wright639c8be2014-01-17 18:29:12 -0800753 if (sendUpdate) {
754 mCallbacks.updateBrightness();
755 }
756 }
757 }
758
759 private int clampScreenBrightness(int value) {
760 return MathUtils.constrain(value,
761 mScreenBrightnessRangeMinimum, mScreenBrightnessRangeMaximum);
762 }
763
Jeff Browna576b4d2015-04-23 19:58:06 -0700764 private void prepareBrightnessAdjustmentSample() {
765 if (!mBrightnessAdjustmentSamplePending) {
766 mBrightnessAdjustmentSamplePending = true;
Jeff Browna576b4d2015-04-23 19:58:06 -0700767 mBrightnessAdjustmentSampleOldLux = mAmbientLuxValid ? mAmbientLux : -1;
768 mBrightnessAdjustmentSampleOldBrightness = mScreenAutoBrightness;
Jeff Browna576b4d2015-04-23 19:58:06 -0700769 } else {
770 mHandler.removeMessages(MSG_BRIGHTNESS_ADJUSTMENT_SAMPLE);
771 }
772
773 mHandler.sendEmptyMessageDelayed(MSG_BRIGHTNESS_ADJUSTMENT_SAMPLE,
774 BRIGHTNESS_ADJUSTMENT_SAMPLE_DEBOUNCE_MILLIS);
775 }
776
Sudheer Shankab3f60652019-01-04 20:30:14 +0000777 private void cancelBrightnessAdjustmentSample() {
778 if (mBrightnessAdjustmentSamplePending) {
779 mBrightnessAdjustmentSamplePending = false;
780 mHandler.removeMessages(MSG_BRIGHTNESS_ADJUSTMENT_SAMPLE);
781 }
782 }
783
Jeff Browna576b4d2015-04-23 19:58:06 -0700784 private void collectBrightnessAdjustmentSample() {
785 if (mBrightnessAdjustmentSamplePending) {
786 mBrightnessAdjustmentSamplePending = false;
787 if (mAmbientLuxValid && mScreenAutoBrightness >= 0) {
Dan Gittika5a2d632019-01-09 14:25:29 +0000788 if (mLoggingEnabled) {
Dan Gittikc5d32912018-02-22 13:53:47 +0000789 Slog.d(TAG, "Auto-brightness adjustment changed by user: " +
Dan Gittik57d6f112018-03-27 18:14:22 +0100790 "lux=" + mAmbientLux + ", " +
791 "brightness=" + mScreenAutoBrightness + ", " +
792 "ring=" + mAmbientLightRingBuffer);
Jeff Browna576b4d2015-04-23 19:58:06 -0700793 }
794
795 EventLog.writeEvent(EventLogTags.AUTO_BRIGHTNESS_ADJ,
Jeff Browna576b4d2015-04-23 19:58:06 -0700796 mBrightnessAdjustmentSampleOldLux,
797 mBrightnessAdjustmentSampleOldBrightness,
Jeff Browna576b4d2015-04-23 19:58:06 -0700798 mAmbientLux,
Dan Gittik57d6f112018-03-27 18:14:22 +0100799 mScreenAutoBrightness);
Jeff Browna576b4d2015-04-23 19:58:06 -0700800 }
801 }
802 }
803
Dan Gittika5a2d632019-01-09 14:25:29 +0000804 // Register a TaskStackListener to call back to us onTaskStackChanged, so we can update the
805 // foreground app's package name and category and correct the brightness accordingly.
806 private void registerForegroundAppUpdater() {
807 try {
808 mActivityTaskManager.registerTaskStackListener(mTaskStackListener);
809 // This will not get called until the foreground app changes for the first time, so
810 // call it explicitly to get the current foreground app's info.
811 updateForegroundApp();
812 } catch (RemoteException e) {
813 if (mLoggingEnabled) {
814 Slog.e(TAG, "Failed to register foreground app updater: " + e);
815 }
816 // Nothing to do.
817 }
818 }
819
820 private void unregisterForegroundAppUpdater() {
821 try {
822 mActivityTaskManager.unregisterTaskStackListener(mTaskStackListener);
823 } catch (RemoteException e) {
824 // Nothing to do.
825 }
826 mForegroundAppPackageName = null;
827 mForegroundAppCategory = ApplicationInfo.CATEGORY_UNDEFINED;
828 }
829
830 // Set the foreground app's package name and category, so brightness can be corrected per app.
831 private void updateForegroundApp() {
832 if (mLoggingEnabled) {
833 Slog.d(TAG, "Attempting to update foreground app");
834 }
835 // The ActivityTaskManager's lock tends to get contended, so this is done in a background
836 // thread and applied via this thread's handler synchronously.
837 BackgroundThread.getHandler().post(new Runnable() {
838 public void run() {
839 try {
840 // The foreground app is the top activity of the focused tasks stack.
841 final StackInfo info = mActivityTaskManager.getFocusedStackInfo();
842 if (info == null || info.topActivity == null) {
843 return;
844 }
845 final String packageName = info.topActivity.getPackageName();
846 // If the app didn't change, there's nothing to do. Otherwise, we have to
847 // update the category and re-apply the brightness correction.
848 if (mForegroundAppPackageName != null
849 && mForegroundAppPackageName.equals(packageName)) {
850 return;
851 }
852 mPendingForegroundAppPackageName = packageName;
853 mPendingForegroundAppCategory = ApplicationInfo.CATEGORY_UNDEFINED;
854 try {
855 ApplicationInfo app = mPackageManager.getApplicationInfo(packageName,
856 PackageManager.MATCH_ANY_USER);
857 mPendingForegroundAppCategory = app.category;
858 } catch (PackageManager.NameNotFoundException e) {
859 // Nothing to do
860 }
861 mHandler.sendEmptyMessage(MSG_UPDATE_FOREGROUND_APP_SYNC);
862 } catch (RemoteException e) {
863 // Nothing to do
864 }
865 }
866 });
867 }
868
869 private void updateForegroundAppSync() {
870 if (mLoggingEnabled) {
871 Slog.d(TAG, "Updating foreground app: packageName=" + mPendingForegroundAppPackageName
872 + ", category=" + mPendingForegroundAppCategory);
873 }
874 mForegroundAppPackageName = mPendingForegroundAppPackageName;
875 mPendingForegroundAppPackageName = null;
876 mForegroundAppCategory = mPendingForegroundAppCategory;
877 mPendingForegroundAppCategory = ApplicationInfo.CATEGORY_UNDEFINED;
878 updateAutoBrightness(true /* sendUpdate */);
879 }
880
Michael Wright639c8be2014-01-17 18:29:12 -0800881 private final class AutomaticBrightnessHandler extends Handler {
882 public AutomaticBrightnessHandler(Looper looper) {
883 super(looper, null, true /*async*/);
884 }
885
886 @Override
887 public void handleMessage(Message msg) {
888 switch (msg.what) {
889 case MSG_UPDATE_AMBIENT_LUX:
890 updateAmbientLux();
891 break;
Jeff Browna576b4d2015-04-23 19:58:06 -0700892
893 case MSG_BRIGHTNESS_ADJUSTMENT_SAMPLE:
894 collectBrightnessAdjustmentSample();
895 break;
Michael Wrightd8460232018-01-16 18:04:59 +0000896
Dan Gittikc5d32912018-02-22 13:53:47 +0000897 case MSG_INVALIDATE_SHORT_TERM_MODEL:
898 invalidateShortTermModel();
Michael Wrightd8460232018-01-16 18:04:59 +0000899 break;
Dan Gittika5a2d632019-01-09 14:25:29 +0000900
901 case MSG_UPDATE_FOREGROUND_APP:
902 updateForegroundApp();
903 break;
904
905 case MSG_UPDATE_FOREGROUND_APP_SYNC:
906 updateForegroundAppSync();
907 break;
Michael Wright639c8be2014-01-17 18:29:12 -0800908 }
909 }
910 }
911
912 private final SensorEventListener mLightSensorListener = new SensorEventListener() {
913 @Override
914 public void onSensorChanged(SensorEvent event) {
915 if (mLightSensorEnabled) {
916 final long time = SystemClock.uptimeMillis();
917 final float lux = event.values[0];
918 handleLightSensorEvent(time, lux);
919 }
920 }
921
922 @Override
923 public void onAccuracyChanged(Sensor sensor, int accuracy) {
924 // Not used.
925 }
926 };
927
Dan Gittika5a2d632019-01-09 14:25:29 +0000928 // Call back whenever the tasks stack changes, which includes tasks being created, removed, and
929 // moving to top.
930 class TaskStackListenerImpl extends TaskStackListener {
931 @Override
932 public void onTaskStackChanged() {
933 mHandler.sendEmptyMessage(MSG_UPDATE_FOREGROUND_APP);
934 }
935 }
936
Michael Wright639c8be2014-01-17 18:29:12 -0800937 /** Callbacks to request updates to the display's power state. */
938 interface Callbacks {
939 void updateBrightness();
940 }
941
Michael Wright0a933142017-08-16 20:38:21 +0100942 /**
943 * A ring buffer of ambient light measurements sorted by time.
944 *
945 * Each entry consists of a timestamp and a lux measurement, and the overall buffer is sorted
946 * from oldest to newest.
947 */
Michael Wright103fb782016-04-22 01:03:09 -0400948 private static final class AmbientLightRingBuffer {
Michael Wright639c8be2014-01-17 18:29:12 -0800949 // Proportional extra capacity of the buffer beyond the expected number of light samples
950 // in the horizon
951 private static final float BUFFER_SLACK = 1.5f;
Michael Wright639c8be2014-01-17 18:29:12 -0800952 private float[] mRingLux;
953 private long[] mRingTime;
954 private int mCapacity;
955
956 // The first valid element and the next open slot.
957 // Note that if mCount is zero then there are no valid elements.
958 private int mStart;
959 private int mEnd;
960 private int mCount;
961
Zoran Jovanovic6fc42f52015-12-10 17:01:16 +0100962 public AmbientLightRingBuffer(long lightSensorRate, int ambientLightHorizon) {
963 mCapacity = (int) Math.ceil(ambientLightHorizon * BUFFER_SLACK / lightSensorRate);
Michael Wright639c8be2014-01-17 18:29:12 -0800964 mRingLux = new float[mCapacity];
965 mRingTime = new long[mCapacity];
966 }
967
968 public float getLux(int index) {
969 return mRingLux[offsetOf(index)];
970 }
971
972 public long getTime(int index) {
973 return mRingTime[offsetOf(index)];
974 }
975
976 public void push(long time, float lux) {
977 int next = mEnd;
978 if (mCount == mCapacity) {
979 int newSize = mCapacity * 2;
980
981 float[] newRingLux = new float[newSize];
982 long[] newRingTime = new long[newSize];
983 int length = mCapacity - mStart;
984 System.arraycopy(mRingLux, mStart, newRingLux, 0, length);
985 System.arraycopy(mRingTime, mStart, newRingTime, 0, length);
986 if (mStart != 0) {
987 System.arraycopy(mRingLux, 0, newRingLux, length, mStart);
988 System.arraycopy(mRingTime, 0, newRingTime, length, mStart);
989 }
990 mRingLux = newRingLux;
991 mRingTime = newRingTime;
992
993 next = mCapacity;
994 mCapacity = newSize;
995 mStart = 0;
996 }
997 mRingTime[next] = time;
998 mRingLux[next] = lux;
999 mEnd = next + 1;
1000 if (mEnd == mCapacity) {
1001 mEnd = 0;
1002 }
1003 mCount++;
1004 }
1005
1006 public void prune(long horizon) {
1007 if (mCount == 0) {
1008 return;
1009 }
1010
1011 while (mCount > 1) {
1012 int next = mStart + 1;
1013 if (next >= mCapacity) {
1014 next -= mCapacity;
1015 }
1016 if (mRingTime[next] > horizon) {
1017 // Some light sensors only produce data upon a change in the ambient light
1018 // levels, so we need to consider the previous measurement as the ambient light
1019 // level for all points in time up until we receive a new measurement. Thus, we
1020 // always want to keep the youngest element that would be removed from the
1021 // buffer and just set its measurement time to the horizon time since at that
1022 // point it is the ambient light level, and to remove it would be to drop a
1023 // valid data point within our horizon.
1024 break;
1025 }
1026 mStart = next;
1027 mCount -= 1;
1028 }
1029
1030 if (mRingTime[mStart] < horizon) {
1031 mRingTime[mStart] = horizon;
1032 }
1033 }
1034
1035 public int size() {
1036 return mCount;
1037 }
1038
Michael Wright639c8be2014-01-17 18:29:12 -08001039 public void clear() {
1040 mStart = 0;
1041 mEnd = 0;
1042 mCount = 0;
1043 }
1044
1045 @Override
1046 public String toString() {
Jeff Browna576b4d2015-04-23 19:58:06 -07001047 StringBuffer buf = new StringBuffer();
1048 buf.append('[');
1049 for (int i = 0; i < mCount; i++) {
1050 final long next = i + 1 < mCount ? getTime(i + 1) : SystemClock.uptimeMillis();
1051 if (i != 0) {
1052 buf.append(", ");
1053 }
1054 buf.append(getLux(i));
1055 buf.append(" / ");
1056 buf.append(next - getTime(i));
1057 buf.append("ms");
Michael Wright639c8be2014-01-17 18:29:12 -08001058 }
Jeff Browna576b4d2015-04-23 19:58:06 -07001059 buf.append(']');
1060 return buf.toString();
Michael Wright639c8be2014-01-17 18:29:12 -08001061 }
1062
1063 private int offsetOf(int index) {
1064 if (index >= mCount || index < 0) {
1065 throw new ArrayIndexOutOfBoundsException(index);
1066 }
1067 index += mStart;
1068 if (index >= mCapacity) {
1069 index -= mCapacity;
1070 }
1071 return index;
1072 }
1073 }
1074}