1 /* 2 * Copyright (C) 2017 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 android.hardware.display; 18 19 import android.annotation.Nullable; 20 import android.annotation.SystemApi; 21 import android.annotation.TestApi; 22 import android.os.Parcel; 23 import android.os.Parcelable; 24 import android.util.Pair; 25 26 import com.android.internal.util.Preconditions; 27 28 import java.util.Arrays; 29 import java.util.Objects; 30 31 /** @hide */ 32 @SystemApi 33 @TestApi 34 public final class BrightnessConfiguration implements Parcelable { 35 private final float[] mLux; 36 private final float[] mNits; 37 private final String mDescription; 38 39 private BrightnessConfiguration(float[] lux, float[] nits, String description) { 40 mLux = lux; 41 mNits = nits; 42 mDescription = description; 43 } 44 45 /** 46 * Gets the base brightness as curve. 47 * 48 * The curve is returned as a pair of float arrays, the first representing all of the lux 49 * points of the brightness curve and the second representing all of the nits values of the 50 * brightness curve. 51 * 52 * @return the control points for the brightness curve. 53 */ 54 public Pair<float[], float[]> getCurve() { 55 return Pair.create(Arrays.copyOf(mLux, mLux.length), Arrays.copyOf(mNits, mNits.length)); 56 } 57 58 /** 59 * Returns description string. 60 * @hide 61 */ 62 public String getDescription() { 63 return mDescription; 64 } 65 66 @Override 67 public void writeToParcel(Parcel dest, int flags) { 68 dest.writeFloatArray(mLux); 69 dest.writeFloatArray(mNits); 70 dest.writeString(mDescription); 71 } 72 73 @Override 74 public int describeContents() { 75 return 0; 76 } 77 78 @Override 79 public String toString() { 80 StringBuilder sb = new StringBuilder("BrightnessConfiguration{["); 81 final int size = mLux.length; 82 for (int i = 0; i < size; i++) { 83 if (i != 0) { 84 sb.append(", "); 85 } 86 sb.append("(").append(mLux[i]).append(", ").append(mNits[i]).append(")"); 87 } 88 sb.append("], '"); 89 if (mDescription != null) { 90 sb.append(mDescription); 91 } 92 sb.append("'}"); 93 return sb.toString(); 94 } 95 96 @Override 97 public int hashCode() { 98 int result = 1; 99 result = result * 31 + Arrays.hashCode(mLux); 100 result = result * 31 + Arrays.hashCode(mNits); 101 if (mDescription != null) { 102 result = result * 31 + mDescription.hashCode(); 103 } 104 return result; 105 } 106 107 @Override 108 public boolean equals(Object o) { 109 if (o == this) { 110 return true; 111 } 112 if (!(o instanceof BrightnessConfiguration)) { 113 return false; 114 } 115 final BrightnessConfiguration other = (BrightnessConfiguration) o; 116 return Arrays.equals(mLux, other.mLux) && Arrays.equals(mNits, other.mNits) 117 && Objects.equals(mDescription, other.mDescription); 118 } 119 120 public static final Creator<BrightnessConfiguration> CREATOR = 121 new Creator<BrightnessConfiguration>() { 122 public BrightnessConfiguration createFromParcel(Parcel in) { 123 float[] lux = in.createFloatArray(); 124 float[] nits = in.createFloatArray(); 125 Builder builder = new Builder(lux, nits); 126 builder.setDescription(in.readString()); 127 return builder.build(); 128 } 129 130 public BrightnessConfiguration[] newArray(int size) { 131 return new BrightnessConfiguration[size]; 132 } 133 }; 134 135 /** 136 * A builder class for {@link BrightnessConfiguration}s. 137 */ 138 public static class Builder { 139 private float[] mCurveLux; 140 private float[] mCurveNits; 141 private String mDescription; 142 143 /** 144 * STOPSHIP remove when app has stopped using this. 145 * @hide 146 */ 147 public Builder() { 148 } 149 150 /** 151 * Constructs the builder with the control points for the brightness curve. 152 * 153 * Brightness curves must have strictly increasing ambient brightness values in lux and 154 * monotonically increasing display brightness values in nits. In addition, the initial 155 * control point must be 0 lux. 156 * 157 * @throws IllegalArgumentException if the initial control point is not at 0 lux. 158 * @throws IllegalArgumentException if the lux levels are not strictly increasing. 159 * @throws IllegalArgumentException if the nit levels are not monotonically increasing. 160 */ 161 public Builder(float[] lux, float[] nits) { 162 setCurve(lux, nits); 163 } 164 165 /** 166 * Sets the control points for the brightness curve. 167 * 168 * Brightness curves must have strictly increasing ambient brightness values in lux and 169 * monotonically increasing display brightness values in nits. In addition, the initial 170 * control point must be 0 lux. 171 * 172 * @throws IllegalArgumentException if the initial control point is not at 0 lux. 173 * @throws IllegalArgumentException if the lux levels are not strictly increasing. 174 * @throws IllegalArgumentException if the nit levels are not monotonically increasing. 175 * 176 * STOPSHIP remove when app has stopped using this. 177 * @hide 178 */ 179 public Builder setCurve(float[] lux, float[] nits) { 180 Preconditions.checkNotNull(lux); 181 Preconditions.checkNotNull(nits); 182 if (lux.length == 0 || nits.length == 0) { 183 throw new IllegalArgumentException("Lux and nits arrays must not be empty"); 184 } 185 if (lux.length != nits.length) { 186 throw new IllegalArgumentException("Lux and nits arrays must be the same length"); 187 } 188 if (lux[0] != 0) { 189 throw new IllegalArgumentException("Initial control point must be for 0 lux"); 190 } 191 Preconditions.checkArrayElementsInRange(lux, 0, Float.MAX_VALUE, "lux"); 192 Preconditions.checkArrayElementsInRange(nits, 0, Float.MAX_VALUE, "nits"); 193 checkMonotonic(lux, true/*strictly increasing*/, "lux"); 194 checkMonotonic(nits, false /*strictly increasing*/, "nits"); 195 mCurveLux = lux; 196 mCurveNits = nits; 197 return this; 198 } 199 200 /** 201 * Set description of the brightness curve. 202 * 203 * @param description brief text describing the curve pushed. It maybe truncated 204 * and will not be displayed in the UI 205 */ 206 public Builder setDescription(@Nullable String description) { 207 mDescription = description; 208 return this; 209 } 210 211 /** 212 * Builds the {@link BrightnessConfiguration}. 213 * 214 * A brightness curve <b>must</b> be set before calling this. 215 */ 216 public BrightnessConfiguration build() { 217 if (mCurveLux == null || mCurveNits == null) { 218 throw new IllegalStateException("A curve must be set!"); 219 } 220 return new BrightnessConfiguration(mCurveLux, mCurveNits, mDescription); 221 } 222 223 private static void checkMonotonic(float[] vals, boolean strictlyIncreasing, String name) { 224 if (vals.length <= 1) { 225 return; 226 } 227 float prev = vals[0]; 228 for (int i = 1; i < vals.length; i++) { 229 if (prev > vals[i] || prev == vals[i] && strictlyIncreasing) { 230 String condition = strictlyIncreasing ? "strictly increasing" : "monotonic"; 231 throw new IllegalArgumentException(name + " values must be " + condition); 232 } 233 prev = vals[i]; 234 } 235 } 236 } 237 } 238