blob: 36d69c93c1cbfe49ed893b64da22272a1f285dde [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;
Fiona Campbelld4eb2952019-11-04 17:19:56 +000024import android.content.Context;
Dan Gittika5a2d632019-01-09 14:25:29 +000025import android.content.pm.ApplicationInfo;
26import android.content.pm.PackageManager;
Michael Wright639c8be2014-01-17 18:29:12 -080027import android.hardware.Sensor;
28import android.hardware.SensorEvent;
29import android.hardware.SensorEventListener;
30import android.hardware.SensorManager;
Michael Wrighteef0e132017-11-21 17:57:52 +000031import android.hardware.display.BrightnessConfiguration;
Michael Wrightd8460232018-01-16 18:04:59 +000032import android.hardware.display.DisplayManagerInternal.DisplayPowerRequest;
Michael Wright639c8be2014-01-17 18:29:12 -080033import android.os.Handler;
34import android.os.Looper;
35import android.os.Message;
36import android.os.PowerManager;
Dan Gittika5a2d632019-01-09 14:25:29 +000037import android.os.RemoteException;
Michael Wright639c8be2014-01-17 18:29:12 -080038import android.os.SystemClock;
Michael Wrightb0a1d3d2017-09-22 15:05:02 +010039import android.os.Trace;
Jeff Browna576b4d2015-04-23 19:58:06 -070040import android.util.EventLog;
Michael Wright639c8be2014-01-17 18:29:12 -080041import android.util.MathUtils;
Michael Wright639c8be2014-01-17 18:29:12 -080042import android.util.Slog;
43import android.util.TimeUtils;
44
Fiona Campbelld4eb2952019-11-04 17:19:56 +000045import com.android.internal.BrightnessSynchronizer;
Santos Cordon64a86272019-11-28 11:24:21 +000046import com.android.internal.annotations.VisibleForTesting;
Dan Gittika5a2d632019-01-09 14:25:29 +000047import com.android.internal.os.BackgroundThread;
Dan Gittiked958e92018-11-13 14:58:20 +000048import com.android.server.EventLogTags;
49
Michael Wright639c8be2014-01-17 18:29:12 -080050import java.io.PrintWriter;
Michael Wright639c8be2014-01-17 18:29:12 -080051
52class AutomaticBrightnessController {
53 private static final String TAG = "AutomaticBrightnessController";
54
Michael Wright639c8be2014-01-17 18:29:12 -080055 private static final boolean DEBUG_PRETEND_LIGHT_SENSOR_ABSENT = false;
56
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.
Fiona Campbellf972a082020-03-25 18:05:25 +000092 private final float mScreenBrightnessRangeMinimum;
93 private final float 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
Michael Wright639c8be2014-01-17 18:29:12 -0800133 // Amount of time to delay auto-brightness after screen on while waiting for
134 // the light sensor to warm-up in milliseconds.
135 // May be 0 if no warm-up is required.
136 private int mLightSensorWarmUpTimeConfig;
137
138 // Set to true if the light sensor is enabled.
139 private boolean mLightSensorEnabled;
140
141 // The time when the light sensor was enabled.
142 private long mLightSensorEnableTime;
143
144 // The currently accepted nominal ambient light level.
145 private float mAmbientLux;
146
147 // True if mAmbientLux holds a valid value.
148 private boolean mAmbientLuxValid;
149
150 // The ambient light level threshold at which to brighten or darken the screen.
Dan Gittiked958e92018-11-13 14:58:20 +0000151 private float mAmbientBrighteningThreshold;
152 private float mAmbientDarkeningThreshold;
153
154 // The screen brightness threshold at which to brighten or darken the screen.
155 private float mScreenBrighteningThreshold;
156 private float mScreenDarkeningThreshold;
Michael Wright639c8be2014-01-17 18:29:12 -0800157 // The most recent light sample.
158 private float mLastObservedLux;
159
160 // The time of the most light recent sample.
161 private long mLastObservedLuxTime;
162
163 // The number of light samples collected since the light sensor was enabled.
164 private int mRecentLightSamples;
165
166 // A ring buffer containing all of the recent ambient light sensor readings.
167 private AmbientLightRingBuffer mAmbientLightRingBuffer;
168
169 // The handler
170 private AutomaticBrightnessHandler mHandler;
171
172 // The screen brightness level that has been chosen by the auto-brightness
173 // algorithm. The actual brightness should ramp towards this value.
174 // We preserve this value even when we stop using the light sensor so
175 // that we can quickly revert to the previous auto-brightness level
176 // while the light sensor warms up.
Fiona Campbellf972a082020-03-25 18:05:25 +0000177 // Use PowerManager.BRIGHTNESS_INVALID_FLOAT if there is no current auto-brightness value
178 // available.
179 private float mScreenAutoBrightness = PowerManager.BRIGHTNESS_INVALID_FLOAT;
Michael Wright639c8be2014-01-17 18:29:12 -0800180
Michael Wrightd8460232018-01-16 18:04:59 +0000181 // The current display policy. This is useful, for example, for knowing when we're dozing,
182 // where the light sensor may not be available.
183 private int mDisplayPolicy = DisplayPowerRequest.POLICY_OFF;
Filip Gruszczynskia15aa7d2014-10-28 14:12:40 -0700184
Jeff Browna576b4d2015-04-23 19:58:06 -0700185 // True if we are collecting a brightness adjustment sample, along with some data
186 // for the initial state of the sample.
187 private boolean mBrightnessAdjustmentSamplePending;
Jeff Browna576b4d2015-04-23 19:58:06 -0700188 private float mBrightnessAdjustmentSampleOldLux;
Fiona Campbellf972a082020-03-25 18:05:25 +0000189 private float mBrightnessAdjustmentSampleOldBrightness;
Jeff Browna576b4d2015-04-23 19:58:06 -0700190
Dan Gittikc5d32912018-02-22 13:53:47 +0000191 // When the short term model is invalidated, we don't necessarily reset it (i.e. clear the
192 // user's adjustment) immediately, but wait for a drastic enough change in the ambient light.
193 // The anchor determines what were the light levels when the user has set her preference, and
194 // we use a relative threshold to determine when to revert to the OEM curve.
195 private boolean mShortTermModelValid;
196 private float mShortTermModelAnchor;
Dan Gittikc5d32912018-02-22 13:53:47 +0000197
Dan Gittika5a2d632019-01-09 14:25:29 +0000198 // Context-sensitive brightness configurations require keeping track of the foreground app's
199 // package name and category, which is done by registering a TaskStackListener to call back to
200 // us onTaskStackChanged, and then using the ActivityTaskManager to get the foreground app's
Fiona Campbell172fd4a2020-03-13 16:34:30 +0000201 // package name and PackageManager to get its category (so might as well cache them).
Dan Gittika5a2d632019-01-09 14:25:29 +0000202 private String mForegroundAppPackageName;
203 private String mPendingForegroundAppPackageName;
204 private @ApplicationInfo.Category int mForegroundAppCategory;
205 private @ApplicationInfo.Category int mPendingForegroundAppCategory;
206 private TaskStackListenerImpl mTaskStackListener;
207 private IActivityTaskManager mActivityTaskManager;
208 private PackageManager mPackageManager;
Fiona Campbelld4eb2952019-11-04 17:19:56 +0000209 private Context mContext;
Dan Gittika5a2d632019-01-09 14:25:29 +0000210
Fiona Campbell172fd4a2020-03-13 16:34:30 +0000211 private DisplayDeviceConfig mDisplayDeviceConfig;
Santos Cordon64a86272019-11-28 11:24:21 +0000212 private final Injector mInjector;
213
214 AutomaticBrightnessController(Callbacks callbacks, Looper looper,
Michael Wrighte02db662019-03-08 21:24:36 +0000215 SensorManager sensorManager, Sensor lightSensor, BrightnessMappingStrategy mapper,
Fiona Campbelld4eb2952019-11-04 17:19:56 +0000216 int lightSensorWarmUpTime, float brightnessMin, float brightnessMax,
217 float dozeScaleFactor, int lightSensorRate, int initialLightSensorRate,
218 long brighteningLightDebounceConfig, long darkeningLightDebounceConfig,
219 boolean resetAmbientLuxAfterWarmUpConfig, HysteresisLevels ambientBrightnessThresholds,
Fiona Campbell172fd4a2020-03-13 16:34:30 +0000220 HysteresisLevels screenBrightnessThresholds, Context context, DisplayDeviceConfig
221 displayDeviceConfig) {
Santos Cordon64a86272019-11-28 11:24:21 +0000222 this(new Injector(), callbacks, looper, sensorManager, lightSensor, mapper,
223 lightSensorWarmUpTime, brightnessMin, brightnessMax, dozeScaleFactor,
224 lightSensorRate, initialLightSensorRate, brighteningLightDebounceConfig,
225 darkeningLightDebounceConfig, resetAmbientLuxAfterWarmUpConfig,
Fiona Campbell172fd4a2020-03-13 16:34:30 +0000226 ambientBrightnessThresholds, screenBrightnessThresholds, context,
227 displayDeviceConfig);
Santos Cordon64a86272019-11-28 11:24:21 +0000228 }
229
230 @VisibleForTesting
231 AutomaticBrightnessController(Injector injector, Callbacks callbacks, Looper looper,
232 SensorManager sensorManager, Sensor lightSensor, BrightnessMappingStrategy mapper,
Fiona Campbelld4eb2952019-11-04 17:19:56 +0000233 int lightSensorWarmUpTime, float brightnessMin, float brightnessMax,
234 float dozeScaleFactor, int lightSensorRate, int initialLightSensorRate,
235 long brighteningLightDebounceConfig, long darkeningLightDebounceConfig,
236 boolean resetAmbientLuxAfterWarmUpConfig, HysteresisLevels ambientBrightnessThresholds,
Fiona Campbell172fd4a2020-03-13 16:34:30 +0000237 HysteresisLevels screenBrightnessThresholds, Context context, DisplayDeviceConfig
238 displayDeviceConfig) {
Santos Cordon64a86272019-11-28 11:24:21 +0000239 mInjector = injector;
Fiona Campbelld4eb2952019-11-04 17:19:56 +0000240 mContext = context;
Michael Wright639c8be2014-01-17 18:29:12 -0800241 mCallbacks = callbacks;
Michael Wright639c8be2014-01-17 18:29:12 -0800242 mSensorManager = sensorManager;
Michael Wrighteef0e132017-11-21 17:57:52 +0000243 mBrightnessMapper = mapper;
Fiona Campbellf972a082020-03-25 18:05:25 +0000244 mScreenBrightnessRangeMinimum = brightnessMin;
245 mScreenBrightnessRangeMaximum = brightnessMax;
Michael Wright639c8be2014-01-17 18:29:12 -0800246 mLightSensorWarmUpTimeConfig = lightSensorWarmUpTime;
Filip Gruszczynskia15aa7d2014-10-28 14:12:40 -0700247 mDozeScaleFactor = dozeScaleFactor;
Julius D'souza5d717092016-10-24 19:26:45 -0700248 mNormalLightSensorRate = lightSensorRate;
249 mInitialLightSensorRate = initialLightSensorRate;
250 mCurrentLightSensorRate = -1;
Filip Gruszczynskid81ecd12015-02-06 12:38:47 -0800251 mBrighteningLightDebounceConfig = brighteningLightDebounceConfig;
252 mDarkeningLightDebounceConfig = darkeningLightDebounceConfig;
253 mResetAmbientLuxAfterWarmUpConfig = resetAmbientLuxAfterWarmUpConfig;
Michael Wright2155bc22018-05-01 00:38:32 +0100254 mAmbientLightHorizon = AMBIENT_LIGHT_LONG_HORIZON_MILLIS;
255 mWeightingIntercept = AMBIENT_LIGHT_LONG_HORIZON_MILLIS;
Dan Gittiked958e92018-11-13 14:58:20 +0000256 mAmbientBrightnessThresholds = ambientBrightnessThresholds;
257 mScreenBrightnessThresholds = screenBrightnessThresholds;
Dan Gittikc5d32912018-02-22 13:53:47 +0000258 mShortTermModelValid = true;
259 mShortTermModelAnchor = -1;
Fiona Campbell172fd4a2020-03-13 16:34:30 +0000260 mDisplayDeviceConfig = displayDeviceConfig;
Michael Wright639c8be2014-01-17 18:29:12 -0800261 mHandler = new AutomaticBrightnessHandler(looper);
Michael Wright103fb782016-04-22 01:03:09 -0400262 mAmbientLightRingBuffer =
Julius D'souza5d717092016-10-24 19:26:45 -0700263 new AmbientLightRingBuffer(mNormalLightSensorRate, mAmbientLightHorizon);
Michael Wright639c8be2014-01-17 18:29:12 -0800264
265 if (!DEBUG_PRETEND_LIGHT_SENSOR_ABSENT) {
Michael Wrighte02db662019-03-08 21:24:36 +0000266 mLightSensor = lightSensor;
Michael Wright639c8be2014-01-17 18:29:12 -0800267 }
Dan Gittika5a2d632019-01-09 14:25:29 +0000268
269 mActivityTaskManager = ActivityTaskManager.getService();
Fiona Campbelld4eb2952019-11-04 17:19:56 +0000270 mPackageManager = mContext.getPackageManager();
Dan Gittika5a2d632019-01-09 14:25:29 +0000271 mTaskStackListener = new TaskStackListenerImpl();
272 mForegroundAppPackageName = null;
273 mPendingForegroundAppPackageName = null;
274 mForegroundAppCategory = ApplicationInfo.CATEGORY_UNDEFINED;
275 mPendingForegroundAppCategory = ApplicationInfo.CATEGORY_UNDEFINED;
276 }
277
278 /**
279 * Enable/disable logging.
280 *
281 * @param loggingEnabled
282 * Whether logging should be on/off.
283 *
284 * @return Whether the method succeeded or not.
285 */
286 public boolean setLoggingEnabled(boolean loggingEnabled) {
287 if (mLoggingEnabled == loggingEnabled) {
288 return false;
289 }
290 mBrightnessMapper.setLoggingEnabled(loggingEnabled);
291 mLoggingEnabled = loggingEnabled;
292 return true;
Michael Wright639c8be2014-01-17 18:29:12 -0800293 }
294
Fiona Campbellf972a082020-03-25 18:05:25 +0000295 public float getAutomaticScreenBrightness() {
Dan Gittik58784422018-04-05 12:30:38 +0100296 if (!mAmbientLuxValid) {
Fiona Campbellf972a082020-03-25 18:05:25 +0000297 return PowerManager.BRIGHTNESS_INVALID_FLOAT;
Dan Gittik58784422018-04-05 12:30:38 +0100298 }
Michael Wrightd8460232018-01-16 18:04:59 +0000299 if (mDisplayPolicy == DisplayPowerRequest.POLICY_DOZE) {
Fiona Campbellf972a082020-03-25 18:05:25 +0000300 return mScreenAutoBrightness * mDozeScaleFactor;
Filip Gruszczynskia15aa7d2014-10-28 14:12:40 -0700301 }
Michael Wright639c8be2014-01-17 18:29:12 -0800302 return mScreenAutoBrightness;
303 }
304
Kenny Guyb54d40b2019-02-28 12:49:53 +0000305 public boolean hasValidAmbientLux() {
306 return mAmbientLuxValid;
307 }
308
Michael Wright617564f2018-01-25 22:20:54 +0000309 public float getAutomaticScreenBrightnessAdjustment() {
Dan Gittik57d6f112018-03-27 18:14:22 +0100310 return mBrightnessMapper.getAutoBrightnessAdjustment();
Michael Wright617564f2018-01-25 22:20:54 +0000311 }
312
Michael Wrighteef0e132017-11-21 17:57:52 +0000313 public void configure(boolean enable, @Nullable BrightnessConfiguration configuration,
Michael Wright617564f2018-01-25 22:20:54 +0000314 float brightness, boolean userChangedBrightness, float adjustment,
315 boolean userChangedAutoBrightnessAdjustment, int displayPolicy) {
Filip Gruszczynskia15aa7d2014-10-28 14:12:40 -0700316 // While dozing, the application processor may be suspended which will prevent us from
317 // receiving new information from the light sensor. On some devices, we may be able to
318 // switch to a wake-up light sensor instead but for now we will simply disable the sensor
319 // and hold onto the last computed screen auto brightness. We save the dozing flag for
320 // debugging purposes.
Michael Wrightd8460232018-01-16 18:04:59 +0000321 boolean dozing = (displayPolicy == DisplayPowerRequest.POLICY_DOZE);
Michael Wrighteef0e132017-11-21 17:57:52 +0000322 boolean changed = setBrightnessConfiguration(configuration);
Michael Wrightd8460232018-01-16 18:04:59 +0000323 changed |= setDisplayPolicy(displayPolicy);
Dan Gittik57d6f112018-03-27 18:14:22 +0100324 if (userChangedAutoBrightnessAdjustment) {
325 changed |= setAutoBrightnessAdjustment(adjustment);
326 }
Michael Wright617564f2018-01-25 22:20:54 +0000327 if (userChangedBrightness && enable) {
328 // Update the brightness curve with the new user control point. It's critical this
329 // happens after we update the autobrightness adjustment since it may reset it.
Michael Wrightd8460232018-01-16 18:04:59 +0000330 changed |= setScreenBrightnessByUser(brightness);
Michael Wright617564f2018-01-25 22:20:54 +0000331 }
332 final boolean userInitiatedChange =
333 userChangedBrightness || userChangedAutoBrightnessAdjustment;
334 if (userInitiatedChange && enable && !dozing) {
Soroosh Mariooryada8edffd2017-03-22 17:08:26 -0700335 prepareBrightnessAdjustmentSample();
336 }
Michael Wrightd8460232018-01-16 18:04:59 +0000337 changed |= setLightSensorEnabled(enable && !dozing);
Jeff Brown970d4132014-07-19 11:33:47 -0700338 if (changed) {
Santos Cordon4acbedb2019-06-07 17:20:41 +0100339 updateAutoBrightness(false /*sendUpdate*/, userInitiatedChange);
Michael Wright639c8be2014-01-17 18:29:12 -0800340 }
341 }
342
Kenny Guy53d06612018-01-30 14:19:13 +0000343 public boolean hasUserDataPoints() {
344 return mBrightnessMapper.hasUserDataPoints();
345 }
346
347 public boolean isDefaultConfig() {
348 return mBrightnessMapper.isDefaultConfig();
349 }
350
Kenny Guy6d1009f2018-03-14 14:28:23 +0000351 public BrightnessConfiguration getDefaultConfig() {
352 return mBrightnessMapper.getDefaultConfig();
353 }
354
Michael Wrightd8460232018-01-16 18:04:59 +0000355 private boolean setDisplayPolicy(int policy) {
356 if (mDisplayPolicy == policy) {
357 return false;
358 }
359 final int oldPolicy = mDisplayPolicy;
360 mDisplayPolicy = policy;
Dan Gittika5a2d632019-01-09 14:25:29 +0000361 if (mLoggingEnabled) {
Dan Gittikc5d32912018-02-22 13:53:47 +0000362 Slog.d(TAG, "Display policy transitioning from " + oldPolicy + " to " + policy);
Michael Wrightd8460232018-01-16 18:04:59 +0000363 }
364 if (!isInteractivePolicy(policy) && isInteractivePolicy(oldPolicy)) {
Dan Gittikc5d32912018-02-22 13:53:47 +0000365 mHandler.sendEmptyMessageDelayed(MSG_INVALIDATE_SHORT_TERM_MODEL,
Kenny Guyb29fdf12019-12-04 12:57:04 +0000366 mBrightnessMapper.getShortTermModelTimeout());
Michael Wrightd8460232018-01-16 18:04:59 +0000367 } else if (isInteractivePolicy(policy) && !isInteractivePolicy(oldPolicy)) {
Dan Gittikc5d32912018-02-22 13:53:47 +0000368 mHandler.removeMessages(MSG_INVALIDATE_SHORT_TERM_MODEL);
Michael Wrightd8460232018-01-16 18:04:59 +0000369 }
370 return true;
371 }
372
373 private static boolean isInteractivePolicy(int policy) {
374 return policy == DisplayPowerRequest.POLICY_BRIGHT
375 || policy == DisplayPowerRequest.POLICY_DIM
376 || policy == DisplayPowerRequest.POLICY_VR;
377 }
378
379 private boolean setScreenBrightnessByUser(float brightness) {
380 if (!mAmbientLuxValid) {
Fiona Campbellf972a082020-03-25 18:05:25 +0000381 // If we don't have a valid ambient lux then we don't have a valid brightness anyway,
Michael Wrightd8460232018-01-16 18:04:59 +0000382 // and we can't use this data to add a new control point to the short-term model.
383 return false;
384 }
385 mBrightnessMapper.addUserDataPoint(mAmbientLux, brightness);
Dan Gittikc5d32912018-02-22 13:53:47 +0000386 mShortTermModelValid = true;
387 mShortTermModelAnchor = mAmbientLux;
Dan Gittika5a2d632019-01-09 14:25:29 +0000388 if (mLoggingEnabled) {
Dan Gittikc5d32912018-02-22 13:53:47 +0000389 Slog.d(TAG, "ShortTermModel: anchor=" + mShortTermModelAnchor);
390 }
Michael Wrightd8460232018-01-16 18:04:59 +0000391 return true;
392 }
393
Dan Gittikc1352252018-04-27 17:48:31 +0100394 public void resetShortTermModel() {
Michael Wrightd8460232018-01-16 18:04:59 +0000395 mBrightnessMapper.clearUserDataPoints();
Dan Gittikc5d32912018-02-22 13:53:47 +0000396 mShortTermModelValid = true;
397 mShortTermModelAnchor = -1;
398 }
399
400 private void invalidateShortTermModel() {
Dan Gittika5a2d632019-01-09 14:25:29 +0000401 if (mLoggingEnabled) {
Dan Gittikc5d32912018-02-22 13:53:47 +0000402 Slog.d(TAG, "ShortTermModel: invalidate user data");
403 }
404 mShortTermModelValid = false;
Michael Wrightd8460232018-01-16 18:04:59 +0000405 }
406
Michael Wrighteef0e132017-11-21 17:57:52 +0000407 public boolean setBrightnessConfiguration(BrightnessConfiguration configuration) {
Michael Wrightb8f4f772018-05-01 18:28:58 +0100408 if (mBrightnessMapper.setBrightnessConfiguration(configuration)) {
409 resetShortTermModel();
410 return true;
411 }
412 return false;
Michael Wrighteef0e132017-11-21 17:57:52 +0000413 }
414
Michael Wright639c8be2014-01-17 18:29:12 -0800415 public void dump(PrintWriter pw) {
416 pw.println();
417 pw.println("Automatic Brightness Controller Configuration:");
Michael Wright639c8be2014-01-17 18:29:12 -0800418 pw.println(" mScreenBrightnessRangeMinimum=" + mScreenBrightnessRangeMinimum);
419 pw.println(" mScreenBrightnessRangeMaximum=" + mScreenBrightnessRangeMaximum);
Michael Wright2155bc22018-05-01 00:38:32 +0100420 pw.println(" mDozeScaleFactor=" + mDozeScaleFactor);
421 pw.println(" mInitialLightSensorRate=" + mInitialLightSensorRate);
422 pw.println(" mNormalLightSensorRate=" + mNormalLightSensorRate);
Michael Wright639c8be2014-01-17 18:29:12 -0800423 pw.println(" mLightSensorWarmUpTimeConfig=" + mLightSensorWarmUpTimeConfig);
Filip Gruszczynskid81ecd12015-02-06 12:38:47 -0800424 pw.println(" mBrighteningLightDebounceConfig=" + mBrighteningLightDebounceConfig);
425 pw.println(" mDarkeningLightDebounceConfig=" + mDarkeningLightDebounceConfig);
426 pw.println(" mResetAmbientLuxAfterWarmUpConfig=" + mResetAmbientLuxAfterWarmUpConfig);
Michael Wright2155bc22018-05-01 00:38:32 +0100427 pw.println(" mAmbientLightHorizon=" + mAmbientLightHorizon);
428 pw.println(" mWeightingIntercept=" + mWeightingIntercept);
Michael Wright639c8be2014-01-17 18:29:12 -0800429
430 pw.println();
431 pw.println("Automatic Brightness Controller State:");
432 pw.println(" mLightSensor=" + mLightSensor);
Michael Wright639c8be2014-01-17 18:29:12 -0800433 pw.println(" mLightSensorEnabled=" + mLightSensorEnabled);
434 pw.println(" mLightSensorEnableTime=" + TimeUtils.formatUptime(mLightSensorEnableTime));
Michael Wright2155bc22018-05-01 00:38:32 +0100435 pw.println(" mCurrentLightSensorRate=" + mCurrentLightSensorRate);
Michael Wright639c8be2014-01-17 18:29:12 -0800436 pw.println(" mAmbientLux=" + mAmbientLux);
Dan Gittik58784422018-04-05 12:30:38 +0100437 pw.println(" mAmbientLuxValid=" + mAmbientLuxValid);
Dan Gittiked958e92018-11-13 14:58:20 +0000438 pw.println(" mAmbientBrighteningThreshold=" + mAmbientBrighteningThreshold);
439 pw.println(" mAmbientDarkeningThreshold=" + mAmbientDarkeningThreshold);
440 pw.println(" mScreenBrighteningThreshold=" + mScreenBrighteningThreshold);
441 pw.println(" mScreenDarkeningThreshold=" + mScreenDarkeningThreshold);
Michael Wright639c8be2014-01-17 18:29:12 -0800442 pw.println(" mLastObservedLux=" + mLastObservedLux);
443 pw.println(" mLastObservedLuxTime=" + TimeUtils.formatUptime(mLastObservedLuxTime));
444 pw.println(" mRecentLightSamples=" + mRecentLightSamples);
445 pw.println(" mAmbientLightRingBuffer=" + mAmbientLightRingBuffer);
446 pw.println(" mScreenAutoBrightness=" + mScreenAutoBrightness);
Michael Wright2155bc22018-05-01 00:38:32 +0100447 pw.println(" mDisplayPolicy=" + DisplayPowerRequest.policyToString(mDisplayPolicy));
Kenny Guyb29fdf12019-12-04 12:57:04 +0000448 pw.println(" mShortTermModelTimeout=" + mBrightnessMapper.getShortTermModelTimeout());
Dan Gittikc5d32912018-02-22 13:53:47 +0000449 pw.println(" mShortTermModelAnchor=" + mShortTermModelAnchor);
Michael Wright2155bc22018-05-01 00:38:32 +0100450 pw.println(" mShortTermModelValid=" + mShortTermModelValid);
451 pw.println(" mBrightnessAdjustmentSamplePending=" + mBrightnessAdjustmentSamplePending);
452 pw.println(" mBrightnessAdjustmentSampleOldLux=" + mBrightnessAdjustmentSampleOldLux);
453 pw.println(" mBrightnessAdjustmentSampleOldBrightness="
454 + mBrightnessAdjustmentSampleOldBrightness);
Dan Gittika5a2d632019-01-09 14:25:29 +0000455 pw.println(" mForegroundAppPackageName=" + mForegroundAppPackageName);
456 pw.println(" mPendingForegroundAppPackageName=" + mPendingForegroundAppPackageName);
457 pw.println(" mForegroundAppCategory=" + mForegroundAppCategory);
458 pw.println(" mPendingForegroundAppCategory=" + mPendingForegroundAppCategory);
Michael Wrighteef0e132017-11-21 17:57:52 +0000459
460 pw.println();
461 mBrightnessMapper.dump(pw);
Michael Wright2155bc22018-05-01 00:38:32 +0100462
463 pw.println();
Dan Gittiked958e92018-11-13 14:58:20 +0000464 mAmbientBrightnessThresholds.dump(pw);
465 mScreenBrightnessThresholds.dump(pw);
Michael Wright639c8be2014-01-17 18:29:12 -0800466 }
467
468 private boolean setLightSensorEnabled(boolean enable) {
469 if (enable) {
470 if (!mLightSensorEnabled) {
471 mLightSensorEnabled = true;
472 mLightSensorEnableTime = SystemClock.uptimeMillis();
Julius D'souza5d717092016-10-24 19:26:45 -0700473 mCurrentLightSensorRate = mInitialLightSensorRate;
Dan Gittika5a2d632019-01-09 14:25:29 +0000474 registerForegroundAppUpdater();
Michael Wright639c8be2014-01-17 18:29:12 -0800475 mSensorManager.registerListener(mLightSensorListener, mLightSensor,
Julius D'souza5d717092016-10-24 19:26:45 -0700476 mCurrentLightSensorRate * 1000, mHandler);
Michael Wright639c8be2014-01-17 18:29:12 -0800477 return true;
478 }
Dan Gittikc5d32912018-02-22 13:53:47 +0000479 } else if (mLightSensorEnabled) {
480 mLightSensorEnabled = false;
481 mAmbientLuxValid = !mResetAmbientLuxAfterWarmUpConfig;
Fiona Campbellf972a082020-03-25 18:05:25 +0000482 mScreenAutoBrightness = PowerManager.BRIGHTNESS_INVALID_FLOAT;
Dan Gittikc5d32912018-02-22 13:53:47 +0000483 mRecentLightSamples = 0;
484 mAmbientLightRingBuffer.clear();
485 mCurrentLightSensorRate = -1;
486 mHandler.removeMessages(MSG_UPDATE_AMBIENT_LUX);
Dan Gittika5a2d632019-01-09 14:25:29 +0000487 unregisterForegroundAppUpdater();
Dan Gittikc5d32912018-02-22 13:53:47 +0000488 mSensorManager.unregisterListener(mLightSensorListener);
Michael Wright639c8be2014-01-17 18:29:12 -0800489 }
490 return false;
491 }
492
493 private void handleLightSensorEvent(long time, float lux) {
Michael Wrightb0a1d3d2017-09-22 15:05:02 +0100494 Trace.traceCounter(Trace.TRACE_TAG_POWER, "ALS", (int) lux);
Michael Wright639c8be2014-01-17 18:29:12 -0800495 mHandler.removeMessages(MSG_UPDATE_AMBIENT_LUX);
496
Julius D'souza5d717092016-10-24 19:26:45 -0700497 if (mAmbientLightRingBuffer.size() == 0) {
498 // switch to using the steady-state sample rate after grabbing the initial light sample
499 adjustLightSensorRate(mNormalLightSensorRate);
500 }
Michael Wright639c8be2014-01-17 18:29:12 -0800501 applyLightSensorMeasurement(time, lux);
502 updateAmbientLux(time);
503 }
504
505 private void applyLightSensorMeasurement(long time, float lux) {
506 mRecentLightSamples++;
Zoran Jovanovic6fc42f52015-12-10 17:01:16 +0100507 mAmbientLightRingBuffer.prune(time - mAmbientLightHorizon);
Michael Wright639c8be2014-01-17 18:29:12 -0800508 mAmbientLightRingBuffer.push(time, lux);
509
510 // Remember this sample value.
511 mLastObservedLux = lux;
512 mLastObservedLuxTime = time;
513 }
514
Julius D'souza5d717092016-10-24 19:26:45 -0700515 private void adjustLightSensorRate(int lightSensorRate) {
516 // if the light sensor rate changed, update the sensor listener
517 if (lightSensorRate != mCurrentLightSensorRate) {
Dan Gittika5a2d632019-01-09 14:25:29 +0000518 if (mLoggingEnabled) {
Dan Gittikc5d32912018-02-22 13:53:47 +0000519 Slog.d(TAG, "adjustLightSensorRate: " +
Dan Gittik57d6f112018-03-27 18:14:22 +0100520 "previousRate=" + mCurrentLightSensorRate + ", " +
521 "currentRate=" + lightSensorRate);
Julius D'souza5d717092016-10-24 19:26:45 -0700522 }
523 mCurrentLightSensorRate = lightSensorRate;
524 mSensorManager.unregisterListener(mLightSensorListener);
525 mSensorManager.registerListener(mLightSensorListener, mLightSensor,
526 lightSensorRate * 1000, mHandler);
527 }
528 }
529
Dan Gittik57d6f112018-03-27 18:14:22 +0100530 private boolean setAutoBrightnessAdjustment(float adjustment) {
531 return mBrightnessMapper.setAutoBrightnessAdjustment(adjustment);
Michael Wright639c8be2014-01-17 18:29:12 -0800532 }
533
534 private void setAmbientLux(float lux) {
Dan Gittika5a2d632019-01-09 14:25:29 +0000535 if (mLoggingEnabled) {
Michael Wright0a933142017-08-16 20:38:21 +0100536 Slog.d(TAG, "setAmbientLux(" + lux + ")");
537 }
Michael Wrightd8460232018-01-16 18:04:59 +0000538 if (lux < 0) {
Dan Gittikc5d32912018-02-22 13:53:47 +0000539 Slog.w(TAG, "Ambient lux was negative, ignoring and setting to 0");
Michael Wrightd8460232018-01-16 18:04:59 +0000540 lux = 0;
541 }
Michael Wright639c8be2014-01-17 18:29:12 -0800542 mAmbientLux = lux;
Dan Gittiked958e92018-11-13 14:58:20 +0000543 mAmbientBrighteningThreshold = mAmbientBrightnessThresholds.getBrighteningThreshold(lux);
544 mAmbientDarkeningThreshold = mAmbientBrightnessThresholds.getDarkeningThreshold(lux);
Dan Gittikc5d32912018-02-22 13:53:47 +0000545
546 // If the short term model was invalidated and the change is drastic enough, reset it.
547 if (!mShortTermModelValid && mShortTermModelAnchor != -1) {
Kenny Guyb29fdf12019-12-04 12:57:04 +0000548 if (mBrightnessMapper.shouldResetShortTermModel(mAmbientLux, mShortTermModelAnchor)) {
Dan Gittikc5d32912018-02-22 13:53:47 +0000549 resetShortTermModel();
Kenny Guyb29fdf12019-12-04 12:57:04 +0000550 } else {
551 mShortTermModelValid = true;
Dan Gittikc5d32912018-02-22 13:53:47 +0000552 }
553 }
Michael Wright639c8be2014-01-17 18:29:12 -0800554 }
555
Michael Wright0a933142017-08-16 20:38:21 +0100556 private float calculateAmbientLux(long now, long horizon) {
Dan Gittika5a2d632019-01-09 14:25:29 +0000557 if (mLoggingEnabled) {
Michael Wright0a933142017-08-16 20:38:21 +0100558 Slog.d(TAG, "calculateAmbientLux(" + now + ", " + horizon + ")");
559 }
Michael Wright639c8be2014-01-17 18:29:12 -0800560 final int N = mAmbientLightRingBuffer.size();
561 if (N == 0) {
562 Slog.e(TAG, "calculateAmbientLux: No ambient light readings available");
563 return -1;
564 }
Michael Wright0a933142017-08-16 20:38:21 +0100565
566 // Find the first measurement that is just outside of the horizon.
567 int endIndex = 0;
568 final long horizonStartTime = now - horizon;
569 for (int i = 0; i < N-1; i++) {
570 if (mAmbientLightRingBuffer.getTime(i + 1) <= horizonStartTime) {
571 endIndex++;
572 } else {
573 break;
574 }
575 }
Dan Gittika5a2d632019-01-09 14:25:29 +0000576 if (mLoggingEnabled) {
Dan Gittik57d6f112018-03-27 18:14:22 +0100577 Slog.d(TAG, "calculateAmbientLux: selected endIndex=" + endIndex + ", point=(" +
578 mAmbientLightRingBuffer.getTime(endIndex) + ", " +
579 mAmbientLightRingBuffer.getLux(endIndex) + ")");
Michael Wright0a933142017-08-16 20:38:21 +0100580 }
Michael Wright639c8be2014-01-17 18:29:12 -0800581 float sum = 0;
582 float totalWeight = 0;
583 long endTime = AMBIENT_LIGHT_PREDICTION_TIME_MILLIS;
Michael Wright0a933142017-08-16 20:38:21 +0100584 for (int i = N - 1; i >= endIndex; i--) {
585 long eventTime = mAmbientLightRingBuffer.getTime(i);
586 if (i == endIndex && eventTime < horizonStartTime) {
587 // If we're at the final value, make sure we only consider the part of the sample
588 // within our desired horizon.
589 eventTime = horizonStartTime;
590 }
591 final long startTime = eventTime - now;
Michael Wright639c8be2014-01-17 18:29:12 -0800592 float weight = calculateWeight(startTime, endTime);
593 float lux = mAmbientLightRingBuffer.getLux(i);
Dan Gittika5a2d632019-01-09 14:25:29 +0000594 if (mLoggingEnabled) {
Dan Gittikc5d32912018-02-22 13:53:47 +0000595 Slog.d(TAG, "calculateAmbientLux: [" + startTime + ", " + endTime + "]: " +
Dan Gittik57d6f112018-03-27 18:14:22 +0100596 "lux=" + lux + ", " +
597 "weight=" + weight);
Michael Wright639c8be2014-01-17 18:29:12 -0800598 }
599 totalWeight += weight;
Dan Gittikc5d32912018-02-22 13:53:47 +0000600 sum += lux * weight;
Michael Wright639c8be2014-01-17 18:29:12 -0800601 endTime = startTime;
602 }
Dan Gittika5a2d632019-01-09 14:25:29 +0000603 if (mLoggingEnabled) {
Dan Gittikc5d32912018-02-22 13:53:47 +0000604 Slog.d(TAG, "calculateAmbientLux: " +
Dan Gittik57d6f112018-03-27 18:14:22 +0100605 "totalWeight=" + totalWeight + ", " +
606 "newAmbientLux=" + (sum / totalWeight));
Michael Wright639c8be2014-01-17 18:29:12 -0800607 }
608 return sum / totalWeight;
609 }
610
Zoran Jovanovic6fc42f52015-12-10 17:01:16 +0100611 private float calculateWeight(long startDelta, long endDelta) {
Michael Wright639c8be2014-01-17 18:29:12 -0800612 return weightIntegral(endDelta) - weightIntegral(startDelta);
613 }
614
Zoran Jovanovic6fc42f52015-12-10 17:01:16 +0100615 // Evaluates the integral of y = x + mWeightingIntercept. This is always positive for the
Michael Wright639c8be2014-01-17 18:29:12 -0800616 // horizon we're looking at and provides a non-linear weighting for light samples.
Zoran Jovanovic6fc42f52015-12-10 17:01:16 +0100617 private float weightIntegral(long x) {
618 return x * (x * 0.5f + mWeightingIntercept);
Michael Wright639c8be2014-01-17 18:29:12 -0800619 }
620
621 private long nextAmbientLightBrighteningTransition(long time) {
622 final int N = mAmbientLightRingBuffer.size();
623 long earliestValidTime = time;
624 for (int i = N - 1; i >= 0; i--) {
Dan Gittiked958e92018-11-13 14:58:20 +0000625 if (mAmbientLightRingBuffer.getLux(i) <= mAmbientBrighteningThreshold) {
Michael Wright639c8be2014-01-17 18:29:12 -0800626 break;
627 }
628 earliestValidTime = mAmbientLightRingBuffer.getTime(i);
629 }
Filip Gruszczynskid81ecd12015-02-06 12:38:47 -0800630 return earliestValidTime + mBrighteningLightDebounceConfig;
Michael Wright639c8be2014-01-17 18:29:12 -0800631 }
632
633 private long nextAmbientLightDarkeningTransition(long time) {
634 final int N = mAmbientLightRingBuffer.size();
635 long earliestValidTime = time;
636 for (int i = N - 1; i >= 0; i--) {
Dan Gittiked958e92018-11-13 14:58:20 +0000637 if (mAmbientLightRingBuffer.getLux(i) >= mAmbientDarkeningThreshold) {
Michael Wright639c8be2014-01-17 18:29:12 -0800638 break;
639 }
640 earliestValidTime = mAmbientLightRingBuffer.getTime(i);
641 }
Filip Gruszczynskid81ecd12015-02-06 12:38:47 -0800642 return earliestValidTime + mDarkeningLightDebounceConfig;
Michael Wright639c8be2014-01-17 18:29:12 -0800643 }
644
645 private void updateAmbientLux() {
646 long time = SystemClock.uptimeMillis();
Zoran Jovanovic6fc42f52015-12-10 17:01:16 +0100647 mAmbientLightRingBuffer.prune(time - mAmbientLightHorizon);
Michael Wright639c8be2014-01-17 18:29:12 -0800648 updateAmbientLux(time);
649 }
650
651 private void updateAmbientLux(long time) {
652 // If the light sensor was just turned on then immediately update our initial
653 // estimate of the current ambient light level.
654 if (!mAmbientLuxValid) {
655 final long timeWhenSensorWarmedUp =
656 mLightSensorWarmUpTimeConfig + mLightSensorEnableTime;
657 if (time < timeWhenSensorWarmedUp) {
Dan Gittika5a2d632019-01-09 14:25:29 +0000658 if (mLoggingEnabled) {
Kenny Guyb54d40b2019-02-28 12:49:53 +0000659 Slog.d(TAG, "updateAmbientLux: Sensor not ready yet: "
660 + "time=" + time + ", "
661 + "timeWhenSensorWarmedUp=" + timeWhenSensorWarmedUp);
Michael Wright639c8be2014-01-17 18:29:12 -0800662 }
663 mHandler.sendEmptyMessageAtTime(MSG_UPDATE_AMBIENT_LUX,
664 timeWhenSensorWarmedUp);
665 return;
666 }
Michael Wright0a933142017-08-16 20:38:21 +0100667 setAmbientLux(calculateAmbientLux(time, AMBIENT_LIGHT_SHORT_HORIZON_MILLIS));
Michael Wright639c8be2014-01-17 18:29:12 -0800668 mAmbientLuxValid = true;
Dan Gittika5a2d632019-01-09 14:25:29 +0000669 if (mLoggingEnabled) {
Dan Gittikc5d32912018-02-22 13:53:47 +0000670 Slog.d(TAG, "updateAmbientLux: Initializing: " +
671 "mAmbientLightRingBuffer=" + mAmbientLightRingBuffer + ", " +
672 "mAmbientLux=" + mAmbientLux);
Michael Wright639c8be2014-01-17 18:29:12 -0800673 }
Santos Cordon4acbedb2019-06-07 17:20:41 +0100674 updateAutoBrightness(true /* sendUpdate */, false /* isManuallySet */);
Michael Wright639c8be2014-01-17 18:29:12 -0800675 }
676
677 long nextBrightenTransition = nextAmbientLightBrighteningTransition(time);
678 long nextDarkenTransition = nextAmbientLightDarkeningTransition(time);
Michael Wright0a933142017-08-16 20:38:21 +0100679 // Essentially, we calculate both a slow ambient lux, to ensure there's a true long-term
680 // change in lighting conditions, and a fast ambient lux to determine what the new
681 // brightness situation is since the slow lux can be quite slow to converge.
682 //
683 // Note that both values need to be checked for sufficient change before updating the
684 // proposed ambient light value since the slow value might be sufficiently far enough away
685 // from the fast value to cause a recalculation while its actually just converging on
686 // the fast value still.
687 float slowAmbientLux = calculateAmbientLux(time, AMBIENT_LIGHT_LONG_HORIZON_MILLIS);
688 float fastAmbientLux = calculateAmbientLux(time, AMBIENT_LIGHT_SHORT_HORIZON_MILLIS);
Michael Wright639c8be2014-01-17 18:29:12 -0800689
Dan Gittiked958e92018-11-13 14:58:20 +0000690 if ((slowAmbientLux >= mAmbientBrighteningThreshold
691 && fastAmbientLux >= mAmbientBrighteningThreshold
692 && nextBrightenTransition <= time)
693 || (slowAmbientLux <= mAmbientDarkeningThreshold
694 && fastAmbientLux <= mAmbientDarkeningThreshold
695 && nextDarkenTransition <= time)) {
Michael Wright0a933142017-08-16 20:38:21 +0100696 setAmbientLux(fastAmbientLux);
Dan Gittika5a2d632019-01-09 14:25:29 +0000697 if (mLoggingEnabled) {
Dan Gittiked958e92018-11-13 14:58:20 +0000698 Slog.d(TAG, "updateAmbientLux: "
699 + ((fastAmbientLux > mAmbientLux) ? "Brightened" : "Darkened") + ": "
Dan Gittika5a2d632019-01-09 14:25:29 +0000700 + "mBrighteningLuxThreshold=" + mAmbientBrighteningThreshold + ", "
Dan Gittiked958e92018-11-13 14:58:20 +0000701 + "mAmbientLightRingBuffer=" + mAmbientLightRingBuffer + ", "
702 + "mAmbientLux=" + mAmbientLux);
Michael Wright639c8be2014-01-17 18:29:12 -0800703 }
Santos Cordon4acbedb2019-06-07 17:20:41 +0100704 updateAutoBrightness(true /* sendUpdate */, false /* isManuallySet */);
Michael Wright639c8be2014-01-17 18:29:12 -0800705 nextBrightenTransition = nextAmbientLightBrighteningTransition(time);
706 nextDarkenTransition = nextAmbientLightDarkeningTransition(time);
707 }
708 long nextTransitionTime = Math.min(nextDarkenTransition, nextBrightenTransition);
709 // If one of the transitions is ready to occur, but the total weighted ambient lux doesn't
710 // exceed the necessary threshold, then it's possible we'll get a transition time prior to
711 // now. Rather than continually checking to see whether the weighted lux exceeds the
712 // threshold, schedule an update for when we'd normally expect another light sample, which
713 // should be enough time to decide whether we should actually transition to the new
714 // weighted ambient lux or not.
715 nextTransitionTime =
Julius D'souza5d717092016-10-24 19:26:45 -0700716 nextTransitionTime > time ? nextTransitionTime : time + mNormalLightSensorRate;
Dan Gittika5a2d632019-01-09 14:25:29 +0000717 if (mLoggingEnabled) {
Dan Gittikc5d32912018-02-22 13:53:47 +0000718 Slog.d(TAG, "updateAmbientLux: Scheduling ambient lux update for " +
Dan Gittik57d6f112018-03-27 18:14:22 +0100719 nextTransitionTime + TimeUtils.formatUptime(nextTransitionTime));
Michael Wright639c8be2014-01-17 18:29:12 -0800720 }
721 mHandler.sendEmptyMessageAtTime(MSG_UPDATE_AMBIENT_LUX, nextTransitionTime);
722 }
723
Santos Cordon4acbedb2019-06-07 17:20:41 +0100724 private void updateAutoBrightness(boolean sendUpdate, boolean isManuallySet) {
Michael Wright639c8be2014-01-17 18:29:12 -0800725 if (!mAmbientLuxValid) {
726 return;
727 }
728
Dan Gittika5a2d632019-01-09 14:25:29 +0000729 float value = mBrightnessMapper.getBrightness(mAmbientLux, mForegroundAppPackageName,
730 mForegroundAppCategory);
Fiona Campbellf972a082020-03-25 18:05:25 +0000731 float newScreenAutoBrightness = clampScreenBrightness(value);
Dan Gittiked958e92018-11-13 14:58:20 +0000732 // If screenAutoBrightness is set, we should have screen{Brightening,Darkening}Threshold,
733 // in which case we ignore the new screen brightness if it doesn't differ enough from the
734 // previous one.
Fiona Campbellf972a082020-03-25 18:05:25 +0000735 if (!Float.isNaN(mScreenAutoBrightness)
Santos Cordon4acbedb2019-06-07 17:20:41 +0100736 && !isManuallySet
Dan Gittiked958e92018-11-13 14:58:20 +0000737 && newScreenAutoBrightness > mScreenDarkeningThreshold
738 && newScreenAutoBrightness < mScreenBrighteningThreshold) {
Dan Gittika5a2d632019-01-09 14:25:29 +0000739 if (mLoggingEnabled) {
Fiona Campbellf972a082020-03-25 18:05:25 +0000740 Slog.d(TAG, "ignoring newScreenAutoBrightness: "
741 + mScreenDarkeningThreshold + " < " + newScreenAutoBrightness
742 + " < " + mScreenBrighteningThreshold);
Dan Gittiked958e92018-11-13 14:58:20 +0000743 }
744 return;
745 }
Fiona Campbellf972a082020-03-25 18:05:25 +0000746 if (!BrightnessSynchronizer.floatEquals(mScreenAutoBrightness,
747 newScreenAutoBrightness)) {
Dan Gittika5a2d632019-01-09 14:25:29 +0000748 if (mLoggingEnabled) {
Fiona Campbellf972a082020-03-25 18:05:25 +0000749 Slog.d(TAG, "updateAutoBrightness: "
750 + "mScreenAutoBrightness=" + mScreenAutoBrightness + ", "
751 + "newScreenAutoBrightness=" + newScreenAutoBrightness);
Michael Wright639c8be2014-01-17 18:29:12 -0800752 }
Michael Wright639c8be2014-01-17 18:29:12 -0800753 mScreenAutoBrightness = newScreenAutoBrightness;
Santos Cordon64a86272019-11-28 11:24:21 +0000754 mScreenBrighteningThreshold = clampScreenBrightness(
755 mScreenBrightnessThresholds.getBrighteningThreshold(newScreenAutoBrightness));
756 mScreenDarkeningThreshold = clampScreenBrightness(
757 mScreenBrightnessThresholds.getDarkeningThreshold(newScreenAutoBrightness));
Dan Gittiked958e92018-11-13 14:58:20 +0000758
Michael Wright639c8be2014-01-17 18:29:12 -0800759 if (sendUpdate) {
760 mCallbacks.updateBrightness();
761 }
762 }
763 }
764
Fiona Campbellf972a082020-03-25 18:05:25 +0000765 // Clamps values with float range [0.0-1.0]
Santos Cordon64a86272019-11-28 11:24:21 +0000766 private float clampScreenBrightness(float value) {
Michael Wright639c8be2014-01-17 18:29:12 -0800767 return MathUtils.constrain(value,
768 mScreenBrightnessRangeMinimum, mScreenBrightnessRangeMaximum);
769 }
770
Jeff Browna576b4d2015-04-23 19:58:06 -0700771 private void prepareBrightnessAdjustmentSample() {
772 if (!mBrightnessAdjustmentSamplePending) {
773 mBrightnessAdjustmentSamplePending = true;
Jeff Browna576b4d2015-04-23 19:58:06 -0700774 mBrightnessAdjustmentSampleOldLux = mAmbientLuxValid ? mAmbientLux : -1;
775 mBrightnessAdjustmentSampleOldBrightness = mScreenAutoBrightness;
Jeff Browna576b4d2015-04-23 19:58:06 -0700776 } else {
777 mHandler.removeMessages(MSG_BRIGHTNESS_ADJUSTMENT_SAMPLE);
778 }
779
780 mHandler.sendEmptyMessageDelayed(MSG_BRIGHTNESS_ADJUSTMENT_SAMPLE,
781 BRIGHTNESS_ADJUSTMENT_SAMPLE_DEBOUNCE_MILLIS);
782 }
783
Sudheer Shankab3f60652019-01-04 20:30:14 +0000784 private void cancelBrightnessAdjustmentSample() {
785 if (mBrightnessAdjustmentSamplePending) {
786 mBrightnessAdjustmentSamplePending = false;
787 mHandler.removeMessages(MSG_BRIGHTNESS_ADJUSTMENT_SAMPLE);
788 }
789 }
790
Jeff Browna576b4d2015-04-23 19:58:06 -0700791 private void collectBrightnessAdjustmentSample() {
792 if (mBrightnessAdjustmentSamplePending) {
793 mBrightnessAdjustmentSamplePending = false;
Fiona Campbellf972a082020-03-25 18:05:25 +0000794 if (mAmbientLuxValid && (mScreenAutoBrightness >= PowerManager.BRIGHTNESS_MIN
795 || mScreenAutoBrightness == PowerManager.BRIGHTNESS_OFF_FLOAT)) {
Dan Gittika5a2d632019-01-09 14:25:29 +0000796 if (mLoggingEnabled) {
Fiona Campbellf972a082020-03-25 18:05:25 +0000797 Slog.d(TAG, "Auto-brightness adjustment changed by user: "
798 + "lux=" + mAmbientLux + ", "
799 + "brightness=" + mScreenAutoBrightness + ", "
800 + "ring=" + mAmbientLightRingBuffer);
Jeff Browna576b4d2015-04-23 19:58:06 -0700801 }
802
803 EventLog.writeEvent(EventLogTags.AUTO_BRIGHTNESS_ADJ,
Jeff Browna576b4d2015-04-23 19:58:06 -0700804 mBrightnessAdjustmentSampleOldLux,
805 mBrightnessAdjustmentSampleOldBrightness,
Jeff Browna576b4d2015-04-23 19:58:06 -0700806 mAmbientLux,
Dan Gittik57d6f112018-03-27 18:14:22 +0100807 mScreenAutoBrightness);
Jeff Browna576b4d2015-04-23 19:58:06 -0700808 }
809 }
810 }
811
Dan Gittika5a2d632019-01-09 14:25:29 +0000812 // Register a TaskStackListener to call back to us onTaskStackChanged, so we can update the
813 // foreground app's package name and category and correct the brightness accordingly.
814 private void registerForegroundAppUpdater() {
815 try {
816 mActivityTaskManager.registerTaskStackListener(mTaskStackListener);
817 // This will not get called until the foreground app changes for the first time, so
818 // call it explicitly to get the current foreground app's info.
819 updateForegroundApp();
820 } catch (RemoteException e) {
821 if (mLoggingEnabled) {
822 Slog.e(TAG, "Failed to register foreground app updater: " + e);
823 }
824 // Nothing to do.
825 }
826 }
827
828 private void unregisterForegroundAppUpdater() {
829 try {
830 mActivityTaskManager.unregisterTaskStackListener(mTaskStackListener);
831 } catch (RemoteException e) {
832 // Nothing to do.
833 }
834 mForegroundAppPackageName = null;
835 mForegroundAppCategory = ApplicationInfo.CATEGORY_UNDEFINED;
836 }
837
838 // Set the foreground app's package name and category, so brightness can be corrected per app.
839 private void updateForegroundApp() {
840 if (mLoggingEnabled) {
841 Slog.d(TAG, "Attempting to update foreground app");
842 }
843 // The ActivityTaskManager's lock tends to get contended, so this is done in a background
844 // thread and applied via this thread's handler synchronously.
Santos Cordon64a86272019-11-28 11:24:21 +0000845 mInjector.getBackgroundThreadHandler().post(new Runnable() {
Dan Gittika5a2d632019-01-09 14:25:29 +0000846 public void run() {
847 try {
848 // The foreground app is the top activity of the focused tasks stack.
849 final StackInfo info = mActivityTaskManager.getFocusedStackInfo();
850 if (info == null || info.topActivity == null) {
851 return;
852 }
853 final String packageName = info.topActivity.getPackageName();
854 // If the app didn't change, there's nothing to do. Otherwise, we have to
855 // update the category and re-apply the brightness correction.
856 if (mForegroundAppPackageName != null
857 && mForegroundAppPackageName.equals(packageName)) {
858 return;
859 }
860 mPendingForegroundAppPackageName = packageName;
861 mPendingForegroundAppCategory = ApplicationInfo.CATEGORY_UNDEFINED;
862 try {
863 ApplicationInfo app = mPackageManager.getApplicationInfo(packageName,
864 PackageManager.MATCH_ANY_USER);
865 mPendingForegroundAppCategory = app.category;
866 } catch (PackageManager.NameNotFoundException e) {
867 // Nothing to do
868 }
869 mHandler.sendEmptyMessage(MSG_UPDATE_FOREGROUND_APP_SYNC);
870 } catch (RemoteException e) {
871 // Nothing to do
872 }
873 }
874 });
875 }
876
877 private void updateForegroundAppSync() {
878 if (mLoggingEnabled) {
879 Slog.d(TAG, "Updating foreground app: packageName=" + mPendingForegroundAppPackageName
880 + ", category=" + mPendingForegroundAppCategory);
881 }
882 mForegroundAppPackageName = mPendingForegroundAppPackageName;
883 mPendingForegroundAppPackageName = null;
884 mForegroundAppCategory = mPendingForegroundAppCategory;
885 mPendingForegroundAppCategory = ApplicationInfo.CATEGORY_UNDEFINED;
Santos Cordon4acbedb2019-06-07 17:20:41 +0100886 updateAutoBrightness(true /* sendUpdate */, false /* isManuallySet */);
Dan Gittika5a2d632019-01-09 14:25:29 +0000887 }
888
Michael Wright639c8be2014-01-17 18:29:12 -0800889 private final class AutomaticBrightnessHandler extends Handler {
890 public AutomaticBrightnessHandler(Looper looper) {
891 super(looper, null, true /*async*/);
892 }
893
894 @Override
895 public void handleMessage(Message msg) {
896 switch (msg.what) {
897 case MSG_UPDATE_AMBIENT_LUX:
898 updateAmbientLux();
899 break;
Jeff Browna576b4d2015-04-23 19:58:06 -0700900
901 case MSG_BRIGHTNESS_ADJUSTMENT_SAMPLE:
902 collectBrightnessAdjustmentSample();
903 break;
Michael Wrightd8460232018-01-16 18:04:59 +0000904
Dan Gittikc5d32912018-02-22 13:53:47 +0000905 case MSG_INVALIDATE_SHORT_TERM_MODEL:
906 invalidateShortTermModel();
Michael Wrightd8460232018-01-16 18:04:59 +0000907 break;
Dan Gittika5a2d632019-01-09 14:25:29 +0000908
909 case MSG_UPDATE_FOREGROUND_APP:
910 updateForegroundApp();
911 break;
912
913 case MSG_UPDATE_FOREGROUND_APP_SYNC:
914 updateForegroundAppSync();
915 break;
Michael Wright639c8be2014-01-17 18:29:12 -0800916 }
917 }
918 }
919
920 private final SensorEventListener mLightSensorListener = new SensorEventListener() {
921 @Override
922 public void onSensorChanged(SensorEvent event) {
923 if (mLightSensorEnabled) {
924 final long time = SystemClock.uptimeMillis();
925 final float lux = event.values[0];
926 handleLightSensorEvent(time, lux);
927 }
928 }
929
930 @Override
931 public void onAccuracyChanged(Sensor sensor, int accuracy) {
932 // Not used.
933 }
934 };
935
Dan Gittika5a2d632019-01-09 14:25:29 +0000936 // Call back whenever the tasks stack changes, which includes tasks being created, removed, and
937 // moving to top.
938 class TaskStackListenerImpl extends TaskStackListener {
939 @Override
940 public void onTaskStackChanged() {
941 mHandler.sendEmptyMessage(MSG_UPDATE_FOREGROUND_APP);
942 }
943 }
944
Michael Wright639c8be2014-01-17 18:29:12 -0800945 /** Callbacks to request updates to the display's power state. */
946 interface Callbacks {
947 void updateBrightness();
948 }
949
Michael Wright0a933142017-08-16 20:38:21 +0100950 /**
951 * A ring buffer of ambient light measurements sorted by time.
952 *
953 * Each entry consists of a timestamp and a lux measurement, and the overall buffer is sorted
954 * from oldest to newest.
955 */
Michael Wright103fb782016-04-22 01:03:09 -0400956 private static final class AmbientLightRingBuffer {
Michael Wright639c8be2014-01-17 18:29:12 -0800957 // Proportional extra capacity of the buffer beyond the expected number of light samples
958 // in the horizon
959 private static final float BUFFER_SLACK = 1.5f;
Michael Wright639c8be2014-01-17 18:29:12 -0800960 private float[] mRingLux;
961 private long[] mRingTime;
962 private int mCapacity;
963
964 // The first valid element and the next open slot.
965 // Note that if mCount is zero then there are no valid elements.
966 private int mStart;
967 private int mEnd;
968 private int mCount;
969
Zoran Jovanovic6fc42f52015-12-10 17:01:16 +0100970 public AmbientLightRingBuffer(long lightSensorRate, int ambientLightHorizon) {
Santos Cordon64a86272019-11-28 11:24:21 +0000971 if (lightSensorRate <= 0) {
972 throw new IllegalArgumentException("lightSensorRate must be above 0");
973 }
Zoran Jovanovic6fc42f52015-12-10 17:01:16 +0100974 mCapacity = (int) Math.ceil(ambientLightHorizon * BUFFER_SLACK / lightSensorRate);
Michael Wright639c8be2014-01-17 18:29:12 -0800975 mRingLux = new float[mCapacity];
976 mRingTime = new long[mCapacity];
977 }
978
979 public float getLux(int index) {
980 return mRingLux[offsetOf(index)];
981 }
982
983 public long getTime(int index) {
984 return mRingTime[offsetOf(index)];
985 }
986
987 public void push(long time, float lux) {
988 int next = mEnd;
989 if (mCount == mCapacity) {
990 int newSize = mCapacity * 2;
991
992 float[] newRingLux = new float[newSize];
993 long[] newRingTime = new long[newSize];
994 int length = mCapacity - mStart;
995 System.arraycopy(mRingLux, mStart, newRingLux, 0, length);
996 System.arraycopy(mRingTime, mStart, newRingTime, 0, length);
997 if (mStart != 0) {
998 System.arraycopy(mRingLux, 0, newRingLux, length, mStart);
999 System.arraycopy(mRingTime, 0, newRingTime, length, mStart);
1000 }
1001 mRingLux = newRingLux;
1002 mRingTime = newRingTime;
1003
1004 next = mCapacity;
1005 mCapacity = newSize;
1006 mStart = 0;
1007 }
1008 mRingTime[next] = time;
1009 mRingLux[next] = lux;
1010 mEnd = next + 1;
1011 if (mEnd == mCapacity) {
1012 mEnd = 0;
1013 }
1014 mCount++;
1015 }
1016
1017 public void prune(long horizon) {
1018 if (mCount == 0) {
1019 return;
1020 }
1021
1022 while (mCount > 1) {
1023 int next = mStart + 1;
1024 if (next >= mCapacity) {
1025 next -= mCapacity;
1026 }
1027 if (mRingTime[next] > horizon) {
1028 // Some light sensors only produce data upon a change in the ambient light
1029 // levels, so we need to consider the previous measurement as the ambient light
1030 // level for all points in time up until we receive a new measurement. Thus, we
1031 // always want to keep the youngest element that would be removed from the
1032 // buffer and just set its measurement time to the horizon time since at that
1033 // point it is the ambient light level, and to remove it would be to drop a
1034 // valid data point within our horizon.
1035 break;
1036 }
1037 mStart = next;
1038 mCount -= 1;
1039 }
1040
1041 if (mRingTime[mStart] < horizon) {
1042 mRingTime[mStart] = horizon;
1043 }
1044 }
1045
1046 public int size() {
1047 return mCount;
1048 }
1049
Michael Wright639c8be2014-01-17 18:29:12 -08001050 public void clear() {
1051 mStart = 0;
1052 mEnd = 0;
1053 mCount = 0;
1054 }
1055
1056 @Override
1057 public String toString() {
Jeff Browna576b4d2015-04-23 19:58:06 -07001058 StringBuffer buf = new StringBuffer();
1059 buf.append('[');
1060 for (int i = 0; i < mCount; i++) {
1061 final long next = i + 1 < mCount ? getTime(i + 1) : SystemClock.uptimeMillis();
1062 if (i != 0) {
1063 buf.append(", ");
1064 }
1065 buf.append(getLux(i));
1066 buf.append(" / ");
1067 buf.append(next - getTime(i));
1068 buf.append("ms");
Michael Wright639c8be2014-01-17 18:29:12 -08001069 }
Jeff Browna576b4d2015-04-23 19:58:06 -07001070 buf.append(']');
1071 return buf.toString();
Michael Wright639c8be2014-01-17 18:29:12 -08001072 }
1073
1074 private int offsetOf(int index) {
1075 if (index >= mCount || index < 0) {
1076 throw new ArrayIndexOutOfBoundsException(index);
1077 }
1078 index += mStart;
1079 if (index >= mCapacity) {
1080 index -= mCapacity;
1081 }
1082 return index;
1083 }
1084 }
Santos Cordon64a86272019-11-28 11:24:21 +00001085
1086 public static class Injector {
1087 public Handler getBackgroundThreadHandler() {
1088 return BackgroundThread.getHandler();
1089 }
1090 }
Michael Wright639c8be2014-01-17 18:29:12 -08001091}