1 /*
2  * Copyright (C) 2020 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;
18 
19 import static com.android.server.display.utils.DeviceConfigParsingUtils.ambientBrightnessThresholdsIntToFloat;
20 import static com.android.server.display.utils.DeviceConfigParsingUtils.displayBrightnessThresholdsIntToFloat;
21 
22 import android.annotation.NonNull;
23 import android.annotation.Nullable;
24 import android.content.Context;
25 import android.content.res.Configuration;
26 import android.content.res.Resources;
27 import android.content.res.TypedArray;
28 import android.hardware.display.DisplayManagerInternal;
29 import android.hardware.display.DisplayManagerInternal.RefreshRateLimitation;
30 import android.hardware.input.HostUsiVersion;
31 import android.os.Environment;
32 import android.os.PowerManager;
33 import android.text.TextUtils;
34 import android.util.MathUtils;
35 import android.util.Pair;
36 import android.util.Slog;
37 import android.util.SparseArray;
38 import android.util.Spline;
39 import android.view.DisplayAddress;
40 import android.view.SurfaceControl;
41 
42 import com.android.internal.R;
43 import com.android.internal.annotations.VisibleForTesting;
44 import com.android.internal.display.BrightnessSynchronizer;
45 import com.android.server.display.config.AutoBrightness;
46 import com.android.server.display.config.BlockingZoneConfig;
47 import com.android.server.display.config.BrightnessLimitMap;
48 import com.android.server.display.config.BrightnessThresholds;
49 import com.android.server.display.config.BrightnessThrottlingMap;
50 import com.android.server.display.config.BrightnessThrottlingPoint;
51 import com.android.server.display.config.Density;
52 import com.android.server.display.config.DisplayBrightnessPoint;
53 import com.android.server.display.config.DisplayConfiguration;
54 import com.android.server.display.config.DisplayQuirks;
55 import com.android.server.display.config.HbmTiming;
56 import com.android.server.display.config.HighBrightnessMode;
57 import com.android.server.display.config.IntegerArray;
58 import com.android.server.display.config.LuxThrottling;
59 import com.android.server.display.config.NitsMap;
60 import com.android.server.display.config.NonNegativeFloatToFloatPoint;
61 import com.android.server.display.config.Point;
62 import com.android.server.display.config.PredefinedBrightnessLimitNames;
63 import com.android.server.display.config.RefreshRateConfigs;
64 import com.android.server.display.config.RefreshRateRange;
65 import com.android.server.display.config.RefreshRateThrottlingMap;
66 import com.android.server.display.config.RefreshRateThrottlingPoint;
67 import com.android.server.display.config.RefreshRateZone;
68 import com.android.server.display.config.SdrHdrRatioMap;
69 import com.android.server.display.config.SdrHdrRatioPoint;
70 import com.android.server.display.config.SensorDetails;
71 import com.android.server.display.config.ThermalStatus;
72 import com.android.server.display.config.ThermalThrottling;
73 import com.android.server.display.config.ThresholdPoint;
74 import com.android.server.display.config.UsiVersion;
75 import com.android.server.display.config.XmlParser;
76 
77 import org.xmlpull.v1.XmlPullParserException;
78 
79 import java.io.BufferedInputStream;
80 import java.io.File;
81 import java.io.FileInputStream;
82 import java.io.IOException;
83 import java.io.InputStream;
84 import java.math.BigDecimal;
85 import java.math.BigInteger;
86 import java.util.ArrayList;
87 import java.util.Arrays;
88 import java.util.Collection;
89 import java.util.HashMap;
90 import java.util.List;
91 import java.util.Locale;
92 import java.util.Map;
93 
94 import javax.xml.datatype.DatatypeConfigurationException;
95 
96 /**
97  * Reads and stores display-specific configurations. File format:
98  * <pre>
99  *  {@code
100  *    <displayConfiguration>
101  *      <name>Built-In Display</name>
102  *      <densityMapping>
103  *        <density>
104  *          <height>480</height>
105  *          <width>720</width>
106  *          <density>120</density>
107  *        </density>
108  *        <density>
109  *          <height>720</height>
110  *          <width>1280</width>
111  *          <density>213</density>
112  *        </density>
113  *        <density>
114  *          <height>1080</height>
115  *          <width>1920</width>
116  *          <density>320</density>
117  *        </density>
118  *        <density>
119  *          <height>2160</height>
120  *          <width>3840</width>
121  *          <density>640</density>
122  *        </density>
123  *      </densityMapping>
124  *
125  *      <screenBrightnessMap>
126  *        <point>
127  *          <value>0.0</value>
128  *          <nits>2.0</nits>
129  *        </point>
130  *        <point>
131  *          <value>0.62</value>
132  *          <nits>500.0</nits>
133  *        </point>
134  *        <point>
135  *          <value>1.0</value>
136  *          <nits>800.0</nits>
137  *        </point>
138  *      </screenBrightnessMap>
139  *
140  *      <screenBrightnessDefault>0.65</screenBrightnessDefault>
141  *
142  *      <thermalThrottling>
143  *        <brightnessThrottlingMap>
144  *          <brightnessThrottlingPoint>
145  *            <thermalStatus>severe</thermalStatus>
146  *            <brightness>0.1</brightness>
147  *          </brightnessThrottlingPoint>
148  *          <brightnessThrottlingPoint>
149  *            <thermalStatus>critical</thermalStatus>
150  *            <brightness>0.01</brightness>
151  *          </brightnessThrottlingPoint>
152  *        </brightnessThrottlingMap>
153  *        <brightnessThrottlingMap id="id_2"> // optional attribute, leave blank for default
154  *             <brightnessThrottlingPoint>
155  *                 <thermalStatus>moderate</thermalStatus>
156  *                 <brightness>0.2</brightness>
157  *             </brightnessThrottlingPoint>
158  *             <brightnessThrottlingPoint>
159  *                 <thermalStatus>severe</thermalStatus>
160  *                 <brightness>0.1</brightness>
161  *            </brightnessThrottlingPoint>
162  *        </brightnessThrottlingMap>
163          <refreshRateThrottlingMap>
164  *            <refreshRateThrottlingPoint>
165  *                <thermalStatus>critical</thermalStatus>
166  *                <refreshRateRange>
167  *                     <minimum>0</minimum>
168  *                     <maximum>60</maximum>
169  *                 </refreshRateRange>
170  *            </refreshRateThrottlingPoint>
171  *        </refreshRateThrottlingMap>
172  *      </thermalThrottling>
173  *
174  *      <refreshRate>
175  *       <refreshRateZoneProfiles>
176  *         <refreshRateZoneProfile id="concurrent">
177  *           <refreshRateRange>
178  *             <minimum>60</minimum>
179  *             <maximum>60</maximum>
180  *            </refreshRateRange>
181  *          </refreshRateZoneProfile>
182  *        </refreshRateZoneProfiles>
183  *        <defaultRefreshRateInHbmHdr>75</defaultRefreshRateInHbmHdr>
184  *        <defaultRefreshRateInHbmSunlight>75</defaultRefreshRateInHbmSunlight>
185  *        <lowerBlockingZoneConfigs>
186  *          <defaultRefreshRate>75</defaultRefreshRate>
187  *          <refreshRateThermalThrottlingId>id_of_a_throttling_map</refreshRateThermalThrottlingId>
188  *          <blockingZoneThreshold>
189  *            <displayBrightnessPoint>
190  *              <lux>50</lux>
191  *              <nits>45.3</nits>
192  *            </displayBrightnessPoint>
193  *            <displayBrightnessPoint>
194  *              <lux>60</lux>
195  *              <nits>55.2</nits>
196  *            </displayBrightnessPoint>
197  *          </blockingZoneThreshold>
198  *        </lowerBlockingZoneConfigs>
199  *        <higherBlockingZoneConfigs>
200  *          <defaultRefreshRate>90</defaultRefreshRate>
201  *          <blockingZoneThreshold>
202  *            <displayBrightnessPoint>
203  *              <lux>500</lux>
204  *              <nits>245.3</nits>
205  *            </displayBrightnessPoint>
206  *            <displayBrightnessPoint>
207  *              <lux>600</lux>
208  *              <nits>232.3</nits>
209  *            </displayBrightnessPoint>
210  *          </blockingZoneThreshold>
211  *        </higherBlockingZoneConfigs>
212  *      </refreshRate>
213  *
214  *      <highBrightnessMode enabled="true">
215  *        <transitionPoint>0.62</transitionPoint>
216  *        <minimumLux>10000</minimumLux>
217  *        <timing>
218  *          <timeWindowSecs>1800</timeWindowSecs> // Window in which we restrict HBM.
219  *          <timeMaxSecs>300</timeMaxSecs>        // Maximum time of HBM allowed in that window.
220  *          <timeMinSecs>60</timeMinSecs>         // Minimum time remaining required to switch
221  *        </timing>                               //   HBM on for.
222  *        <refreshRate>
223  *          <minimum>120</minimum>
224  *          <maximum>120</maximum>
225  *        </refreshRate>
226  *        <thermalStatusLimit>light</thermalStatusLimit>
227  *        <allowInLowPowerMode>false</allowInLowPowerMode>
228  *      </highBrightnessMode>
229  *
230  *      <luxThrottling>
231  *        <brightnessLimitMap>
232  *          <type>default</type>
233  *          <map>
234  *            <point>
235  *                <first>5000</first>
236  *                <second>0.3</second>
237  *            </point>
238  *            <point>
239  *               <first>5000</first>
240  *               <second>0.3</second>
241  *            </point>
242  *          </map>
243  *        </brightnessPeakMap>
244  *      </luxThrottling>
245  *
246  *      <quirks>
247  *       <quirk>canSetBrightnessViaHwc</quirk>
248  *      </quirks>
249  *
250  *      <autoBrightness enable="true">
251  *          <brighteningLightDebounceMillis>
252  *              2000
253  *          </brighteningLightDebounceMillis>
254  *          <darkeningLightDebounceMillis>
255  *              1000
256  *          </darkeningLightDebounceMillis>
257  *          <displayBrightnessMapping>
258  *              <displayBrightnessPoint>
259  *                  <lux>50</lux>
260  *                  <nits>45.32</nits>
261  *              </displayBrightnessPoint>
262  *              <displayBrightnessPoint>
263  *                  <lux>80</lux>
264  *                  <nits>75.43</nits>
265  *              </displayBrightnessPoint>
266  *          </displayBrightnessMapping>
267  *      </autoBrightness>
268  *
269  *      <screenBrightnessRampFastDecrease>0.01</screenBrightnessRampFastDecrease>
270  *      <screenBrightnessRampFastIncrease>0.02</screenBrightnessRampFastIncrease>
271  *      <screenBrightnessRampSlowDecrease>0.03</screenBrightnessRampSlowDecrease>
272  *      <screenBrightnessRampSlowIncrease>0.04</screenBrightnessRampSlowIncrease>
273  *
274  *      <screenBrightnessRampIncreaseMaxMillis>2000</screenBrightnessRampIncreaseMaxMillis>
275  *      <screenBrightnessRampDecreaseMaxMillis>3000</screenBrightnessRampDecreaseMaxMillis>
276  *
277  *      <lightSensor>
278  *        <type>android.sensor.light</type>
279  *        <name>1234 Ambient Light Sensor</name>
280  *      </lightSensor>
281  *      <screenOffBrightnessSensor>
282  *        <type>com.google.sensor.binned_brightness</type>
283  *        <name>Binned Brightness 0 (wake-up)</name>
284  *      </screenOffBrightnessSensor>
285  *      <proxSensor>
286  *        <type>android.sensor.proximity</type>
287  *        <name>1234 Proximity Sensor</name>
288  *      </proxSensor>
289  *
290  *      <ambientLightHorizonLong>10001</ambientLightHorizonLong>
291  *      <ambientLightHorizonShort>2001</ambientLightHorizonShort>
292  *
293  *     <ambientBrightnessChangeThresholds>  // Thresholds for lux changes
294  *         <brighteningThresholds>
295  *             // Minimum change needed in ambient brightness to brighten screen.
296  *             <minimum>10</minimum>
297  *             // Percentage increase of lux needed to increase the screen brightness at a lux range
298  *             // above the specified threshold.
299  *             <brightnessThresholdPoints>
300  *                 <brightnessThresholdPoint>
301  *                     <threshold>0</threshold><percentage>13</percentage>
302  *                 </brightnessThresholdPoint>
303  *                 <brightnessThresholdPoint>
304  *                     <threshold>100</threshold><percentage>14</percentage>
305  *                 </brightnessThresholdPoint>
306  *                 <brightnessThresholdPoint>
307  *                     <threshold>200</threshold><percentage>15</percentage>
308  *                 </brightnessThresholdPoint>
309  *             </brightnessThresholdPoints>
310  *         </brighteningThresholds>
311  *         <darkeningThresholds>
312  *             // Minimum change needed in ambient brightness to darken screen.
313  *             <minimum>30</minimum>
314  *             // Percentage increase of lux needed to decrease the screen brightness at a lux range
315  *             // above the specified threshold.
316  *             <brightnessThresholdPoints>
317  *                 <brightnessThresholdPoint>
318  *                     <threshold>0</threshold><percentage>15</percentage>
319  *                 </brightnessThresholdPoint>
320  *                 <brightnessThresholdPoint>
321  *                     <threshold>300</threshold><percentage>16</percentage>
322  *                 </brightnessThresholdPoint>
323  *                 <brightnessThresholdPoint>
324  *                     <threshold>400</threshold><percentage>17</percentage>
325  *                 </brightnessThresholdPoint>
326  *             </brightnessThresholdPoints>
327  *         </darkeningThresholds>
328  *     </ambientBrightnessChangeThresholds>
329  *     <displayBrightnessChangeThresholds>   // Thresholds for screen brightness changes
330  *         <brighteningThresholds>
331  *             // Minimum change needed in screen brightness to brighten screen.
332  *             <minimum>0.1</minimum>
333  *             // Percentage increase of screen brightness needed to increase the screen brightness
334  *             // at a lux range above the specified threshold.
335  *             <brightnessThresholdPoints>
336  *                 <brightnessThresholdPoint>
337  *                     <threshold>0</threshold>
338  *                     <percentage>9</percentage>
339  *                 </brightnessThresholdPoint>
340  *                 <brightnessThresholdPoint>
341  *                     <threshold>0.10</threshold>
342  *                     <percentage>10</percentage>
343  *                 </brightnessThresholdPoint>
344  *                 <brightnessThresholdPoint>
345  *                     <threshold>0.20</threshold>
346  *                     <percentage>11</percentage>
347  *                 </brightnessThresholdPoint>
348  *             </brightnessThresholdPoints>
349  *         </brighteningThresholds>
350  *         <darkeningThresholds>
351  *             // Minimum change needed in screen brightness to darken screen.
352  *             <minimum>0.3</minimum>
353  *             // Percentage increase of screen brightness needed to decrease the screen brightness
354  *             // at a lux range above the specified threshold.
355  *             <brightnessThresholdPoints>
356  *                 <brightnessThresholdPoint>
357  *                     <threshold>0</threshold><percentage>11</percentage>
358  *                 </brightnessThresholdPoint>
359  *                 <brightnessThresholdPoint>
360  *                     <threshold>0.11</threshold><percentage>12</percentage>
361  *                 </brightnessThresholdPoint>
362  *                 <brightnessThresholdPoint>
363  *                     <threshold>0.21</threshold><percentage>13</percentage>
364  *                 </brightnessThresholdPoint>
365  *             </brightnessThresholdPoints>
366  *         </darkeningThresholds>
367  *     </displayBrightnessChangeThresholds>
368  *     <ambientBrightnessChangeThresholdsIdle>   // Thresholds for lux changes in idle mode
369  *         <brighteningThresholds>
370  *             // Minimum change needed in ambient brightness to brighten screen in idle mode
371  *             <minimum>20</minimum>
372  *             // Percentage increase of lux needed to increase the screen brightness at a lux range
373  *             // above the specified threshold whilst in idle mode.
374  *             <brightnessThresholdPoints>
375  *                 <brightnessThresholdPoint>
376  *                     <threshold>0</threshold><percentage>21</percentage>
377  *                 </brightnessThresholdPoint>
378  *                 <brightnessThresholdPoint>
379  *                     <threshold>500</threshold><percentage>22</percentage>
380  *                 </brightnessThresholdPoint>
381  *                 <brightnessThresholdPoint>
382  *                     <threshold>600</threshold><percentage>23</percentage>
383  *                 </brightnessThresholdPoint>
384  *             </brightnessThresholdPoints>
385  *         </brighteningThresholds>
386  *         <darkeningThresholds>
387  *             // Minimum change needed in ambient brightness to darken screen in idle mode
388  *             <minimum>40</minimum>
389  *             // Percentage increase of lux needed to decrease the screen brightness at a lux range
390  *             // above the specified threshold whilst in idle mode.
391  *             <brightnessThresholdPoints>
392  *                 <brightnessThresholdPoint>
393  *                     <threshold>0</threshold><percentage>23</percentage>
394  *                 </brightnessThresholdPoint>
395  *                 <brightnessThresholdPoint>
396  *                     <threshold>700</threshold><percentage>24</percentage>
397  *                 </brightnessThresholdPoint>
398  *                 <brightnessThresholdPoint>
399  *                     <threshold>800</threshold><percentage>25</percentage>
400  *                 </brightnessThresholdPoint>
401  *             </brightnessThresholdPoints>
402  *         </darkeningThresholds>
403  *     </ambientBrightnessChangeThresholdsIdle>
404  *     <displayBrightnessChangeThresholdsIdle>    // Thresholds for idle screen brightness changes
405  *         <brighteningThresholds>
406  *             // Minimum change needed in screen brightness to brighten screen in idle mode
407  *             <minimum>0.2</minimum>
408  *             // Percentage increase of screen brightness needed to increase the screen brightness
409  *             // at a lux range above the specified threshold whilst in idle mode
410  *             <brightnessThresholdPoints>
411  *                 <brightnessThresholdPoint>
412  *                     <threshold>0</threshold><percentage>17</percentage>
413  *                 </brightnessThresholdPoint>
414  *                 <brightnessThresholdPoint>
415  *                     <threshold>0.12</threshold><percentage>18</percentage>
416  *                 </brightnessThresholdPoint>
417  *                 <brightnessThresholdPoint>
418  *                     <threshold>0.22</threshold><percentage>19</percentage>
419  *                 </brightnessThresholdPoint>
420  *             </brightnessThresholdPoints>
421  *         </brighteningThresholds>
422  *         <darkeningThresholds>
423  *             // Minimum change needed in screen brightness to darken screen in idle mode
424  *             <minimum>0.4</minimum>
425  *             // Percentage increase of screen brightness needed to decrease the screen brightness
426  *             // at a lux range above the specified threshold whilst in idle mode
427  *             <brightnessThresholdPoints>
428  *                 <brightnessThresholdPoint>
429  *                     <threshold>0</threshold><percentage>19</percentage>
430  *                 </brightnessThresholdPoint>
431  *                 <brightnessThresholdPoint>
432  *                     <threshold>0.13</threshold><percentage>20</percentage>
433  *                 </brightnessThresholdPoint>
434  *                 <brightnessThresholdPoint>
435  *                     <threshold>0.23</threshold><percentage>21</percentage>
436  *                 </brightnessThresholdPoint>
437  *             </brightnessThresholdPoints>
438  *         </darkeningThresholds>
439  *     </displayBrightnessChangeThresholdsIdle>
440  *     <screenOffBrightnessSensorValueToLux>
441  *         <item>-1</item>
442  *         <item>0</item>
443  *         <item>5</item>
444  *         <item>80</item>
445  *         <item>1500</item>
446  *     </screenOffBrightnessSensorValueToLux>
447  *     // The version of the Universal Stylus Initiative (USI) protocol supported by this display.
448  *     // This should be omitted if the display does not support USI styluses.
449  *     <usiVersion>
450  *         <majorVersion>2</majorVersion>
451  *         <minorVersion>0</minorVersion>
452  *     </usiVersion>
453  *    </displayConfiguration>
454  *  }
455  *  </pre>
456  */
457 public class DisplayDeviceConfig {
458     private static final String TAG = "DisplayDeviceConfig";
459     private static final boolean DEBUG = false;
460 
461     public static final float HIGH_BRIGHTNESS_MODE_UNSUPPORTED = Float.NaN;
462 
463     public static final String QUIRK_CAN_SET_BRIGHTNESS_VIA_HWC = "canSetBrightnessViaHwc";
464 
465     public static final String DEFAULT_ID = "default";
466 
467     private static final float BRIGHTNESS_DEFAULT = 0.5f;
468     private static final String ETC_DIR = "etc";
469     private static final String DISPLAY_CONFIG_DIR = "displayconfig";
470     private static final String CONFIG_FILE_FORMAT = "display_%s.xml";
471     private static final String DEFAULT_CONFIG_FILE = "default.xml";
472     private static final String DEFAULT_CONFIG_FILE_WITH_UIMODE_FORMAT = "default_%s.xml";
473     private static final String PORT_SUFFIX_FORMAT = "port_%d";
474     private static final String STABLE_ID_SUFFIX_FORMAT = "id_%d";
475     private static final String NO_SUFFIX_FORMAT = "%d";
476     private static final long STABLE_FLAG = 1L << 62;
477     private static final int DEFAULT_PEAK_REFRESH_RATE = 0;
478     private static final int DEFAULT_REFRESH_RATE = 60;
479     private static final int DEFAULT_REFRESH_RATE_IN_HBM = 0;
480     private static final int DEFAULT_LOW_REFRESH_RATE = 60;
481     private static final int DEFAULT_HIGH_REFRESH_RATE = 0;
482     private static final float[] DEFAULT_BRIGHTNESS_THRESHOLDS = new float[]{};
483 
484     private static final float[] DEFAULT_AMBIENT_THRESHOLD_LEVELS = new float[]{0f};
485     private static final float[] DEFAULT_AMBIENT_BRIGHTENING_THRESHOLDS = new float[]{100f};
486     private static final float[] DEFAULT_AMBIENT_DARKENING_THRESHOLDS = new float[]{200f};
487     private static final float[] DEFAULT_SCREEN_THRESHOLD_LEVELS = new float[]{0f};
488     private static final float[] DEFAULT_SCREEN_BRIGHTENING_THRESHOLDS = new float[]{100f};
489     private static final float[] DEFAULT_SCREEN_DARKENING_THRESHOLDS = new float[]{200f};
490 
491     private static final int INTERPOLATION_DEFAULT = 0;
492     private static final int INTERPOLATION_LINEAR = 1;
493 
494     // Float.NaN (used as invalid for brightness) cannot be stored in config.xml
495     // so -2 is used instead
496     private static final float INVALID_BRIGHTNESS_IN_CONFIG = -2f;
497 
498     static final float NITS_INVALID = -1;
499 
500     // Length of the ambient light horizon used to calculate the long term estimate of ambient
501     // light.
502     private static final int AMBIENT_LIGHT_LONG_HORIZON_MILLIS = 10000;
503 
504     // Length of the ambient light horizon used to calculate short-term estimate of ambient light.
505     private static final int AMBIENT_LIGHT_SHORT_HORIZON_MILLIS = 2000;
506 
507     // Invalid value of AutoBrightness brightening and darkening light debounce
508     private static final int INVALID_AUTO_BRIGHTNESS_LIGHT_DEBOUNCE = -1;
509 
510     @VisibleForTesting
511     static final float HDR_PERCENT_OF_SCREEN_REQUIRED_DEFAULT = 0.5f;
512 
513     private final Context mContext;
514 
515     // The details of the ambient light sensor associated with this display.
516     private final SensorData mAmbientLightSensor = new SensorData();
517 
518     // The details of the doze brightness sensor associated with this display.
519     private final SensorData mScreenOffBrightnessSensor = new SensorData();
520 
521     // The details of the proximity sensor associated with this display.
522     // Is null when no sensor should be used for that display
523     @Nullable
524     private SensorData mProximitySensor = new SensorData();
525 
526     private final List<RefreshRateLimitation> mRefreshRateLimitations =
527             new ArrayList<>(2 /*initialCapacity*/);
528 
529     // Name of the display, if configured.
530     @Nullable
531     private String mName;
532 
533     // Nits and backlight values that are loaded from either the display device config file, or
534     // config.xml. These are the raw values and just used for the dumpsys
535     private float[] mRawNits;
536     private float[] mRawBacklight;
537     private int mInterpolationType;
538 
539     // These arrays are calculated from the raw arrays, but clamped to contain values equal to and
540     // between mBacklightMinimum and mBacklightMaximum. These three arrays should all be the same
541     // length
542     // Nits array that is used to store the entire range of nits values that the device supports
543     private float[] mNits;
544     // Backlight array holds the values that the HAL uses to display the corresponding nits values
545     private float[] mBacklight;
546     // Purely an array that covers the ranges of values 0.0 - 1.0, indicating the system brightness
547     // for the corresponding values above
548     private float[] mBrightness;
549 
550 
551     /**
552      * Array of desired screen brightness in nits corresponding to the lux values
553      * in the mBrightnessLevelsLux array. The display brightness is defined as the
554      * measured brightness of an all-white image. The brightness values must be non-negative and
555      * non-decreasing. This must be overridden in platform specific overlays
556      */
557     private float[] mBrightnessLevelsNits;
558 
559     /**
560      * Array of light sensor lux values to define our levels for auto backlight
561      * brightness support.
562      *
563      * The N + 1 entries of this array define N control points defined in mBrightnessLevelsNits,
564      * with first value always being 0 lux
565      *
566      * The control points must be strictly increasing.  Each control point
567      * corresponds to an entry in the brightness backlight values arrays.
568      * For example, if lux == level[1] (second element of the levels array)
569      * then the brightness will be determined by value[0] (first element
570      * of the brightness values array).
571      *
572      * Spline interpolation is used to determine the auto-brightness
573      * backlight values for lux levels between these control points.
574      */
575     private float[] mBrightnessLevelsLux;
576 
577     private float mBacklightMinimum = Float.NaN;
578     private float mBacklightMaximum = Float.NaN;
579     private float mBrightnessDefault = Float.NaN;
580     private float mBrightnessRampFastDecrease = Float.NaN;
581     private float mBrightnessRampFastIncrease = Float.NaN;
582     private float mBrightnessRampSlowDecrease = Float.NaN;
583     private float mBrightnessRampSlowIncrease = Float.NaN;
584     private long mBrightnessRampDecreaseMaxMillis = 0;
585     private long mBrightnessRampIncreaseMaxMillis = 0;
586     private int mAmbientHorizonLong = AMBIENT_LIGHT_LONG_HORIZON_MILLIS;
587     private int mAmbientHorizonShort = AMBIENT_LIGHT_SHORT_HORIZON_MILLIS;
588     private float mScreenBrighteningMinThreshold = 0.0f;     // Retain behaviour as though there is
589     private float mScreenBrighteningMinThresholdIdle = 0.0f; // no minimum threshold for change in
590     private float mScreenDarkeningMinThreshold = 0.0f;       // screen brightness or ambient
591     private float mScreenDarkeningMinThresholdIdle = 0.0f;   // brightness.
592     private float mAmbientLuxBrighteningMinThreshold = 0.0f;
593     private float mAmbientLuxBrighteningMinThresholdIdle = 0.0f;
594     private float mAmbientLuxDarkeningMinThreshold = 0.0f;
595     private float mAmbientLuxDarkeningMinThresholdIdle = 0.0f;
596 
597     // Screen brightness thresholds levels & percentages
598     private float[] mScreenBrighteningLevels = DEFAULT_SCREEN_THRESHOLD_LEVELS;
599     private float[] mScreenBrighteningPercentages = DEFAULT_SCREEN_BRIGHTENING_THRESHOLDS;
600     private float[] mScreenDarkeningLevels = DEFAULT_SCREEN_THRESHOLD_LEVELS;
601     private float[] mScreenDarkeningPercentages = DEFAULT_SCREEN_DARKENING_THRESHOLDS;
602 
603     // Screen brightness thresholds levels & percentages for idle mode
604     private float[] mScreenBrighteningLevelsIdle = DEFAULT_SCREEN_THRESHOLD_LEVELS;
605     private float[] mScreenBrighteningPercentagesIdle = DEFAULT_SCREEN_BRIGHTENING_THRESHOLDS;
606     private float[] mScreenDarkeningLevelsIdle = DEFAULT_SCREEN_THRESHOLD_LEVELS;
607     private float[] mScreenDarkeningPercentagesIdle = DEFAULT_SCREEN_DARKENING_THRESHOLDS;
608 
609     // Ambient brightness thresholds levels & percentages
610     private float[] mAmbientBrighteningLevels = DEFAULT_AMBIENT_THRESHOLD_LEVELS;
611     private float[] mAmbientBrighteningPercentages = DEFAULT_AMBIENT_BRIGHTENING_THRESHOLDS;
612     private float[] mAmbientDarkeningLevels = DEFAULT_AMBIENT_THRESHOLD_LEVELS;
613     private float[] mAmbientDarkeningPercentages = DEFAULT_AMBIENT_DARKENING_THRESHOLDS;
614 
615     // Ambient brightness thresholds levels & percentages for idle mode
616     private float[] mAmbientBrighteningLevelsIdle = DEFAULT_AMBIENT_THRESHOLD_LEVELS;
617     private float[] mAmbientBrighteningPercentagesIdle = DEFAULT_AMBIENT_BRIGHTENING_THRESHOLDS;
618     private float[] mAmbientDarkeningLevelsIdle = DEFAULT_AMBIENT_THRESHOLD_LEVELS;
619     private float[] mAmbientDarkeningPercentagesIdle = DEFAULT_AMBIENT_DARKENING_THRESHOLDS;
620 
621     // A mapping between screen off sensor values and lux values
622     private int[] mScreenOffBrightnessSensorValueToLux;
623 
624     private Spline mBrightnessToBacklightSpline;
625     private Spline mBacklightToBrightnessSpline;
626     private Spline mBacklightToNitsSpline;
627     private Spline mNitsToBacklightSpline;
628     private List<String> mQuirks;
629     private boolean mIsHighBrightnessModeEnabled = false;
630     private HighBrightnessModeData mHbmData;
631     private DensityMapping mDensityMapping;
632     private String mLoadedFrom = null;
633     private Spline mSdrToHdrRatioSpline;
634 
635     // Represents the auto-brightness brightening light debounce.
636     private long mAutoBrightnessBrighteningLightDebounce =
637             INVALID_AUTO_BRIGHTNESS_LIGHT_DEBOUNCE;
638 
639     // Represents the auto-brightness darkening light debounce.
640     private long mAutoBrightnessDarkeningLightDebounce =
641             INVALID_AUTO_BRIGHTNESS_LIGHT_DEBOUNCE;
642 
643     // This setting allows non-default displays to have autobrightness enabled.
644     private boolean mAutoBrightnessAvailable = false;
645     // This stores the raw value loaded from the config file - true if not written.
646     private boolean mDdcAutoBrightnessAvailable = true;
647 
648     /**
649      * The default peak refresh rate for a given device. This value prevents the framework from
650      * using higher refresh rates, even if display modes with higher refresh rates are available
651      * from hardware composer. Only has an effect if the value is non-zero.
652      */
653     private int mDefaultPeakRefreshRate = DEFAULT_PEAK_REFRESH_RATE;
654 
655     /**
656      * The default refresh rate for a given device. This value sets the higher default
657      * refresh rate. If the hardware composer on the device supports display modes with
658      * a higher refresh rate than the default value specified here, the framework may use those
659      * higher refresh rate modes if an app chooses one by setting preferredDisplayModeId or calling
660      * setFrameRate(). We have historically allowed fallback to mDefaultPeakRefreshRate if
661      * mDefaultRefreshRate is set to 0, but this is not supported anymore.
662      */
663     private int mDefaultRefreshRate = DEFAULT_REFRESH_RATE;
664 
665     /**
666      * Default refresh rate while the device has high brightness mode enabled for HDR.
667      */
668     private int mDefaultRefreshRateInHbmHdr = DEFAULT_REFRESH_RATE_IN_HBM;
669 
670     /**
671      * Default refresh rate while the device has high brightness mode enabled for Sunlight.
672      */
673     private int mDefaultRefreshRateInHbmSunlight = DEFAULT_REFRESH_RATE_IN_HBM;
674     /**
675      * Default refresh rate in the high zone defined by brightness and ambient thresholds.
676      * If non-positive, then the refresh rate is unchanged even if thresholds are configured.
677      */
678     private int mDefaultHighBlockingZoneRefreshRate = DEFAULT_HIGH_REFRESH_RATE;
679 
680     /**
681      * Default refresh rate in the zone defined by brightness and ambient thresholds.
682      * If non-positive, then the refresh rate is unchanged even if thresholds are configured.
683      */
684     private int mDefaultLowBlockingZoneRefreshRate = DEFAULT_LOW_REFRESH_RATE;
685 
686     // Refresh rate profiles, currently only for concurrent mode profile and controlled by Layout
687     private final Map<String, SurfaceControl.RefreshRateRange> mRefreshRateZoneProfiles =
688             new HashMap<>();
689 
690     /**
691      * The display uses different gamma curves for different refresh rates. It's hard for panel
692      * vendors to tune the curves to have exact same brightness for different refresh rate. So
693      * brightness flickers could be observed at switch time. The issue is worse at the gamma lower
694      * end. In addition, human eyes are more sensitive to the flicker at darker environment. To
695      * prevent flicker, we only support higher refresh rates if the display brightness is above a
696      * threshold. For example, no higher refresh rate if display brightness <= disp0 && ambient
697      * brightness <= amb0 || display brightness <= disp1 && ambient brightness <= amb1
698      *
699      * Brightness thresholds are paired with lux thresholds - they both have to be met.
700      *
701      * A negative brightness or lux value means that only one threshold should be used - e.g. if
702      * the brightness value is negative, only the lux threshold is applied.
703      */
704     private float[] mLowDisplayBrightnessThresholds = DEFAULT_BRIGHTNESS_THRESHOLDS;
705     private float[] mLowAmbientBrightnessThresholds = DEFAULT_BRIGHTNESS_THRESHOLDS;
706 
707     /**
708      * The display uses different gamma curves for different refresh rates. It's hard for panel
709      * vendors to tune the curves to have exact same brightness for different refresh rate. So
710      * brightness flickers could be observed at switch time. The issue can be observed on the screen
711      * with even full white content at the high brightness. To prevent flickering, we support fixed
712      * refresh rates if the display and ambient brightness are equal to or above the provided
713      * thresholds. You can define multiple threshold levels as higher brightness environments may
714      * have lower display brightness requirements for the flickering is visible. For example, fixed
715      * refresh rate if display brightness >= disp0 && ambient brightness >= amb0 || display
716      * brightness >= disp1 && ambient brightness >= amb1
717      *
718      * Brightness thresholds are paired with lux thresholds - they both have to be met.
719      *
720      * A negative brightness or lux value means that only one threshold should be used - e.g. if
721      * the brightness value is negative, only the lux threshold is applied.
722      */
723     private float[] mHighDisplayBrightnessThresholds = DEFAULT_BRIGHTNESS_THRESHOLDS;
724     private float[] mHighAmbientBrightnessThresholds = DEFAULT_BRIGHTNESS_THRESHOLDS;
725 
726     /**
727      * Thermal throttling maps for the low and high blocking zones.
728      */
729     private String mLowBlockingZoneThermalMapId = null;
730     private String mHighBlockingZoneThermalMapId = null;
731 
732     private final HashMap<String, ThermalBrightnessThrottlingData>
733             mThermalBrightnessThrottlingDataMapByThrottlingId = new HashMap<>();
734 
735     private final Map<String, SparseArray<SurfaceControl.RefreshRateRange>>
736             mRefreshRateThrottlingMap = new HashMap<>();
737 
738     private final Map<BrightnessLimitMapType, Map<Float, Float>>
739             mLuxThrottlingData = new HashMap<>();
740 
741     @Nullable
742     private HostUsiVersion mHostUsiVersion;
743 
744     @VisibleForTesting
DisplayDeviceConfig(Context context)745     DisplayDeviceConfig(Context context) {
746         mContext = context;
747     }
748 
749     /**
750      * Creates an instance for the specified display. Tries to find a file with identifier in the
751      * following priority order:
752      * <ol>
753      *     <li>physicalDisplayId</li>
754      *     <li>physicalDisplayId without a stable flag (old system)</li>
755      *     <li>portId</li>
756      * </ol>
757      *
758      * @param physicalDisplayId The display ID for which to load the configuration.
759      * @return A configuration instance for the specified display.
760      */
create(Context context, long physicalDisplayId, boolean isFirstDisplay)761     public static DisplayDeviceConfig create(Context context, long physicalDisplayId,
762             boolean isFirstDisplay) {
763         final DisplayDeviceConfig config = createWithoutDefaultValues(context, physicalDisplayId,
764                 isFirstDisplay);
765 
766         config.copyUninitializedValuesFromSecondaryConfig(loadDefaultConfigurationXml(context));
767         return config;
768     }
769 
770     /**
771      * Creates an instance using global values since no display device config xml exists. Uses
772      * values from config or PowerManager.
773      *
774      * @param context      The context from which the DisplayDeviceConfig is to be constructed.
775      * @param useConfigXml A flag indicating if values are to be loaded from the configuration file,
776      *                     or the default values.
777      * @return A configuration instance.
778      */
create(Context context, boolean useConfigXml)779     public static DisplayDeviceConfig create(Context context, boolean useConfigXml) {
780         final DisplayDeviceConfig config;
781         if (useConfigXml) {
782             config = getConfigFromGlobalXml(context);
783         } else {
784             config = getConfigFromPmValues(context);
785         }
786         return config;
787     }
788 
createWithoutDefaultValues(Context context, long physicalDisplayId, boolean isFirstDisplay)789     private static DisplayDeviceConfig createWithoutDefaultValues(Context context,
790             long physicalDisplayId, boolean isFirstDisplay) {
791         DisplayDeviceConfig config;
792 
793         config = loadConfigFromDirectory(context, Environment.getProductDirectory(),
794                 physicalDisplayId);
795         if (config != null) {
796             return config;
797         }
798 
799         config = loadConfigFromDirectory(context, Environment.getVendorDirectory(),
800                 physicalDisplayId);
801         if (config != null) {
802             return config;
803         }
804 
805         // If no config can be loaded from any ddc xml at all,
806         // prepare a whole config using the global config.xml.
807         // Guaranteed not null
808         return create(context, isFirstDisplay);
809     }
810 
loadDefaultConfigurationXml(Context context)811     private static DisplayConfiguration loadDefaultConfigurationXml(Context context) {
812         List<File> defaultXmlLocations = new ArrayList<>();
813         defaultXmlLocations.add(Environment.buildPath(Environment.getProductDirectory(),
814                 ETC_DIR, DISPLAY_CONFIG_DIR, DEFAULT_CONFIG_FILE));
815         defaultXmlLocations.add(Environment.buildPath(Environment.getVendorDirectory(),
816                 ETC_DIR, DISPLAY_CONFIG_DIR, DEFAULT_CONFIG_FILE));
817 
818         // Read config_defaultUiModeType directly because UiModeManager hasn't started yet.
819         final int uiModeType = context.getResources()
820                 .getInteger(com.android.internal.R.integer.config_defaultUiModeType);
821         final String uiModeTypeStr = Configuration.getUiModeTypeString(uiModeType);
822         if (uiModeTypeStr != null) {
823             defaultXmlLocations.add(Environment.buildPath(Environment.getRootDirectory(),
824                     ETC_DIR, DISPLAY_CONFIG_DIR,
825                     String.format(DEFAULT_CONFIG_FILE_WITH_UIMODE_FORMAT, uiModeTypeStr)));
826         }
827         defaultXmlLocations.add(Environment.buildPath(Environment.getRootDirectory(),
828                 ETC_DIR, DISPLAY_CONFIG_DIR, DEFAULT_CONFIG_FILE));
829 
830         final File configFile = getFirstExistingFile(defaultXmlLocations);
831         if (configFile == null) {
832             // Display configuration files aren't required to exist.
833             return null;
834         }
835 
836         DisplayConfiguration defaultConfig = null;
837 
838         try (InputStream in = new BufferedInputStream(new FileInputStream(configFile))) {
839             defaultConfig = XmlParser.read(in);
840             if (defaultConfig == null) {
841                 Slog.i(TAG, "Default DisplayDeviceConfig file is null");
842             }
843         } catch (IOException | DatatypeConfigurationException | XmlPullParserException e) {
844             Slog.e(TAG, "Encountered an error while reading/parsing display config file: "
845                     + configFile, e);
846         }
847 
848         return defaultConfig;
849     }
850 
getFirstExistingFile(Collection<File> files)851     private static File getFirstExistingFile(Collection<File> files) {
852         for (File file : files) {
853             if (file.exists() && file.isFile()) {
854                 return file;
855             }
856         }
857         return null;
858     }
859 
loadConfigFromDirectory(Context context, File baseDirectory, long physicalDisplayId)860     private static DisplayDeviceConfig loadConfigFromDirectory(Context context,
861             File baseDirectory, long physicalDisplayId) {
862         DisplayDeviceConfig config;
863         // Create config using filename from physical ID (including "stable" bit).
864         config = getConfigFromSuffix(context, baseDirectory, STABLE_ID_SUFFIX_FORMAT,
865                 physicalDisplayId);
866         if (config != null) {
867             return config;
868         }
869 
870         // Create config using filename from physical ID (excluding "stable" bit).
871         final long withoutStableFlag = physicalDisplayId & ~STABLE_FLAG;
872         config = getConfigFromSuffix(context, baseDirectory, NO_SUFFIX_FORMAT, withoutStableFlag);
873         if (config != null) {
874             return config;
875         }
876 
877         // Create config using filename from port ID.
878         final DisplayAddress.Physical physicalAddress =
879                 DisplayAddress.fromPhysicalDisplayId(physicalDisplayId);
880         int port = physicalAddress.getPort();
881         config = getConfigFromSuffix(context, baseDirectory, PORT_SUFFIX_FORMAT, port);
882         return config;
883     }
884 
885     /** The name of the display.
886      *
887      * @return The name of the display.
888      */
889     @Nullable
getName()890     public String getName() {
891         return mName;
892     }
893 
894     /**
895      * Return the brightness mapping nits array.
896      *
897      * @return The brightness mapping nits array.
898      */
getNits()899     public float[] getNits() {
900         return mNits;
901     }
902 
903     /**
904      * Return the brightness mapping backlight array.
905      *
906      * @return The backlight mapping value array.
907      */
getBacklight()908     public float[] getBacklight() {
909         return mBacklight;
910     }
911 
912     /**
913      * Calculates the backlight value, as recognised by the HAL, from the brightness value given
914      * that the rest of the system deals with.
915      *
916      * @param brightness value on the framework scale of 0-1
917      * @return backlight value on the HAL scale of 0-1
918      */
getBacklightFromBrightness(float brightness)919     public float getBacklightFromBrightness(float brightness) {
920         return mBrightnessToBacklightSpline.interpolate(brightness);
921     }
922 
923     /**
924      * Calculates the nits value for the specified backlight value if a mapping exists.
925      *
926      * @return The mapped nits or {@link #NITS_INVALID} if no mapping exits.
927      */
getNitsFromBacklight(float backlight)928     public float getNitsFromBacklight(float backlight) {
929         if (mBacklightToNitsSpline == null) {
930             return NITS_INVALID;
931         }
932         backlight = Math.max(backlight, mBacklightMinimum);
933         return mBacklightToNitsSpline.interpolate(backlight);
934     }
935 
936     /**
937      * @return true if there is sdrHdrRatioMap, false otherwise.
938      */
hasSdrToHdrRatioSpline()939     public boolean hasSdrToHdrRatioSpline() {
940         return mSdrToHdrRatioSpline != null;
941     }
942 
943     /**
944      * Calculate the HDR brightness for the specified SDR brightenss, restricted by the
945      * maxDesiredHdrSdrRatio (the ratio between the HDR luminance and SDR luminance)
946      *
947      * @return the HDR brightness or BRIGHTNESS_INVALID when no mapping exists.
948      */
getHdrBrightnessFromSdr(float brightness, float maxDesiredHdrSdrRatio)949     public float getHdrBrightnessFromSdr(float brightness, float maxDesiredHdrSdrRatio) {
950         if (mSdrToHdrRatioSpline == null) {
951             return PowerManager.BRIGHTNESS_INVALID;
952         }
953 
954         float backlight = getBacklightFromBrightness(brightness);
955         float nits = getNitsFromBacklight(backlight);
956         if (nits == NITS_INVALID) {
957             return PowerManager.BRIGHTNESS_INVALID;
958         }
959 
960         float ratio = Math.min(mSdrToHdrRatioSpline.interpolate(nits), maxDesiredHdrSdrRatio);
961         float hdrNits = nits * ratio;
962         if (mNitsToBacklightSpline == null) {
963             return PowerManager.BRIGHTNESS_INVALID;
964         }
965 
966         float hdrBacklight = mNitsToBacklightSpline.interpolate(hdrNits);
967         hdrBacklight = Math.max(mBacklightMinimum, Math.min(mBacklightMaximum, hdrBacklight));
968         float hdrBrightness = mBacklightToBrightnessSpline.interpolate(hdrBacklight);
969 
970         if (DEBUG) {
971             Slog.d(TAG, "getHdrBrightnessFromSdr: sdr brightness " + brightness
972                     + " backlight " + backlight
973                     + " nits " + nits
974                     + " ratio " + ratio
975                     + " hdrNits " + hdrNits
976                     + " hdrBacklight " + hdrBacklight
977                     + " hdrBrightness " + hdrBrightness
978             );
979         }
980         return hdrBrightness;
981     }
982 
983     /**
984      * Return an array of equal length to backlight and nits, that covers the entire system
985      * brightness range of 0.0-1.0.
986      *
987      * @return brightness array
988      */
getBrightness()989     public float[] getBrightness() {
990         return mBrightness;
991     }
992 
993     /**
994      * Return the default brightness on a scale of 0.0f - 1.0f
995      *
996      * @return default brightness
997      */
getBrightnessDefault()998     public float getBrightnessDefault() {
999         return mBrightnessDefault;
1000     }
1001 
getBrightnessRampFastDecrease()1002     public float getBrightnessRampFastDecrease() {
1003         return mBrightnessRampFastDecrease;
1004     }
1005 
getBrightnessRampFastIncrease()1006     public float getBrightnessRampFastIncrease() {
1007         return mBrightnessRampFastIncrease;
1008     }
1009 
getBrightnessRampSlowDecrease()1010     public float getBrightnessRampSlowDecrease() {
1011         return mBrightnessRampSlowDecrease;
1012     }
1013 
getBrightnessRampSlowIncrease()1014     public float getBrightnessRampSlowIncrease() {
1015         return mBrightnessRampSlowIncrease;
1016     }
1017 
getBrightnessRampDecreaseMaxMillis()1018     public long getBrightnessRampDecreaseMaxMillis() {
1019         return mBrightnessRampDecreaseMaxMillis;
1020     }
1021 
getBrightnessRampIncreaseMaxMillis()1022     public long getBrightnessRampIncreaseMaxMillis() {
1023         return mBrightnessRampIncreaseMaxMillis;
1024     }
1025 
getAmbientHorizonLong()1026     public int getAmbientHorizonLong() {
1027         return mAmbientHorizonLong;
1028     }
1029 
getAmbientHorizonShort()1030     public int getAmbientHorizonShort() {
1031         return mAmbientHorizonShort;
1032     }
1033 
1034     /**
1035      * The minimum value for the screen brightness increase to actually occur.
1036      * @return float value in brightness scale of 0 - 1.
1037      */
getScreenBrighteningMinThreshold()1038     public float getScreenBrighteningMinThreshold() {
1039         return mScreenBrighteningMinThreshold;
1040     }
1041 
1042     /**
1043      * The minimum value for the screen brightness decrease to actually occur.
1044      * @return float value in brightness scale of 0 - 1.
1045      */
getScreenDarkeningMinThreshold()1046     public float getScreenDarkeningMinThreshold() {
1047         return mScreenDarkeningMinThreshold;
1048     }
1049 
1050     /**
1051      * The minimum value for the screen brightness increase to actually occur while in idle screen
1052      * brightness mode.
1053      * @return float value in brightness scale of 0 - 1.
1054      */
getScreenBrighteningMinThresholdIdle()1055     public float getScreenBrighteningMinThresholdIdle() {
1056         return mScreenBrighteningMinThresholdIdle;
1057     }
1058 
1059     /**
1060      * The minimum value for the screen brightness decrease to actually occur while in idle screen
1061      * brightness mode.
1062      * @return float value in brightness scale of 0 - 1.
1063      */
getScreenDarkeningMinThresholdIdle()1064     public float getScreenDarkeningMinThresholdIdle() {
1065         return mScreenDarkeningMinThresholdIdle;
1066     }
1067 
1068     /**
1069      * The minimum value for the ambient lux increase for a screen brightness change to actually
1070      * occur.
1071      * @return float value in lux.
1072      */
getAmbientLuxBrighteningMinThreshold()1073     public float getAmbientLuxBrighteningMinThreshold() {
1074         return mAmbientLuxBrighteningMinThreshold;
1075     }
1076 
1077     /**
1078      * The minimum value for the ambient lux decrease for a screen brightness change to actually
1079      * occur.
1080      * @return float value in lux.
1081      */
getAmbientLuxDarkeningMinThreshold()1082     public float getAmbientLuxDarkeningMinThreshold() {
1083         return mAmbientLuxDarkeningMinThreshold;
1084     }
1085 
1086     /**
1087      * The minimum value for the ambient lux increase for a screen brightness change to actually
1088      * occur while in idle screen brightness mode.
1089      * @return float value in lux.
1090      */
getAmbientLuxBrighteningMinThresholdIdle()1091     public float getAmbientLuxBrighteningMinThresholdIdle() {
1092         return mAmbientLuxBrighteningMinThresholdIdle;
1093     }
1094 
1095     /**
1096      * The minimum value for the ambient lux decrease for a screen brightness change to actually
1097      * occur while in idle screen brightness mode.
1098      * @return float value in lux.
1099      */
getAmbientLuxDarkeningMinThresholdIdle()1100     public float getAmbientLuxDarkeningMinThresholdIdle() {
1101         return mAmbientLuxDarkeningMinThresholdIdle;
1102     }
1103 
1104     /**
1105      * The array that describes the range of screen brightness that each threshold percentage
1106      * applies within.
1107      *
1108      * The (zero-based) index is calculated as follows
1109      * value = current screen brightness value
1110      * level = mScreenBrighteningLevels
1111      *
1112      * condition                       return
1113      * value < level[0]                = 0.0f
1114      * level[n] <= value < level[n+1]  = mScreenBrighteningPercentages[n]
1115      * level[MAX] <= value             = mScreenBrighteningPercentages[MAX]
1116      *
1117      * @return the screen brightness levels between 0.0 and 1.0 for which each
1118      * mScreenBrighteningPercentages applies
1119      */
getScreenBrighteningLevels()1120     public float[] getScreenBrighteningLevels() {
1121         return mScreenBrighteningLevels;
1122     }
1123 
1124     /**
1125      * The array that describes the screen brightening threshold percentage change at each screen
1126      * brightness level described in mScreenBrighteningLevels.
1127      *
1128      * @return the percentages between 0 and 100 of brightness increase required in order for the
1129      * screen brightness to change
1130      */
getScreenBrighteningPercentages()1131     public float[] getScreenBrighteningPercentages() {
1132         return mScreenBrighteningPercentages;
1133     }
1134 
1135     /**
1136      * The array that describes the range of screen brightness that each threshold percentage
1137      * applies within.
1138      *
1139      * The (zero-based) index is calculated as follows
1140      * value = current screen brightness value
1141      * level = mScreenDarkeningLevels
1142      *
1143      * condition                       return
1144      * value < level[0]                = 0.0f
1145      * level[n] <= value < level[n+1]  = mScreenDarkeningPercentages[n]
1146      * level[MAX] <= value             = mScreenDarkeningPercentages[MAX]
1147      *
1148      * @return the screen brightness levels between 0.0 and 1.0 for which each
1149      * mScreenDarkeningPercentages applies
1150      */
getScreenDarkeningLevels()1151     public float[] getScreenDarkeningLevels() {
1152         return mScreenDarkeningLevels;
1153     }
1154 
1155     /**
1156      * The array that describes the screen darkening threshold percentage change at each screen
1157      * brightness level described in mScreenDarkeningLevels.
1158      *
1159      * @return the percentages between 0 and 100 of brightness decrease required in order for the
1160      * screen brightness to change
1161      */
getScreenDarkeningPercentages()1162     public float[] getScreenDarkeningPercentages() {
1163         return mScreenDarkeningPercentages;
1164     }
1165 
1166     /**
1167      * The array that describes the range of ambient brightness that each threshold
1168      * percentage applies within.
1169      *
1170      * The (zero-based) index is calculated as follows
1171      * value = current ambient brightness value
1172      * level = mAmbientBrighteningLevels
1173      *
1174      * condition                       return
1175      * value < level[0]                = 0.0f
1176      * level[n] <= value < level[n+1]  = mAmbientBrighteningPercentages[n]
1177      * level[MAX] <= value             = mAmbientBrighteningPercentages[MAX]
1178      *
1179      * @return the ambient brightness levels from 0 lux upwards for which each
1180      * mAmbientBrighteningPercentages applies
1181      */
getAmbientBrighteningLevels()1182     public float[] getAmbientBrighteningLevels() {
1183         return mAmbientBrighteningLevels;
1184     }
1185 
1186     /**
1187      * The array that describes the ambient brightening threshold percentage change at each ambient
1188      * brightness level described in mAmbientBrighteningLevels.
1189      *
1190      * @return the percentages between 0 and 100 of brightness increase required in order for the
1191      * screen brightness to change
1192      */
getAmbientBrighteningPercentages()1193     public float[] getAmbientBrighteningPercentages() {
1194         return mAmbientBrighteningPercentages;
1195     }
1196 
1197     /**
1198      * The array that describes the range of ambient brightness that each threshold percentage
1199      * applies within.
1200      *
1201      * The (zero-based) index is calculated as follows
1202      * value = current ambient brightness value
1203      * level = mAmbientDarkeningLevels
1204      *
1205      * condition                       return
1206      * value < level[0]                = 0.0f
1207      * level[n] <= value < level[n+1]  = mAmbientDarkeningPercentages[n]
1208      * level[MAX] <= value             = mAmbientDarkeningPercentages[MAX]
1209      *
1210      * @return the ambient brightness levels from 0 lux upwards for which each
1211      * mAmbientDarkeningPercentages applies
1212      */
getAmbientDarkeningLevels()1213     public float[] getAmbientDarkeningLevels() {
1214         return mAmbientDarkeningLevels;
1215     }
1216 
1217     /**
1218      * The array that describes the ambient darkening threshold percentage change at each ambient
1219      * brightness level described in mAmbientDarkeningLevels.
1220      *
1221      * @return the percentages between 0 and 100 of brightness decrease required in order for the
1222      * screen brightness to change
1223      */
getAmbientDarkeningPercentages()1224     public float[] getAmbientDarkeningPercentages() {
1225         return mAmbientDarkeningPercentages;
1226     }
1227 
1228     /**
1229      * The array that describes the range of screen brightness that each threshold percentage
1230      * applies within whilst in idle screen brightness mode.
1231      *
1232      * The (zero-based) index is calculated as follows
1233      * value = current screen brightness value
1234      * level = mScreenBrighteningLevelsIdle
1235      *
1236      * condition                       return
1237      * value < level[0]                = 0.0f
1238      * level[n] <= value < level[n+1]  = mScreenBrighteningPercentagesIdle[n]
1239      * level[MAX] <= value             = mScreenBrighteningPercentagesIdle[MAX]
1240      *
1241      * @return the screen brightness levels between 0.0 and 1.0 for which each
1242      * mScreenBrighteningPercentagesIdle applies
1243      */
getScreenBrighteningLevelsIdle()1244     public float[] getScreenBrighteningLevelsIdle() {
1245         return mScreenBrighteningLevelsIdle;
1246     }
1247 
1248     /**
1249      * The array that describes the screen brightening threshold percentage change at each screen
1250      * brightness level described in mScreenBrighteningLevelsIdle.
1251      *
1252      * @return the percentages between 0 and 100 of brightness increase required in order for the
1253      * screen brightness to change while in idle mode.
1254      */
getScreenBrighteningPercentagesIdle()1255     public float[] getScreenBrighteningPercentagesIdle() {
1256         return mScreenBrighteningPercentagesIdle;
1257     }
1258 
1259     /**
1260      * The array that describes the range of screen brightness that each threshold percentage
1261      * applies within whilst in idle screen brightness mode.
1262      *
1263      * The (zero-based) index is calculated as follows
1264      * value = current screen brightness value
1265      * level = mScreenDarkeningLevelsIdle
1266      *
1267      * condition                       return
1268      * value < level[0]                = 0.0f
1269      * level[n] <= value < level[n+1]  = mScreenDarkeningPercentagesIdle[n]
1270      * level[MAX] <= value             = mScreenDarkeningPercentagesIdle[MAX]
1271      *
1272      * @return the screen brightness levels between 0.0 and 1.0 for which each
1273      * mScreenDarkeningPercentagesIdle applies
1274      */
getScreenDarkeningLevelsIdle()1275     public float[] getScreenDarkeningLevelsIdle() {
1276         return mScreenDarkeningLevelsIdle;
1277     }
1278 
1279     /**
1280      * The array that describes the screen darkening threshold percentage change at each screen
1281      * brightness level described in mScreenDarkeningLevelsIdle.
1282      *
1283      * @return the percentages between 0 and 100 of brightness decrease required in order for the
1284      * screen brightness to change while in idle mode.
1285      */
getScreenDarkeningPercentagesIdle()1286     public float[] getScreenDarkeningPercentagesIdle() {
1287         return mScreenDarkeningPercentagesIdle;
1288     }
1289 
1290     /**
1291      * The array that describes the range of ambient brightness that each threshold percentage
1292      * applies within whilst in idle screen brightness mode.
1293      *
1294      * The (zero-based) index is calculated as follows
1295      * value = current ambient brightness value
1296      * level = mAmbientBrighteningLevelsIdle
1297      *
1298      * condition                       return
1299      * value < level[0]                = 0.0f
1300      * level[n] <= value < level[n+1]  = mAmbientBrighteningPercentagesIdle[n]
1301      * level[MAX] <= value             = mAmbientBrighteningPercentagesIdle[MAX]
1302      *
1303      * @return the ambient brightness levels from 0 lux upwards for which each
1304      * mAmbientBrighteningPercentagesIdle applies
1305      */
getAmbientBrighteningLevelsIdle()1306     public float[] getAmbientBrighteningLevelsIdle() {
1307         return mAmbientBrighteningLevelsIdle;
1308     }
1309 
1310     /**
1311      * The array that describes the ambient brightness threshold percentage change whilst in
1312      * idle screen brightness mode at each ambient brightness level described in
1313      * mAmbientBrighteningLevelsIdle.
1314      *
1315      * @return the percentages between 0 and 100 of ambient brightness increase required in order
1316      * for the screen brightness to change
1317      */
getAmbientBrighteningPercentagesIdle()1318     public float[] getAmbientBrighteningPercentagesIdle() {
1319         return mAmbientBrighteningPercentagesIdle;
1320     }
1321 
1322     /**
1323      * The array that describes the range of ambient brightness that each threshold percentage
1324      * applies within whilst in idle screen brightness mode.
1325      *
1326      * The (zero-based) index is calculated as follows
1327      * value = current ambient brightness value
1328      * level = mAmbientDarkeningLevelsIdle
1329      *
1330      * condition                       return
1331      * value < level[0]                = 0.0f
1332      * level[n] <= value < level[n+1]  = mAmbientDarkeningPercentagesIdle[n]
1333      * level[MAX] <= value             = mAmbientDarkeningPercentagesIdle[MAX]
1334      *
1335      * @return the ambient brightness levels from 0 lux upwards for which each
1336      * mAmbientDarkeningPercentagesIdle applies
1337      */
getAmbientDarkeningLevelsIdle()1338     public float[] getAmbientDarkeningLevelsIdle() {
1339         return mAmbientDarkeningLevelsIdle;
1340     }
1341 
1342     /**
1343      * The array that describes the ambient brightness threshold percentage change whilst in
1344      * idle screen brightness mode at each ambient brightness level described in
1345      * mAmbientDarkeningLevelsIdle.
1346      *
1347      * @return the percentages between 0 and 100 of ambient brightness decrease required in order
1348      * for the screen brightness to change
1349      */
getAmbientDarkeningPercentagesIdle()1350     public float[] getAmbientDarkeningPercentagesIdle() {
1351         return mAmbientDarkeningPercentagesIdle;
1352     }
1353 
getAmbientLightSensor()1354     public SensorData getAmbientLightSensor() {
1355         return mAmbientLightSensor;
1356     }
1357 
getScreenOffBrightnessSensor()1358     SensorData getScreenOffBrightnessSensor() {
1359         return mScreenOffBrightnessSensor;
1360     }
1361 
1362     @Nullable
getProximitySensor()1363     public SensorData getProximitySensor() {
1364         return mProximitySensor;
1365     }
1366 
isAutoBrightnessAvailable()1367     boolean isAutoBrightnessAvailable() {
1368         return mAutoBrightnessAvailable;
1369     }
1370 
1371     /**
1372      * @param quirkValue The quirk to test.
1373      * @return {@code true} if the specified quirk is present in this configuration, {@code false}
1374      * otherwise.
1375      */
hasQuirk(String quirkValue)1376     public boolean hasQuirk(String quirkValue) {
1377         return mQuirks != null && mQuirks.contains(quirkValue);
1378     }
1379 
1380     /**
1381      * @return high brightness mode configuration data for the display.
1382      */
getHighBrightnessModeData()1383     public HighBrightnessModeData getHighBrightnessModeData() {
1384         if (!mIsHighBrightnessModeEnabled || mHbmData == null) {
1385             return null;
1386         }
1387 
1388         HighBrightnessModeData hbmData = new HighBrightnessModeData();
1389         mHbmData.copyTo(hbmData);
1390         return hbmData;
1391     }
1392 
1393     @NonNull
getLuxThrottlingData()1394     public Map<BrightnessLimitMapType, Map<Float, Float>> getLuxThrottlingData() {
1395         return mLuxThrottlingData;
1396     }
1397 
getRefreshRateLimitations()1398     public List<RefreshRateLimitation> getRefreshRateLimitations() {
1399         return mRefreshRateLimitations;
1400     }
1401 
getDensityMapping()1402     public DensityMapping getDensityMapping() {
1403         return mDensityMapping;
1404     }
1405 
1406     /**
1407      * @return brightness throttling configuration data for this display, for each throttling id.
1408      */
1409     public HashMap<String, ThermalBrightnessThrottlingData>
getThermalBrightnessThrottlingDataMapByThrottlingId()1410             getThermalBrightnessThrottlingDataMapByThrottlingId() {
1411         return mThermalBrightnessThrottlingDataMapByThrottlingId;
1412     }
1413 
1414     /**
1415      * @param id - throttling data id or null for default
1416      * @return refresh rate throttling configuration
1417      */
1418     @Nullable
getThermalRefreshRateThrottlingData( @ullable String id)1419     public SparseArray<SurfaceControl.RefreshRateRange> getThermalRefreshRateThrottlingData(
1420             @Nullable String id) {
1421         String key = id == null ? DEFAULT_ID : id;
1422         return mRefreshRateThrottlingMap.get(key);
1423     }
1424 
1425     /**
1426      * @return Auto brightness darkening light debounce
1427      */
getAutoBrightnessDarkeningLightDebounce()1428     public long getAutoBrightnessDarkeningLightDebounce() {
1429         return mAutoBrightnessDarkeningLightDebounce;
1430     }
1431 
1432     /**
1433      * @return Auto brightness brightening light debounce
1434      */
getAutoBrightnessBrighteningLightDebounce()1435     public long getAutoBrightnessBrighteningLightDebounce() {
1436         return mAutoBrightnessBrighteningLightDebounce;
1437     }
1438 
1439     /**
1440      * @return Auto brightness brightening ambient lux levels
1441      */
getAutoBrightnessBrighteningLevelsLux()1442     public float[] getAutoBrightnessBrighteningLevelsLux() {
1443         return mBrightnessLevelsLux;
1444     }
1445 
1446     /**
1447      * @return Auto brightness brightening nits levels
1448      */
getAutoBrightnessBrighteningLevelsNits()1449     public float[] getAutoBrightnessBrighteningLevelsNits() {
1450         return mBrightnessLevelsNits;
1451     }
1452 
1453     /**
1454      * @return Default peak refresh rate of the associated display
1455      */
getDefaultPeakRefreshRate()1456     public int getDefaultPeakRefreshRate() {
1457         return mDefaultPeakRefreshRate;
1458     }
1459 
1460     /**
1461      * @return Default refresh rate of the associated display
1462      */
getDefaultRefreshRate()1463     public int getDefaultRefreshRate() {
1464         return mDefaultRefreshRate;
1465     }
1466 
1467     /**
1468      * @return Default refresh rate while the device has high brightness mode enabled for HDR.
1469      */
getDefaultRefreshRateInHbmHdr()1470     public int getDefaultRefreshRateInHbmHdr() {
1471         return mDefaultRefreshRateInHbmHdr;
1472     }
1473 
1474     /**
1475      * @return Default refresh rate while the device has high brightness mode enabled because of
1476      * high lux.
1477      */
getDefaultRefreshRateInHbmSunlight()1478     public int getDefaultRefreshRateInHbmSunlight() {
1479         return mDefaultRefreshRateInHbmSunlight;
1480     }
1481 
1482     /**
1483      * @return Default refresh rate in the higher blocking zone of the associated display
1484      */
getDefaultHighBlockingZoneRefreshRate()1485     public int getDefaultHighBlockingZoneRefreshRate() {
1486         return mDefaultHighBlockingZoneRefreshRate;
1487     }
1488 
1489     /**
1490      * @return Default refresh rate in the lower blocking zone of the associated display
1491      */
getDefaultLowBlockingZoneRefreshRate()1492     public int getDefaultLowBlockingZoneRefreshRate() {
1493         return mDefaultLowBlockingZoneRefreshRate;
1494     }
1495 
1496     /**
1497      * @return Refresh rate range for specific profile id or null
1498      */
1499     @Nullable
getRefreshRange(@ullable String id)1500     public SurfaceControl.RefreshRateRange getRefreshRange(@Nullable String id) {
1501         if (TextUtils.isEmpty(id)) {
1502             return null;
1503         }
1504         return mRefreshRateZoneProfiles.get(id);
1505     }
1506 
1507     @NonNull
1508     @VisibleForTesting
getRefreshRangeProfiles()1509     Map<String, SurfaceControl.RefreshRateRange> getRefreshRangeProfiles() {
1510         return mRefreshRateZoneProfiles;
1511     }
1512 
1513     /**
1514      * @return An array of lower display brightness thresholds. This, in combination with lower
1515      * ambient brightness thresholds help define buckets in which the refresh rate switching is not
1516      * allowed.
1517      *
1518      * A negative threshold value means that only the lux threshold is applied.
1519      */
getLowDisplayBrightnessThresholds()1520     public float[] getLowDisplayBrightnessThresholds() {
1521         return mLowDisplayBrightnessThresholds;
1522     }
1523 
1524     /**
1525      * @return An array of lower ambient brightness thresholds. This, in combination with lower
1526      * display brightness thresholds help define buckets in which the refresh rate switching is not
1527      * allowed.
1528      *
1529      * A negative threshold value means that only the display brightness threshold is applied.
1530      */
getLowAmbientBrightnessThresholds()1531     public float[] getLowAmbientBrightnessThresholds() {
1532         return mLowAmbientBrightnessThresholds;
1533     }
1534 
1535     /**
1536      * @return The refresh rate thermal map for low blocking zone.
1537      */
getLowBlockingZoneThermalMap()1538     public SparseArray<SurfaceControl.RefreshRateRange> getLowBlockingZoneThermalMap() {
1539         return getThermalRefreshRateThrottlingData(mLowBlockingZoneThermalMapId);
1540     }
1541 
1542     /**
1543      * @return An array of high display brightness thresholds. This, in combination with high
1544      * ambient brightness thresholds help define buckets in which the refresh rate switching is not
1545      * allowed.
1546      *
1547      * A negative threshold value means that only the lux threshold is applied.
1548      */
getHighDisplayBrightnessThresholds()1549     public float[] getHighDisplayBrightnessThresholds() {
1550         return mHighDisplayBrightnessThresholds;
1551     }
1552 
1553     /**
1554      * @return An array of high ambient brightness thresholds. This, in combination with high
1555      * display brightness thresholds help define buckets in which the refresh rate switching is not
1556      * allowed.
1557      *
1558      * A negative threshold value means that only the display brightness threshold is applied.
1559      */
getHighAmbientBrightnessThresholds()1560     public float[] getHighAmbientBrightnessThresholds() {
1561         return mHighAmbientBrightnessThresholds;
1562     }
1563 
1564     /**
1565      * @return The refresh rate thermal map for high blocking zone.
1566      */
getHighBlockingZoneThermalMap()1567     public SparseArray<SurfaceControl.RefreshRateRange> getHighBlockingZoneThermalMap() {
1568         return getThermalRefreshRateThrottlingData(mHighBlockingZoneThermalMapId);
1569     }
1570 
1571     /**
1572      * @return A mapping from screen off brightness sensor readings to lux values. This estimates
1573      * the ambient lux when the screen is off to determine the initial brightness
1574      */
getScreenOffBrightnessSensorValueToLux()1575     public int[] getScreenOffBrightnessSensorValueToLux() {
1576         return mScreenOffBrightnessSensorValueToLux;
1577     }
1578 
1579     /**
1580      * @return The USI version supported by this display, or null if USI is not supported.
1581      * @see HostUsiVersion
1582      */
1583     @Nullable
getHostUsiVersion()1584     public HostUsiVersion getHostUsiVersion() {
1585         return mHostUsiVersion;
1586     }
1587 
1588     @Override
toString()1589     public String toString() {
1590         return "DisplayDeviceConfig{"
1591                 + "mLoadedFrom=" + mLoadedFrom
1592                 + ", mBacklight=" + Arrays.toString(mBacklight)
1593                 + ", mNits=" + Arrays.toString(mNits)
1594                 + ", mRawBacklight=" + Arrays.toString(mRawBacklight)
1595                 + ", mRawNits=" + Arrays.toString(mRawNits)
1596                 + ", mInterpolationType=" + mInterpolationType
1597                 + ", mBrightness=" + Arrays.toString(mBrightness)
1598                 + ", mBrightnessToBacklightSpline=" + mBrightnessToBacklightSpline
1599                 + ", mBacklightToBrightnessSpline=" + mBacklightToBrightnessSpline
1600                 + ", mNitsToBacklightSpline=" + mNitsToBacklightSpline
1601                 + ", mBacklightMinimum=" + mBacklightMinimum
1602                 + ", mBacklightMaximum=" + mBacklightMaximum
1603                 + ", mBrightnessDefault=" + mBrightnessDefault
1604                 + ", mQuirks=" + mQuirks
1605                 + ", isHbmEnabled=" + mIsHighBrightnessModeEnabled
1606                 + ", mLuxThrottlingData=" + mLuxThrottlingData
1607                 + ", mHbmData=" + mHbmData
1608                 + ", mSdrToHdrRatioSpline=" + mSdrToHdrRatioSpline
1609                 + ", mThermalBrightnessThrottlingDataMapByThrottlingId="
1610                 + mThermalBrightnessThrottlingDataMapByThrottlingId
1611                 + "\n"
1612                 + ", mBrightnessRampFastDecrease=" + mBrightnessRampFastDecrease
1613                 + ", mBrightnessRampFastIncrease=" + mBrightnessRampFastIncrease
1614                 + ", mBrightnessRampSlowDecrease=" + mBrightnessRampSlowDecrease
1615                 + ", mBrightnessRampSlowIncrease=" + mBrightnessRampSlowIncrease
1616                 + ", mBrightnessRampDecreaseMaxMillis=" + mBrightnessRampDecreaseMaxMillis
1617                 + ", mBrightnessRampIncreaseMaxMillis=" + mBrightnessRampIncreaseMaxMillis
1618                 + "\n"
1619                 + ", mAmbientHorizonLong=" + mAmbientHorizonLong
1620                 + ", mAmbientHorizonShort=" + mAmbientHorizonShort
1621                 + "\n"
1622                 + ", mScreenDarkeningMinThreshold=" + mScreenDarkeningMinThreshold
1623                 + ", mScreenDarkeningMinThresholdIdle=" + mScreenDarkeningMinThresholdIdle
1624                 + ", mScreenBrighteningMinThreshold=" + mScreenBrighteningMinThreshold
1625                 + ", mScreenBrighteningMinThresholdIdle=" + mScreenBrighteningMinThresholdIdle
1626                 + ", mAmbientLuxDarkeningMinThreshold=" + mAmbientLuxDarkeningMinThreshold
1627                 + ", mAmbientLuxDarkeningMinThresholdIdle=" + mAmbientLuxDarkeningMinThresholdIdle
1628                 + ", mAmbientLuxBrighteningMinThreshold=" + mAmbientLuxBrighteningMinThreshold
1629                 + ", mAmbientLuxBrighteningMinThresholdIdle="
1630                 + mAmbientLuxBrighteningMinThresholdIdle
1631                 + "\n"
1632                 + ", mScreenBrighteningLevels=" + Arrays.toString(
1633                 mScreenBrighteningLevels)
1634                 + ", mScreenBrighteningPercentages=" + Arrays.toString(
1635                 mScreenBrighteningPercentages)
1636                 + ", mScreenDarkeningLevels=" + Arrays.toString(
1637                 mScreenDarkeningLevels)
1638                 + ", mScreenDarkeningPercentages=" + Arrays.toString(
1639                 mScreenDarkeningPercentages)
1640                 + ", mAmbientBrighteningLevels=" + Arrays.toString(
1641                 mAmbientBrighteningLevels)
1642                 + ", mAmbientBrighteningPercentages=" + Arrays.toString(
1643                 mAmbientBrighteningPercentages)
1644                 + ", mAmbientDarkeningLevels=" + Arrays.toString(
1645                 mAmbientDarkeningLevels)
1646                 + ", mAmbientDarkeningPercentages=" + Arrays.toString(
1647                 mAmbientDarkeningPercentages)
1648                 + "\n"
1649                 + ", mAmbientBrighteningLevelsIdle=" + Arrays.toString(
1650                 mAmbientBrighteningLevelsIdle)
1651                 + ", mAmbientBrighteningPercentagesIdle=" + Arrays.toString(
1652                 mAmbientBrighteningPercentagesIdle)
1653                 + ", mAmbientDarkeningLevelsIdle=" + Arrays.toString(
1654                 mAmbientDarkeningLevelsIdle)
1655                 + ", mAmbientDarkeningPercentagesIdle=" + Arrays.toString(
1656                 mAmbientDarkeningPercentagesIdle)
1657                 + ", mScreenBrighteningLevelsIdle=" + Arrays.toString(
1658                 mScreenBrighteningLevelsIdle)
1659                 + ", mScreenBrighteningPercentagesIdle=" + Arrays.toString(
1660                 mScreenBrighteningPercentagesIdle)
1661                 + ", mScreenDarkeningLevelsIdle=" + Arrays.toString(
1662                 mScreenDarkeningLevelsIdle)
1663                 + ", mScreenDarkeningPercentagesIdle=" + Arrays.toString(
1664                 mScreenDarkeningPercentagesIdle)
1665                 + "\n"
1666                 + ", mAmbientLightSensor=" + mAmbientLightSensor
1667                 + ", mScreenOffBrightnessSensor=" + mScreenOffBrightnessSensor
1668                 + ", mProximitySensor=" + mProximitySensor
1669                 + ", mRefreshRateLimitations= " + Arrays.toString(mRefreshRateLimitations.toArray())
1670                 + ", mDensityMapping= " + mDensityMapping
1671                 + ", mAutoBrightnessBrighteningLightDebounce= "
1672                 + mAutoBrightnessBrighteningLightDebounce
1673                 + ", mAutoBrightnessDarkeningLightDebounce= "
1674                 + mAutoBrightnessDarkeningLightDebounce
1675                 + ", mBrightnessLevelsLux= " + Arrays.toString(mBrightnessLevelsLux)
1676                 + ", mBrightnessLevelsNits= " + Arrays.toString(mBrightnessLevelsNits)
1677                 + ", mDdcAutoBrightnessAvailable= " + mDdcAutoBrightnessAvailable
1678                 + ", mAutoBrightnessAvailable= " + mAutoBrightnessAvailable
1679                 + "\n"
1680                 + ", mDefaultLowBlockingZoneRefreshRate= " + mDefaultLowBlockingZoneRefreshRate
1681                 + ", mDefaultHighBlockingZoneRefreshRate= " + mDefaultHighBlockingZoneRefreshRate
1682                 + ", mDefaultPeakRefreshRate= " + mDefaultPeakRefreshRate
1683                 + ", mDefaultRefreshRate= " + mDefaultRefreshRate
1684                 + ", mRefreshRateZoneProfiles= " + mRefreshRateZoneProfiles
1685                 + ", mDefaultRefreshRateInHbmHdr= " + mDefaultRefreshRateInHbmHdr
1686                 + ", mDefaultRefreshRateInHbmSunlight= " + mDefaultRefreshRateInHbmSunlight
1687                 + ", mRefreshRateThrottlingMap= " + mRefreshRateThrottlingMap
1688                 + ", mLowBlockingZoneThermalMapId= " + mLowBlockingZoneThermalMapId
1689                 + ", mHighBlockingZoneThermalMapId= " + mHighBlockingZoneThermalMapId
1690                 + "\n"
1691                 + ", mLowDisplayBrightnessThresholds= "
1692                 + Arrays.toString(mLowDisplayBrightnessThresholds)
1693                 + ", mLowAmbientBrightnessThresholds= "
1694                 + Arrays.toString(mLowAmbientBrightnessThresholds)
1695                 + ", mHighDisplayBrightnessThresholds= "
1696                 + Arrays.toString(mHighDisplayBrightnessThresholds)
1697                 + ", mHighAmbientBrightnessThresholds= "
1698                 + Arrays.toString(mHighAmbientBrightnessThresholds)
1699                 + "\n"
1700                 + ", mScreenOffBrightnessSensorValueToLux=" + Arrays.toString(
1701                 mScreenOffBrightnessSensorValueToLux)
1702                 + "\n"
1703                 + ", mUsiVersion= " + mHostUsiVersion
1704                 + "}";
1705     }
1706 
getConfigFromSuffix(Context context, File baseDirectory, String suffixFormat, long idNumber)1707     private static DisplayDeviceConfig getConfigFromSuffix(Context context, File baseDirectory,
1708             String suffixFormat, long idNumber) {
1709 
1710         final String suffix = String.format(Locale.ROOT, suffixFormat, idNumber);
1711         final String filename = String.format(Locale.ROOT, CONFIG_FILE_FORMAT, suffix);
1712         final File filePath = Environment.buildPath(
1713                 baseDirectory, ETC_DIR, DISPLAY_CONFIG_DIR, filename);
1714         final DisplayDeviceConfig config = new DisplayDeviceConfig(context);
1715         if (config.initFromFile(filePath)) {
1716             return config;
1717         }
1718         return null;
1719     }
1720 
getConfigFromGlobalXml(Context context)1721     private static DisplayDeviceConfig getConfigFromGlobalXml(Context context) {
1722         DisplayDeviceConfig config = new DisplayDeviceConfig(context);
1723         config.initFromGlobalXml();
1724         return config;
1725     }
1726 
getConfigFromPmValues(Context context)1727     private static DisplayDeviceConfig getConfigFromPmValues(Context context) {
1728         DisplayDeviceConfig config = new DisplayDeviceConfig(context);
1729         config.initFromDefaultValues();
1730         return config;
1731     }
1732 
1733     @VisibleForTesting
initFromFile(File configFile)1734     boolean initFromFile(File configFile) {
1735         if (!configFile.exists()) {
1736             // Display configuration files aren't required to exist.
1737             return false;
1738         }
1739 
1740         if (!configFile.isFile()) {
1741             Slog.e(TAG, "Display configuration is not a file: " + configFile + ", skipping");
1742             return false;
1743         }
1744 
1745         try (InputStream in = new BufferedInputStream(new FileInputStream(configFile))) {
1746             final DisplayConfiguration config = XmlParser.read(in);
1747             if (config != null) {
1748                 loadName(config);
1749                 loadDensityMapping(config);
1750                 loadBrightnessDefaultFromDdcXml(config);
1751                 loadBrightnessConstraintsFromConfigXml();
1752                 loadBrightnessMap(config);
1753                 loadThermalThrottlingConfig(config);
1754                 loadHighBrightnessModeData(config);
1755                 loadLuxThrottling(config);
1756                 loadQuirks(config);
1757                 loadBrightnessRamps(config);
1758                 loadAmbientLightSensorFromDdc(config);
1759                 loadScreenOffBrightnessSensorFromDdc(config);
1760                 loadProxSensorFromDdc(config);
1761                 loadAmbientHorizonFromDdc(config);
1762                 loadBrightnessChangeThresholds(config);
1763                 loadAutoBrightnessConfigValues(config);
1764                 loadRefreshRateSetting(config);
1765                 loadScreenOffBrightnessSensorValueToLuxFromDdc(config);
1766                 loadUsiVersion(config);
1767             } else {
1768                 Slog.w(TAG, "DisplayDeviceConfig file is null");
1769             }
1770         } catch (IOException | DatatypeConfigurationException | XmlPullParserException e) {
1771             Slog.e(TAG, "Encountered an error while reading/parsing display config file: "
1772                     + configFile, e);
1773         }
1774         mLoadedFrom = configFile.toString();
1775         return true;
1776     }
1777 
initFromGlobalXml()1778     private void initFromGlobalXml() {
1779         // If no ddc exists, use config.xml
1780         loadBrightnessDefaultFromConfigXml();
1781         loadBrightnessConstraintsFromConfigXml();
1782         loadBrightnessMapFromConfigXml();
1783         loadBrightnessRampsFromConfigXml();
1784         loadAmbientLightSensorFromConfigXml();
1785         loadBrightnessChangeThresholdsFromXml();
1786         setProxSensorUnspecified();
1787         loadAutoBrightnessConfigsFromConfigXml();
1788         loadAutoBrightnessAvailableFromConfigXml();
1789         loadRefreshRateSetting(null);
1790         mLoadedFrom = "<config.xml>";
1791     }
1792 
initFromDefaultValues()1793     private void initFromDefaultValues() {
1794         // Set all to basic values
1795         mLoadedFrom = "Static values";
1796         mBacklightMinimum = PowerManager.BRIGHTNESS_MIN;
1797         mBacklightMaximum = PowerManager.BRIGHTNESS_MAX;
1798         mBrightnessDefault = BRIGHTNESS_DEFAULT;
1799         mBrightnessRampFastDecrease = PowerManager.BRIGHTNESS_MAX;
1800         mBrightnessRampFastIncrease = PowerManager.BRIGHTNESS_MAX;
1801         mBrightnessRampSlowDecrease = PowerManager.BRIGHTNESS_MAX;
1802         mBrightnessRampSlowIncrease = PowerManager.BRIGHTNESS_MAX;
1803         mBrightnessRampDecreaseMaxMillis = 0;
1804         mBrightnessRampIncreaseMaxMillis = 0;
1805         setSimpleMappingStrategyValues();
1806         loadAmbientLightSensorFromConfigXml();
1807         setProxSensorUnspecified();
1808         loadAutoBrightnessAvailableFromConfigXml();
1809     }
1810 
copyUninitializedValuesFromSecondaryConfig(DisplayConfiguration defaultConfig)1811     private void copyUninitializedValuesFromSecondaryConfig(DisplayConfiguration defaultConfig) {
1812         if (defaultConfig == null) {
1813             return;
1814         }
1815 
1816         if (mDensityMapping == null) {
1817             loadDensityMapping(defaultConfig);
1818         }
1819     }
1820 
loadName(DisplayConfiguration config)1821     private void loadName(DisplayConfiguration config) {
1822         mName = config.getName();
1823     }
1824 
loadDensityMapping(DisplayConfiguration config)1825     private void loadDensityMapping(DisplayConfiguration config) {
1826         if (config.getDensityMapping() == null) {
1827             return;
1828         }
1829 
1830         final List<Density> entriesFromXml = config.getDensityMapping().getDensity();
1831 
1832         final DensityMapping.Entry[] entries =
1833                 new DensityMapping.Entry[entriesFromXml.size()];
1834         for (int i = 0; i < entriesFromXml.size(); i++) {
1835             final Density density = entriesFromXml.get(i);
1836             entries[i] = new DensityMapping.Entry(
1837                     density.getWidth().intValue(),
1838                     density.getHeight().intValue(),
1839                     density.getDensity().intValue());
1840         }
1841         mDensityMapping = DensityMapping.createByOwning(entries);
1842     }
1843 
loadBrightnessDefaultFromDdcXml(DisplayConfiguration config)1844     private void loadBrightnessDefaultFromDdcXml(DisplayConfiguration config) {
1845         // Default brightness values are stored in the displayDeviceConfig file,
1846         // Or we fallback standard values if not.
1847         // Priority 1: Value in the displayDeviceConfig
1848         // Priority 2: Value in the config.xml (float)
1849         // Priority 3: Value in the config.xml (int)
1850         if (config != null) {
1851             BigDecimal configBrightnessDefault = config.getScreenBrightnessDefault();
1852             if (configBrightnessDefault != null) {
1853                 mBrightnessDefault = configBrightnessDefault.floatValue();
1854             } else {
1855                 loadBrightnessDefaultFromConfigXml();
1856             }
1857         }
1858     }
1859 
loadBrightnessDefaultFromConfigXml()1860     private void loadBrightnessDefaultFromConfigXml() {
1861         // Priority 1: Value in the config.xml (float)
1862         // Priority 2: Value in the config.xml (int)
1863         final float def = mContext.getResources().getFloat(com.android.internal.R.dimen
1864                 .config_screenBrightnessSettingDefaultFloat);
1865         if (def == INVALID_BRIGHTNESS_IN_CONFIG) {
1866             mBrightnessDefault = BrightnessSynchronizer.brightnessIntToFloat(
1867                     mContext.getResources().getInteger(com.android.internal.R.integer
1868                             .config_screenBrightnessSettingDefault));
1869         } else {
1870             mBrightnessDefault = def;
1871         }
1872     }
1873 
loadBrightnessConstraintsFromConfigXml()1874     private void loadBrightnessConstraintsFromConfigXml() {
1875         // TODO(b/175373898) add constraints (min / max) to ddc.
1876         final float min = mContext.getResources().getFloat(com.android.internal.R.dimen
1877                 .config_screenBrightnessSettingMinimumFloat);
1878         final float max = mContext.getResources().getFloat(com.android.internal.R.dimen
1879                 .config_screenBrightnessSettingMaximumFloat);
1880         if (min == INVALID_BRIGHTNESS_IN_CONFIG || max == INVALID_BRIGHTNESS_IN_CONFIG) {
1881             mBacklightMinimum = BrightnessSynchronizer.brightnessIntToFloat(
1882                     mContext.getResources().getInteger(com.android.internal.R.integer
1883                             .config_screenBrightnessSettingMinimum));
1884             mBacklightMaximum = BrightnessSynchronizer.brightnessIntToFloat(
1885                     mContext.getResources().getInteger(com.android.internal.R.integer
1886                             .config_screenBrightnessSettingMaximum));
1887         } else {
1888             mBacklightMinimum = min;
1889             mBacklightMaximum = max;
1890         }
1891     }
1892 
loadBrightnessMap(DisplayConfiguration config)1893     private void loadBrightnessMap(DisplayConfiguration config) {
1894         final NitsMap map = config.getScreenBrightnessMap();
1895         // Map may not exist in display device config
1896         if (map == null) {
1897             loadBrightnessMapFromConfigXml();
1898             return;
1899         }
1900 
1901         // Use the (preferred) display device config mapping
1902         final List<Point> points = map.getPoint();
1903         final int size = points.size();
1904 
1905         float[] nits = new float[size];
1906         float[] backlight = new float[size];
1907 
1908         mInterpolationType = convertInterpolationType(map.getInterpolation());
1909         int i = 0;
1910         for (Point point : points) {
1911             nits[i] = point.getNits().floatValue();
1912             backlight[i] = point.getValue().floatValue();
1913             if (i > 0) {
1914                 if (nits[i] < nits[i - 1]) {
1915                     Slog.e(TAG, "screenBrightnessMap must be non-decreasing, ignoring rest "
1916                             + " of configuration. Nits: " + nits[i] + " < " + nits[i - 1]);
1917                     return;
1918                 }
1919 
1920                 if (backlight[i] < backlight[i - 1]) {
1921                     Slog.e(TAG, "screenBrightnessMap must be non-decreasing, ignoring rest "
1922                             + " of configuration. Value: " + backlight[i] + " < "
1923                             + backlight[i - 1]);
1924                     return;
1925                 }
1926             }
1927             ++i;
1928         }
1929         mRawNits = nits;
1930         mRawBacklight = backlight;
1931         constrainNitsAndBacklightArrays();
1932     }
1933 
loadSdrHdrRatioMap(HighBrightnessMode hbmConfig)1934     private Spline loadSdrHdrRatioMap(HighBrightnessMode hbmConfig) {
1935         final SdrHdrRatioMap sdrHdrRatioMap = hbmConfig.getSdrHdrRatioMap_all();
1936 
1937         if (sdrHdrRatioMap == null) {
1938             return null;
1939         }
1940 
1941         final List<SdrHdrRatioPoint> points = sdrHdrRatioMap.getPoint();
1942         final int size = points.size();
1943         if (size <= 0) {
1944             return null;
1945         }
1946 
1947         float[] nits = new float[size];
1948         float[] ratios = new float[size];
1949 
1950         int i = 0;
1951         for (SdrHdrRatioPoint point : points) {
1952             nits[i] = point.getSdrNits().floatValue();
1953             if (i > 0) {
1954                 if (nits[i] < nits[i - 1]) {
1955                     Slog.e(TAG, "sdrHdrRatioMap must be non-decreasing, ignoring rest "
1956                             + " of configuration. nits: " + nits[i] + " < "
1957                             + nits[i - 1]);
1958                     return null;
1959                 }
1960             }
1961             ratios[i] = point.getHdrRatio().floatValue();
1962             ++i;
1963         }
1964 
1965         return Spline.createSpline(nits, ratios);
1966     }
1967 
loadThermalThrottlingConfig(DisplayConfiguration config)1968     private void loadThermalThrottlingConfig(DisplayConfiguration config) {
1969         final ThermalThrottling throttlingConfig = config.getThermalThrottling();
1970         if (throttlingConfig == null) {
1971             Slog.i(TAG, "No thermal throttling config found");
1972             return;
1973         }
1974         loadThermalBrightnessThrottlingMaps(throttlingConfig);
1975         loadThermalRefreshRateThrottlingMap(throttlingConfig);
1976     }
1977 
loadThermalBrightnessThrottlingMaps(ThermalThrottling throttlingConfig)1978     private void loadThermalBrightnessThrottlingMaps(ThermalThrottling throttlingConfig) {
1979         final List<BrightnessThrottlingMap> maps = throttlingConfig.getBrightnessThrottlingMap();
1980         if (maps == null || maps.isEmpty()) {
1981             Slog.i(TAG, "No brightness throttling map found");
1982             return;
1983         }
1984 
1985         for (BrightnessThrottlingMap map : maps) {
1986             final List<BrightnessThrottlingPoint> points = map.getBrightnessThrottlingPoint();
1987             // At least 1 point is guaranteed by the display device config schema
1988             List<ThermalBrightnessThrottlingData.ThrottlingLevel> throttlingLevels =
1989                     new ArrayList<>(points.size());
1990 
1991             boolean badConfig = false;
1992             for (BrightnessThrottlingPoint point : points) {
1993                 ThermalStatus status = point.getThermalStatus();
1994                 if (!thermalStatusIsValid(status)) {
1995                     badConfig = true;
1996                     break;
1997                 }
1998 
1999                 throttlingLevels.add(new ThermalBrightnessThrottlingData.ThrottlingLevel(
2000                         convertThermalStatus(status), point.getBrightness().floatValue()));
2001             }
2002 
2003             if (!badConfig) {
2004                 String id = map.getId() == null ? DEFAULT_ID
2005                         : map.getId();
2006                 if (mThermalBrightnessThrottlingDataMapByThrottlingId.containsKey(id)) {
2007                     throw new RuntimeException("Brightness throttling data with ID " + id
2008                             + " already exists");
2009                 }
2010                 mThermalBrightnessThrottlingDataMapByThrottlingId.put(id,
2011                         ThermalBrightnessThrottlingData.create(throttlingLevels));
2012             }
2013         }
2014     }
2015 
loadThermalRefreshRateThrottlingMap(ThermalThrottling throttlingConfig)2016     private void loadThermalRefreshRateThrottlingMap(ThermalThrottling throttlingConfig) {
2017         List<RefreshRateThrottlingMap> maps = throttlingConfig.getRefreshRateThrottlingMap();
2018         if (maps == null || maps.isEmpty()) {
2019             Slog.w(TAG, "RefreshRateThrottling: map not found");
2020             return;
2021         }
2022 
2023         for (RefreshRateThrottlingMap map : maps) {
2024             List<RefreshRateThrottlingPoint> points = map.getRefreshRateThrottlingPoint();
2025             String id = map.getId() == null ? DEFAULT_ID : map.getId();
2026 
2027             if (points == null || points.isEmpty()) {
2028                 // Expected at lease 1 throttling point for each map
2029                 Slog.w(TAG, "RefreshRateThrottling: points not found for mapId=" + id);
2030                 continue;
2031             }
2032             if (mRefreshRateThrottlingMap.containsKey(id)) {
2033                 Slog.wtf(TAG, "RefreshRateThrottling: map already exists, mapId=" + id);
2034                 continue;
2035             }
2036 
2037             SparseArray<SurfaceControl.RefreshRateRange> refreshRates = new SparseArray<>();
2038             for (RefreshRateThrottlingPoint point : points) {
2039                 ThermalStatus status = point.getThermalStatus();
2040                 if (!thermalStatusIsValid(status)) {
2041                     Slog.wtf(TAG,
2042                             "RefreshRateThrottling: Invalid thermalStatus=" + status.getRawName()
2043                                     + ",mapId=" + id);
2044                     continue;
2045                 }
2046                 int thermalStatusInt = convertThermalStatus(status);
2047                 if (refreshRates.contains(thermalStatusInt)) {
2048                     Slog.wtf(TAG, "RefreshRateThrottling: thermalStatus=" + status.getRawName()
2049                             + " is already in the map, mapId=" + id);
2050                     continue;
2051                 }
2052 
2053                 refreshRates.put(thermalStatusInt, new SurfaceControl.RefreshRateRange(
2054                         point.getRefreshRateRange().getMinimum().floatValue(),
2055                         point.getRefreshRateRange().getMaximum().floatValue()
2056                 ));
2057             }
2058             if (refreshRates.size() == 0) {
2059                 Slog.w(TAG, "RefreshRateThrottling: no valid throttling points found for map, "
2060                         + "mapId=" + id);
2061                 continue;
2062             }
2063             mRefreshRateThrottlingMap.put(id, refreshRates);
2064         }
2065     }
2066 
loadRefreshRateSetting(DisplayConfiguration config)2067     private void loadRefreshRateSetting(DisplayConfiguration config) {
2068         final RefreshRateConfigs refreshRateConfigs =
2069                 (config == null) ? null : config.getRefreshRate();
2070         BlockingZoneConfig lowerBlockingZoneConfig =
2071                 (refreshRateConfigs == null) ? null
2072                         : refreshRateConfigs.getLowerBlockingZoneConfigs();
2073         BlockingZoneConfig higherBlockingZoneConfig =
2074                 (refreshRateConfigs == null) ? null
2075                         : refreshRateConfigs.getHigherBlockingZoneConfigs();
2076         loadPeakDefaultRefreshRate(refreshRateConfigs);
2077         loadDefaultRefreshRate(refreshRateConfigs);
2078         loadDefaultRefreshRateInHbm(refreshRateConfigs);
2079         loadLowerRefreshRateBlockingZones(lowerBlockingZoneConfig);
2080         loadHigherRefreshRateBlockingZones(higherBlockingZoneConfig);
2081         loadRefreshRateZoneProfiles(refreshRateConfigs);
2082     }
2083 
loadPeakDefaultRefreshRate(RefreshRateConfigs refreshRateConfigs)2084     private void loadPeakDefaultRefreshRate(RefreshRateConfigs refreshRateConfigs) {
2085         if (refreshRateConfigs == null || refreshRateConfigs.getDefaultPeakRefreshRate() == null) {
2086             mDefaultPeakRefreshRate = mContext.getResources().getInteger(
2087                 R.integer.config_defaultPeakRefreshRate);
2088         } else {
2089             mDefaultPeakRefreshRate =
2090                 refreshRateConfigs.getDefaultPeakRefreshRate().intValue();
2091         }
2092     }
2093 
loadDefaultRefreshRate(RefreshRateConfigs refreshRateConfigs)2094     private void loadDefaultRefreshRate(RefreshRateConfigs refreshRateConfigs) {
2095         if (refreshRateConfigs == null || refreshRateConfigs.getDefaultRefreshRate() == null) {
2096             mDefaultRefreshRate = mContext.getResources().getInteger(
2097                 R.integer.config_defaultRefreshRate);
2098         } else {
2099             mDefaultRefreshRate =
2100                 refreshRateConfigs.getDefaultRefreshRate().intValue();
2101         }
2102     }
2103 
2104     /** Loads the refresh rate profiles. */
loadRefreshRateZoneProfiles(RefreshRateConfigs refreshRateConfigs)2105     private void loadRefreshRateZoneProfiles(RefreshRateConfigs refreshRateConfigs) {
2106         if (refreshRateConfigs == null || refreshRateConfigs.getRefreshRateZoneProfiles() == null) {
2107             return;
2108         }
2109         for (RefreshRateZone zone :
2110                 refreshRateConfigs.getRefreshRateZoneProfiles().getRefreshRateZoneProfile()) {
2111             RefreshRateRange range = zone.getRefreshRateRange();
2112             mRefreshRateZoneProfiles.put(
2113                     zone.getId(),
2114                     new SurfaceControl.RefreshRateRange(
2115                     range.getMinimum().floatValue(), range.getMaximum().floatValue()));
2116         }
2117     }
2118 
loadDefaultRefreshRateInHbm(RefreshRateConfigs refreshRateConfigs)2119     private void loadDefaultRefreshRateInHbm(RefreshRateConfigs refreshRateConfigs) {
2120         if (refreshRateConfigs != null
2121                 && refreshRateConfigs.getDefaultRefreshRateInHbmHdr() != null) {
2122             mDefaultRefreshRateInHbmHdr = refreshRateConfigs.getDefaultRefreshRateInHbmHdr()
2123                     .intValue();
2124         } else {
2125             mDefaultRefreshRateInHbmHdr = mContext.getResources().getInteger(
2126                     R.integer.config_defaultRefreshRateInHbmHdr);
2127         }
2128 
2129         if (refreshRateConfigs != null
2130                 && refreshRateConfigs.getDefaultRefreshRateInHbmSunlight() != null) {
2131             mDefaultRefreshRateInHbmSunlight =
2132                     refreshRateConfigs.getDefaultRefreshRateInHbmSunlight().intValue();
2133         } else {
2134             mDefaultRefreshRateInHbmSunlight = mContext.getResources().getInteger(
2135                 R.integer.config_defaultRefreshRateInHbmSunlight);
2136         }
2137     }
2138 
2139     /**
2140      * Loads the refresh rate configurations pertaining to the lower blocking zones.
2141      */
loadLowerRefreshRateBlockingZones(BlockingZoneConfig lowerBlockingZoneConfig)2142     private void loadLowerRefreshRateBlockingZones(BlockingZoneConfig lowerBlockingZoneConfig) {
2143         if (lowerBlockingZoneConfig != null) {
2144             mLowBlockingZoneThermalMapId =
2145                     lowerBlockingZoneConfig.getRefreshRateThermalThrottlingId();
2146         }
2147         loadLowerBlockingZoneDefaultRefreshRate(lowerBlockingZoneConfig);
2148         loadLowerBrightnessThresholds(lowerBlockingZoneConfig);
2149     }
2150 
2151     /**
2152      * Loads the refresh rate configurations pertaining to the upper blocking zones.
2153      */
loadHigherRefreshRateBlockingZones(BlockingZoneConfig upperBlockingZoneConfig)2154     private void loadHigherRefreshRateBlockingZones(BlockingZoneConfig upperBlockingZoneConfig) {
2155         if (upperBlockingZoneConfig != null) {
2156             mHighBlockingZoneThermalMapId =
2157                     upperBlockingZoneConfig.getRefreshRateThermalThrottlingId();
2158         }
2159         loadHigherBlockingZoneDefaultRefreshRate(upperBlockingZoneConfig);
2160         loadHigherBrightnessThresholds(upperBlockingZoneConfig);
2161     }
2162 
2163     /**
2164      * Loads the default peak refresh rate. Internally, this takes care of loading
2165      * the value from the display config, and if not present, falls back to config.xml.
2166      */
loadHigherBlockingZoneDefaultRefreshRate( BlockingZoneConfig upperBlockingZoneConfig)2167     private void loadHigherBlockingZoneDefaultRefreshRate(
2168                 BlockingZoneConfig upperBlockingZoneConfig) {
2169         if (upperBlockingZoneConfig == null) {
2170             mDefaultHighBlockingZoneRefreshRate = mContext.getResources().getInteger(
2171                 com.android.internal.R.integer.config_fixedRefreshRateInHighZone);
2172         } else {
2173             mDefaultHighBlockingZoneRefreshRate =
2174                 upperBlockingZoneConfig.getDefaultRefreshRate().intValue();
2175         }
2176     }
2177 
2178     /**
2179      * Loads the default refresh rate. Internally, this takes care of loading
2180      * the value from the display config, and if not present, falls back to config.xml.
2181      */
loadLowerBlockingZoneDefaultRefreshRate( BlockingZoneConfig lowerBlockingZoneConfig)2182     private void loadLowerBlockingZoneDefaultRefreshRate(
2183                 BlockingZoneConfig lowerBlockingZoneConfig) {
2184         if (lowerBlockingZoneConfig == null) {
2185             mDefaultLowBlockingZoneRefreshRate = mContext.getResources().getInteger(
2186                 com.android.internal.R.integer.config_defaultRefreshRateInZone);
2187         } else {
2188             mDefaultLowBlockingZoneRefreshRate =
2189                 lowerBlockingZoneConfig.getDefaultRefreshRate().intValue();
2190         }
2191     }
2192 
2193     /**
2194      * Loads the lower brightness thresholds for refresh rate switching. Internally, this takes care
2195      * of loading the value from the display config, and if not present, falls back to config.xml.
2196      */
loadLowerBrightnessThresholds(BlockingZoneConfig lowerBlockingZoneConfig)2197     private void loadLowerBrightnessThresholds(BlockingZoneConfig lowerBlockingZoneConfig) {
2198         if (lowerBlockingZoneConfig == null) {
2199             int[] lowDisplayBrightnessThresholdsInt = mContext.getResources().getIntArray(
2200                 R.array.config_brightnessThresholdsOfPeakRefreshRate);
2201             int[] lowAmbientBrightnessThresholdsInt = mContext.getResources().getIntArray(
2202                 R.array.config_ambientThresholdsOfPeakRefreshRate);
2203             if (lowDisplayBrightnessThresholdsInt == null
2204                     || lowAmbientBrightnessThresholdsInt == null
2205                     || lowDisplayBrightnessThresholdsInt.length
2206                     != lowAmbientBrightnessThresholdsInt.length) {
2207                 throw new RuntimeException("display low brightness threshold array and ambient "
2208                     + "brightness threshold array have different length: "
2209                     + "lowDisplayBrightnessThresholdsInt="
2210                     + Arrays.toString(lowDisplayBrightnessThresholdsInt)
2211                     + ", lowAmbientBrightnessThresholdsInt="
2212                     + Arrays.toString(lowAmbientBrightnessThresholdsInt));
2213             }
2214 
2215             mLowDisplayBrightnessThresholds =
2216                     displayBrightnessThresholdsIntToFloat(lowDisplayBrightnessThresholdsInt);
2217             mLowAmbientBrightnessThresholds =
2218                     ambientBrightnessThresholdsIntToFloat(lowAmbientBrightnessThresholdsInt);
2219         } else {
2220             List<DisplayBrightnessPoint> lowerThresholdDisplayBrightnessPoints =
2221                     lowerBlockingZoneConfig.getBlockingZoneThreshold().getDisplayBrightnessPoint();
2222             int size = lowerThresholdDisplayBrightnessPoints.size();
2223             mLowDisplayBrightnessThresholds = new float[size];
2224             mLowAmbientBrightnessThresholds = new float[size];
2225             for (int i = 0; i < size; i++) {
2226                 float thresholdNits = lowerThresholdDisplayBrightnessPoints
2227                         .get(i).getNits().floatValue();
2228                 if (thresholdNits < 0) {
2229                     // A negative value means that there's no threshold
2230                     mLowDisplayBrightnessThresholds[i] = thresholdNits;
2231                 } else {
2232                     float thresholdBacklight = mNitsToBacklightSpline.interpolate(thresholdNits);
2233                     mLowDisplayBrightnessThresholds[i] =
2234                             mBacklightToBrightnessSpline.interpolate(thresholdBacklight);
2235                 }
2236 
2237                 mLowAmbientBrightnessThresholds[i] = lowerThresholdDisplayBrightnessPoints
2238                     .get(i).getLux().floatValue();
2239             }
2240         }
2241     }
2242 
2243     /**
2244      * Loads the higher brightness thresholds for refresh rate switching. Internally, this takes
2245      * care of loading the value from the display config, and if not present, falls back to
2246      * config.xml.
2247      */
loadHigherBrightnessThresholds(BlockingZoneConfig blockingZoneConfig)2248     private void loadHigherBrightnessThresholds(BlockingZoneConfig blockingZoneConfig) {
2249         if (blockingZoneConfig == null) {
2250             int[] highDisplayBrightnessThresholdsInt = mContext.getResources().getIntArray(
2251                 R.array.config_highDisplayBrightnessThresholdsOfFixedRefreshRate);
2252             int[] highAmbientBrightnessThresholdsInt = mContext.getResources().getIntArray(
2253                 R.array.config_highAmbientBrightnessThresholdsOfFixedRefreshRate);
2254             if (highDisplayBrightnessThresholdsInt == null
2255                     || highAmbientBrightnessThresholdsInt == null
2256                     || highDisplayBrightnessThresholdsInt.length
2257                     != highAmbientBrightnessThresholdsInt.length) {
2258                 throw new RuntimeException("display high brightness threshold array and ambient "
2259                     + "brightness threshold array have different length: "
2260                     + "highDisplayBrightnessThresholdsInt="
2261                     + Arrays.toString(highDisplayBrightnessThresholdsInt)
2262                     + ", highAmbientBrightnessThresholdsInt="
2263                     + Arrays.toString(highAmbientBrightnessThresholdsInt));
2264             }
2265 
2266             mHighDisplayBrightnessThresholds =
2267                     displayBrightnessThresholdsIntToFloat(highDisplayBrightnessThresholdsInt);
2268             mHighAmbientBrightnessThresholds =
2269                     ambientBrightnessThresholdsIntToFloat(highAmbientBrightnessThresholdsInt);
2270         } else {
2271             List<DisplayBrightnessPoint> higherThresholdDisplayBrightnessPoints =
2272                     blockingZoneConfig.getBlockingZoneThreshold().getDisplayBrightnessPoint();
2273             int size = higherThresholdDisplayBrightnessPoints.size();
2274             mHighDisplayBrightnessThresholds = new float[size];
2275             mHighAmbientBrightnessThresholds = new float[size];
2276             for (int i = 0; i < size; i++) {
2277                 float thresholdNits = higherThresholdDisplayBrightnessPoints
2278                         .get(i).getNits().floatValue();
2279                 if (thresholdNits < 0) {
2280                     // A negative value means that there's no threshold
2281                     mHighDisplayBrightnessThresholds[i] = thresholdNits;
2282                 } else {
2283                     float thresholdBacklight = mNitsToBacklightSpline.interpolate(thresholdNits);
2284                     mHighDisplayBrightnessThresholds[i] =
2285                             mBacklightToBrightnessSpline.interpolate(thresholdBacklight);
2286                 }
2287 
2288                 mHighAmbientBrightnessThresholds[i] = higherThresholdDisplayBrightnessPoints
2289                     .get(i).getLux().floatValue();
2290             }
2291         }
2292     }
2293 
loadAutoBrightnessConfigValues(DisplayConfiguration config)2294     private void loadAutoBrightnessConfigValues(DisplayConfiguration config) {
2295         final AutoBrightness autoBrightness = config.getAutoBrightness();
2296         loadAutoBrightnessBrighteningLightDebounce(autoBrightness);
2297         loadAutoBrightnessDarkeningLightDebounce(autoBrightness);
2298         loadAutoBrightnessDisplayBrightnessMapping(autoBrightness);
2299         loadEnableAutoBrightness(autoBrightness);
2300     }
2301 
2302     /**
2303      * Loads the auto-brightness brightening light debounce. Internally, this takes care of loading
2304      * the value from the display config, and if not present, falls back to config.xml.
2305      */
loadAutoBrightnessBrighteningLightDebounce(AutoBrightness autoBrightnessConfig)2306     private void loadAutoBrightnessBrighteningLightDebounce(AutoBrightness autoBrightnessConfig) {
2307         if (autoBrightnessConfig == null
2308                 || autoBrightnessConfig.getBrighteningLightDebounceMillis() == null) {
2309             mAutoBrightnessBrighteningLightDebounce = mContext.getResources().getInteger(
2310                     com.android.internal.R.integer.config_autoBrightnessBrighteningLightDebounce);
2311         } else {
2312             mAutoBrightnessBrighteningLightDebounce =
2313                     autoBrightnessConfig.getBrighteningLightDebounceMillis().intValue();
2314         }
2315     }
2316 
2317     /**
2318      * Loads the auto-brightness darkening light debounce. Internally, this takes care of loading
2319      * the value from the display config, and if not present, falls back to config.xml.
2320      */
loadAutoBrightnessDarkeningLightDebounce(AutoBrightness autoBrightnessConfig)2321     private void loadAutoBrightnessDarkeningLightDebounce(AutoBrightness autoBrightnessConfig) {
2322         if (autoBrightnessConfig == null
2323                 || autoBrightnessConfig.getDarkeningLightDebounceMillis() == null) {
2324             mAutoBrightnessDarkeningLightDebounce = mContext.getResources().getInteger(
2325                     com.android.internal.R.integer.config_autoBrightnessDarkeningLightDebounce);
2326         } else {
2327             mAutoBrightnessDarkeningLightDebounce =
2328                     autoBrightnessConfig.getDarkeningLightDebounceMillis().intValue();
2329         }
2330     }
2331 
2332     /**
2333      * Loads the auto-brightness display brightness mappings. Internally, this takes care of
2334      * loading the value from the display config, and if not present, falls back to config.xml.
2335      */
loadAutoBrightnessDisplayBrightnessMapping(AutoBrightness autoBrightnessConfig)2336     private void loadAutoBrightnessDisplayBrightnessMapping(AutoBrightness autoBrightnessConfig) {
2337         if (autoBrightnessConfig == null
2338                 || autoBrightnessConfig.getDisplayBrightnessMapping() == null) {
2339             mBrightnessLevelsNits = getFloatArray(mContext.getResources()
2340                     .obtainTypedArray(com.android.internal.R.array
2341                             .config_autoBrightnessDisplayValuesNits), PowerManager
2342                     .BRIGHTNESS_OFF_FLOAT);
2343             mBrightnessLevelsLux = getLuxLevels(mContext.getResources()
2344                     .getIntArray(com.android.internal.R.array
2345                             .config_autoBrightnessLevels));
2346         } else {
2347             final int size = autoBrightnessConfig.getDisplayBrightnessMapping()
2348                     .getDisplayBrightnessPoint().size();
2349             mBrightnessLevelsNits = new float[size];
2350             // The first control point is implicit and always at 0 lux.
2351             mBrightnessLevelsLux = new float[size + 1];
2352             for (int i = 0; i < size; i++) {
2353                 mBrightnessLevelsNits[i] = autoBrightnessConfig.getDisplayBrightnessMapping()
2354                         .getDisplayBrightnessPoint().get(i).getNits().floatValue();
2355                 mBrightnessLevelsLux[i + 1] = autoBrightnessConfig.getDisplayBrightnessMapping()
2356                         .getDisplayBrightnessPoint().get(i).getLux().floatValue();
2357             }
2358         }
2359     }
2360 
loadAutoBrightnessAvailableFromConfigXml()2361     private void loadAutoBrightnessAvailableFromConfigXml() {
2362         mAutoBrightnessAvailable = mContext.getResources().getBoolean(
2363                 R.bool.config_automatic_brightness_available);
2364     }
2365 
loadBrightnessMapFromConfigXml()2366     private void loadBrightnessMapFromConfigXml() {
2367         // Use the config.xml mapping
2368         final Resources res = mContext.getResources();
2369         final float[] sysNits = BrightnessMappingStrategy.getFloatArray(res.obtainTypedArray(
2370                 com.android.internal.R.array.config_screenBrightnessNits));
2371         final int[] sysBrightness = res.getIntArray(
2372                 com.android.internal.R.array.config_screenBrightnessBacklight);
2373         final float[] sysBrightnessFloat = new float[sysBrightness.length];
2374 
2375         for (int i = 0; i < sysBrightness.length; i++) {
2376             sysBrightnessFloat[i] = BrightnessSynchronizer.brightnessIntToFloat(
2377                     sysBrightness[i]);
2378         }
2379 
2380         // These arrays are allowed to be empty, we set null values so that
2381         // BrightnessMappingStrategy will create a SimpleMappingStrategy instead.
2382         if (sysBrightnessFloat.length == 0 || sysNits.length == 0) {
2383             setSimpleMappingStrategyValues();
2384             return;
2385         }
2386 
2387         mRawNits = sysNits;
2388         mRawBacklight = sysBrightnessFloat;
2389         constrainNitsAndBacklightArrays();
2390     }
2391 
setSimpleMappingStrategyValues()2392     private void setSimpleMappingStrategyValues() {
2393         // No translation from backlight to brightness should occur if we are using a
2394         // SimpleMappingStrategy (ie they should be the same) so the splines are
2395         // set to be linear, between 0.0 and 1.0
2396         mNits = null;
2397         mBacklight = null;
2398         float[] simpleMappingStrategyArray = new float[]{0.0f, 1.0f};
2399         mBrightnessToBacklightSpline = Spline.createSpline(simpleMappingStrategyArray,
2400                 simpleMappingStrategyArray);
2401         mBacklightToBrightnessSpline = Spline.createSpline(simpleMappingStrategyArray,
2402                 simpleMappingStrategyArray);
2403     }
2404 
2405     /**
2406      * Change the nits and backlight arrays, so that they cover only the allowed backlight values
2407      * Use the brightness minimum and maximum values to clamp these arrays.
2408      */
constrainNitsAndBacklightArrays()2409     private void constrainNitsAndBacklightArrays() {
2410         if (mRawBacklight[0] > mBacklightMinimum
2411                 || mRawBacklight[mRawBacklight.length - 1] < mBacklightMaximum
2412                 || mBacklightMinimum > mBacklightMaximum) {
2413             throw new IllegalStateException("Min or max values are invalid"
2414                     + "; raw min=" + mRawBacklight[0]
2415                     + "; raw max=" + mRawBacklight[mRawBacklight.length - 1]
2416                     + "; backlight min=" + mBacklightMinimum
2417                     + "; backlight max=" + mBacklightMaximum);
2418         }
2419 
2420         float[] newNits = new float[mRawBacklight.length];
2421         float[] newBacklight = new float[mRawBacklight.length];
2422         // Find the starting index of the clamped arrays. This may be less than the min so
2423         // we'll need to clamp this value still when actually doing the remapping.
2424         int newStart = 0;
2425         for (int i = 0; i < mRawBacklight.length - 1; i++) {
2426             if (mRawBacklight[i + 1] > mBacklightMinimum) {
2427                 newStart = i;
2428                 break;
2429             }
2430         }
2431 
2432         boolean isLastValue = false;
2433         int newIndex = 0;
2434         for (int i = newStart; i < mRawBacklight.length && !isLastValue; i++) {
2435             newIndex = i - newStart;
2436             final float newBacklightVal;
2437             final float newNitsVal;
2438             isLastValue = mRawBacklight[i] >= mBacklightMaximum
2439                     || i >= mRawBacklight.length - 1;
2440             // Clamp beginning and end to valid backlight values.
2441             if (newIndex == 0) {
2442                 newBacklightVal = MathUtils.max(mRawBacklight[i], mBacklightMinimum);
2443                 newNitsVal = rawBacklightToNits(i, newBacklightVal);
2444             } else if (isLastValue) {
2445                 newBacklightVal = MathUtils.min(mRawBacklight[i], mBacklightMaximum);
2446                 newNitsVal = rawBacklightToNits(i - 1, newBacklightVal);
2447             } else {
2448                 newBacklightVal = mRawBacklight[i];
2449                 newNitsVal = mRawNits[i];
2450             }
2451             newBacklight[newIndex] = newBacklightVal;
2452             newNits[newIndex] = newNitsVal;
2453         }
2454         mBacklight = Arrays.copyOf(newBacklight, newIndex + 1);
2455         mNits = Arrays.copyOf(newNits, newIndex + 1);
2456         createBacklightConversionSplines();
2457     }
2458 
rawBacklightToNits(int i, float backlight)2459     private float rawBacklightToNits(int i, float backlight) {
2460         return MathUtils.map(mRawBacklight[i], mRawBacklight[i + 1],
2461                 mRawNits[i], mRawNits[i + 1], backlight);
2462     }
2463 
2464     // This method creates a brightness spline that is of equal length with proportional increments
2465     // to the backlight spline. The values of this array range from 0.0f to 1.0f instead of the
2466     // potential constrained range that the backlight array covers
2467     // These splines are used to convert from the system brightness value to the HAL backlight
2468     // value
createBacklightConversionSplines()2469     private void createBacklightConversionSplines() {
2470         mBrightness = new float[mBacklight.length];
2471         for (int i = 0; i < mBrightness.length; i++) {
2472             mBrightness[i] = MathUtils.map(mBacklight[0],
2473                     mBacklight[mBacklight.length - 1],
2474                     PowerManager.BRIGHTNESS_MIN, PowerManager.BRIGHTNESS_MAX, mBacklight[i]);
2475         }
2476         mBrightnessToBacklightSpline = mInterpolationType == INTERPOLATION_LINEAR
2477                 ? Spline.createLinearSpline(mBrightness, mBacklight)
2478                 : Spline.createSpline(mBrightness, mBacklight);
2479         mBacklightToBrightnessSpline = mInterpolationType == INTERPOLATION_LINEAR
2480                 ? Spline.createLinearSpline(mBacklight, mBrightness)
2481                 : Spline.createSpline(mBacklight, mBrightness);
2482         mBacklightToNitsSpline = mInterpolationType == INTERPOLATION_LINEAR
2483                 ? Spline.createLinearSpline(mBacklight, mNits)
2484                 : Spline.createSpline(mBacklight, mNits);
2485         mNitsToBacklightSpline = mInterpolationType == INTERPOLATION_LINEAR
2486                 ? Spline.createLinearSpline(mNits, mBacklight)
2487                 : Spline.createSpline(mNits, mBacklight);
2488     }
2489 
loadQuirks(DisplayConfiguration config)2490     private void loadQuirks(DisplayConfiguration config) {
2491         final DisplayQuirks quirks = config.getQuirks();
2492         if (quirks != null) {
2493             mQuirks = new ArrayList<>(quirks.getQuirk());
2494         }
2495     }
2496 
loadHighBrightnessModeData(DisplayConfiguration config)2497     private void loadHighBrightnessModeData(DisplayConfiguration config) {
2498         final HighBrightnessMode hbm = config.getHighBrightnessMode();
2499         if (hbm != null) {
2500             mIsHighBrightnessModeEnabled = hbm.getEnabled();
2501             mHbmData = new HighBrightnessModeData();
2502             mHbmData.minimumLux = hbm.getMinimumLux_all().floatValue();
2503             float transitionPointBacklightScale = hbm.getTransitionPoint_all().floatValue();
2504             if (transitionPointBacklightScale >= mBacklightMaximum) {
2505                 throw new IllegalArgumentException("HBM transition point invalid. "
2506                         + mHbmData.transitionPoint + " is not less than "
2507                         + mBacklightMaximum);
2508             }
2509             mHbmData.transitionPoint =
2510                     mBacklightToBrightnessSpline.interpolate(transitionPointBacklightScale);
2511             final HbmTiming hbmTiming = hbm.getTiming_all();
2512             mHbmData.timeWindowMillis = hbmTiming.getTimeWindowSecs_all().longValue() * 1000;
2513             mHbmData.timeMaxMillis = hbmTiming.getTimeMaxSecs_all().longValue() * 1000;
2514             mHbmData.timeMinMillis = hbmTiming.getTimeMinSecs_all().longValue() * 1000;
2515             mHbmData.allowInLowPowerMode = hbm.getAllowInLowPowerMode_all();
2516             final RefreshRateRange rr = hbm.getRefreshRate_all();
2517             if (rr != null) {
2518                 final float min = rr.getMinimum().floatValue();
2519                 final float max = rr.getMaximum().floatValue();
2520                 mRefreshRateLimitations.add(new RefreshRateLimitation(
2521                         DisplayManagerInternal.REFRESH_RATE_LIMIT_HIGH_BRIGHTNESS_MODE, min, max));
2522             }
2523             BigDecimal minHdrPctOfScreen = hbm.getMinimumHdrPercentOfScreen_all();
2524             if (minHdrPctOfScreen != null) {
2525                 mHbmData.minimumHdrPercentOfScreen = minHdrPctOfScreen.floatValue();
2526                 if (mHbmData.minimumHdrPercentOfScreen > 1
2527                         || mHbmData.minimumHdrPercentOfScreen < 0) {
2528                     Slog.w(TAG, "Invalid minimum HDR percent of screen: "
2529                             + String.valueOf(mHbmData.minimumHdrPercentOfScreen));
2530                     mHbmData.minimumHdrPercentOfScreen = HDR_PERCENT_OF_SCREEN_REQUIRED_DEFAULT;
2531                 }
2532             } else {
2533                 mHbmData.minimumHdrPercentOfScreen = HDR_PERCENT_OF_SCREEN_REQUIRED_DEFAULT;
2534             }
2535 
2536             mSdrToHdrRatioSpline = loadSdrHdrRatioMap(hbm);
2537         }
2538     }
2539 
loadLuxThrottling(DisplayConfiguration config)2540     private void loadLuxThrottling(DisplayConfiguration config) {
2541         LuxThrottling cfg = config.getLuxThrottling();
2542         if (cfg != null) {
2543             HighBrightnessMode hbm = config.getHighBrightnessMode();
2544             float hbmTransitionPoint = hbm != null ? hbm.getTransitionPoint_all().floatValue()
2545                     : PowerManager.BRIGHTNESS_MAX;
2546             List<BrightnessLimitMap> limitMaps = cfg.getBrightnessLimitMap();
2547             for (BrightnessLimitMap map : limitMaps) {
2548                 PredefinedBrightnessLimitNames type = map.getType();
2549                 BrightnessLimitMapType mappedType = BrightnessLimitMapType.convert(type);
2550                 if (mappedType == null) {
2551                     Slog.wtf(TAG, "Invalid NBM config: unsupported map type=" + type);
2552                     continue;
2553                 }
2554                 if (mLuxThrottlingData.containsKey(mappedType)) {
2555                     Slog.wtf(TAG, "Invalid NBM config: duplicate map type=" + mappedType);
2556                     continue;
2557                 }
2558                 Map<Float, Float> luxToTransitionPointMap = new HashMap<>();
2559 
2560                 List<NonNegativeFloatToFloatPoint> points = map.getMap().getPoint();
2561                 for (NonNegativeFloatToFloatPoint point : points) {
2562                     float lux = point.getFirst().floatValue();
2563                     float maxBrightness = point.getSecond().floatValue();
2564                     if (maxBrightness > hbmTransitionPoint) {
2565                         Slog.wtf(TAG,
2566                                 "Invalid NBM config: maxBrightness is greater than hbm"
2567                                         + ".transitionPoint. type="
2568                                         + type + "; lux=" + lux + "; maxBrightness="
2569                                         + maxBrightness);
2570                         continue;
2571                     }
2572                     if (luxToTransitionPointMap.containsKey(lux)) {
2573                         Slog.wtf(TAG,
2574                                 "Invalid NBM config: duplicate lux key. type=" + type + "; lux="
2575                                         + lux);
2576                         continue;
2577                     }
2578                     luxToTransitionPointMap.put(lux,
2579                             mBacklightToBrightnessSpline.interpolate(maxBrightness));
2580                 }
2581                 if (!luxToTransitionPointMap.isEmpty()) {
2582                     mLuxThrottlingData.put(mappedType, luxToTransitionPointMap);
2583                 }
2584             }
2585         }
2586     }
2587 
loadBrightnessRamps(DisplayConfiguration config)2588     private void loadBrightnessRamps(DisplayConfiguration config) {
2589         // Priority 1: Value in the display device config (float)
2590         // Priority 2: Value in the config.xml (int)
2591         final BigDecimal fastDownDecimal = config.getScreenBrightnessRampFastDecrease();
2592         final BigDecimal fastUpDecimal = config.getScreenBrightnessRampFastIncrease();
2593         final BigDecimal slowDownDecimal = config.getScreenBrightnessRampSlowDecrease();
2594         final BigDecimal slowUpDecimal = config.getScreenBrightnessRampSlowIncrease();
2595 
2596         if (fastDownDecimal != null && fastUpDecimal != null && slowDownDecimal != null
2597                 && slowUpDecimal != null) {
2598             mBrightnessRampFastDecrease = fastDownDecimal.floatValue();
2599             mBrightnessRampFastIncrease = fastUpDecimal.floatValue();
2600             mBrightnessRampSlowDecrease = slowDownDecimal.floatValue();
2601             mBrightnessRampSlowIncrease = slowUpDecimal.floatValue();
2602         } else {
2603             if (fastDownDecimal != null || fastUpDecimal != null || slowDownDecimal != null
2604                     || slowUpDecimal != null) {
2605                 Slog.w(TAG, "Per display brightness ramp values ignored because not all "
2606                         + "values are present in display device config");
2607             }
2608             loadBrightnessRampsFromConfigXml();
2609         }
2610 
2611         final BigInteger increaseMax = config.getScreenBrightnessRampIncreaseMaxMillis();
2612         if (increaseMax != null) {
2613             mBrightnessRampIncreaseMaxMillis = increaseMax.intValue();
2614         }
2615         final BigInteger decreaseMax = config.getScreenBrightnessRampDecreaseMaxMillis();
2616         if (decreaseMax != null) {
2617             mBrightnessRampDecreaseMaxMillis = decreaseMax.intValue();
2618         }
2619     }
2620 
loadBrightnessRampsFromConfigXml()2621     private void loadBrightnessRampsFromConfigXml() {
2622         mBrightnessRampFastIncrease = BrightnessSynchronizer.brightnessIntToFloat(
2623                 mContext.getResources().getInteger(R.integer.config_brightness_ramp_rate_fast));
2624         mBrightnessRampSlowIncrease = BrightnessSynchronizer.brightnessIntToFloat(
2625                 mContext.getResources().getInteger(R.integer.config_brightness_ramp_rate_slow));
2626         // config.xml uses the same values for both increasing and decreasing brightness
2627         // transitions so we assign them to the same values here.
2628         mBrightnessRampFastDecrease = mBrightnessRampFastIncrease;
2629         mBrightnessRampSlowDecrease = mBrightnessRampSlowIncrease;
2630     }
2631 
loadAmbientLightSensorFromConfigXml()2632     private void loadAmbientLightSensorFromConfigXml() {
2633         mAmbientLightSensor.name = "";
2634         mAmbientLightSensor.type = mContext.getResources().getString(
2635                 com.android.internal.R.string.config_displayLightSensorType);
2636     }
2637 
loadAutoBrightnessConfigsFromConfigXml()2638     private void loadAutoBrightnessConfigsFromConfigXml() {
2639         loadAutoBrightnessDisplayBrightnessMapping(null /*AutoBrightnessConfig*/);
2640     }
2641 
loadAmbientLightSensorFromDdc(DisplayConfiguration config)2642     private void loadAmbientLightSensorFromDdc(DisplayConfiguration config) {
2643         final SensorDetails sensorDetails = config.getLightSensor();
2644         if (sensorDetails != null) {
2645             loadSensorData(sensorDetails, mAmbientLightSensor);
2646         } else {
2647             loadAmbientLightSensorFromConfigXml();
2648         }
2649     }
2650 
setProxSensorUnspecified()2651     private void setProxSensorUnspecified() {
2652         mProximitySensor = new SensorData();
2653     }
2654 
loadScreenOffBrightnessSensorFromDdc(DisplayConfiguration config)2655     private void loadScreenOffBrightnessSensorFromDdc(DisplayConfiguration config) {
2656         final SensorDetails sensorDetails = config.getScreenOffBrightnessSensor();
2657         if (sensorDetails != null) {
2658             loadSensorData(sensorDetails, mScreenOffBrightnessSensor);
2659         }
2660     }
2661 
loadProxSensorFromDdc(DisplayConfiguration config)2662     private void loadProxSensorFromDdc(DisplayConfiguration config) {
2663         SensorDetails sensorDetails = config.getProxSensor();
2664         if (sensorDetails != null) {
2665             String name = sensorDetails.getName();
2666             String type = sensorDetails.getType();
2667             if ("".equals(name) && "".equals(type)) {
2668                 // <proxSensor> with empty values to the config means no sensor should be used
2669                 mProximitySensor = null;
2670             } else {
2671                 mProximitySensor = new SensorData();
2672                 loadSensorData(sensorDetails, mProximitySensor);
2673             }
2674         } else {
2675             setProxSensorUnspecified();
2676         }
2677     }
2678 
loadSensorData(@onNull SensorDetails sensorDetails, @NonNull SensorData sensorData)2679     private void loadSensorData(@NonNull SensorDetails sensorDetails,
2680             @NonNull SensorData sensorData) {
2681         sensorData.name = sensorDetails.getName();
2682         sensorData.type = sensorDetails.getType();
2683         final RefreshRateRange rr = sensorDetails.getRefreshRate();
2684         if (rr != null) {
2685             sensorData.minRefreshRate = rr.getMinimum().floatValue();
2686             sensorData.maxRefreshRate = rr.getMaximum().floatValue();
2687         }
2688     }
2689 
loadBrightnessChangeThresholdsFromXml()2690     private void loadBrightnessChangeThresholdsFromXml() {
2691         loadBrightnessChangeThresholds(/* config= */ null);
2692     }
2693 
loadBrightnessChangeThresholds(DisplayConfiguration config)2694     private void loadBrightnessChangeThresholds(DisplayConfiguration config) {
2695         loadDisplayBrightnessThresholds(config);
2696         loadAmbientBrightnessThresholds(config);
2697         loadDisplayBrightnessThresholdsIdle(config);
2698         loadAmbientBrightnessThresholdsIdle(config);
2699     }
2700 
loadDisplayBrightnessThresholds(DisplayConfiguration config)2701     private void loadDisplayBrightnessThresholds(DisplayConfiguration config) {
2702         BrightnessThresholds brighteningScreen = null;
2703         BrightnessThresholds darkeningScreen = null;
2704         if (config != null && config.getDisplayBrightnessChangeThresholds() != null) {
2705             brighteningScreen =
2706                     config.getDisplayBrightnessChangeThresholds().getBrighteningThresholds();
2707             darkeningScreen =
2708                     config.getDisplayBrightnessChangeThresholds().getDarkeningThresholds();
2709 
2710         }
2711 
2712         // Screen bright/darkening threshold levels for active mode
2713         Pair<float[], float[]> screenBrighteningPair = getBrightnessLevelAndPercentage(
2714                 brighteningScreen,
2715                 com.android.internal.R.array.config_screenThresholdLevels,
2716                 com.android.internal.R.array.config_screenBrighteningThresholds,
2717                 DEFAULT_SCREEN_THRESHOLD_LEVELS, DEFAULT_SCREEN_BRIGHTENING_THRESHOLDS,
2718                 /* potentialOldBrightnessScale= */ true);
2719 
2720         mScreenBrighteningLevels = screenBrighteningPair.first;
2721         mScreenBrighteningPercentages = screenBrighteningPair.second;
2722 
2723         Pair<float[], float[]> screenDarkeningPair = getBrightnessLevelAndPercentage(
2724                 darkeningScreen,
2725                 com.android.internal.R.array.config_screenThresholdLevels,
2726                 com.android.internal.R.array.config_screenDarkeningThresholds,
2727                 DEFAULT_SCREEN_THRESHOLD_LEVELS, DEFAULT_SCREEN_DARKENING_THRESHOLDS,
2728                 /* potentialOldBrightnessScale= */ true);
2729         mScreenDarkeningLevels = screenDarkeningPair.first;
2730         mScreenDarkeningPercentages = screenDarkeningPair.second;
2731 
2732         // Screen bright/darkening threshold minimums for active mode
2733         if (brighteningScreen != null && brighteningScreen.getMinimum() != null) {
2734             mScreenBrighteningMinThreshold = brighteningScreen.getMinimum().floatValue();
2735         }
2736         if (darkeningScreen != null && darkeningScreen.getMinimum() != null) {
2737             mScreenDarkeningMinThreshold = darkeningScreen.getMinimum().floatValue();
2738         }
2739     }
2740 
loadAmbientBrightnessThresholds(DisplayConfiguration config)2741     private void loadAmbientBrightnessThresholds(DisplayConfiguration config) {
2742         // Ambient Brightness Threshold Levels
2743         BrightnessThresholds brighteningAmbientLux = null;
2744         BrightnessThresholds darkeningAmbientLux = null;
2745         if (config != null && config.getAmbientBrightnessChangeThresholds() != null) {
2746             brighteningAmbientLux =
2747                     config.getAmbientBrightnessChangeThresholds().getBrighteningThresholds();
2748             darkeningAmbientLux =
2749                     config.getAmbientBrightnessChangeThresholds().getDarkeningThresholds();
2750         }
2751 
2752         // Ambient bright/darkening threshold levels for active mode
2753         Pair<float[], float[]> ambientBrighteningPair = getBrightnessLevelAndPercentage(
2754                 brighteningAmbientLux,
2755                 com.android.internal.R.array.config_ambientThresholdLevels,
2756                 com.android.internal.R.array.config_ambientBrighteningThresholds,
2757                 DEFAULT_AMBIENT_THRESHOLD_LEVELS, DEFAULT_AMBIENT_BRIGHTENING_THRESHOLDS);
2758         mAmbientBrighteningLevels = ambientBrighteningPair.first;
2759         mAmbientBrighteningPercentages = ambientBrighteningPair.second;
2760 
2761         Pair<float[], float[]> ambientDarkeningPair = getBrightnessLevelAndPercentage(
2762                 darkeningAmbientLux,
2763                 com.android.internal.R.array.config_ambientThresholdLevels,
2764                 com.android.internal.R.array.config_ambientDarkeningThresholds,
2765                 DEFAULT_AMBIENT_THRESHOLD_LEVELS, DEFAULT_AMBIENT_DARKENING_THRESHOLDS);
2766         mAmbientDarkeningLevels = ambientDarkeningPair.first;
2767         mAmbientDarkeningPercentages = ambientDarkeningPair.second;
2768 
2769         // Ambient bright/darkening threshold minimums for active/idle mode
2770         if (brighteningAmbientLux != null && brighteningAmbientLux.getMinimum() != null) {
2771             mAmbientLuxBrighteningMinThreshold =
2772                     brighteningAmbientLux.getMinimum().floatValue();
2773         }
2774 
2775         if (darkeningAmbientLux != null && darkeningAmbientLux.getMinimum() != null) {
2776             mAmbientLuxDarkeningMinThreshold = darkeningAmbientLux.getMinimum().floatValue();
2777         }
2778     }
2779 
loadDisplayBrightnessThresholdsIdle(DisplayConfiguration config)2780     private void loadDisplayBrightnessThresholdsIdle(DisplayConfiguration config) {
2781         BrightnessThresholds brighteningScreenIdle = null;
2782         BrightnessThresholds darkeningScreenIdle = null;
2783         if (config != null && config.getDisplayBrightnessChangeThresholdsIdle() != null) {
2784             brighteningScreenIdle =
2785                     config.getDisplayBrightnessChangeThresholdsIdle().getBrighteningThresholds();
2786             darkeningScreenIdle =
2787                     config.getDisplayBrightnessChangeThresholdsIdle().getDarkeningThresholds();
2788         }
2789 
2790         Pair<float[], float[]> screenBrighteningPair = getBrightnessLevelAndPercentage(
2791                 brighteningScreenIdle,
2792                 com.android.internal.R.array.config_screenThresholdLevels,
2793                 com.android.internal.R.array.config_screenBrighteningThresholds,
2794                 DEFAULT_SCREEN_THRESHOLD_LEVELS, DEFAULT_SCREEN_BRIGHTENING_THRESHOLDS,
2795                 /* potentialOldBrightnessScale= */ true);
2796         mScreenBrighteningLevelsIdle = screenBrighteningPair.first;
2797         mScreenBrighteningPercentagesIdle = screenBrighteningPair.second;
2798 
2799         Pair<float[], float[]> screenDarkeningPair = getBrightnessLevelAndPercentage(
2800                 darkeningScreenIdle,
2801                 com.android.internal.R.array.config_screenThresholdLevels,
2802                 com.android.internal.R.array.config_screenDarkeningThresholds,
2803                 DEFAULT_SCREEN_THRESHOLD_LEVELS, DEFAULT_SCREEN_DARKENING_THRESHOLDS,
2804                 /* potentialOldBrightnessScale= */ true);
2805         mScreenDarkeningLevelsIdle = screenDarkeningPair.first;
2806         mScreenDarkeningPercentagesIdle = screenDarkeningPair.second;
2807 
2808         if (brighteningScreenIdle != null
2809                 && brighteningScreenIdle.getMinimum() != null) {
2810             mScreenBrighteningMinThresholdIdle =
2811                     brighteningScreenIdle.getMinimum().floatValue();
2812         }
2813         if (darkeningScreenIdle != null && darkeningScreenIdle.getMinimum() != null) {
2814             mScreenDarkeningMinThresholdIdle =
2815                     darkeningScreenIdle.getMinimum().floatValue();
2816         }
2817     }
2818 
loadAmbientBrightnessThresholdsIdle(DisplayConfiguration config)2819     private void loadAmbientBrightnessThresholdsIdle(DisplayConfiguration config) {
2820         BrightnessThresholds brighteningAmbientLuxIdle = null;
2821         BrightnessThresholds darkeningAmbientLuxIdle = null;
2822         if (config != null && config.getAmbientBrightnessChangeThresholdsIdle() != null) {
2823             brighteningAmbientLuxIdle =
2824                     config.getAmbientBrightnessChangeThresholdsIdle().getBrighteningThresholds();
2825             darkeningAmbientLuxIdle =
2826                     config.getAmbientBrightnessChangeThresholdsIdle().getDarkeningThresholds();
2827         }
2828 
2829         Pair<float[], float[]> ambientBrighteningPair = getBrightnessLevelAndPercentage(
2830                 brighteningAmbientLuxIdle,
2831                 com.android.internal.R.array.config_ambientThresholdLevels,
2832                 com.android.internal.R.array.config_ambientBrighteningThresholds,
2833                 DEFAULT_AMBIENT_THRESHOLD_LEVELS, DEFAULT_AMBIENT_BRIGHTENING_THRESHOLDS);
2834         mAmbientBrighteningLevelsIdle = ambientBrighteningPair.first;
2835         mAmbientBrighteningPercentagesIdle = ambientBrighteningPair.second;
2836 
2837         Pair<float[], float[]> ambientDarkeningPair = getBrightnessLevelAndPercentage(
2838                 darkeningAmbientLuxIdle,
2839                 com.android.internal.R.array.config_ambientThresholdLevels,
2840                 com.android.internal.R.array.config_ambientDarkeningThresholds,
2841                 DEFAULT_AMBIENT_THRESHOLD_LEVELS, DEFAULT_AMBIENT_DARKENING_THRESHOLDS);
2842         mAmbientDarkeningLevelsIdle = ambientDarkeningPair.first;
2843         mAmbientDarkeningPercentagesIdle = ambientDarkeningPair.second;
2844 
2845         if (brighteningAmbientLuxIdle != null
2846                 && brighteningAmbientLuxIdle.getMinimum() != null) {
2847             mAmbientLuxBrighteningMinThresholdIdle =
2848                     brighteningAmbientLuxIdle.getMinimum().floatValue();
2849         }
2850 
2851         if (darkeningAmbientLuxIdle != null && darkeningAmbientLuxIdle.getMinimum() != null) {
2852             mAmbientLuxDarkeningMinThresholdIdle =
2853                     darkeningAmbientLuxIdle.getMinimum().floatValue();
2854         }
2855     }
2856 
getBrightnessLevelAndPercentage(BrightnessThresholds thresholds, int configFallbackThreshold, int configFallbackPercentage, float[] defaultLevels, float[] defaultPercentage)2857     private Pair<float[], float[]> getBrightnessLevelAndPercentage(BrightnessThresholds thresholds,
2858             int configFallbackThreshold, int configFallbackPercentage, float[] defaultLevels,
2859             float[] defaultPercentage) {
2860         return getBrightnessLevelAndPercentage(thresholds, configFallbackThreshold,
2861                 configFallbackPercentage, defaultLevels, defaultPercentage, false);
2862     }
2863 
2864     // Returns two float arrays, one of the brightness levels and one of the corresponding threshold
2865     // percentages for brightness levels at or above the lux value.
2866     // Historically, config.xml would have an array for brightness levels that was 1 shorter than
2867     // the levels array. Now we prepend a 0 to this array so they can be treated the same in the
2868     // rest of the framework. Values were also defined in different units (permille vs percent).
getBrightnessLevelAndPercentage(BrightnessThresholds thresholds, int configFallbackThreshold, int configFallbackPermille, float[] defaultLevels, float[] defaultPercentage, boolean potentialOldBrightnessScale)2869     private Pair<float[], float[]> getBrightnessLevelAndPercentage(BrightnessThresholds thresholds,
2870             int configFallbackThreshold, int configFallbackPermille,
2871             float[] defaultLevels, float[] defaultPercentage,
2872             boolean potentialOldBrightnessScale) {
2873         if (thresholds != null
2874                 && thresholds.getBrightnessThresholdPoints() != null
2875                 && thresholds.getBrightnessThresholdPoints()
2876                         .getBrightnessThresholdPoint().size() != 0) {
2877 
2878             // The level and percentages arrays are equal length in the ddc (new system)
2879             List<ThresholdPoint> points =
2880                     thresholds.getBrightnessThresholdPoints().getBrightnessThresholdPoint();
2881             final int size = points.size();
2882 
2883             float[] thresholdLevels = new float[size];
2884             float[] thresholdPercentages = new float[size];
2885 
2886             int i = 0;
2887             for (ThresholdPoint point : points) {
2888                 thresholdLevels[i] = point.getThreshold().floatValue();
2889                 thresholdPercentages[i] = point.getPercentage().floatValue();
2890                 i++;
2891             }
2892             return new Pair<>(thresholdLevels, thresholdPercentages);
2893         } else {
2894             // The level and percentages arrays are unequal length in config.xml (old system)
2895             // We prefix the array with a 0 value to ensure they can be handled consistently
2896             // with the new system.
2897 
2898             // Load levels array
2899             int[] configThresholdArray = mContext.getResources().getIntArray(
2900                     configFallbackThreshold);
2901             int configThresholdsSize;
2902             if (configThresholdArray == null || configThresholdArray.length == 0) {
2903                 configThresholdsSize = 1;
2904             } else {
2905                 configThresholdsSize = configThresholdArray.length + 1;
2906             }
2907 
2908 
2909             // Load percentage array
2910             int[] configPermille = mContext.getResources().getIntArray(
2911                     configFallbackPermille);
2912 
2913             // Ensure lengths match up
2914             boolean emptyArray = configPermille == null || configPermille.length == 0;
2915             if (emptyArray && configThresholdsSize == 1) {
2916                 return new Pair<>(defaultLevels, defaultPercentage);
2917             }
2918             if (emptyArray || configPermille.length != configThresholdsSize) {
2919                 throw new IllegalArgumentException(
2920                         "Brightness threshold arrays do not align in length");
2921             }
2922 
2923             // Calculate levels array
2924             float[] configThresholdWithZeroPrefixed = new float[configThresholdsSize];
2925             // Start at 1, so that 0 index value is 0.0f (default)
2926             for (int i = 1; i < configThresholdsSize; i++) {
2927                 configThresholdWithZeroPrefixed[i] = (float) configThresholdArray[i - 1];
2928             }
2929             if (potentialOldBrightnessScale) {
2930                 configThresholdWithZeroPrefixed =
2931                         constraintInRangeIfNeeded(configThresholdWithZeroPrefixed);
2932             }
2933 
2934             // Calculate percentages array
2935             float[] configPercentage = new float[configThresholdsSize];
2936             for (int i = 0; i < configPermille.length; i++) {
2937                 configPercentage[i] = configPermille[i] / 10.0f;
2938             }            return new Pair<>(configThresholdWithZeroPrefixed, configPercentage);
2939         }
2940     }
2941 
2942     /**
2943      * This check is due to historical reasons, where screen thresholdLevels used to be
2944      * integer values in the range of [0-255], but then was changed to be float values from [0,1].
2945      * To accommodate both the possibilities, we first check if all the thresholdLevels are in
2946      * [0,1], and if not, we divide all the levels with 255 to bring them down to the same scale.
2947      */
constraintInRangeIfNeeded(float[] thresholdLevels)2948     private float[] constraintInRangeIfNeeded(float[] thresholdLevels) {
2949         if (isAllInRange(thresholdLevels, /* minValueInclusive= */ 0.0f,
2950                 /* maxValueInclusive= */ 1.0f)) {
2951             return thresholdLevels;
2952         }
2953 
2954         Slog.w(TAG, "Detected screen thresholdLevels on a deprecated brightness scale");
2955         float[] thresholdLevelsScaled = new float[thresholdLevels.length];
2956         for (int index = 0; thresholdLevels.length > index; ++index) {
2957             thresholdLevelsScaled[index] = thresholdLevels[index] / 255.0f;
2958         }
2959         return thresholdLevelsScaled;
2960     }
2961 
isAllInRange(float[] configArray, float minValueInclusive, float maxValueInclusive)2962     private boolean isAllInRange(float[] configArray, float minValueInclusive,
2963             float maxValueInclusive) {
2964         for (float v : configArray) {
2965             if (v < minValueInclusive || v > maxValueInclusive) {
2966                 return false;
2967             }
2968         }
2969         return true;
2970     }
2971 
thermalStatusIsValid(ThermalStatus value)2972     private boolean thermalStatusIsValid(ThermalStatus value) {
2973         if (value == null) {
2974             return false;
2975         }
2976 
2977         switch (value) {
2978             case none:
2979             case light:
2980             case moderate:
2981             case severe:
2982             case critical:
2983             case emergency:
2984             case shutdown:
2985                 return true;
2986             default:
2987                 return false;
2988         }
2989     }
2990 
2991     @VisibleForTesting
convertThermalStatus(ThermalStatus value)2992     static @PowerManager.ThermalStatus int convertThermalStatus(ThermalStatus value) {
2993         if (value == null) {
2994             return PowerManager.THERMAL_STATUS_NONE;
2995         }
2996         switch (value) {
2997             case none:
2998                 return PowerManager.THERMAL_STATUS_NONE;
2999             case light:
3000                 return PowerManager.THERMAL_STATUS_LIGHT;
3001             case moderate:
3002                 return PowerManager.THERMAL_STATUS_MODERATE;
3003             case severe:
3004                 return PowerManager.THERMAL_STATUS_SEVERE;
3005             case critical:
3006                 return PowerManager.THERMAL_STATUS_CRITICAL;
3007             case emergency:
3008                 return PowerManager.THERMAL_STATUS_EMERGENCY;
3009             case shutdown:
3010                 return PowerManager.THERMAL_STATUS_SHUTDOWN;
3011             default:
3012                 Slog.wtf(TAG, "Unexpected Thermal Status: " + value);
3013                 return PowerManager.THERMAL_STATUS_NONE;
3014         }
3015     }
3016 
convertInterpolationType(String value)3017     private int convertInterpolationType(String value) {
3018         if (TextUtils.isEmpty(value)) {
3019             return INTERPOLATION_DEFAULT;
3020         }
3021 
3022         if ("linear".equals(value)) {
3023             return INTERPOLATION_LINEAR;
3024         }
3025 
3026         Slog.wtf(TAG, "Unexpected Interpolation Type: " + value);
3027         return INTERPOLATION_DEFAULT;
3028     }
3029 
loadAmbientHorizonFromDdc(DisplayConfiguration config)3030     private void loadAmbientHorizonFromDdc(DisplayConfiguration config) {
3031         final BigInteger configLongHorizon = config.getAmbientLightHorizonLong();
3032         if (configLongHorizon != null) {
3033             mAmbientHorizonLong = configLongHorizon.intValue();
3034         }
3035         final BigInteger configShortHorizon = config.getAmbientLightHorizonShort();
3036         if (configShortHorizon != null) {
3037             mAmbientHorizonShort = configShortHorizon.intValue();
3038         }
3039     }
3040 
3041     /**
3042      * Extracts a float array from the specified {@link TypedArray}.
3043      *
3044      * @param array The array to convert.
3045      * @return the given array as a float array.
3046      */
getFloatArray(TypedArray array, float defaultValue)3047     public static float[] getFloatArray(TypedArray array, float defaultValue) {
3048         final int n = array.length();
3049         float[] vals = new float[n];
3050         for (int i = 0; i < n; i++) {
3051             vals[i] = array.getFloat(i, defaultValue);
3052         }
3053         array.recycle();
3054         return vals;
3055     }
3056 
getLuxLevels(int[] lux)3057     private static float[] getLuxLevels(int[] lux) {
3058         // The first control point is implicit and always at 0 lux.
3059         float[] levels = new float[lux.length + 1];
3060         for (int i = 0; i < lux.length; i++) {
3061             levels[i + 1] = (float) lux[i];
3062         }
3063         return levels;
3064     }
3065 
loadEnableAutoBrightness(AutoBrightness autobrightness)3066     private void loadEnableAutoBrightness(AutoBrightness autobrightness) {
3067         // mDdcAutoBrightnessAvailable is initialised to true, so that we fallback to using the
3068         // config.xml values if the autobrightness tag is not defined in the ddc file.
3069         // Autobrightness can still be turned off globally via config_automatic_brightness_available
3070         mDdcAutoBrightnessAvailable = true;
3071         if (autobrightness != null) {
3072             mDdcAutoBrightnessAvailable = autobrightness.getEnabled();
3073         }
3074 
3075         mAutoBrightnessAvailable = mContext.getResources().getBoolean(
3076                 com.android.internal.R.bool.config_automatic_brightness_available)
3077                 && mDdcAutoBrightnessAvailable;
3078     }
3079 
loadScreenOffBrightnessSensorValueToLuxFromDdc(DisplayConfiguration config)3080     private void loadScreenOffBrightnessSensorValueToLuxFromDdc(DisplayConfiguration config) {
3081         IntegerArray sensorValueToLux = config.getScreenOffBrightnessSensorValueToLux();
3082         if (sensorValueToLux == null) {
3083             return;
3084         }
3085 
3086         List<BigInteger> items = sensorValueToLux.getItem();
3087         mScreenOffBrightnessSensorValueToLux = new int[items.size()];
3088         for (int i = 0; i < items.size(); i++) {
3089             mScreenOffBrightnessSensorValueToLux[i] = items.get(i).intValue();
3090         }
3091     }
3092 
loadUsiVersion(DisplayConfiguration config)3093     private void loadUsiVersion(DisplayConfiguration config) {
3094         final UsiVersion usiVersion = config.getUsiVersion();
3095         mHostUsiVersion = usiVersion != null
3096                 ? new HostUsiVersion(
3097                         usiVersion.getMajorVersion().intValue(),
3098                         usiVersion.getMinorVersion().intValue())
3099                 : null;
3100     }
3101 
3102     /**
3103      * Uniquely identifies a Sensor, with the combination of Type and Name.
3104      */
3105     public static class SensorData {
3106         public String type;
3107         public String name;
3108         public float minRefreshRate = 0.0f;
3109         public float maxRefreshRate = Float.POSITIVE_INFINITY;
3110 
3111         @Override
toString()3112         public String toString() {
3113             return "Sensor{"
3114                     + "type: " + type
3115                     + ", name: " + name
3116                     + ", refreshRateRange: [" + minRefreshRate + ", " + maxRefreshRate + "]"
3117                     + "} ";
3118         }
3119 
3120         /**
3121          * @return True if the sensor matches both the specified name and type, or one if only one
3122          * is specified (not-empty). Always returns false if both parameters are null or empty.
3123          */
matches(String sensorName, String sensorType)3124         public boolean matches(String sensorName, String sensorType) {
3125             final boolean isNameSpecified = !TextUtils.isEmpty(sensorName);
3126             final boolean isTypeSpecified = !TextUtils.isEmpty(sensorType);
3127             return (isNameSpecified || isTypeSpecified)
3128                     && (!isNameSpecified || sensorName.equals(name))
3129                     && (!isTypeSpecified || sensorType.equals(type));
3130         }
3131     }
3132 
3133     /**
3134      * Container for high brightness mode configuration data.
3135      */
3136     static class HighBrightnessModeData {
3137         /** Minimum lux needed to enter high brightness mode */
3138         public float minimumLux;
3139 
3140         /** Brightness level at which we transition from normal to high-brightness. */
3141         public float transitionPoint;
3142 
3143         /** Whether HBM is allowed when {@code Settings.Global.LOW_POWER_MODE} is active. */
3144         public boolean allowInLowPowerMode;
3145 
3146         /** Time window for HBM. */
3147         public long timeWindowMillis;
3148 
3149         /** Maximum time HBM is allowed to be during in a {@code timeWindowMillis}. */
3150         public long timeMaxMillis;
3151 
3152         /** Minimum time that HBM can be on before being enabled. */
3153         public long timeMinMillis;
3154 
3155         /** Minimum HDR video size to enter high brightness mode */
3156         public float minimumHdrPercentOfScreen;
3157 
HighBrightnessModeData()3158         HighBrightnessModeData() {}
3159 
HighBrightnessModeData(float minimumLux, float transitionPoint, long timeWindowMillis, long timeMaxMillis, long timeMinMillis, boolean allowInLowPowerMode, float minimumHdrPercentOfScreen)3160         HighBrightnessModeData(float minimumLux, float transitionPoint, long timeWindowMillis,
3161                 long timeMaxMillis, long timeMinMillis, boolean allowInLowPowerMode,
3162                 float minimumHdrPercentOfScreen) {
3163             this.minimumLux = minimumLux;
3164             this.transitionPoint = transitionPoint;
3165             this.timeWindowMillis = timeWindowMillis;
3166             this.timeMaxMillis = timeMaxMillis;
3167             this.timeMinMillis = timeMinMillis;
3168             this.allowInLowPowerMode = allowInLowPowerMode;
3169             this.minimumHdrPercentOfScreen = minimumHdrPercentOfScreen;
3170         }
3171 
3172         /**
3173          * Copies the HBM data to the specified parameter instance.
3174          * @param other the instance to copy data to.
3175          */
copyTo(@onNull HighBrightnessModeData other)3176         public void copyTo(@NonNull HighBrightnessModeData other) {
3177             other.minimumLux = minimumLux;
3178             other.timeWindowMillis = timeWindowMillis;
3179             other.timeMaxMillis = timeMaxMillis;
3180             other.timeMinMillis = timeMinMillis;
3181             other.transitionPoint = transitionPoint;
3182             other.allowInLowPowerMode = allowInLowPowerMode;
3183             other.minimumHdrPercentOfScreen = minimumHdrPercentOfScreen;
3184         }
3185 
3186         @Override
toString()3187         public String toString() {
3188             return "HBM{"
3189                     + "minLux: " + minimumLux
3190                     + ", transition: " + transitionPoint
3191                     + ", timeWindow: " + timeWindowMillis + "ms"
3192                     + ", timeMax: " + timeMaxMillis + "ms"
3193                     + ", timeMin: " + timeMinMillis + "ms"
3194                     + ", allowInLowPowerMode: " + allowInLowPowerMode
3195                     + ", minimumHdrPercentOfScreen: " + minimumHdrPercentOfScreen
3196                     + "} ";
3197         }
3198     }
3199 
3200     /**
3201      * Container for brightness throttling data.
3202      */
3203     public static class ThermalBrightnessThrottlingData {
3204         public List<ThrottlingLevel> throttlingLevels;
3205 
3206         /**
3207          * thermal status to brightness cap holder
3208          */
3209         public static class ThrottlingLevel {
3210             public @PowerManager.ThermalStatus int thermalStatus;
3211             public float brightness;
3212 
ThrottlingLevel( @owerManager.ThermalStatus int thermalStatus, float brightness)3213             public ThrottlingLevel(
3214                     @PowerManager.ThermalStatus int thermalStatus, float brightness) {
3215                 this.thermalStatus = thermalStatus;
3216                 this.brightness = brightness;
3217             }
3218 
3219             @Override
toString()3220             public String toString() {
3221                 return "[" + thermalStatus + "," + brightness + "]";
3222             }
3223 
3224             @Override
equals(Object obj)3225             public boolean equals(Object obj) {
3226                 if (!(obj instanceof ThrottlingLevel)) {
3227                     return false;
3228                 }
3229                 ThrottlingLevel otherThrottlingLevel = (ThrottlingLevel) obj;
3230 
3231                 return otherThrottlingLevel.thermalStatus == this.thermalStatus
3232                         && otherThrottlingLevel.brightness == this.brightness;
3233             }
3234 
3235             @Override
hashCode()3236             public int hashCode() {
3237                 int result = 1;
3238                 result = 31 * result + thermalStatus;
3239                 result = 31 * result + Float.hashCode(brightness);
3240                 return result;
3241             }
3242         }
3243 
3244 
3245         /**
3246          * Creates multiple temperature based throttling levels of brightness
3247          */
create( List<ThrottlingLevel> throttlingLevels)3248         public static ThermalBrightnessThrottlingData create(
3249                 List<ThrottlingLevel> throttlingLevels) {
3250             if (throttlingLevels == null || throttlingLevels.size() == 0) {
3251                 Slog.e(TAG, "BrightnessThrottlingData received null or empty throttling levels");
3252                 return null;
3253             }
3254 
3255             ThrottlingLevel prevLevel = throttlingLevels.get(0);
3256             final int numLevels = throttlingLevels.size();
3257             for (int i = 1; i < numLevels; i++) {
3258                 ThrottlingLevel thisLevel = throttlingLevels.get(i);
3259 
3260                 if (thisLevel.thermalStatus <= prevLevel.thermalStatus) {
3261                     Slog.e(TAG, "brightnessThrottlingMap must be strictly increasing, ignoring "
3262                             + "configuration. ThermalStatus " + thisLevel.thermalStatus + " <= "
3263                             + prevLevel.thermalStatus);
3264                     return null;
3265                 }
3266 
3267                 if (thisLevel.brightness >= prevLevel.brightness) {
3268                     Slog.e(TAG, "brightnessThrottlingMap must be strictly decreasing, ignoring "
3269                             + "configuration. Brightness " + thisLevel.brightness + " >= "
3270                             + thisLevel.brightness);
3271                     return null;
3272                 }
3273 
3274                 prevLevel = thisLevel;
3275             }
3276 
3277             for (ThrottlingLevel level : throttlingLevels) {
3278                 // Non-negative brightness values are enforced by device config schema
3279                 if (level.brightness > PowerManager.BRIGHTNESS_MAX) {
3280                     Slog.e(TAG, "brightnessThrottlingMap contains a brightness value exceeding "
3281                             + "system max. Brightness " + level.brightness + " > "
3282                             + PowerManager.BRIGHTNESS_MAX);
3283                     return null;
3284                 }
3285             }
3286 
3287             return new ThermalBrightnessThrottlingData(throttlingLevels);
3288         }
3289 
3290         @Override
toString()3291         public String toString() {
3292             return "ThermalBrightnessThrottlingData{"
3293                     + "throttlingLevels:" + throttlingLevels
3294                     + "} ";
3295         }
3296 
3297         @Override
equals(Object obj)3298         public boolean equals(Object obj) {
3299             if (this == obj) {
3300                 return true;
3301             }
3302 
3303             if (!(obj instanceof ThermalBrightnessThrottlingData)) {
3304                 return false;
3305             }
3306 
3307             ThermalBrightnessThrottlingData otherData = (ThermalBrightnessThrottlingData) obj;
3308             return throttlingLevels.equals(otherData.throttlingLevels);
3309         }
3310 
3311         @Override
hashCode()3312         public int hashCode() {
3313             return throttlingLevels.hashCode();
3314         }
3315 
3316         @VisibleForTesting
ThermalBrightnessThrottlingData(List<ThrottlingLevel> inLevels)3317         ThermalBrightnessThrottlingData(List<ThrottlingLevel> inLevels) {
3318             throttlingLevels = new ArrayList<>(inLevels.size());
3319             for (ThrottlingLevel level : inLevels) {
3320                 throttlingLevels.add(new ThrottlingLevel(level.thermalStatus, level.brightness));
3321             }
3322         }
3323     }
3324 
3325     public enum BrightnessLimitMapType {
3326         DEFAULT, ADAPTIVE;
3327 
3328         @Nullable
convert(PredefinedBrightnessLimitNames type)3329         private static BrightnessLimitMapType convert(PredefinedBrightnessLimitNames type) {
3330             switch (type) {
3331                 case _default:
3332                     return DEFAULT;
3333                 case adaptive:
3334                     return ADAPTIVE;
3335             }
3336             return null;
3337         }
3338     }
3339 }
3340