blob: 6ff2b09988e60cb1ec01b8073e503352d8ce4f70 [file] [log] [blame]
Dan Gittik8dbd7e92018-12-03 15:35:53 +00001/*
2 * Copyright (C) 2019 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 com.android.server.display.whitebalance;
18
19import android.content.res.Resources;
20import android.content.res.TypedArray;
21import android.hardware.SensorManager;
22import android.os.Handler;
23import android.util.TypedValue;
24
Santos Cordonceb0ae12019-04-29 18:06:09 +010025import com.android.internal.annotations.VisibleForTesting;
26
Dan Gittik8dbd7e92018-12-03 15:35:53 +000027/**
28 * The DisplayWhiteBalanceFactory creates and configures an DisplayWhiteBalanceController.
29 */
30public class DisplayWhiteBalanceFactory {
31
32 private static final String BRIGHTNESS_FILTER_TAG = "AmbientBrightnessFilter";
33 private static final String COLOR_TEMPERATURE_FILTER_TAG = "AmbientColorTemperatureFilter";
34
35 /**
36 * Create and configure an DisplayWhiteBalanceController.
37 *
38 * @param handler
39 * The handler used to determine which thread to run on.
40 * @param sensorManager
41 * The sensor manager used to acquire necessary sensors.
42 * @param resources
43 * The resources used to configure the various components.
44 *
Santos Cordonceb0ae12019-04-29 18:06:09 +010045 * @return A DisplayWhiteBalanceController.
Dan Gittik8dbd7e92018-12-03 15:35:53 +000046 *
47 * @throws NullPointerException
48 * - handler is null;
49 * - sensorManager is null.
50 * @throws Resources.NotFoundException
51 * - Configurations are missing.
52 * @throws IllegalArgumentException
53 * - Configurations are invalid.
54 * @throws IllegalStateException
55 * - Cannot find the necessary sensors.
56 */
57 public static DisplayWhiteBalanceController create(Handler handler,
58 SensorManager sensorManager, Resources resources) {
59 final AmbientSensor.AmbientBrightnessSensor brightnessSensor =
60 createBrightnessSensor(handler, sensorManager, resources);
61 final AmbientFilter brightnessFilter = createBrightnessFilter(resources);
62 final AmbientSensor.AmbientColorTemperatureSensor colorTemperatureSensor =
63 createColorTemperatureSensor(handler, sensorManager, resources);
64 final AmbientFilter colorTemperatureFilter = createColorTemperatureFilter(resources);
65 final DisplayWhiteBalanceThrottler throttler = createThrottler(resources);
66 final float lowLightAmbientBrightnessThreshold = getFloat(resources,
67 com.android.internal.R.dimen
68 .config_displayWhiteBalanceLowLightAmbientBrightnessThreshold);
69 final float lowLightAmbientColorTemperature = getFloat(resources,
70 com.android.internal.R.dimen
71 .config_displayWhiteBalanceLowLightAmbientColorTemperature);
Dan Gittik1151ac02019-02-13 14:05:37 +000072 final float[] ambientColorTemperatures = getFloatArray(resources,
73 com.android.internal.R.array.config_displayWhiteBalanceAmbientColorTemperatures);
74 final float[] displayColorTempeartures = getFloatArray(resources,
75 com.android.internal.R.array.config_displayWhiteBalanceDisplayColorTemperatures);
Dan Gittik8dbd7e92018-12-03 15:35:53 +000076 final DisplayWhiteBalanceController controller = new DisplayWhiteBalanceController(
77 brightnessSensor, brightnessFilter, colorTemperatureSensor, colorTemperatureFilter,
Daniel Solomonfb393e52019-02-08 20:26:27 -080078 throttler, lowLightAmbientBrightnessThreshold, lowLightAmbientColorTemperature,
Dan Gittik1151ac02019-02-13 14:05:37 +000079 ambientColorTemperatures, displayColorTempeartures);
Dan Gittik8dbd7e92018-12-03 15:35:53 +000080 brightnessSensor.setCallbacks(controller);
81 colorTemperatureSensor.setCallbacks(controller);
82 return controller;
83 }
84
85 // Instantiation is disabled.
86 private DisplayWhiteBalanceFactory() { }
87
Santos Cordonceb0ae12019-04-29 18:06:09 +010088 /**
89 * Creates a brightness sensor instance to redirect sensor data to callbacks.
90 */
91 @VisibleForTesting
92 public static AmbientSensor.AmbientBrightnessSensor createBrightnessSensor(Handler handler,
Dan Gittik8dbd7e92018-12-03 15:35:53 +000093 SensorManager sensorManager, Resources resources) {
94 final int rate = resources.getInteger(
95 com.android.internal.R.integer.config_displayWhiteBalanceBrightnessSensorRate);
96 return new AmbientSensor.AmbientBrightnessSensor(handler, sensorManager, rate);
97 }
98
Santos Cordonceb0ae12019-04-29 18:06:09 +010099 /**
100 * Creates a BrightnessFilter which functions as a weighted moving average buffer for recent
101 * brightness values.
102 */
103 @VisibleForTesting
104 static AmbientFilter createBrightnessFilter(Resources resources) {
Dan Gittik8dbd7e92018-12-03 15:35:53 +0000105 final int horizon = resources.getInteger(
106 com.android.internal.R.integer.config_displayWhiteBalanceBrightnessFilterHorizon);
107 final float intercept = getFloat(resources,
108 com.android.internal.R.dimen.config_displayWhiteBalanceBrightnessFilterIntercept);
109 if (!Float.isNaN(intercept)) {
110 return new AmbientFilter.WeightedMovingAverageAmbientFilter(
111 BRIGHTNESS_FILTER_TAG, horizon, intercept);
112 }
113 throw new IllegalArgumentException("missing configurations: "
114 + "expected config_displayWhiteBalanceBrightnessFilterIntercept");
115 }
116
117
Santos Cordonceb0ae12019-04-29 18:06:09 +0100118 /**
119 * Creates an ambient color sensor instance to redirect sensor data to callbacks.
120 */
121 @VisibleForTesting
122 public static AmbientSensor.AmbientColorTemperatureSensor createColorTemperatureSensor(
Dan Gittik8dbd7e92018-12-03 15:35:53 +0000123 Handler handler, SensorManager sensorManager, Resources resources) {
124 final String name = resources.getString(
125 com.android.internal.R.string
126 .config_displayWhiteBalanceColorTemperatureSensorName);
127 final int rate = resources.getInteger(
128 com.android.internal.R.integer
129 .config_displayWhiteBalanceColorTemperatureSensorRate);
130 return new AmbientSensor.AmbientColorTemperatureSensor(handler, sensorManager, name, rate);
131 }
132
133 private static AmbientFilter createColorTemperatureFilter(Resources resources) {
134 final int horizon = resources.getInteger(
135 com.android.internal.R.integer
136 .config_displayWhiteBalanceColorTemperatureFilterHorizon);
137 final float intercept = getFloat(resources,
138 com.android.internal.R.dimen
139 .config_displayWhiteBalanceColorTemperatureFilterIntercept);
140 if (!Float.isNaN(intercept)) {
141 return new AmbientFilter.WeightedMovingAverageAmbientFilter(
142 COLOR_TEMPERATURE_FILTER_TAG, horizon, intercept);
143 }
144 throw new IllegalArgumentException("missing configurations: "
145 + "expected config_displayWhiteBalanceColorTemperatureFilterIntercept");
146 }
147
148 private static DisplayWhiteBalanceThrottler createThrottler(Resources resources) {
149 final int increaseDebounce = resources.getInteger(
150 com.android.internal.R.integer.config_displayWhiteBalanceDecreaseDebounce);
151 final int decreaseDebounce = resources.getInteger(
152 com.android.internal.R.integer.config_displayWhiteBalanceIncreaseDebounce);
153 final float[] baseThresholds = getFloatArray(resources,
154 com.android.internal.R.array.config_displayWhiteBalanceBaseThresholds);
155 final float[] increaseThresholds = getFloatArray(resources,
156 com.android.internal.R.array.config_displayWhiteBalanceIncreaseThresholds);
157 final float[] decreaseThresholds = getFloatArray(resources,
158 com.android.internal.R.array.config_displayWhiteBalanceDecreaseThresholds);
159 return new DisplayWhiteBalanceThrottler(increaseDebounce, decreaseDebounce, baseThresholds,
160 increaseThresholds, decreaseThresholds);
161 }
162
163 private static float getFloat(Resources resources, int id) {
164 TypedValue value = new TypedValue();
165 resources.getValue(id, value, true /* resolveRefs */);
166 if (value.type != TypedValue.TYPE_FLOAT) {
167 return Float.NaN;
168 }
169 return value.getFloat();
170 }
171
172 private static float[] getFloatArray(Resources resources, int id) {
173 TypedArray array = resources.obtainTypedArray(id);
174 try {
175 if (array.length() == 0) {
176 return null;
177 }
178 float[] values = new float[array.length()];
179 for (int i = 0; i < values.length; i++) {
180 values[i] = array.getFloat(i, Float.NaN);
181 if (Float.isNaN(values[i])) {
182 return null;
183 }
184 }
185 return values;
186 } finally {
187 array.recycle();
188 }
189 }
190
191}