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 com.android.internal.annotations.VisibleForTesting;
22 
23 import java.io.PrintWriter;
24 import java.util.Arrays;
25 
26 /**
27  * A helper class for handling access to illuminance hysteresis level values.
28  */
29 @VisibleForTesting
30 public class HysteresisLevels {
31     private static final String TAG = "HysteresisLevels";
32 
33     private static final boolean DEBUG = false;
34 
35     private final float[] mBrighteningThresholds;
36     private final float[] mDarkeningThresholds;
37     private final float[] mThresholdLevels;
38     private final float mMinDarkening;
39     private final float mMinBrightening;
40 
41     /**
42      * Creates a {@code HysteresisLevels} object with the given equal-length
43      * integer arrays.
44      * @param brighteningThresholds an array of brightening hysteresis constraint constants.
45      * @param darkeningThresholds an array of darkening hysteresis constraint constants.
46      * @param thresholdLevels a monotonically increasing array of threshold levels.
47      * @param minBrighteningThreshold the minimum value for which the brightening value needs to
48      *                                return.
49      * @param minDarkeningThreshold the minimum value for which the darkening value needs to return.
50     */
HysteresisLevels(int[] brighteningThresholds, int[] darkeningThresholds, int[] thresholdLevels, float minDarkeningThreshold, float minBrighteningThreshold)51     HysteresisLevels(int[] brighteningThresholds, int[] darkeningThresholds,
52             int[] thresholdLevels, float minDarkeningThreshold, float minBrighteningThreshold) {
53         if (brighteningThresholds.length != darkeningThresholds.length
54                 || darkeningThresholds.length != thresholdLevels.length + 1) {
55             throw new IllegalArgumentException("Mismatch between hysteresis array lengths.");
56         }
57         mBrighteningThresholds = setArrayFormat(brighteningThresholds, 1000.0f);
58         mDarkeningThresholds = setArrayFormat(darkeningThresholds, 1000.0f);
59         mThresholdLevels = setArrayFormat(thresholdLevels, 1.0f);
60         mMinDarkening = minDarkeningThreshold;
61         mMinBrightening = minBrighteningThreshold;
62     }
63 
64     /**
65      * Return the brightening hysteresis threshold for the given value level.
66      */
getBrighteningThreshold(float value)67     public float getBrighteningThreshold(float value) {
68         final float brightConstant = getReferenceLevel(value, mBrighteningThresholds);
69         float brightThreshold = value * (1.0f + brightConstant);
70         if (DEBUG) {
71             Slog.d(TAG, "bright hysteresis constant=" + brightConstant + ", threshold="
72                     + brightThreshold + ", value=" + value);
73         }
74 
75         brightThreshold = Math.max(brightThreshold, value + mMinBrightening);
76         return brightThreshold;
77     }
78 
79     /**
80      * Return the darkening hysteresis threshold for the given value level.
81      */
getDarkeningThreshold(float value)82     public float getDarkeningThreshold(float value) {
83         final float darkConstant = getReferenceLevel(value, mDarkeningThresholds);
84         float darkThreshold = value * (1.0f - darkConstant);
85         if (DEBUG) {
86             Slog.d(TAG, "dark hysteresis constant=: " + darkConstant + ", threshold="
87                     + darkThreshold + ", value=" + value);
88         }
89         darkThreshold = Math.min(darkThreshold, value - mMinDarkening);
90         return Math.max(darkThreshold, 0.0f);
91     }
92 
93     /**
94      * Return the hysteresis constant for the closest threshold value from the given array.
95      */
getReferenceLevel(float value, float[] referenceLevels)96     private float getReferenceLevel(float value, float[] referenceLevels) {
97         int index = 0;
98         while (mThresholdLevels.length > index && value >= mThresholdLevels[index]) {
99             ++index;
100         }
101         return referenceLevels[index];
102     }
103 
104     /**
105      * Return a float array where each i-th element equals {@code configArray[i]/divideFactor}.
106      */
setArrayFormat(int[] configArray, float divideFactor)107     private float[] setArrayFormat(int[] configArray, float divideFactor) {
108         float[] levelArray = new float[configArray.length];
109         for (int index = 0; levelArray.length > index; ++index) {
110             levelArray[index] = (float)configArray[index] / divideFactor;
111         }
112         return levelArray;
113     }
114 
dump(PrintWriter pw)115     void dump(PrintWriter pw) {
116         pw.println("HysteresisLevels");
117         pw.println("  mBrighteningThresholds=" + Arrays.toString(mBrighteningThresholds));
118         pw.println("  mDarkeningThresholds=" + Arrays.toString(mDarkeningThresholds));
119         pw.println("  mThresholdLevels=" + Arrays.toString(mThresholdLevels));
120     }
121 }
122