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