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