blob: 6f12155c5ec6d8180d9c9e2b09f7b1134fca65f6 [file] [log] [blame]
Michael Wrighteef0e132017-11-21 17:57:52 +00001/*
2 * Copyright (C) 2017 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
17package com.android.server.display;
18
19import android.annotation.Nullable;
Dan Gittika5a2d632019-01-09 14:25:29 +000020import android.content.pm.ApplicationInfo;
Michael Wright144aac92017-12-21 18:37:41 +000021import android.content.res.Resources;
22import android.content.res.TypedArray;
Michael Wrighteef0e132017-11-21 17:57:52 +000023import android.hardware.display.BrightnessConfiguration;
Dan Gittika5a2d632019-01-09 14:25:29 +000024import android.hardware.display.BrightnessCorrection;
Michael Wrighteef0e132017-11-21 17:57:52 +000025import android.os.PowerManager;
26import android.util.MathUtils;
27import android.util.Pair;
28import android.util.Slog;
29import android.util.Spline;
30
Fiona Campbellf74a7192020-06-08 15:39:11 +010031import com.android.internal.BrightnessSynchronizer;
Michael Wrighteef0e132017-11-21 17:57:52 +000032import com.android.internal.annotations.VisibleForTesting;
Kenny Guyd62c3cf2018-09-11 11:41:06 +010033import com.android.internal.util.Preconditions;
Dan Gittik57d6f112018-03-27 18:14:22 +010034import com.android.server.display.utils.Plog;
Michael Wrighteef0e132017-11-21 17:57:52 +000035
36import java.io.PrintWriter;
Michael Wrightd8460232018-01-16 18:04:59 +000037import java.util.Arrays;
Daulet Zhanguzin82201022020-01-03 09:41:39 +000038import java.util.Objects;
Michael Wrighteef0e132017-11-21 17:57:52 +000039
40/**
41 * A utility to map from an ambient brightness to a display's "backlight" brightness based on the
42 * available display information and brightness configuration.
43 *
44 * Note that without a mapping from the nits to a display backlight level, any
45 * {@link BrightnessConfiguration}s that are set are just ignored.
46 */
47public abstract class BrightnessMappingStrategy {
48 private static final String TAG = "BrightnessMappingStrategy";
Michael Wrighteef0e132017-11-21 17:57:52 +000049
Michael Wrightd8460232018-01-16 18:04:59 +000050 private static final float LUX_GRAD_SMOOTHING = 0.25f;
51 private static final float MAX_GRAD = 1.0f;
Kenny Guyb29fdf12019-12-04 12:57:04 +000052 private static final float SHORT_TERM_MODEL_THRESHOLD_RATIO = 0.6f;
Michael Wrightd8460232018-01-16 18:04:59 +000053
Fiona Campbelld7ab9492020-05-01 19:37:39 +010054 // Constant that ensures that each step of the curve can increase by up to at least
55 // MIN_PERMISSABLE_INCREASE. Otherwise when the brightness is set to 0, the curve will never
56 // increase and will always be 0.
57 private static final float MIN_PERMISSABLE_INCREASE = 0.004f;
58
Dan Gittika5a2d632019-01-09 14:25:29 +000059 protected boolean mLoggingEnabled;
60
Dan Gittik57d6f112018-03-27 18:14:22 +010061 private static final Plog PLOG = Plog.createSystemPlog(TAG);
62
Michael Wrighteef0e132017-11-21 17:57:52 +000063 @Nullable
Michael Wright144aac92017-12-21 18:37:41 +000064 public static BrightnessMappingStrategy create(Resources resources) {
65 float[] luxLevels = getLuxLevels(resources.getIntArray(
66 com.android.internal.R.array.config_autoBrightnessLevels));
67 int[] brightnessLevelsBacklight = resources.getIntArray(
68 com.android.internal.R.array.config_autoBrightnessLcdBacklightValues);
69 float[] brightnessLevelsNits = getFloatArray(resources.obtainTypedArray(
70 com.android.internal.R.array.config_autoBrightnessDisplayValuesNits));
Dan Gittik57d6f112018-03-27 18:14:22 +010071 float autoBrightnessAdjustmentMaxGamma = resources.getFraction(
72 com.android.internal.R.fraction.config_autoBrightnessAdjustmentMaxGamma,
73 1, 1);
Michael Wright144aac92017-12-21 18:37:41 +000074
75 float[] nitsRange = getFloatArray(resources.obtainTypedArray(
76 com.android.internal.R.array.config_screenBrightnessNits));
77 int[] backlightRange = resources.getIntArray(
78 com.android.internal.R.array.config_screenBrightnessBacklight);
79
Kenny Guyb29fdf12019-12-04 12:57:04 +000080 long shortTermModelTimeout = resources.getInteger(
81 com.android.internal.R.integer.config_autoBrightnessShortTermModelTimeout);
82
Michael Wrighteef0e132017-11-21 17:57:52 +000083 if (isValidMapping(nitsRange, backlightRange)
Artem Iglikove5cd25e2018-03-28 09:12:40 +000084 && isValidMapping(luxLevels, brightnessLevelsNits)) {
Michael Wright144aac92017-12-21 18:37:41 +000085 int minimumBacklight = resources.getInteger(
86 com.android.internal.R.integer.config_screenBrightnessSettingMinimum);
87 int maximumBacklight = resources.getInteger(
88 com.android.internal.R.integer.config_screenBrightnessSettingMaximum);
89 if (backlightRange[0] > minimumBacklight
90 || backlightRange[backlightRange.length - 1] < maximumBacklight) {
Dan Gittik57d6f112018-03-27 18:14:22 +010091 Slog.w(TAG, "Screen brightness mapping does not cover whole range of available " +
92 "backlight values, autobrightness functionality may be impaired.");
Michael Wright144aac92017-12-21 18:37:41 +000093 }
Kenny Guyd62c3cf2018-09-11 11:41:06 +010094 BrightnessConfiguration.Builder builder = new BrightnessConfiguration.Builder(
95 luxLevels, brightnessLevelsNits);
Kenny Guycae6c352020-01-20 14:56:00 +000096 builder.setShortTermModelTimeoutMillis(shortTermModelTimeout);
Kenny Guyb29fdf12019-12-04 12:57:04 +000097 builder.setShortTermModelLowerLuxMultiplier(SHORT_TERM_MODEL_THRESHOLD_RATIO);
98 builder.setShortTermModelUpperLuxMultiplier(SHORT_TERM_MODEL_THRESHOLD_RATIO);
Dan Gittik57d6f112018-03-27 18:14:22 +010099 return new PhysicalMappingStrategy(builder.build(), nitsRange, backlightRange,
100 autoBrightnessAdjustmentMaxGamma);
Michael Wrighteef0e132017-11-21 17:57:52 +0000101 } else if (isValidMapping(luxLevels, brightnessLevelsBacklight)) {
Dan Gittik57d6f112018-03-27 18:14:22 +0100102 return new SimpleMappingStrategy(luxLevels, brightnessLevelsBacklight,
Kenny Guyb29fdf12019-12-04 12:57:04 +0000103 autoBrightnessAdjustmentMaxGamma, shortTermModelTimeout);
Michael Wrighteef0e132017-11-21 17:57:52 +0000104 } else {
105 return null;
106 }
107 }
108
Michael Wright144aac92017-12-21 18:37:41 +0000109 private static float[] getLuxLevels(int[] lux) {
110 // The first control point is implicit and always at 0 lux.
111 float[] levels = new float[lux.length + 1];
112 for (int i = 0; i < lux.length; i++) {
113 levels[i + 1] = (float) lux[i];
114 }
115 return levels;
116 }
117
Santos Cordon4505e5e2020-01-17 15:18:10 +0000118 /**
119 * Extracts a float array from the specified {@link TypedArray}.
120 *
121 * @param array The array to convert.
122 * @return the given array as a float array.
123 */
124 public static float[] getFloatArray(TypedArray array) {
Michael Wright144aac92017-12-21 18:37:41 +0000125 final int N = array.length();
126 float[] vals = new float[N];
127 for (int i = 0; i < N; i++) {
Santos Cordon4505e5e2020-01-17 15:18:10 +0000128 vals[i] = array.getFloat(i, PowerManager.BRIGHTNESS_OFF_FLOAT);
Michael Wright144aac92017-12-21 18:37:41 +0000129 }
130 array.recycle();
131 return vals;
132 }
133
Michael Wrighteef0e132017-11-21 17:57:52 +0000134 private static boolean isValidMapping(float[] x, float[] y) {
135 if (x == null || y == null || x.length == 0 || y.length == 0) {
136 return false;
137 }
138 if (x.length != y.length) {
139 return false;
140 }
141 final int N = x.length;
142 float prevX = x[0];
143 float prevY = y[0];
144 if (prevX < 0 || prevY < 0 || Float.isNaN(prevX) || Float.isNaN(prevY)) {
145 return false;
146 }
147 for (int i = 1; i < N; i++) {
148 if (prevX >= x[i] || prevY > y[i]) {
149 return false;
150 }
151 if (Float.isNaN(x[i]) || Float.isNaN(y[i])) {
152 return false;
153 }
154 prevX = x[i];
155 prevY = y[i];
156 }
157 return true;
158 }
159
160 private static boolean isValidMapping(float[] x, int[] y) {
161 if (x == null || y == null || x.length == 0 || y.length == 0) {
162 return false;
163 }
164 if (x.length != y.length) {
165 return false;
166 }
167 final int N = x.length;
168 float prevX = x[0];
169 int prevY = y[0];
170 if (prevX < 0 || prevY < 0 || Float.isNaN(prevX)) {
171 return false;
172 }
173 for (int i = 1; i < N; i++) {
174 if (prevX >= x[i] || prevY > y[i]) {
175 return false;
176 }
177 if (Float.isNaN(x[i])) {
178 return false;
179 }
180 prevX = x[i];
181 prevY = y[i];
182 }
183 return true;
184 }
185
186 /**
Dan Gittika5a2d632019-01-09 14:25:29 +0000187 * Enable/disable logging.
188 *
189 * @param loggingEnabled
190 * Whether logging should be on/off.
191 *
192 * @return Whether the method succeeded or not.
193 */
194 public boolean setLoggingEnabled(boolean loggingEnabled) {
195 if (mLoggingEnabled == loggingEnabled) {
196 return false;
197 }
198 mLoggingEnabled = loggingEnabled;
199 return true;
200 }
201
202 /**
Michael Wrighteef0e132017-11-21 17:57:52 +0000203 * Sets the {@link BrightnessConfiguration}.
204 *
205 * @param config The new configuration. If {@code null} is passed, the default configuration is
206 * used.
207 * @return Whether the brightness configuration has changed.
208 */
209 public abstract boolean setBrightnessConfiguration(@Nullable BrightnessConfiguration config);
210
211 /**
Kenny Guyb29fdf12019-12-04 12:57:04 +0000212 * Gets the current {@link BrightnessConfiguration}.
213 */
214 @Nullable
215 public abstract BrightnessConfiguration getBrightnessConfiguration();
216
217 /**
Dan Gittika5a2d632019-01-09 14:25:29 +0000218 * Returns the desired brightness of the display based on the current ambient lux, including
219 * any context-related corrections.
Michael Wrighteef0e132017-11-21 17:57:52 +0000220 *
221 * The returned brightness will be in the range [0, 1.0], where 1.0 is the display at max
222 * brightness and 0 is the display at minimum brightness.
223 *
224 * @param lux The current ambient brightness in lux.
Dan Gittika5a2d632019-01-09 14:25:29 +0000225 * @param packageName the foreground app package name.
226 * @param category the foreground app package category.
Michael Wright144aac92017-12-21 18:37:41 +0000227 * @return The desired brightness of the display normalized to the range [0, 1.0].
Michael Wrighteef0e132017-11-21 17:57:52 +0000228 */
Dan Gittika5a2d632019-01-09 14:25:29 +0000229 public abstract float getBrightness(float lux, String packageName,
230 @ApplicationInfo.Category int category);
231
232 /**
233 * Returns the desired brightness of the display based on the current ambient lux.
234 *
235 * The returned brightness wil be in the range [0, 1.0], where 1.0 is the display at max
236 * brightness and 0 is the display at minimum brightness.
237 *
238 * @param lux The current ambient brightness in lux.
239 *
240 * @return The desired brightness of the display normalized to the range [0, 1.0].
241 */
242 public float getBrightness(float lux) {
243 return getBrightness(lux, null /* packageName */, ApplicationInfo.CATEGORY_UNDEFINED);
244 }
Michael Wrighteef0e132017-11-21 17:57:52 +0000245
Michael Wright144aac92017-12-21 18:37:41 +0000246 /**
Dan Gittik57d6f112018-03-27 18:14:22 +0100247 * Returns the current auto-brightness adjustment.
248 *
249 * The returned adjustment is a value in the range [-1.0, 1.0] such that
250 * {@code config_autoBrightnessAdjustmentMaxGamma<sup>-adjustment</sup>} is used to gamma
251 * correct the brightness curve.
252 */
253 public abstract float getAutoBrightnessAdjustment();
254
255 /**
256 * Sets the auto-brightness adjustment.
257 *
258 * @param adjustment The desired auto-brightness adjustment.
259 * @return Whether the auto-brightness adjustment has changed.
260 *
261 * @Deprecated The auto-brightness adjustment should not be set directly, but rather inferred
262 * from user data points.
263 */
264 public abstract boolean setAutoBrightnessAdjustment(float adjustment);
265
266 /**
Michael Wrightd8460232018-01-16 18:04:59 +0000267 * Converts the provided backlight value to nits if possible.
Michael Wright144aac92017-12-21 18:37:41 +0000268 *
269 * Returns -1.0f if there's no available mapping for the backlight to nits.
270 */
Michael Wrightd8460232018-01-16 18:04:59 +0000271 public abstract float convertToNits(int backlight);
272
273 /**
274 * Adds a user interaction data point to the brightness mapping.
275 *
Michael Wright617564f2018-01-25 22:20:54 +0000276 * This data point <b>must</b> exist on the brightness curve as a result of this call. This is
277 * so that the next time we come to query what the screen brightness should be, we get what the
278 * user requested rather than immediately changing to some other value.
279 *
Michael Wrightd8460232018-01-16 18:04:59 +0000280 * Currently, we only keep track of one of these at a time to constrain what can happen to the
281 * curve.
282 */
283 public abstract void addUserDataPoint(float lux, float brightness);
284
285 /**
286 * Removes any short term adjustments made to the curve from user interactions.
287 *
288 * Note that this does *not* reset the mapping to its initial state, any brightness
289 * configurations that have been applied will continue to be in effect. This solely removes the
290 * effects of user interactions on the model.
291 */
292 public abstract void clearUserDataPoints();
Michael Wright144aac92017-12-21 18:37:41 +0000293
Dan Gittik57d6f112018-03-27 18:14:22 +0100294 /** @return True if there are any short term adjustments applied to the curve. */
Kenny Guy53d06612018-01-30 14:19:13 +0000295 public abstract boolean hasUserDataPoints();
296
Dan Gittik57d6f112018-03-27 18:14:22 +0100297 /** @return True if the current brightness configuration is the default one. */
Kenny Guy53d06612018-01-30 14:19:13 +0000298 public abstract boolean isDefaultConfig();
299
Dan Gittik57d6f112018-03-27 18:14:22 +0100300 /** @return The default brightness configuration. */
Kenny Guy6d1009f2018-03-14 14:28:23 +0000301 public abstract BrightnessConfiguration getDefaultConfig();
302
Kenny Guyb29fdf12019-12-04 12:57:04 +0000303
304 /**
305 * Returns the timeout for the short term model
306 *
307 * Timeout after which we remove the effects any user interactions might've had on the
308 * brightness mapping. This timeout doesn't start until we transition to a non-interactive
309 * display policy so that we don't reset while users are using their devices, but also so that
310 * we don't erroneously keep the short-term model if the device is dozing but the
311 * display is fully on.
312 */
313 public abstract long getShortTermModelTimeout();
314
Michael Wrighteef0e132017-11-21 17:57:52 +0000315 public abstract void dump(PrintWriter pw);
316
Kenny Guyb29fdf12019-12-04 12:57:04 +0000317 /**
318 * Check if the short term model should be reset given the anchor lux the last
319 * brightness change was made at and the current ambient lux.
320 */
321 public boolean shouldResetShortTermModel(float ambientLux, float shortTermModelAnchor) {
322 BrightnessConfiguration config = getBrightnessConfiguration();
323 float minThresholdRatio = SHORT_TERM_MODEL_THRESHOLD_RATIO;
324 float maxThresholdRatio = SHORT_TERM_MODEL_THRESHOLD_RATIO;
325 if (config != null) {
326 if (!Float.isNaN(config.getShortTermModelLowerLuxMultiplier())) {
327 minThresholdRatio = config.getShortTermModelLowerLuxMultiplier();
328 }
329 if (!Float.isNaN(config.getShortTermModelUpperLuxMultiplier())) {
330 maxThresholdRatio = config.getShortTermModelUpperLuxMultiplier();
331 }
332 }
333 final float minAmbientLux =
334 shortTermModelAnchor - shortTermModelAnchor * minThresholdRatio;
335 final float maxAmbientLux =
336 shortTermModelAnchor + shortTermModelAnchor * maxThresholdRatio;
337 if (minAmbientLux < ambientLux && ambientLux <= maxAmbientLux) {
338 if (mLoggingEnabled) {
339 Slog.d(TAG, "ShortTermModel: re-validate user data, ambient lux is "
340 + minAmbientLux + " < " + ambientLux + " < " + maxAmbientLux);
341 }
342 return false;
343 } else {
344 Slog.d(TAG, "ShortTermModel: reset data, ambient lux is " + ambientLux
345 + "(" + minAmbientLux + ", " + maxAmbientLux + ")");
346 return true;
347 }
348 }
349
Fiona Campbell270ea412020-05-12 19:55:03 +0100350 // Normalize entire brightness range to 0 - 1.
Santos Cordon4505e5e2020-01-17 15:18:10 +0000351 protected static float normalizeAbsoluteBrightness(int brightness) {
Fiona Campbellf74a7192020-06-08 15:39:11 +0100352 return BrightnessSynchronizer.brightnessIntToFloat(brightness,
353 PowerManager.BRIGHTNESS_OFF + 1, PowerManager.BRIGHTNESS_ON,
354 PowerManager.BRIGHTNESS_MIN, PowerManager.BRIGHTNESS_MAX);
Michael Wrighteef0e132017-11-21 17:57:52 +0000355 }
356
Dan Gittika5a2d632019-01-09 14:25:29 +0000357 private Pair<float[], float[]> insertControlPoint(
Michael Wrightd8460232018-01-16 18:04:59 +0000358 float[] luxLevels, float[] brightnessLevels, float lux, float brightness) {
Michael Wrightd8460232018-01-16 18:04:59 +0000359 final int idx = findInsertionPoint(luxLevels, lux);
360 final float[] newLuxLevels;
361 final float[] newBrightnessLevels;
362 if (idx == luxLevels.length) {
363 newLuxLevels = Arrays.copyOf(luxLevels, luxLevels.length + 1);
364 newBrightnessLevels = Arrays.copyOf(brightnessLevels, brightnessLevels.length + 1);
365 newLuxLevels[idx] = lux;
366 newBrightnessLevels[idx] = brightness;
367 } else if (luxLevels[idx] == lux) {
368 newLuxLevels = Arrays.copyOf(luxLevels, luxLevels.length);
369 newBrightnessLevels = Arrays.copyOf(brightnessLevels, brightnessLevels.length);
370 newBrightnessLevels[idx] = brightness;
371 } else {
372 newLuxLevels = Arrays.copyOf(luxLevels, luxLevels.length + 1);
373 System.arraycopy(newLuxLevels, idx, newLuxLevels, idx+1, luxLevels.length - idx);
374 newLuxLevels[idx] = lux;
375 newBrightnessLevels = Arrays.copyOf(brightnessLevels, brightnessLevels.length + 1);
376 System.arraycopy(newBrightnessLevels, idx, newBrightnessLevels, idx+1,
377 brightnessLevels.length - idx);
378 newBrightnessLevels[idx] = brightness;
379 }
380 smoothCurve(newLuxLevels, newBrightnessLevels, idx);
381 return Pair.create(newLuxLevels, newBrightnessLevels);
382 }
383
384 /**
385 * Returns the index of the first value that's less than or equal to {@code val}.
386 *
387 * This assumes that {@code arr} is sorted. If all values in {@code arr} are greater
388 * than val, then it will return the length of arr as the insertion point.
389 */
Dan Gittika5a2d632019-01-09 14:25:29 +0000390 private int findInsertionPoint(float[] arr, float val) {
Michael Wrightd8460232018-01-16 18:04:59 +0000391 for (int i = 0; i < arr.length; i++) {
392 if (val <= arr[i]) {
393 return i;
394 }
395 }
396 return arr.length;
397 }
398
Dan Gittika5a2d632019-01-09 14:25:29 +0000399 private void smoothCurve(float[] lux, float[] brightness, int idx) {
400 if (mLoggingEnabled) {
Dan Gittik57d6f112018-03-27 18:14:22 +0100401 PLOG.logCurve("unsmoothed curve", lux, brightness);
Michael Wrightd8460232018-01-16 18:04:59 +0000402 }
403 float prevLux = lux[idx];
404 float prevBrightness = brightness[idx];
405 // Smooth curve for data points above the newly introduced point
406 for (int i = idx+1; i < lux.length; i++) {
407 float currLux = lux[i];
408 float currBrightness = brightness[i];
Fiona Campbelld7ab9492020-05-01 19:37:39 +0100409 float maxBrightness = MathUtils.max(
410 prevBrightness * permissibleRatio(currLux, prevLux),
411 prevBrightness + MIN_PERMISSABLE_INCREASE);
Michael Wrightd8460232018-01-16 18:04:59 +0000412 float newBrightness = MathUtils.constrain(
413 currBrightness, prevBrightness, maxBrightness);
414 if (newBrightness == currBrightness) {
415 break;
416 }
417 prevLux = currLux;
418 prevBrightness = newBrightness;
419 brightness[i] = newBrightness;
420 }
Michael Wrightd8460232018-01-16 18:04:59 +0000421 // Smooth curve for data points below the newly introduced point
422 prevLux = lux[idx];
423 prevBrightness = brightness[idx];
424 for (int i = idx-1; i >= 0; i--) {
425 float currLux = lux[i];
426 float currBrightness = brightness[i];
427 float minBrightness = prevBrightness * permissibleRatio(currLux, prevLux);
428 float newBrightness = MathUtils.constrain(
429 currBrightness, minBrightness, prevBrightness);
430 if (newBrightness == currBrightness) {
431 break;
432 }
433 prevLux = currLux;
434 prevBrightness = newBrightness;
435 brightness[i] = newBrightness;
436 }
Dan Gittika5a2d632019-01-09 14:25:29 +0000437 if (mLoggingEnabled) {
Dan Gittik57d6f112018-03-27 18:14:22 +0100438 PLOG.logCurve("smoothed curve", lux, brightness);
Michael Wrightd8460232018-01-16 18:04:59 +0000439 }
440 }
441
Dan Gittika5a2d632019-01-09 14:25:29 +0000442 private float permissibleRatio(float currLux, float prevLux) {
Michael Wrightd8460232018-01-16 18:04:59 +0000443 return MathUtils.exp(MAX_GRAD
444 * (MathUtils.log(currLux + LUX_GRAD_SMOOTHING)
445 - MathUtils.log(prevLux + LUX_GRAD_SMOOTHING)));
446 }
Michael Wrighteef0e132017-11-21 17:57:52 +0000447
Dan Gittika5a2d632019-01-09 14:25:29 +0000448 protected float inferAutoBrightnessAdjustment(float maxGamma, float desiredBrightness,
449 float currentBrightness) {
Dan Gittik57d6f112018-03-27 18:14:22 +0100450 float adjustment = 0;
451 float gamma = Float.NaN;
452 // Extreme edge cases: use a simpler heuristic, as proper gamma correction around the edges
453 // affects the curve rather drastically.
454 if (currentBrightness <= 0.1f || currentBrightness >= 0.9f) {
Michael Wright95f77e12018-05-14 15:53:48 -0700455 adjustment = (desiredBrightness - currentBrightness);
Dan Gittik57d6f112018-03-27 18:14:22 +0100456 // Edge case: darkest adjustment possible.
457 } else if (desiredBrightness == 0) {
458 adjustment = -1;
459 // Edge case: brightest adjustment possible.
460 } else if (desiredBrightness == 1) {
461 adjustment = +1;
462 } else {
463 // current^gamma = desired => gamma = log[current](desired)
464 gamma = MathUtils.log(desiredBrightness) / MathUtils.log(currentBrightness);
465 // max^-adjustment = gamma => adjustment = -log[max](gamma)
Dan Gittikc8a6db82018-04-03 14:57:35 +0100466 adjustment = -MathUtils.log(gamma) / MathUtils.log(maxGamma);
Dan Gittik57d6f112018-03-27 18:14:22 +0100467 }
Dan Gittikc8a6db82018-04-03 14:57:35 +0100468 adjustment = MathUtils.constrain(adjustment, -1, +1);
Dan Gittika5a2d632019-01-09 14:25:29 +0000469 if (mLoggingEnabled) {
Dan Gittik57d6f112018-03-27 18:14:22 +0100470 Slog.d(TAG, "inferAutoBrightnessAdjustment: " + maxGamma + "^" + -adjustment + "=" +
471 MathUtils.pow(maxGamma, -adjustment) + " == " + gamma);
472 Slog.d(TAG, "inferAutoBrightnessAdjustment: " + currentBrightness + "^" + gamma + "=" +
473 MathUtils.pow(currentBrightness, gamma) + " == " + desiredBrightness);
474 }
475 return adjustment;
476 }
477
Dan Gittika5a2d632019-01-09 14:25:29 +0000478 protected Pair<float[], float[]> getAdjustedCurve(float[] lux, float[] brightness,
Dan Gittik57d6f112018-03-27 18:14:22 +0100479 float userLux, float userBrightness, float adjustment, float maxGamma) {
480 float[] newLux = lux;
481 float[] newBrightness = Arrays.copyOf(brightness, brightness.length);
Dan Gittika5a2d632019-01-09 14:25:29 +0000482 if (mLoggingEnabled) {
Dan Gittik57d6f112018-03-27 18:14:22 +0100483 PLOG.logCurve("unadjusted curve", newLux, newBrightness);
484 }
485 adjustment = MathUtils.constrain(adjustment, -1, 1);
486 float gamma = MathUtils.pow(maxGamma, -adjustment);
Dan Gittika5a2d632019-01-09 14:25:29 +0000487 if (mLoggingEnabled) {
Dan Gittik57d6f112018-03-27 18:14:22 +0100488 Slog.d(TAG, "getAdjustedCurve: " + maxGamma + "^" + -adjustment + "=" +
489 MathUtils.pow(maxGamma, -adjustment) + " == " + gamma);
490 }
491 if (gamma != 1) {
492 for (int i = 0; i < newBrightness.length; i++) {
493 newBrightness[i] = MathUtils.pow(newBrightness[i], gamma);
494 }
495 }
Dan Gittika5a2d632019-01-09 14:25:29 +0000496 if (mLoggingEnabled) {
Dan Gittik57d6f112018-03-27 18:14:22 +0100497 PLOG.logCurve("gamma adjusted curve", newLux, newBrightness);
498 }
499 if (userLux != -1) {
500 Pair<float[], float[]> curve = insertControlPoint(newLux, newBrightness, userLux,
501 userBrightness);
502 newLux = curve.first;
503 newBrightness = curve.second;
Dan Gittika5a2d632019-01-09 14:25:29 +0000504 if (mLoggingEnabled) {
Dan Gittik57d6f112018-03-27 18:14:22 +0100505 PLOG.logCurve("gamma and user adjusted curve", newLux, newBrightness);
506 // This is done for comparison.
507 curve = insertControlPoint(lux, brightness, userLux, userBrightness);
508 PLOG.logCurve("user adjusted curve", curve.first ,curve.second);
509 }
510 }
511 return Pair.create(newLux, newBrightness);
512 }
513
Michael Wrighteef0e132017-11-21 17:57:52 +0000514 /**
515 * A {@link BrightnessMappingStrategy} that maps from ambient room brightness directly to the
516 * backlight of the display.
517 *
518 * Since we don't have information about the display's physical brightness, any brightness
519 * configurations that are set are just ignored.
520 */
521 private static class SimpleMappingStrategy extends BrightnessMappingStrategy {
Michael Wrightd8460232018-01-16 18:04:59 +0000522 // Lux control points
523 private final float[] mLux;
524 // Brightness control points normalized to [0, 1]
525 private final float[] mBrightness;
526
527 private Spline mSpline;
Dan Gittik57d6f112018-03-27 18:14:22 +0100528 private float mMaxGamma;
529 private float mAutoBrightnessAdjustment;
Michael Wrightd8460232018-01-16 18:04:59 +0000530 private float mUserLux;
531 private float mUserBrightness;
Kenny Guyb29fdf12019-12-04 12:57:04 +0000532 private long mShortTermModelTimeout;
Michael Wrighteef0e132017-11-21 17:57:52 +0000533
Kenny Guyb29fdf12019-12-04 12:57:04 +0000534 private SimpleMappingStrategy(float[] lux, int[] brightness, float maxGamma,
535 long timeout) {
Michael Wrighteef0e132017-11-21 17:57:52 +0000536 Preconditions.checkArgument(lux.length != 0 && brightness.length != 0,
537 "Lux and brightness arrays must not be empty!");
538 Preconditions.checkArgument(lux.length == brightness.length,
539 "Lux and brightness arrays must be the same length!");
540 Preconditions.checkArrayElementsInRange(lux, 0, Float.MAX_VALUE, "lux");
541 Preconditions.checkArrayElementsInRange(brightness,
542 0, Integer.MAX_VALUE, "brightness");
543
544 final int N = brightness.length;
Michael Wrightd8460232018-01-16 18:04:59 +0000545 mLux = new float[N];
546 mBrightness = new float[N];
Michael Wrighteef0e132017-11-21 17:57:52 +0000547 for (int i = 0; i < N; i++) {
Michael Wrightd8460232018-01-16 18:04:59 +0000548 mLux[i] = lux[i];
549 mBrightness[i] = normalizeAbsoluteBrightness(brightness[i]);
Michael Wrighteef0e132017-11-21 17:57:52 +0000550 }
551
Dan Gittik57d6f112018-03-27 18:14:22 +0100552 mMaxGamma = maxGamma;
553 mAutoBrightnessAdjustment = 0;
Michael Wrightd8460232018-01-16 18:04:59 +0000554 mUserLux = -1;
555 mUserBrightness = -1;
Dan Gittika5a2d632019-01-09 14:25:29 +0000556 if (mLoggingEnabled) {
Dan Gittik57d6f112018-03-27 18:14:22 +0100557 PLOG.start("simple mapping strategy");
558 }
559 computeSpline();
Kenny Guyb29fdf12019-12-04 12:57:04 +0000560 mShortTermModelTimeout = timeout;
561 }
562
563 @Override
564 public long getShortTermModelTimeout() {
565 return mShortTermModelTimeout;
Michael Wrighteef0e132017-11-21 17:57:52 +0000566 }
567
568 @Override
569 public boolean setBrightnessConfiguration(@Nullable BrightnessConfiguration config) {
Michael Wrighteef0e132017-11-21 17:57:52 +0000570 return false;
571 }
572
573 @Override
Kenny Guyb29fdf12019-12-04 12:57:04 +0000574 public BrightnessConfiguration getBrightnessConfiguration() {
575 return null;
576 }
577
578 @Override
Dan Gittika5a2d632019-01-09 14:25:29 +0000579 public float getBrightness(float lux, String packageName,
580 @ApplicationInfo.Category int category) {
Michael Wrighteef0e132017-11-21 17:57:52 +0000581 return mSpline.interpolate(lux);
582 }
583
584 @Override
Dan Gittik57d6f112018-03-27 18:14:22 +0100585 public float getAutoBrightnessAdjustment() {
586 return mAutoBrightnessAdjustment;
587 }
588
589 @Override
590 public boolean setAutoBrightnessAdjustment(float adjustment) {
591 adjustment = MathUtils.constrain(adjustment, -1, 1);
592 if (adjustment == mAutoBrightnessAdjustment) {
593 return false;
594 }
Dan Gittika5a2d632019-01-09 14:25:29 +0000595 if (mLoggingEnabled) {
Dan Gittik57d6f112018-03-27 18:14:22 +0100596 Slog.d(TAG, "setAutoBrightnessAdjustment: " + mAutoBrightnessAdjustment + " => " +
597 adjustment);
598 PLOG.start("auto-brightness adjustment");
599 }
600 mAutoBrightnessAdjustment = adjustment;
601 computeSpline();
602 return true;
603 }
604
605 @Override
Michael Wrightd8460232018-01-16 18:04:59 +0000606 public float convertToNits(int backlight) {
Michael Wright144aac92017-12-21 18:37:41 +0000607 return -1.0f;
608 }
609
610 @Override
Michael Wrightd8460232018-01-16 18:04:59 +0000611 public void addUserDataPoint(float lux, float brightness) {
Dan Gittik57d6f112018-03-27 18:14:22 +0100612 float unadjustedBrightness = getUnadjustedBrightness(lux);
Dan Gittika5a2d632019-01-09 14:25:29 +0000613 if (mLoggingEnabled) {
Dan Gittik57d6f112018-03-27 18:14:22 +0100614 Slog.d(TAG, "addUserDataPoint: (" + lux + "," + brightness + ")");
615 PLOG.start("add user data point")
616 .logPoint("user data point", lux, brightness)
617 .logPoint("current brightness", lux, unadjustedBrightness);
Michael Wrightd8460232018-01-16 18:04:59 +0000618 }
Dan Gittik57d6f112018-03-27 18:14:22 +0100619 float adjustment = inferAutoBrightnessAdjustment(mMaxGamma,
620 brightness /* desiredBrightness */,
621 unadjustedBrightness /* currentBrightness */);
Dan Gittika5a2d632019-01-09 14:25:29 +0000622 if (mLoggingEnabled) {
Dan Gittik57d6f112018-03-27 18:14:22 +0100623 Slog.d(TAG, "addUserDataPoint: " + mAutoBrightnessAdjustment + " => " +
624 adjustment);
625 }
626 mAutoBrightnessAdjustment = adjustment;
Michael Wrightd8460232018-01-16 18:04:59 +0000627 mUserLux = lux;
628 mUserBrightness = brightness;
Dan Gittik57d6f112018-03-27 18:14:22 +0100629 computeSpline();
Michael Wrightd8460232018-01-16 18:04:59 +0000630 }
631
632 @Override
633 public void clearUserDataPoints() {
634 if (mUserLux != -1) {
Dan Gittika5a2d632019-01-09 14:25:29 +0000635 if (mLoggingEnabled) {
Dan Gittik57d6f112018-03-27 18:14:22 +0100636 Slog.d(TAG, "clearUserDataPoints: " + mAutoBrightnessAdjustment + " => 0");
637 PLOG.start("clear user data points")
638 .logPoint("user data point", mUserLux, mUserBrightness);
639 }
640 mAutoBrightnessAdjustment = 0;
Michael Wrightd8460232018-01-16 18:04:59 +0000641 mUserLux = -1;
642 mUserBrightness = -1;
Dan Gittik57d6f112018-03-27 18:14:22 +0100643 computeSpline();
Michael Wrightd8460232018-01-16 18:04:59 +0000644 }
645 }
646
647 @Override
Kenny Guy53d06612018-01-30 14:19:13 +0000648 public boolean hasUserDataPoints() {
649 return mUserLux != -1;
650 }
651
652 @Override
653 public boolean isDefaultConfig() {
654 return true;
655 }
656
657 @Override
Dan Gittik57d6f112018-03-27 18:14:22 +0100658 public BrightnessConfiguration getDefaultConfig() {
659 return null;
660 }
Kenny Guy6d1009f2018-03-14 14:28:23 +0000661
662 @Override
Michael Wrighteef0e132017-11-21 17:57:52 +0000663 public void dump(PrintWriter pw) {
664 pw.println("SimpleMappingStrategy");
665 pw.println(" mSpline=" + mSpline);
Dan Gittik57d6f112018-03-27 18:14:22 +0100666 pw.println(" mMaxGamma=" + mMaxGamma);
667 pw.println(" mAutoBrightnessAdjustment=" + mAutoBrightnessAdjustment);
Michael Wrightd8460232018-01-16 18:04:59 +0000668 pw.println(" mUserLux=" + mUserLux);
669 pw.println(" mUserBrightness=" + mUserBrightness);
Michael Wrighteef0e132017-11-21 17:57:52 +0000670 }
Dan Gittik57d6f112018-03-27 18:14:22 +0100671
672 private void computeSpline() {
673 Pair<float[], float[]> curve = getAdjustedCurve(mLux, mBrightness, mUserLux,
674 mUserBrightness, mAutoBrightnessAdjustment, mMaxGamma);
675 mSpline = Spline.createSpline(curve.first, curve.second);
676 }
677
678 private float getUnadjustedBrightness(float lux) {
679 Spline spline = Spline.createSpline(mLux, mBrightness);
680 return spline.interpolate(lux);
681 }
Michael Wrighteef0e132017-11-21 17:57:52 +0000682 }
683
684 /** A {@link BrightnessMappingStrategy} that maps from ambient room brightness to the physical
685 * range of the display, rather than to the range of the backlight control (typically 0-255).
686 *
687 * By mapping through the physical brightness, the curve becomes portable across devices and
688 * gives us more resolution in the resulting mapping.
689 */
690 @VisibleForTesting
691 static class PhysicalMappingStrategy extends BrightnessMappingStrategy {
692 // The current brightness configuration.
693 private BrightnessConfiguration mConfig;
694
695 // A spline mapping from the current ambient light in lux to the desired display brightness
696 // in nits.
697 private Spline mBrightnessSpline;
698
699 // A spline mapping from nits to the corresponding backlight value, normalized to the range
700 // [0, 1.0].
Michael Wright144aac92017-12-21 18:37:41 +0000701 private final Spline mNitsToBacklightSpline;
702
Michael Wrighteef0e132017-11-21 17:57:52 +0000703 // The default brightness configuration.
704 private final BrightnessConfiguration mDefaultConfig;
705
Michael Wrightd8460232018-01-16 18:04:59 +0000706 // A spline mapping from the device's backlight value, normalized to the range [0, 1.0], to
707 // a brightness in nits.
708 private Spline mBacklightToNitsSpline;
709
Dan Gittik57d6f112018-03-27 18:14:22 +0100710 private float mMaxGamma;
711 private float mAutoBrightnessAdjustment;
Michael Wrightd8460232018-01-16 18:04:59 +0000712 private float mUserLux;
713 private float mUserBrightness;
714
Dan Gittik57d6f112018-03-27 18:14:22 +0100715 public PhysicalMappingStrategy(BrightnessConfiguration config, float[] nits,
716 int[] backlight, float maxGamma) {
Michael Wrighteef0e132017-11-21 17:57:52 +0000717 Preconditions.checkArgument(nits.length != 0 && backlight.length != 0,
718 "Nits and backlight arrays must not be empty!");
719 Preconditions.checkArgument(nits.length == backlight.length,
720 "Nits and backlight arrays must be the same length!");
Daulet Zhanguzin82201022020-01-03 09:41:39 +0000721 Objects.requireNonNull(config);
Michael Wrighteef0e132017-11-21 17:57:52 +0000722 Preconditions.checkArrayElementsInRange(nits, 0, Float.MAX_VALUE, "nits");
723 Preconditions.checkArrayElementsInRange(backlight,
724 PowerManager.BRIGHTNESS_OFF, PowerManager.BRIGHTNESS_ON, "backlight");
725
Dan Gittik57d6f112018-03-27 18:14:22 +0100726 mMaxGamma = maxGamma;
727 mAutoBrightnessAdjustment = 0;
Michael Wrightd8460232018-01-16 18:04:59 +0000728 mUserLux = -1;
729 mUserBrightness = -1;
730
Michael Wrighteef0e132017-11-21 17:57:52 +0000731 // Setup the backlight spline
732 final int N = nits.length;
Michael Wright144aac92017-12-21 18:37:41 +0000733 float[] normalizedBacklight = new float[N];
Michael Wrighteef0e132017-11-21 17:57:52 +0000734 for (int i = 0; i < N; i++) {
Michael Wright144aac92017-12-21 18:37:41 +0000735 normalizedBacklight[i] = normalizeAbsoluteBrightness(backlight[i]);
Michael Wrighteef0e132017-11-21 17:57:52 +0000736 }
737
Dan Gittik57d6f112018-03-27 18:14:22 +0100738 mNitsToBacklightSpline = Spline.createSpline(nits, normalizedBacklight);
739 mBacklightToNitsSpline = Spline.createSpline(normalizedBacklight, nits);
Michael Wrighteef0e132017-11-21 17:57:52 +0000740
741 mDefaultConfig = config;
Dan Gittika5a2d632019-01-09 14:25:29 +0000742 if (mLoggingEnabled) {
Dan Gittik57d6f112018-03-27 18:14:22 +0100743 PLOG.start("physical mapping strategy");
744 }
745 mConfig = config;
746 computeSpline();
Michael Wrighteef0e132017-11-21 17:57:52 +0000747 }
748
749 @Override
Kenny Guyb29fdf12019-12-04 12:57:04 +0000750 public long getShortTermModelTimeout() {
Kenny Guycae6c352020-01-20 14:56:00 +0000751 if (mConfig.getShortTermModelTimeoutMillis() >= 0) {
752 return mConfig.getShortTermModelTimeoutMillis();
Kenny Guyb29fdf12019-12-04 12:57:04 +0000753 } else {
Kenny Guycae6c352020-01-20 14:56:00 +0000754 return mDefaultConfig.getShortTermModelTimeoutMillis();
Kenny Guyb29fdf12019-12-04 12:57:04 +0000755 }
756 }
757
758 @Override
Michael Wrighteef0e132017-11-21 17:57:52 +0000759 public boolean setBrightnessConfiguration(@Nullable BrightnessConfiguration config) {
760 if (config == null) {
761 config = mDefaultConfig;
762 }
763 if (config.equals(mConfig)) {
Michael Wrighteef0e132017-11-21 17:57:52 +0000764 return false;
765 }
Dan Gittika5a2d632019-01-09 14:25:29 +0000766 if (mLoggingEnabled) {
Dan Gittik57d6f112018-03-27 18:14:22 +0100767 PLOG.start("brightness configuration");
768 }
Michael Wrighteef0e132017-11-21 17:57:52 +0000769 mConfig = config;
Dan Gittik57d6f112018-03-27 18:14:22 +0100770 computeSpline();
Michael Wrighteef0e132017-11-21 17:57:52 +0000771 return true;
772 }
773
774 @Override
Kenny Guyb29fdf12019-12-04 12:57:04 +0000775 public BrightnessConfiguration getBrightnessConfiguration() {
776 return mConfig;
777 }
778
779 @Override
Dan Gittika5a2d632019-01-09 14:25:29 +0000780 public float getBrightness(float lux, String packageName,
781 @ApplicationInfo.Category int category) {
Michael Wrightd8460232018-01-16 18:04:59 +0000782 float nits = mBrightnessSpline.interpolate(lux);
783 float backlight = mNitsToBacklightSpline.interpolate(nits);
Dan Gittika5a2d632019-01-09 14:25:29 +0000784 // Correct the brightness according to the current application and its category, but
785 // only if no user data point is set (as this will oevrride the user setting).
786 if (mUserLux == -1) {
787 backlight = correctBrightness(backlight, packageName, category);
788 } else if (mLoggingEnabled) {
789 Slog.d(TAG, "user point set, correction not applied");
790 }
Michael Wrightd8460232018-01-16 18:04:59 +0000791 return backlight;
Michael Wright144aac92017-12-21 18:37:41 +0000792 }
793
794 @Override
Dan Gittik57d6f112018-03-27 18:14:22 +0100795 public float getAutoBrightnessAdjustment() {
796 return mAutoBrightnessAdjustment;
797 }
798
799 @Override
800 public boolean setAutoBrightnessAdjustment(float adjustment) {
801 adjustment = MathUtils.constrain(adjustment, -1, 1);
802 if (adjustment == mAutoBrightnessAdjustment) {
803 return false;
804 }
Dan Gittika5a2d632019-01-09 14:25:29 +0000805 if (mLoggingEnabled) {
Dan Gittik57d6f112018-03-27 18:14:22 +0100806 Slog.d(TAG, "setAutoBrightnessAdjustment: " + mAutoBrightnessAdjustment + " => " +
807 adjustment);
808 PLOG.start("auto-brightness adjustment");
809 }
810 mAutoBrightnessAdjustment = adjustment;
811 computeSpline();
812 return true;
813 }
814
815 @Override
Michael Wrightd8460232018-01-16 18:04:59 +0000816 public float convertToNits(int backlight) {
Michael Wright144aac92017-12-21 18:37:41 +0000817 return mBacklightToNitsSpline.interpolate(normalizeAbsoluteBrightness(backlight));
Michael Wrighteef0e132017-11-21 17:57:52 +0000818 }
819
820 @Override
Dan Gittik57d6f112018-03-27 18:14:22 +0100821 public void addUserDataPoint(float lux, float brightness) {
822 float unadjustedBrightness = getUnadjustedBrightness(lux);
Dan Gittika5a2d632019-01-09 14:25:29 +0000823 if (mLoggingEnabled) {
Dan Gittik57d6f112018-03-27 18:14:22 +0100824 Slog.d(TAG, "addUserDataPoint: (" + lux + "," + brightness + ")");
825 PLOG.start("add user data point")
826 .logPoint("user data point", lux, brightness)
827 .logPoint("current brightness", lux, unadjustedBrightness);
Michael Wrightd8460232018-01-16 18:04:59 +0000828 }
Dan Gittik57d6f112018-03-27 18:14:22 +0100829 float adjustment = inferAutoBrightnessAdjustment(mMaxGamma,
830 brightness /* desiredBrightness */,
831 unadjustedBrightness /* currentBrightness */);
Dan Gittika5a2d632019-01-09 14:25:29 +0000832 if (mLoggingEnabled) {
Dan Gittik57d6f112018-03-27 18:14:22 +0100833 Slog.d(TAG, "addUserDataPoint: " + mAutoBrightnessAdjustment + " => " +
834 adjustment);
835 }
836 mAutoBrightnessAdjustment = adjustment;
Michael Wrightd8460232018-01-16 18:04:59 +0000837 mUserLux = lux;
838 mUserBrightness = brightness;
Dan Gittik57d6f112018-03-27 18:14:22 +0100839 computeSpline();
Michael Wrightd8460232018-01-16 18:04:59 +0000840 }
841
842 @Override
843 public void clearUserDataPoints() {
844 if (mUserLux != -1) {
Dan Gittika5a2d632019-01-09 14:25:29 +0000845 if (mLoggingEnabled) {
Dan Gittik57d6f112018-03-27 18:14:22 +0100846 Slog.d(TAG, "clearUserDataPoints: " + mAutoBrightnessAdjustment + " => 0");
847 PLOG.start("clear user data points")
848 .logPoint("user data point", mUserLux, mUserBrightness);
849 }
850 mAutoBrightnessAdjustment = 0;
Michael Wrightd8460232018-01-16 18:04:59 +0000851 mUserLux = -1;
852 mUserBrightness = -1;
Dan Gittik57d6f112018-03-27 18:14:22 +0100853 computeSpline();
Michael Wrightd8460232018-01-16 18:04:59 +0000854 }
855 }
856
857 @Override
Kenny Guy53d06612018-01-30 14:19:13 +0000858 public boolean hasUserDataPoints() {
859 return mUserLux != -1;
860 }
861
862 @Override
863 public boolean isDefaultConfig() {
864 return mDefaultConfig.equals(mConfig);
865 }
866
867 @Override
Dan Gittik57d6f112018-03-27 18:14:22 +0100868 public BrightnessConfiguration getDefaultConfig() {
869 return mDefaultConfig;
870 }
Kenny Guy6d1009f2018-03-14 14:28:23 +0000871
872 @Override
Michael Wrighteef0e132017-11-21 17:57:52 +0000873 public void dump(PrintWriter pw) {
874 pw.println("PhysicalMappingStrategy");
875 pw.println(" mConfig=" + mConfig);
876 pw.println(" mBrightnessSpline=" + mBrightnessSpline);
Michael Wright144aac92017-12-21 18:37:41 +0000877 pw.println(" mNitsToBacklightSpline=" + mNitsToBacklightSpline);
Dan Gittik57d6f112018-03-27 18:14:22 +0100878 pw.println(" mMaxGamma=" + mMaxGamma);
879 pw.println(" mAutoBrightnessAdjustment=" + mAutoBrightnessAdjustment);
Michael Wrightd8460232018-01-16 18:04:59 +0000880 pw.println(" mUserLux=" + mUserLux);
881 pw.println(" mUserBrightness=" + mUserBrightness);
Kenny Guy2ebb5312019-05-01 12:19:18 +0100882 pw.println(" mDefaultConfig=" + mDefaultConfig);
Michael Wrighteef0e132017-11-21 17:57:52 +0000883 }
Dan Gittik57d6f112018-03-27 18:14:22 +0100884
885 private void computeSpline() {
886 Pair<float[], float[]> defaultCurve = mConfig.getCurve();
887 float[] defaultLux = defaultCurve.first;
888 float[] defaultNits = defaultCurve.second;
889 float[] defaultBacklight = new float[defaultNits.length];
890 for (int i = 0; i < defaultBacklight.length; i++) {
891 defaultBacklight[i] = mNitsToBacklightSpline.interpolate(defaultNits[i]);
892 }
893 Pair<float[], float[]> curve = getAdjustedCurve(defaultLux, defaultBacklight, mUserLux,
894 mUserBrightness, mAutoBrightnessAdjustment, mMaxGamma);
895 float[] lux = curve.first;
896 float[] backlight = curve.second;
897 float[] nits = new float[backlight.length];
898 for (int i = 0; i < nits.length; i++) {
899 nits[i] = mBacklightToNitsSpline.interpolate(backlight[i]);
900 }
901 mBrightnessSpline = Spline.createSpline(lux, nits);
902 }
903
904 private float getUnadjustedBrightness(float lux) {
905 Pair<float[], float[]> curve = mConfig.getCurve();
906 Spline spline = Spline.createSpline(curve.first, curve.second);
907 return mNitsToBacklightSpline.interpolate(spline.interpolate(lux));
908 }
Dan Gittika5a2d632019-01-09 14:25:29 +0000909
910 private float correctBrightness(float brightness, String packageName, int category) {
911 if (packageName != null) {
912 BrightnessCorrection correction = mConfig.getCorrectionByPackageName(packageName);
913 if (correction != null) {
914 return correction.apply(brightness);
915 }
916 }
917 if (category != ApplicationInfo.CATEGORY_UNDEFINED) {
918 BrightnessCorrection correction = mConfig.getCorrectionByCategory(category);
919 if (correction != null) {
920 return correction.apply(brightness);
921 }
922 }
923 return brightness;
924 }
Michael Wrighteef0e132017-11-21 17:57:52 +0000925 }
926}