• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2023 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 
17 package com.android.server.display.config;
18 
19 import static com.android.server.display.AutomaticBrightnessController.AUTO_BRIGHTNESS_MODE_BEDTIME_WEAR;
20 import static com.android.server.display.AutomaticBrightnessController.AUTO_BRIGHTNESS_MODE_DEFAULT;
21 import static com.android.server.display.AutomaticBrightnessController.AUTO_BRIGHTNESS_MODE_DOZE;
22 import static com.android.server.display.AutomaticBrightnessController.AUTO_BRIGHTNESS_MODE_IDLE;
23 
24 import android.content.Context;
25 import android.os.PowerManager;
26 import android.provider.Settings;
27 import android.util.Spline;
28 
29 import com.android.internal.display.BrightnessSynchronizer;
30 import com.android.server.display.AutomaticBrightnessController;
31 import com.android.server.display.DisplayDeviceConfig;
32 import com.android.server.display.feature.DisplayManagerFlags;
33 
34 import java.util.Arrays;
35 import java.util.HashMap;
36 import java.util.Map;
37 
38 /**
39  * Provides a mapping between lux and brightness values in order to support auto-brightness.
40  */
41 public class DisplayBrightnessMappingConfig {
42 
43     private static final String DEFAULT_BRIGHTNESS_MAPPING_KEY =
44             AutoBrightnessModeName._default.getRawName() + "_"
45                     + AutoBrightnessSettingName.normal.getRawName();
46 
47     /**
48      * Array of desired screen brightness in nits corresponding to the lux values
49      * in the mBrightnessLevelsLuxMap.get(DEFAULT_ID) array. The display brightness is defined as
50      * the measured brightness of an all-white image. The brightness values must be non-negative and
51      * non-decreasing. This must be overridden in platform specific overlays
52      */
53     private float[] mBrightnessLevelsNits;
54 
55     /**
56      * Map of arrays of desired screen brightness corresponding to the lux values
57      * in mBrightnessLevelsLuxMap, indexed by the auto-brightness mode and the brightness preset.
58      * The brightness values must be non-negative and non-decreasing. They must be between
59      * {@link PowerManager.BRIGHTNESS_MIN} and {@link PowerManager.BRIGHTNESS_MAX}.
60      *
61      * The keys are a concatenation of the auto-brightness mode and the brightness preset separated
62      * by an underscore, e.g. default_normal, default_dim, default_bright, doze_normal, doze_dim,
63      * doze_bright.
64      *
65      * The presets are used on devices that allow users to choose from a set of predefined options
66      * in display auto-brightness settings.
67      */
68     private final Map<String, float[]> mBrightnessLevelsMap = new HashMap<>();
69 
70     /**
71      * Map of arrays of light sensor lux values to define our levels for auto-brightness support,
72      * indexed by the auto-brightness mode and the brightness preset.
73      *
74      * The first lux value in every array is always 0.
75      *
76      * The control points must be strictly increasing. Each control point corresponds to an entry
77      * in the brightness values arrays. For example, if lux == luxLevels[1] (second element
78      * of the levels array) then the brightness will be determined by brightnessLevels[1] (second
79      * element of the brightness values array).
80      *
81      * Spline interpolation is used to determine the auto-brightness values for lux levels between
82      * these control points.
83      *
84      * The keys are a concatenation of the auto-brightness mode and the brightness preset separated
85      * by an underscore, e.g. default_normal, default_dim, default_bright, doze_normal, doze_dim,
86      * doze_bright.
87      *
88      * The presets are used on devices that allow users to choose from a set of predefined options
89      * in display auto-brightness settings.
90      */
91     private final Map<String, float[]> mBrightnessLevelsLuxMap = new HashMap<>();
92 
93     /**
94      * Loads the auto-brightness display brightness mappings. Internally, this takes care of
95      * loading the value from the display config, and if not present, falls back to config.xml.
96      */
DisplayBrightnessMappingConfig(Context context, DisplayManagerFlags flags, AutoBrightness autoBrightnessConfig, Spline backlightToBrightnessSpline)97     public DisplayBrightnessMappingConfig(Context context, DisplayManagerFlags flags,
98             AutoBrightness autoBrightnessConfig, Spline backlightToBrightnessSpline) {
99         if (flags.areAutoBrightnessModesEnabled() && autoBrightnessConfig != null
100                 && autoBrightnessConfig.getLuxToBrightnessMapping() != null
101                 && autoBrightnessConfig.getLuxToBrightnessMapping().size() > 0) {
102             for (LuxToBrightnessMapping mapping
103                     : autoBrightnessConfig.getLuxToBrightnessMapping()) {
104                 final int size = mapping.getMap().getPoint().size();
105                 float[] brightnessLevels = new float[size];
106                 float[] brightnessLevelsLux = new float[size];
107                 for (int i = 0; i < size; i++) {
108                     float backlight = mapping.getMap().getPoint().get(i).getSecond().floatValue();
109                     brightnessLevels[i] = backlightToBrightnessSpline.interpolate(backlight);
110                     brightnessLevelsLux[i] = mapping.getMap().getPoint().get(i).getFirst()
111                             .floatValue();
112                 }
113                 if (size == 0) {
114                     throw new IllegalArgumentException(
115                             "A display brightness mapping should not be empty");
116                 }
117                 if (brightnessLevelsLux[0] != 0) {
118                     throw new IllegalArgumentException(
119                             "The first lux value in the display brightness mapping must be 0");
120                 }
121 
122                 String key = (mapping.getMode() == null
123                         ? AutoBrightnessModeName._default.getRawName()
124                         : mapping.getMode().getRawName())
125                         + "_"
126                         + (mapping.getSetting() == null
127                         ? AutoBrightnessSettingName.normal.getRawName()
128                         : mapping.getSetting().getRawName());
129                 if (mBrightnessLevelsMap.containsKey(key)
130                         || mBrightnessLevelsLuxMap.containsKey(key)) {
131                     throw new IllegalArgumentException(
132                             "A display brightness mapping with key " + key + " already exists");
133                 }
134                 mBrightnessLevelsMap.put(key, brightnessLevels);
135                 mBrightnessLevelsLuxMap.put(key, brightnessLevelsLux);
136             }
137         }
138 
139         if (!mBrightnessLevelsMap.containsKey(DEFAULT_BRIGHTNESS_MAPPING_KEY)
140                 || !mBrightnessLevelsLuxMap.containsKey(DEFAULT_BRIGHTNESS_MAPPING_KEY)) {
141             mBrightnessLevelsNits = DisplayDeviceConfig.getFloatArray(context.getResources()
142                     .obtainTypedArray(com.android.internal.R.array
143                             .config_autoBrightnessDisplayValuesNits), PowerManager
144                     .BRIGHTNESS_OFF_FLOAT);
145 
146             float[] brightnessLevelsLux = DisplayDeviceConfig.getLuxLevels(context.getResources()
147                     .getIntArray(com.android.internal.R.array
148                             .config_autoBrightnessLevels));
149             mBrightnessLevelsLuxMap.put(DEFAULT_BRIGHTNESS_MAPPING_KEY, brightnessLevelsLux);
150 
151             // Load the old configuration in the range [0, 255]. The values need to be normalized
152             // to the range [0, 1].
153             int[] brightnessLevels = context.getResources().getIntArray(
154                     com.android.internal.R.array.config_autoBrightnessLcdBacklightValues);
155             mBrightnessLevelsMap.put(DEFAULT_BRIGHTNESS_MAPPING_KEY,
156                     brightnessArrayIntToFloat(brightnessLevels, backlightToBrightnessSpline));
157         }
158     }
159 
160     /**
161      * @param mode The auto-brightness mode
162      * @param preset The brightness preset. Presets are used on devices that allow users to choose
163      *               from a set of predefined options in display auto-brightness settings.
164      * @return The default auto-brightness brightening ambient lux levels for the specified mode
165      * and preset
166      */
getLuxArray(@utomaticBrightnessController.AutomaticBrightnessMode int mode, int preset)167     public float[] getLuxArray(@AutomaticBrightnessController.AutomaticBrightnessMode int mode,
168             int preset) {
169         float[] luxArray = mBrightnessLevelsLuxMap.get(
170                 autoBrightnessModeToString(mode) + "_" + autoBrightnessPresetToString(preset));
171         if (luxArray != null) {
172             return luxArray;
173         }
174 
175         // No array for this preset, fall back to the normal preset
176         return mBrightnessLevelsLuxMap.get(autoBrightnessModeToString(mode) + "_"
177                 + AutoBrightnessSettingName.normal.getRawName());
178     }
179 
180     /**
181      * @return Auto brightness brightening nits levels
182      */
getNitsArray()183     public float[] getNitsArray() {
184         return mBrightnessLevelsNits;
185     }
186 
187     /**
188      * @param mode The auto-brightness mode
189      * @param preset The brightness preset. Presets are used on devices that allow users to choose
190      *               from a set of predefined options in display auto-brightness settings.
191      * @return The default auto-brightness brightening levels for the specified mode and preset
192      */
getBrightnessArray( @utomaticBrightnessController.AutomaticBrightnessMode int mode, int preset)193     public float[] getBrightnessArray(
194             @AutomaticBrightnessController.AutomaticBrightnessMode int mode, int preset) {
195         float[] brightnessArray = mBrightnessLevelsMap.get(
196                 autoBrightnessModeToString(mode) + "_" + autoBrightnessPresetToString(preset));
197         if (brightnessArray != null) {
198             return brightnessArray;
199         }
200 
201         // No array for this preset, fall back to the normal preset
202         return mBrightnessLevelsMap.get(autoBrightnessModeToString(mode) + "_"
203                 + AutoBrightnessSettingName.normal.getRawName());
204     }
205 
206     @Override
toString()207     public String toString() {
208         StringBuilder brightnessLevelsLuxMapString = new StringBuilder("{");
209         for (Map.Entry<String, float[]> entry : mBrightnessLevelsLuxMap.entrySet()) {
210             brightnessLevelsLuxMapString.append(entry.getKey()).append("=").append(
211                     Arrays.toString(entry.getValue())).append(", ");
212         }
213         if (brightnessLevelsLuxMapString.length() > 2) {
214             brightnessLevelsLuxMapString.delete(brightnessLevelsLuxMapString.length() - 2,
215                     brightnessLevelsLuxMapString.length());
216         }
217         brightnessLevelsLuxMapString.append("}");
218 
219         StringBuilder brightnessLevelsMapString = new StringBuilder("{");
220         for (Map.Entry<String, float[]> entry : mBrightnessLevelsMap.entrySet()) {
221             brightnessLevelsMapString.append(entry.getKey()).append("=").append(
222                     Arrays.toString(entry.getValue())).append(", ");
223         }
224         if (brightnessLevelsMapString.length() > 2) {
225             brightnessLevelsMapString.delete(brightnessLevelsMapString.length() - 2,
226                     brightnessLevelsMapString.length());
227         }
228         brightnessLevelsMapString.append("}");
229 
230         return "mBrightnessLevelsNits= " + Arrays.toString(mBrightnessLevelsNits)
231                 + ", mBrightnessLevelsLuxMap= " + brightnessLevelsLuxMapString
232                 + ", mBrightnessLevelsMap= " + brightnessLevelsMapString;
233     }
234 
235     /**
236      * @param mode The auto-brightness mode
237      * @return The string representing the mode
238      */
autoBrightnessModeToString( @utomaticBrightnessController.AutomaticBrightnessMode int mode)239     public static String autoBrightnessModeToString(
240             @AutomaticBrightnessController.AutomaticBrightnessMode int mode) {
241         switch (mode) {
242             case AUTO_BRIGHTNESS_MODE_DEFAULT -> {
243                 return AutoBrightnessModeName._default.getRawName();
244             }
245             case AUTO_BRIGHTNESS_MODE_IDLE -> {
246                 return AutoBrightnessModeName.idle.getRawName();
247             }
248             case AUTO_BRIGHTNESS_MODE_DOZE -> {
249                 return AutoBrightnessModeName.doze.getRawName();
250             }
251             case AUTO_BRIGHTNESS_MODE_BEDTIME_WEAR -> {
252                 return AutoBrightnessModeName.bedtime_wear.getRawName();
253             }
254             default -> throw new IllegalArgumentException("Unknown auto-brightness mode: " + mode);
255         }
256     }
257 
258     /**
259      * @param preset The brightness preset. Presets are used on devices that allow users to choose
260      *               from a set of predefined options in display auto-brightness settings.
261      * @return The string representing the preset
262      */
autoBrightnessPresetToString(int preset)263     public static String autoBrightnessPresetToString(int preset) {
264         return switch (preset) {
265             case Settings.System.SCREEN_BRIGHTNESS_AUTOMATIC_DIM ->
266                     AutoBrightnessSettingName.dim.getRawName();
267             case Settings.System.SCREEN_BRIGHTNESS_AUTOMATIC_NORMAL ->
268                     AutoBrightnessSettingName.normal.getRawName();
269             case Settings.System.SCREEN_BRIGHTNESS_AUTOMATIC_BRIGHT ->
270                     AutoBrightnessSettingName.bright.getRawName();
271             default -> throw new IllegalArgumentException(
272                     "Unknown auto-brightness preset value: " + preset);
273         };
274     }
275 
brightnessArrayIntToFloat(int[] brightnessInt, Spline backlightToBrightnessSpline)276     private float[] brightnessArrayIntToFloat(int[] brightnessInt,
277             Spline backlightToBrightnessSpline) {
278         float[] brightnessFloat = new float[brightnessInt.length];
279         for (int i = 0; i < brightnessInt.length; i++) {
280             brightnessFloat[i] = backlightToBrightnessSpline.interpolate(
281                     BrightnessSynchronizer.brightnessIntToFloat(brightnessInt[i]));
282         }
283         return brightnessFloat;
284     }
285 }
286