replicant-vendor_cmsdk/cm/lib/main/java/org/cyanogenmod/platform/internal/display/DisplayHardwareController.java

503 lines
16 KiB
Java

/*
* 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.platform.internal.display;
import android.animation.FloatArrayEvaluator;
import android.animation.ValueAnimator;
import android.animation.ValueAnimator.AnimatorUpdateListener;
import android.content.Context;
import android.net.Uri;
import android.os.Handler;
import android.os.IBinder;
import android.os.Parcel;
import android.os.RemoteException;
import android.os.ServiceManager;
import android.util.MathUtils;
import android.util.Slog;
import android.view.animation.LinearInterpolator;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.BitSet;
import cyanogenmod.hardware.CMHardwareManager;
import cyanogenmod.hardware.LiveDisplayManager;
import cyanogenmod.providers.CMSettings;
public class DisplayHardwareController extends LiveDisplayFeature {
private final CMHardwareManager mHardware;
// hardware capabilities
private final boolean mUseAutoContrast;
private final boolean mUseColorAdjustment;
private final boolean mUseColorEnhancement;
private final boolean mUseCABC;
private final boolean mUseDisplayModes;
// default values
private final boolean mDefaultAutoContrast;
private final boolean mDefaultColorEnhancement;
private final boolean mDefaultCABC;
// color adjustment holders
private final float[] mAdditionalAdjustment = getDefaultAdjustment();
private final float[] mColorAdjustment = getDefaultAdjustment();
private ValueAnimator mAnimator;
private final int mMaxColor;
// settings uris
private static final Uri DISPLAY_AUTO_CONTRAST =
CMSettings.System.getUriFor(CMSettings.System.DISPLAY_AUTO_CONTRAST);
private static final Uri DISPLAY_COLOR_ADJUSTMENT =
CMSettings.System.getUriFor(CMSettings.System.DISPLAY_COLOR_ADJUSTMENT);
private static final Uri DISPLAY_COLOR_ENHANCE =
CMSettings.System.getUriFor(CMSettings.System.DISPLAY_COLOR_ENHANCE);
private static final Uri DISPLAY_CABC =
CMSettings.System.getUriFor(CMSettings.System.DISPLAY_CABC);
public DisplayHardwareController(Context context, Handler handler) {
super(context, handler);
mHardware = CMHardwareManager.getInstance(mContext);
mUseCABC = mHardware
.isSupported(CMHardwareManager.FEATURE_ADAPTIVE_BACKLIGHT);
mDefaultCABC = mContext.getResources().getBoolean(
org.cyanogenmod.platform.internal.R.bool.config_defaultCABC);
mUseColorEnhancement = mHardware
.isSupported(CMHardwareManager.FEATURE_COLOR_ENHANCEMENT);
mDefaultColorEnhancement = mContext.getResources().getBoolean(
org.cyanogenmod.platform.internal.R.bool.config_defaultColorEnhancement);
mUseAutoContrast = mHardware
.isSupported(CMHardwareManager.FEATURE_AUTO_CONTRAST);
mDefaultAutoContrast = mContext.getResources().getBoolean(
org.cyanogenmod.platform.internal.R.bool.config_defaultAutoContrast);
mUseColorAdjustment = mHardware
.isSupported(CMHardwareManager.FEATURE_DISPLAY_COLOR_CALIBRATION);
mUseDisplayModes = mHardware
.isSupported(CMHardwareManager.FEATURE_DISPLAY_MODES);
if (mUseColorAdjustment) {
mMaxColor = mHardware.getDisplayColorCalibrationMax();
copyColors(getColorAdjustment(), mColorAdjustment);
} else {
mMaxColor = 0;
}
}
@Override
public void onStart() {
final ArrayList<Uri> settings = new ArrayList<Uri>();
if (mUseCABC) {
settings.add(DISPLAY_CABC);
}
if (mUseColorEnhancement) {
settings.add(DISPLAY_COLOR_ENHANCE);
}
if (mUseAutoContrast) {
settings.add(DISPLAY_AUTO_CONTRAST);
}
if (mUseColorAdjustment) {
settings.add(DISPLAY_COLOR_ADJUSTMENT);
}
if (settings.size() == 0) {
return;
}
registerSettings(settings.toArray(new Uri[settings.size()]));
}
@Override
public boolean getCapabilities(final BitSet caps) {
if (mUseAutoContrast) {
caps.set(LiveDisplayManager.FEATURE_AUTO_CONTRAST);
}
if (mUseColorEnhancement) {
caps.set(LiveDisplayManager.FEATURE_COLOR_ENHANCEMENT);
}
if (mUseCABC) {
caps.set(LiveDisplayManager.FEATURE_CABC);
}
if (mUseColorAdjustment) {
caps.set(LiveDisplayManager.FEATURE_COLOR_ADJUSTMENT);
}
if (mUseDisplayModes) {
caps.set(LiveDisplayManager.FEATURE_DISPLAY_MODES);
}
return mUseAutoContrast || mUseColorEnhancement || mUseCABC || mUseColorAdjustment ||
mUseDisplayModes;
}
@Override
public synchronized void onSettingsChanged(Uri uri) {
if (uri == null || uri.equals(DISPLAY_CABC)) {
updateCABCMode();
}
if (uri == null || uri.equals(DISPLAY_AUTO_CONTRAST)) {
updateAutoContrast();
}
if (uri == null || uri.equals(DISPLAY_COLOR_ENHANCE)) {
updateColorEnhancement();
}
if (uri == null || uri.equals(DISPLAY_COLOR_ADJUSTMENT)) {
copyColors(getColorAdjustment(), mColorAdjustment);
updateColorAdjustment();
}
}
private synchronized void updateHardware() {
if (isScreenOn()) {
updateCABCMode();
updateAutoContrast();
updateColorEnhancement();
}
}
@Override
protected void onUpdate() {
updateHardware();
}
@Override
protected synchronized void onScreenStateChanged() {
if (mUseColorAdjustment) {
if (mAnimator != null && mAnimator.isRunning() && !isScreenOn()) {
mAnimator.cancel();
} else if (isScreenOn()) {
updateColorAdjustment();
}
}
}
@Override
public void dump(PrintWriter pw) {
pw.println();
pw.println("DisplayHardwareController Configuration:");
pw.println(" mUseAutoContrast=" + mUseAutoContrast);
pw.println(" mUseColorAdjustment=" + mUseColorAdjustment);
pw.println(" mUseColorEnhancement=" + mUseColorEnhancement);
pw.println(" mUseCABC=" + mUseCABC);
pw.println(" mUseDisplayModes=" + mUseDisplayModes);
pw.println();
pw.println(" DisplayHardwareController State:");
pw.println(" mAutoContrast=" + isAutoContrastEnabled());
pw.println(" mColorEnhancement=" + isColorEnhancementEnabled());
pw.println(" mCABC=" + isCABCEnabled());
pw.println(" mColorAdjustment=" + Arrays.toString(mColorAdjustment));
pw.println(" mAdditionalAdjustment=" + Arrays.toString(mAdditionalAdjustment));
pw.println(" hardware setting=" + Arrays.toString(mHardware.getDisplayColorCalibration()));
}
/**
* Automatic contrast optimization
*/
private void updateAutoContrast() {
if (!mUseAutoContrast) {
return;
}
mHardware.set(CMHardwareManager.FEATURE_AUTO_CONTRAST,
!isLowPowerMode() && isAutoContrastEnabled());
}
/**
* Color enhancement is optional
*/
private void updateColorEnhancement() {
if (!mUseColorEnhancement) {
return;
}
mHardware.set(CMHardwareManager.FEATURE_COLOR_ENHANCEMENT,
!isLowPowerMode() && isColorEnhancementEnabled());
}
/**
* Adaptive backlight / low power mode. Turn it off when under very bright light.
*/
private void updateCABCMode() {
if (!mUseCABC) {
return;
}
mHardware.set(CMHardwareManager.FEATURE_ADAPTIVE_BACKLIGHT,
!isLowPowerMode() && isCABCEnabled());
}
private synchronized void updateColorAdjustment() {
if (!mUseColorAdjustment) {
return;
}
final float[] rgb = getDefaultAdjustment();
if (!isLowPowerMode()) {
copyColors(mColorAdjustment, rgb);
rgb[0] *= mAdditionalAdjustment[0];
rgb[1] *= mAdditionalAdjustment[1];
rgb[2] *= mAdditionalAdjustment[2];
}
if (DEBUG) {
Slog.d(TAG, "updateColorAdjustment: " + Arrays.toString(rgb));
}
if (validateColors(rgb)) {
animateDisplayColor(rgb);
}
}
/**
* Smoothly animate the current display colors to the new value.
*/
private synchronized void animateDisplayColor(float[] targetColors) {
// always start with the current values in the hardware
int[] currentInts = mHardware.getDisplayColorCalibration();
float[] currentColors = new float[] {
(float)currentInts[0] / (float)mMaxColor,
(float)currentInts[1] / (float)mMaxColor,
(float)currentInts[2] / (float)mMaxColor };
if (currentColors[0] == targetColors[0] &&
currentColors[1] == targetColors[1] &&
currentColors[2] == targetColors[2]) {
return;
}
// max 500 ms, scaled vs. the largest delta
long duration = (long)(750 * (Math.max(Math.max(
Math.abs(currentColors[0] - targetColors[0]),
Math.abs(currentColors[1] - targetColors[1])),
Math.abs(currentColors[2] - targetColors[2]))));
if (DEBUG) {
Slog.d(TAG, "animateDisplayColor current=" + Arrays.toString(currentColors) +
" targetColors=" + Arrays.toString(targetColors) + " duration=" + duration);
}
if (mAnimator != null) {
mAnimator.cancel();
mAnimator.removeAllUpdateListeners();
}
mAnimator = ValueAnimator.ofObject(
new FloatArrayEvaluator(new float[3]), currentColors, targetColors);
mAnimator.setDuration(duration);
mAnimator.setInterpolator(new LinearInterpolator());
mAnimator.addUpdateListener(new AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(final ValueAnimator animation) {
synchronized (DisplayHardwareController.this) {
if (isScreenOn()) {
float[] value = (float[]) animation.getAnimatedValue();
mHardware.setDisplayColorCalibration(new int[] {
(int) (value[0] * mMaxColor),
(int) (value[1] * mMaxColor),
(int) (value[2] * mMaxColor)
});
screenRefresh();
}
}
}
});
mAnimator.start();
}
/**
* Tell SurfaceFlinger to repaint the screen. This is called after updating
* hardware registers for display calibration to have an immediate effect.
*/
private void screenRefresh() {
try {
final IBinder flinger = ServiceManager.getService("SurfaceFlinger");
if (flinger != null) {
final Parcel data = Parcel.obtain();
data.writeInterfaceToken("android.ui.ISurfaceComposer");
flinger.transact(1004, data, null, 0);
data.recycle();
}
} catch (RemoteException ex) {
Slog.e(TAG, "Failed to refresh screen", ex);
}
}
/**
* Ensure all values are within range
*
* @param colors
* @return true if valid
*/
private boolean validateColors(float[] colors) {
if (colors == null || colors.length != 3) {
return false;
}
for (int i = 0; i < 3; i++) {
colors[i] = MathUtils.constrain(colors[i], 0.0f, 1.0f);
}
return true;
}
/**
* Parse and sanity check an RGB triplet from a string.
*/
private boolean parseColorAdjustment(String rgbString, float[] dest) {
String[] adj = rgbString == null ? null : rgbString.split(" ");
if (adj == null || adj.length != 3 || dest == null || dest.length != 3) {
return false;
}
try {
dest[0] = Float.parseFloat(adj[0]);
dest[1] = Float.parseFloat(adj[1]);
dest[2] = Float.parseFloat(adj[2]);
} catch (NumberFormatException e) {
Slog.e(TAG, e.getMessage(), e);
return false;
}
// sanity check
return validateColors(dest);
}
/**
* Additional adjustments provided by night mode
*
* @param adj
*/
synchronized boolean setAdditionalAdjustment(float[] adj) {
if (!mUseColorAdjustment) {
return false;
}
if (DEBUG) {
Slog.d(TAG, "setAdditionalAdjustment: " + Arrays.toString(adj));
}
// Sanity check this so we don't mangle the display
if (validateColors(adj)) {
copyColors(adj, mAdditionalAdjustment);
updateColorAdjustment();
return true;
}
return false;
}
boolean getDefaultCABC() {
return mDefaultCABC;
}
boolean getDefaultAutoContrast() {
return mDefaultAutoContrast;
}
boolean getDefaultColorEnhancement() {
return mDefaultColorEnhancement;
}
boolean isAutoContrastEnabled() {
return mUseAutoContrast &&
getBoolean(CMSettings.System.DISPLAY_AUTO_CONTRAST, mDefaultAutoContrast);
}
boolean setAutoContrastEnabled(boolean enabled) {
if (!mUseAutoContrast) {
return false;
}
putBoolean(CMSettings.System.DISPLAY_AUTO_CONTRAST, enabled);
return true;
}
boolean isCABCEnabled() {
return mUseCABC &&
getBoolean(CMSettings.System.DISPLAY_CABC, mDefaultCABC);
}
boolean setCABCEnabled(boolean enabled) {
if (!mUseCABC) {
return false;
}
putBoolean(CMSettings.System.DISPLAY_CABC, enabled);
return true;
}
boolean isColorEnhancementEnabled() {
return mUseColorEnhancement &&
getBoolean(CMSettings.System.DISPLAY_COLOR_ENHANCE,
mDefaultColorEnhancement);
}
boolean setColorEnhancementEnabled(boolean enabled) {
if (!mUseColorEnhancement) {
return false;
}
putBoolean(CMSettings.System.DISPLAY_COLOR_ENHANCE, enabled);
return true;
}
float[] getColorAdjustment() {
if (!mUseColorAdjustment) {
return getDefaultAdjustment();
}
float[] cur = new float[3];
if (!parseColorAdjustment(getString(CMSettings.System.DISPLAY_COLOR_ADJUSTMENT), cur)) {
// clear it out if invalid
cur = getDefaultAdjustment();
saveColorAdjustmentString(cur);
}
return cur;
}
boolean setColorAdjustment(float[] adj) {
// sanity check
if (!mUseColorAdjustment || !validateColors(adj)) {
return false;
}
saveColorAdjustmentString(adj);
return true;
}
private void saveColorAdjustmentString(final float[] adj) {
StringBuilder sb = new StringBuilder();
sb.append(adj[0]).append(" ").append(adj[1]).append(" ").append(adj[2]);
putString(CMSettings.System.DISPLAY_COLOR_ADJUSTMENT, sb.toString());
}
boolean hasColorAdjustment() {
return mUseColorAdjustment;
}
private static float[] getDefaultAdjustment() {
return new float[] { 1.0f, 1.0f, 1.0f };
}
private void copyColors(float[] src, float[] dst) {
if (src != null && dst != null && src.length == 3 && dst.length == 3) {
dst[0] = src[0];
dst[1] = src[1];
dst[2] = src[2];
}
}
}