blob: 1aa2557f92a2e7c78e2805c09b5743e64c795a53 [file] [log] [blame]
Peeyush Agarwalcc155dd2018-01-10 11:51:33 +00001/*
2 * Copyright 2018 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
17package android.hardware.display;
18
19import android.annotation.NonNull;
Peeyush Agarwale3a08ab52018-01-31 19:07:20 +000020import android.annotation.SystemApi;
21import android.annotation.TestApi;
Peeyush Agarwalcc155dd2018-01-10 11:51:33 +000022import android.os.Parcel;
23import android.os.Parcelable;
24
25import com.android.internal.util.Preconditions;
26
27import java.time.LocalDate;
28import java.util.Arrays;
29
30/**
31 * AmbientBrightnessDayStats stores and manipulates brightness stats over a single day.
32 * {@see DisplayManager.getAmbientBrightnessStats()}
Peeyush Agarwalcc155dd2018-01-10 11:51:33 +000033 *
34 * @hide
35 */
Peeyush Agarwale3a08ab52018-01-31 19:07:20 +000036@SystemApi
37@TestApi
38public final class AmbientBrightnessDayStats implements Parcelable {
Peeyush Agarwalcc155dd2018-01-10 11:51:33 +000039
40 /** The localdate for which brightness stats are being tracked */
41 private final LocalDate mLocalDate;
42
43 /** Ambient brightness values for creating bucket boundaries from */
44 private final float[] mBucketBoundaries;
45
46 /** Stats of how much time (in seconds) was spent in each of the buckets */
47 private final float[] mStats;
48
49 /**
Peeyush Agarwal8c2006d2018-02-08 12:39:39 +000050 * Initialize day stats from the given state. The time spent in each of the bucket is
51 * initialized to 0.
52 *
53 * @param localDate The date for which stats are being tracked
54 * @param bucketBoundaries Bucket boundaries used from creating the buckets from
Peeyush Agarwalcc155dd2018-01-10 11:51:33 +000055 * @hide
56 */
57 public AmbientBrightnessDayStats(@NonNull LocalDate localDate,
58 @NonNull float[] bucketBoundaries) {
Peeyush Agarwale3a08ab52018-01-31 19:07:20 +000059 this(localDate, bucketBoundaries, null);
Peeyush Agarwalcc155dd2018-01-10 11:51:33 +000060 }
61
62 /**
Peeyush Agarwal8c2006d2018-02-08 12:39:39 +000063 * Initialize day stats from the given state
64 *
65 * @param localDate The date for which stats are being tracked
66 * @param bucketBoundaries Bucket boundaries used from creating the buckets from
67 * @param stats Time spent in each of the buckets (in seconds)
Peeyush Agarwalcc155dd2018-01-10 11:51:33 +000068 * @hide
69 */
70 public AmbientBrightnessDayStats(@NonNull LocalDate localDate,
Peeyush Agarwale3a08ab52018-01-31 19:07:20 +000071 @NonNull float[] bucketBoundaries, float[] stats) {
Peeyush Agarwalcc155dd2018-01-10 11:51:33 +000072 Preconditions.checkNotNull(localDate);
73 Preconditions.checkNotNull(bucketBoundaries);
Peeyush Agarwale3a08ab52018-01-31 19:07:20 +000074 Preconditions.checkArrayElementsInRange(bucketBoundaries, 0, Float.MAX_VALUE,
75 "bucketBoundaries");
Peeyush Agarwalcc155dd2018-01-10 11:51:33 +000076 if (bucketBoundaries.length < 1) {
77 throw new IllegalArgumentException("Bucket boundaries must contain at least 1 value");
78 }
Peeyush Agarwale3a08ab52018-01-31 19:07:20 +000079 checkSorted(bucketBoundaries);
80 if (stats == null) {
81 stats = new float[bucketBoundaries.length];
82 } else {
83 Preconditions.checkArrayElementsInRange(stats, 0, Float.MAX_VALUE, "stats");
84 if (bucketBoundaries.length != stats.length) {
85 throw new IllegalArgumentException(
86 "Bucket boundaries and stats must be of same size.");
87 }
Peeyush Agarwalcc155dd2018-01-10 11:51:33 +000088 }
89 mLocalDate = localDate;
90 mBucketBoundaries = bucketBoundaries;
91 mStats = stats;
92 }
93
Peeyush Agarwal8c2006d2018-02-08 12:39:39 +000094 /**
95 * @return The {@link LocalDate} for which brightness stats are being tracked.
96 */
Peeyush Agarwalcc155dd2018-01-10 11:51:33 +000097 public LocalDate getLocalDate() {
98 return mLocalDate;
99 }
100
Peeyush Agarwal8c2006d2018-02-08 12:39:39 +0000101 /**
102 * @return Aggregated stats of time spent (in seconds) in various buckets.
103 */
Peeyush Agarwalcc155dd2018-01-10 11:51:33 +0000104 public float[] getStats() {
105 return mStats;
106 }
107
Peeyush Agarwal8c2006d2018-02-08 12:39:39 +0000108 /**
109 * Returns the bucket boundaries (in lux) used for creating buckets. For eg., if the bucket
110 * boundaries array is {b1, b2, b3}, the buckets will be [b1, b2), [b2, b3), [b3, inf).
111 *
112 * @return The list of bucket boundaries.
113 */
Peeyush Agarwalcc155dd2018-01-10 11:51:33 +0000114 public float[] getBucketBoundaries() {
115 return mBucketBoundaries;
116 }
117
118 private AmbientBrightnessDayStats(Parcel source) {
119 mLocalDate = LocalDate.parse(source.readString());
120 mBucketBoundaries = source.createFloatArray();
121 mStats = source.createFloatArray();
122 }
123
124 public static final Creator<AmbientBrightnessDayStats> CREATOR =
125 new Creator<AmbientBrightnessDayStats>() {
126
127 @Override
128 public AmbientBrightnessDayStats createFromParcel(Parcel source) {
129 return new AmbientBrightnessDayStats(source);
130 }
131
132 @Override
133 public AmbientBrightnessDayStats[] newArray(int size) {
134 return new AmbientBrightnessDayStats[size];
135 }
136 };
137
138 @Override
139 public boolean equals(Object obj) {
140 if (this == obj) {
141 return true;
142 }
143 if (obj == null) {
144 return false;
145 }
146 if (getClass() != obj.getClass()) {
147 return false;
148 }
149 AmbientBrightnessDayStats other = (AmbientBrightnessDayStats) obj;
150 return mLocalDate.equals(other.mLocalDate) && Arrays.equals(mBucketBoundaries,
151 other.mBucketBoundaries) && Arrays.equals(mStats, other.mStats);
152 }
153
154 @Override
155 public int hashCode() {
156 final int prime = 31;
157 int result = 1;
158 result = result * prime + mLocalDate.hashCode();
159 result = result * prime + Arrays.hashCode(mBucketBoundaries);
160 result = result * prime + Arrays.hashCode(mStats);
161 return result;
162 }
163
164 @Override
165 public String toString() {
166 StringBuilder bucketBoundariesString = new StringBuilder();
167 StringBuilder statsString = new StringBuilder();
168 for (int i = 0; i < mBucketBoundaries.length; i++) {
169 if (i != 0) {
170 bucketBoundariesString.append(", ");
171 statsString.append(", ");
172 }
173 bucketBoundariesString.append(mBucketBoundaries[i]);
174 statsString.append(mStats[i]);
175 }
176 return new StringBuilder()
177 .append(mLocalDate).append(" ")
178 .append("{").append(bucketBoundariesString).append("} ")
179 .append("{").append(statsString).append("}").toString();
180 }
181
182 @Override
183 public int describeContents() {
184 return 0;
185 }
186
187 @Override
188 public void writeToParcel(Parcel dest, int flags) {
189 dest.writeString(mLocalDate.toString());
190 dest.writeFloatArray(mBucketBoundaries);
191 dest.writeFloatArray(mStats);
192 }
193
Peeyush Agarwal8c2006d2018-02-08 12:39:39 +0000194 /**
195 * Updates the stats by incrementing the time spent for the appropriate bucket based on ambient
196 * brightness reading.
197 *
198 * @param ambientBrightness Ambient brightness reading (in lux)
199 * @param durationSec Time spent with the given reading (in seconds)
200 * @hide
201 */
Peeyush Agarwalcc155dd2018-01-10 11:51:33 +0000202 public void log(float ambientBrightness, float durationSec) {
203 int bucketIndex = getBucketIndex(ambientBrightness);
204 if (bucketIndex >= 0) {
205 mStats[bucketIndex] += durationSec;
206 }
207 }
208
209 private int getBucketIndex(float ambientBrightness) {
210 if (ambientBrightness < mBucketBoundaries[0]) {
211 return -1;
212 }
213 int low = 0;
214 int high = mBucketBoundaries.length - 1;
215 while (low < high) {
216 int mid = (low + high) / 2;
217 if (mBucketBoundaries[mid] <= ambientBrightness
218 && ambientBrightness < mBucketBoundaries[mid + 1]) {
219 return mid;
220 } else if (mBucketBoundaries[mid] < ambientBrightness) {
221 low = mid + 1;
222 } else if (mBucketBoundaries[mid] > ambientBrightness) {
223 high = mid - 1;
224 }
225 }
226 return low;
227 }
Peeyush Agarwale3a08ab52018-01-31 19:07:20 +0000228
229 private static void checkSorted(float[] values) {
230 if (values.length <= 1) {
231 return;
232 }
233 float prevValue = values[0];
234 for (int i = 1; i < values.length; i++) {
235 Preconditions.checkState(prevValue < values[i]);
236 prevValue = values[i];
237 }
238 return;
239 }
Peeyush Agarwalcc155dd2018-01-10 11:51:33 +0000240}