1 /*
2  * Copyright (C) 2016 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 android.util.Slog;
20 
21 import java.io.PrintWriter;
22 import java.util.Arrays;
23 
24 /**
25  * A helper class for handling access to illuminance hysteresis level values.
26  */
27 public class HysteresisLevels {
28     private static final String TAG = "HysteresisLevels";
29 
30     private static final boolean DEBUG = false;
31 
32     private final float[] mBrighteningThresholdsPercentages;
33     private final float[] mDarkeningThresholdsPercentages;
34     private final float[] mBrighteningThresholdLevels;
35     private final float[] mDarkeningThresholdLevels;
36     private final float mMinDarkening;
37     private final float mMinBrightening;
38 
39     /**
40      * Creates a {@code HysteresisLevels} object with the given equal-length
41      * float arrays.
42      * @param brighteningThresholdsPercentages 0-100 of thresholds
43      * @param darkeningThresholdsPercentages 0-100 of thresholds
44      * @param brighteningThresholdLevels float array of brightness values in the relevant units
45      * @param minBrighteningThreshold the minimum value for which the brightening value needs to
46      *                                return.
47      * @param minDarkeningThreshold the minimum value for which the darkening value needs to return.
48      * @param potentialOldBrightnessRange whether or not the values used could be from the old
49      *                                    screen brightness range ie, between 1-255.
50     */
HysteresisLevels(float[] brighteningThresholdsPercentages, float[] darkeningThresholdsPercentages, float[] brighteningThresholdLevels, float[] darkeningThresholdLevels, float minDarkeningThreshold, float minBrighteningThreshold, boolean potentialOldBrightnessRange)51     HysteresisLevels(float[] brighteningThresholdsPercentages,
52             float[] darkeningThresholdsPercentages,
53             float[] brighteningThresholdLevels, float[] darkeningThresholdLevels,
54             float minDarkeningThreshold, float minBrighteningThreshold,
55             boolean potentialOldBrightnessRange) {
56         if (brighteningThresholdsPercentages.length != brighteningThresholdLevels.length
57                 || darkeningThresholdsPercentages.length != darkeningThresholdLevels.length) {
58             throw new IllegalArgumentException("Mismatch between hysteresis array lengths.");
59         }
60         mBrighteningThresholdsPercentages =
61                 setArrayFormat(brighteningThresholdsPercentages, 100.0f);
62         mDarkeningThresholdsPercentages =
63                 setArrayFormat(darkeningThresholdsPercentages, 100.0f);
64         mBrighteningThresholdLevels = setArrayFormat(brighteningThresholdLevels, 1.0f);
65         mDarkeningThresholdLevels = setArrayFormat(darkeningThresholdLevels, 1.0f);
66         mMinDarkening = minDarkeningThreshold;
67         mMinBrightening = minBrighteningThreshold;
68     }
69 
HysteresisLevels(float[] brighteningThresholdsPercentages, float[] darkeningThresholdsPercentages, float[] brighteningThresholdLevels, float[] darkeningThresholdLevels, float minDarkeningThreshold, float minBrighteningThreshold)70     HysteresisLevels(float[] brighteningThresholdsPercentages,
71             float[] darkeningThresholdsPercentages,
72             float[] brighteningThresholdLevels, float[] darkeningThresholdLevels,
73             float minDarkeningThreshold, float minBrighteningThreshold) {
74         this(brighteningThresholdsPercentages, darkeningThresholdsPercentages,
75                 brighteningThresholdLevels, darkeningThresholdLevels, minDarkeningThreshold,
76                 minBrighteningThreshold, false);
77     }
78 
79     /**
80      * Return the brightening hysteresis threshold for the given value level.
81      */
getBrighteningThreshold(float value)82     public float getBrighteningThreshold(float value) {
83         final float brightConstant = getReferenceLevel(value,
84                 mBrighteningThresholdLevels, mBrighteningThresholdsPercentages);
85 
86         float brightThreshold = value * (1.0f + brightConstant);
87         if (DEBUG) {
88             Slog.d(TAG, "bright hysteresis constant=" + brightConstant + ", threshold="
89                     + brightThreshold + ", value=" + value);
90         }
91 
92         brightThreshold = Math.max(brightThreshold, value + mMinBrightening);
93         return brightThreshold;
94     }
95 
96     /**
97      * Return the darkening hysteresis threshold for the given value level.
98      */
getDarkeningThreshold(float value)99     public float getDarkeningThreshold(float value) {
100         final float darkConstant = getReferenceLevel(value,
101                 mDarkeningThresholdLevels, mDarkeningThresholdsPercentages);
102         float darkThreshold = value * (1.0f - darkConstant);
103         if (DEBUG) {
104             Slog.d(TAG, "dark hysteresis constant=: " + darkConstant + ", threshold="
105                     + darkThreshold + ", value=" + value);
106         }
107         darkThreshold = Math.min(darkThreshold, value - mMinDarkening);
108         return Math.max(darkThreshold, 0.0f);
109     }
110 
111     /**
112      * Return the hysteresis constant for the closest threshold value from the given array.
113      */
getReferenceLevel(float value, float[] thresholdLevels, float[] thresholdPercentages)114     private float getReferenceLevel(float value, float[] thresholdLevels,
115             float[] thresholdPercentages) {
116         if (thresholdLevels == null || thresholdLevels.length == 0 || value < thresholdLevels[0]) {
117             return 0.0f;
118         }
119         int index = 0;
120         while (index < thresholdLevels.length - 1 && value >= thresholdLevels[index + 1]) {
121             index++;
122         }
123         return thresholdPercentages[index];
124     }
125 
126     /**
127      * Return a float array where each i-th element equals {@code configArray[i]/divideFactor}.
128      */
setArrayFormat(float[] configArray, float divideFactor)129     private float[] setArrayFormat(float[] configArray, float divideFactor) {
130         float[] levelArray = new float[configArray.length];
131         for (int index = 0; levelArray.length > index; ++index) {
132             levelArray[index] = configArray[index] / divideFactor;
133         }
134         return levelArray;
135     }
136 
dump(PrintWriter pw)137     void dump(PrintWriter pw) {
138         pw.println("HysteresisLevels");
139         pw.println("  mBrighteningThresholdLevels=" + Arrays.toString(mBrighteningThresholdLevels));
140         pw.println("  mBrighteningThresholdsPercentages="
141                 + Arrays.toString(mBrighteningThresholdsPercentages));
142         pw.println("  mMinBrightening=" + mMinBrightening);
143         pw.println("  mDarkeningThresholdLevels=" + Arrays.toString(mDarkeningThresholdLevels));
144         pw.println("  mDarkeningThresholdsPercentages="
145                 + Arrays.toString(mDarkeningThresholdsPercentages));
146         pw.println("  mMinDarkening=" + mMinDarkening);
147     }
148 }
149