livedisplay: Add support for direct color balance control

* We currently use the DisplayColorCalibration API for setting display
   temperature which makes a lot of guesses about what temperature
   the display really is. Some devices will support the new ColorBalance
   API (via QDCM or other mechanism), which offers a calibrated
   alternative. Add support for this, which will supercede DCC if
   available.
 * Additionally, define the available color temperature range as a
   set of overlayable values so this can be specified per-device.
   This range will be mapped to balance values using the power curve
   calculations in the new MathUtils class.

Change-Id: I99608c09807b747d962680293c7b0cee8d669003
This commit is contained in:
Steve Kondik
2016-07-18 02:36:42 -07:00
parent 25d7081418
commit 86cae92291
13 changed files with 373 additions and 16 deletions

View File

@@ -20,6 +20,7 @@ import android.os.IBinder;
import android.os.RemoteException;
import android.os.ServiceManager;
import android.util.Log;
import android.util.Range;
import cyanogenmod.app.CMContextConstants;
@@ -129,6 +130,11 @@ public final class CMHardwareManager {
*/
public static final int FEATURE_UNIQUE_DEVICE_ID = 0x10000;
/**
* Color balance
*/
public static final int FEATURE_COLOR_BALANCE = 0x20000;
private static final List<Integer> BOOLEAN_FEATURES = Arrays.asList(
FEATURE_ADAPTIVE_BACKLIGHT,
FEATURE_COLOR_ENHANCEMENT,
@@ -803,6 +809,39 @@ public final class CMHardwareManager {
return false;
}
public Range<Integer> getColorBalanceRange() {
int min = 0;
int max = 0;
try {
if (checkService()) {
min = sService.getColorBalanceMin();
max = sService.getColorBalanceMax();
}
} catch (RemoteException e) {
}
return new Range<Integer>(min, max);
}
public int getColorBalance() {
try {
if (checkService()) {
return sService.getColorBalance();
}
} catch (RemoteException e) {
}
return 0;
}
public boolean setColorBalance(int value) {
try {
if (checkService()) {
return sService.setColorBalance(value);
}
} catch (RemoteException e) {
}
return false;
}
/**
* @return true if service is valid
*/

View File

@@ -58,4 +58,9 @@ interface ICMHardwareService {
boolean isSunlightEnhancementSelfManaged();
String getUniqueDeviceId();
int getColorBalanceMin();
int getColorBalanceMax();
int getColorBalance();
boolean setColorBalance(int value);
}

View File

@@ -23,6 +23,7 @@ import static cyanogenmod.hardware.LiveDisplayManager.MODE_OFF;
import android.os.Parcel;
import android.os.Parcelable;
import android.util.Range;
import java.util.BitSet;
@@ -50,10 +51,15 @@ public class LiveDisplayConfig implements Parcelable {
private final boolean mDefaultCABC;
private final boolean mDefaultColorEnhancement;
private final Range<Integer> mColorTemperatureRange;
private final Range<Integer> mColorBalanceRange;
public LiveDisplayConfig(BitSet capabilities, int defaultMode,
int defaultDayTemperature, int defaultNightTemperature,
boolean defaultAutoOutdoorMode, boolean defaultAutoContrast,
boolean defaultCABC, boolean defaultColorEnhancement) {
boolean defaultCABC, boolean defaultColorEnhancement,
Range<Integer> colorTemperatureRange,
Range<Integer> colorBalanceRange) {
super();
mCapabilities = (BitSet) capabilities.clone();
mAllModes.set(MODE_FIRST, MODE_LAST);
@@ -64,6 +70,8 @@ public class LiveDisplayConfig implements Parcelable {
mDefaultAutoOutdoorMode = defaultAutoOutdoorMode;
mDefaultCABC = defaultCABC;
mDefaultColorEnhancement = defaultColorEnhancement;
mColorTemperatureRange = colorTemperatureRange;
mColorBalanceRange = colorBalanceRange;
}
private LiveDisplayConfig(Parcel parcel) {
@@ -80,6 +88,10 @@ public class LiveDisplayConfig implements Parcelable {
boolean defaultAutoOutdoorMode = false;
boolean defaultCABC = false;
boolean defaultColorEnhancement = false;
int minColorTemperature = 0;
int maxColorTemperature = 0;
int minColorBalance = 0;
int maxColorBalance = 0;
if (parcelableVersion >= Build.CM_VERSION_CODES.FIG) {
capabilities = parcel.readLong();
@@ -90,6 +102,10 @@ public class LiveDisplayConfig implements Parcelable {
defaultAutoOutdoorMode = parcel.readInt() == 1;
defaultCABC = parcel.readInt() == 1;
defaultColorEnhancement = parcel.readInt() == 1;
minColorTemperature = parcel.readInt();
maxColorTemperature = parcel.readInt();
minColorBalance = parcel.readInt();
maxColorBalance = parcel.readInt();
}
// set temps
@@ -102,6 +118,8 @@ public class LiveDisplayConfig implements Parcelable {
mDefaultAutoOutdoorMode = defaultAutoOutdoorMode;
mDefaultCABC = defaultCABC;
mDefaultColorEnhancement = defaultColorEnhancement;
mColorTemperatureRange = Range.create(minColorTemperature, maxColorTemperature);
mColorBalanceRange = Range.create(minColorBalance, maxColorBalance);
// Complete parcel info for the concierge
parcelInfo.complete();
@@ -118,6 +136,8 @@ public class LiveDisplayConfig implements Parcelable {
sb.append(" defaultAutoContrast=").append(mDefaultAutoContrast);
sb.append(" defaultCABC=").append(mDefaultCABC);
sb.append(" defaultColorEnhancement=").append(mDefaultColorEnhancement);
sb.append(" colorTemperatureRange=").append(mColorTemperatureRange);
sb.append(" colorBalanceRange=").append(mColorBalanceRange);
return sb.toString();
}
@@ -141,6 +161,10 @@ public class LiveDisplayConfig implements Parcelable {
out.writeInt(mDefaultAutoOutdoorMode ? 1 : 0);
out.writeInt(mDefaultCABC ? 1 : 0);
out.writeInt(mDefaultColorEnhancement ? 1 : 0);
out.writeInt(mColorTemperatureRange.getLower());
out.writeInt(mColorTemperatureRange.getUpper());
out.writeInt(mColorBalanceRange.getLower());
out.writeInt(mColorBalanceRange.getUpper());
// Complete the parcel info for the concierge
parcelInfo.complete();
@@ -243,6 +267,24 @@ public class LiveDisplayConfig implements Parcelable {
return mDefaultColorEnhancement;
}
/**
* Get the range of supported color temperatures
*
* @return range in Kelvin
*/
public Range<Integer> getColorTemperatureRange() {
return mColorTemperatureRange;
}
/**
* Get the range of supported color balance
*
* @return linear range which maps into the temperature range curve
*/
public Range<Integer> getColorBalanceRange() {
return mColorBalanceRange;
}
/** @hide */
public static final Parcelable.Creator<LiveDisplayConfig> CREATOR =
new Parcelable.Creator<LiveDisplayConfig>() {

View File

@@ -102,10 +102,17 @@ public class LiveDisplayManager {
*/
public static final int FEATURE_DISPLAY_MODES = 15;
/**
* System supports direct range-based control of display
* color balance (temperature). This is preferred over
* simple RGB adjustment.
*/
public static final int FEATURE_COLOR_BALANCE = 16;
/** @hide */
public static final int FEATURE_FIRST = FEATURE_CABC;
/** @hide */
public static final int FEATURE_LAST = FEATURE_DISPLAY_MODES;
public static final int FEATURE_LAST = FEATURE_COLOR_BALANCE;
private static final String TAG = "LiveDisplay";

View File

@@ -1311,7 +1311,7 @@ public final class CMSettings {
/** @hide */
public static final Validator DISPLAY_TEMPERATURE_DAY_VALIDATOR =
new InclusiveIntegerRangeValidator(1000, 10000);
new InclusiveIntegerRangeValidator(0, 100000);
/**
* Color temperature of the display at night
@@ -1320,7 +1320,7 @@ public final class CMSettings {
/** @hide */
public static final Validator DISPLAY_TEMPERATURE_NIGHT_VALIDATOR =
new InclusiveIntegerRangeValidator(1000, 10000);
new InclusiveIntegerRangeValidator(0, 100000);
/**
* Display color temperature adjustment mode, one of DAY (default), NIGHT, or AUTO.

View File

@@ -0,0 +1,67 @@
/*
* Copyright (C) 2016 The CyanogenMod 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 org.cyanogenmod.internal.util;
public final class MathUtils {
/**
* Given a range of values which change continuously in a non-linear way,
* we can map back and forth to a linear scale using some quadratic equations.
*
* The linear scale ranges from 0 -> 1. This method will calculate the
* coefficients needed to solve the conversion functions in the next two methods.
*
* lower = actual value when linear value = 0
* mid = actual value when linear value = .5
* upper actual value when linear value = 1
*
* @param lower
* @param mid
* @param upper
* @return array of coefficients
*/
public static double[] powerCurve(double lower, double mid, double upper) {
final double[] curve = new double[3];
curve[0] = ((lower * upper) - (mid * mid)) / (lower - (2 * mid) + upper);
curve[1] = Math.pow((mid - lower), 2) / (lower - (2 * mid) + upper);
curve[2] = 2 * Math.log((upper - mid) / (mid - lower));
return curve;
}
/**
* Map a value on a power curve to a linear value
*
* @param curve obtained from powerCurve()
* @param value to convert to linear scale
* @return linear value from 0 -> 1
*/
public static double powerCurveToLinear(final double[] curve, double value) {
return Math.log((value - curve[0]) / curve[1]) / curve[2];
}
/**
* Map a value on a linear scale to a value on a power curve
*
* @param curve obtained from powerCurve()
* @param value from 0 -> 1 to map onto power curve
* @return actual value on the given curve
*/
public static double linearToPowerCurve(final double[] curve, double value) {
return curve[0] + curve[1] * Math.exp(curve[2] * value);
}
}