blob: bf0a1d16219d274db8f6dbf46fe81f2b1d73f9cf [file] [log] [blame]
/*
* Copyright (C) 2019 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.server.display.whitebalance;
import android.content.res.Resources;
import android.content.res.TypedArray;
import android.hardware.SensorManager;
import android.os.Handler;
import android.util.TypedValue;
import com.android.internal.annotations.VisibleForTesting;
/**
* The DisplayWhiteBalanceFactory creates and configures an DisplayWhiteBalanceController.
*/
public class DisplayWhiteBalanceFactory {
private static final String BRIGHTNESS_FILTER_TAG = "AmbientBrightnessFilter";
private static final String COLOR_TEMPERATURE_FILTER_TAG = "AmbientColorTemperatureFilter";
/**
* Create and configure an DisplayWhiteBalanceController.
*
* @param handler
* The handler used to determine which thread to run on.
* @param sensorManager
* The sensor manager used to acquire necessary sensors.
* @param resources
* The resources used to configure the various components.
*
* @return A DisplayWhiteBalanceController.
*
* @throws NullPointerException
* - handler is null;
* - sensorManager is null.
* @throws Resources.NotFoundException
* - Configurations are missing.
* @throws IllegalArgumentException
* - Configurations are invalid.
* @throws IllegalStateException
* - Cannot find the necessary sensors.
*/
public static DisplayWhiteBalanceController create(Handler handler,
SensorManager sensorManager, Resources resources) {
final AmbientSensor.AmbientBrightnessSensor brightnessSensor =
createBrightnessSensor(handler, sensorManager, resources);
final AmbientFilter brightnessFilter = createBrightnessFilter(resources);
final AmbientSensor.AmbientColorTemperatureSensor colorTemperatureSensor =
createColorTemperatureSensor(handler, sensorManager, resources);
final AmbientFilter colorTemperatureFilter = createColorTemperatureFilter(resources);
final DisplayWhiteBalanceThrottler throttler = createThrottler(resources);
final float[] displayWhiteBalanceLowLightAmbientBrightnesses = getFloatArray(resources,
com.android.internal.R.array
.config_displayWhiteBalanceLowLightAmbientBrightnesses);
final float[] displayWhiteBalanceLowLightAmbientBiases = getFloatArray(resources,
com.android.internal.R.array
.config_displayWhiteBalanceLowLightAmbientBiases);
final float lowLightAmbientColorTemperature = getFloat(resources,
com.android.internal.R.dimen
.config_displayWhiteBalanceLowLightAmbientColorTemperature);
final float[] displayWhiteBalanceHighLightAmbientBrightnesses = getFloatArray(resources,
com.android.internal.R.array
.config_displayWhiteBalanceHighLightAmbientBrightnesses);
final float[] displayWhiteBalanceHighLightAmbientBiases = getFloatArray(resources,
com.android.internal.R.array
.config_displayWhiteBalanceHighLightAmbientBiases);
final float highLightAmbientColorTemperature = getFloat(resources,
com.android.internal.R.dimen
.config_displayWhiteBalanceHighLightAmbientColorTemperature);
final float[] ambientColorTemperatures = getFloatArray(resources,
com.android.internal.R.array.config_displayWhiteBalanceAmbientColorTemperatures);
final float[] displayColorTempeartures = getFloatArray(resources,
com.android.internal.R.array.config_displayWhiteBalanceDisplayColorTemperatures);
final DisplayWhiteBalanceController controller = new DisplayWhiteBalanceController(
brightnessSensor, brightnessFilter, colorTemperatureSensor, colorTemperatureFilter,
throttler, displayWhiteBalanceLowLightAmbientBrightnesses,
displayWhiteBalanceLowLightAmbientBiases, lowLightAmbientColorTemperature,
displayWhiteBalanceHighLightAmbientBrightnesses,
displayWhiteBalanceHighLightAmbientBiases, highLightAmbientColorTemperature,
ambientColorTemperatures, displayColorTempeartures);
brightnessSensor.setCallbacks(controller);
colorTemperatureSensor.setCallbacks(controller);
return controller;
}
// Instantiation is disabled.
private DisplayWhiteBalanceFactory() { }
/**
* Creates a brightness sensor instance to redirect sensor data to callbacks.
*/
@VisibleForTesting
public static AmbientSensor.AmbientBrightnessSensor createBrightnessSensor(Handler handler,
SensorManager sensorManager, Resources resources) {
final int rate = resources.getInteger(
com.android.internal.R.integer.config_displayWhiteBalanceBrightnessSensorRate);
return new AmbientSensor.AmbientBrightnessSensor(handler, sensorManager, rate);
}
/**
* Creates a BrightnessFilter which functions as a weighted moving average buffer for recent
* brightness values.
*/
public static AmbientFilter createBrightnessFilter(Resources resources) {
final int horizon = resources.getInteger(
com.android.internal.R.integer.config_displayWhiteBalanceBrightnessFilterHorizon);
final float intercept = getFloat(resources,
com.android.internal.R.dimen.config_displayWhiteBalanceBrightnessFilterIntercept);
if (!Float.isNaN(intercept)) {
return new AmbientFilter.WeightedMovingAverageAmbientFilter(
BRIGHTNESS_FILTER_TAG, horizon, intercept);
}
throw new IllegalArgumentException("missing configurations: "
+ "expected config_displayWhiteBalanceBrightnessFilterIntercept");
}
/**
* Creates an ambient color sensor instance to redirect sensor data to callbacks.
*/
@VisibleForTesting
public static AmbientSensor.AmbientColorTemperatureSensor createColorTemperatureSensor(
Handler handler, SensorManager sensorManager, Resources resources) {
final String name = resources.getString(
com.android.internal.R.string
.config_displayWhiteBalanceColorTemperatureSensorName);
final int rate = resources.getInteger(
com.android.internal.R.integer
.config_displayWhiteBalanceColorTemperatureSensorRate);
return new AmbientSensor.AmbientColorTemperatureSensor(handler, sensorManager, name, rate);
}
private static AmbientFilter createColorTemperatureFilter(Resources resources) {
final int horizon = resources.getInteger(
com.android.internal.R.integer
.config_displayWhiteBalanceColorTemperatureFilterHorizon);
final float intercept = getFloat(resources,
com.android.internal.R.dimen
.config_displayWhiteBalanceColorTemperatureFilterIntercept);
if (!Float.isNaN(intercept)) {
return new AmbientFilter.WeightedMovingAverageAmbientFilter(
COLOR_TEMPERATURE_FILTER_TAG, horizon, intercept);
}
throw new IllegalArgumentException("missing configurations: "
+ "expected config_displayWhiteBalanceColorTemperatureFilterIntercept");
}
private static DisplayWhiteBalanceThrottler createThrottler(Resources resources) {
final int increaseDebounce = resources.getInteger(
com.android.internal.R.integer.config_displayWhiteBalanceDecreaseDebounce);
final int decreaseDebounce = resources.getInteger(
com.android.internal.R.integer.config_displayWhiteBalanceIncreaseDebounce);
final float[] baseThresholds = getFloatArray(resources,
com.android.internal.R.array.config_displayWhiteBalanceBaseThresholds);
final float[] increaseThresholds = getFloatArray(resources,
com.android.internal.R.array.config_displayWhiteBalanceIncreaseThresholds);
final float[] decreaseThresholds = getFloatArray(resources,
com.android.internal.R.array.config_displayWhiteBalanceDecreaseThresholds);
return new DisplayWhiteBalanceThrottler(increaseDebounce, decreaseDebounce, baseThresholds,
increaseThresholds, decreaseThresholds);
}
private static float getFloat(Resources resources, int id) {
TypedValue value = new TypedValue();
resources.getValue(id, value, true /* resolveRefs */);
if (value.type != TypedValue.TYPE_FLOAT) {
return Float.NaN;
}
return value.getFloat();
}
private static float[] getFloatArray(Resources resources, int id) {
TypedArray array = resources.obtainTypedArray(id);
try {
if (array.length() == 0) {
return null;
}
float[] values = new float[array.length()];
for (int i = 0; i < values.length; i++) {
values[i] = array.getFloat(i, Float.NaN);
if (Float.isNaN(values[i])) {
return null;
}
}
return values;
} finally {
array.recycle();
}
}
}