/*
|
* 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 lowLightAmbientBrightnessThreshold = getFloat(resources,
|
com.android.internal.R.dimen
|
.config_displayWhiteBalanceLowLightAmbientBrightnessThreshold);
|
final float lowLightAmbientColorTemperature = getFloat(resources,
|
com.android.internal.R.dimen
|
.config_displayWhiteBalanceLowLightAmbientColorTemperature);
|
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, lowLightAmbientBrightnessThreshold, lowLightAmbientColorTemperature,
|
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.
|
*/
|
@VisibleForTesting
|
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();
|
}
|
}
|
|
}
|