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