436 lines
14 KiB
Java
436 lines
14 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.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.Slog;
|
|
|
|
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 CMHardwareManager mHardware;
|
|
|
|
// hardware capabilities
|
|
private boolean mUseAutoContrast;
|
|
private boolean mUseColorAdjustment;
|
|
private boolean mUseColorEnhancement;
|
|
private boolean mUseCABC;
|
|
|
|
// default values
|
|
private boolean mDefaultAutoContrast;
|
|
private boolean mDefaultColorEnhancement;
|
|
private boolean mDefaultCABC;
|
|
|
|
// current values
|
|
private boolean mAutoContrast;
|
|
private boolean mColorEnhancement;
|
|
private boolean mCABC;
|
|
|
|
// color adjustment holders
|
|
private final float[] mColorAdjustment = new float[] { 1.0f, 1.0f, 1.0f };
|
|
private final float[] mAdditionalAdjustment = new float[] { 1.0f, 1.0f, 1.0f };
|
|
private final float[] mRGB = new float[] { 1.0f, 1.0f, 1.0f };
|
|
|
|
// 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);
|
|
}
|
|
|
|
@Override
|
|
public boolean onStart() {
|
|
final ArrayList<Uri> settings = new ArrayList<Uri>();
|
|
|
|
mHardware = CMHardwareManager.getInstance(mContext);
|
|
mUseCABC = mHardware
|
|
.isSupported(CMHardwareManager.FEATURE_ADAPTIVE_BACKLIGHT);
|
|
if (mUseCABC) {
|
|
mDefaultCABC = mContext.getResources().getBoolean(
|
|
org.cyanogenmod.platform.internal.R.bool.config_defaultCABC);
|
|
mCABC = mHardware.get(CMHardwareManager.FEATURE_ADAPTIVE_BACKLIGHT);
|
|
settings.add(DISPLAY_CABC);
|
|
}
|
|
|
|
mUseColorEnhancement = mHardware
|
|
.isSupported(CMHardwareManager.FEATURE_COLOR_ENHANCEMENT);
|
|
if (mUseColorEnhancement) {
|
|
mDefaultColorEnhancement = mContext.getResources().getBoolean(
|
|
org.cyanogenmod.platform.internal.R.bool.config_defaultColorEnhancement);
|
|
mColorEnhancement = mHardware.get(CMHardwareManager.FEATURE_COLOR_ENHANCEMENT);
|
|
settings.add(DISPLAY_COLOR_ENHANCE);
|
|
}
|
|
|
|
mUseAutoContrast = mHardware
|
|
.isSupported(CMHardwareManager.FEATURE_AUTO_CONTRAST);
|
|
if (mUseAutoContrast) {
|
|
mDefaultAutoContrast = mContext.getResources().getBoolean(
|
|
org.cyanogenmod.platform.internal.R.bool.config_defaultAutoContrast);
|
|
mAutoContrast = mHardware.get(CMHardwareManager.FEATURE_AUTO_CONTRAST);
|
|
settings.add(DISPLAY_AUTO_CONTRAST);
|
|
}
|
|
|
|
mUseColorAdjustment = mHardware
|
|
.isSupported(CMHardwareManager.FEATURE_DISPLAY_COLOR_CALIBRATION);
|
|
if (mUseColorAdjustment) {
|
|
settings.add(DISPLAY_COLOR_ADJUSTMENT);
|
|
}
|
|
|
|
if (settings.size() == 0) {
|
|
return false;
|
|
}
|
|
|
|
registerSettings(settings.toArray(new Uri[settings.size()]));
|
|
return true;
|
|
}
|
|
|
|
@Override
|
|
void 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);
|
|
}
|
|
}
|
|
|
|
@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)) {
|
|
System.arraycopy(
|
|
parseColorAdjustment(getString(CMSettings.System.DISPLAY_COLOR_ADJUSTMENT)),
|
|
0, mColorAdjustment, 0, 3);
|
|
updateColorAdjustment();
|
|
}
|
|
}
|
|
|
|
@Override
|
|
public synchronized void onLowPowerModeChanged(boolean lowPowerMode) {
|
|
updateCABCMode();
|
|
updateAutoContrast();
|
|
updateColorEnhancement();
|
|
}
|
|
|
|
@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();
|
|
pw.println(" DisplayHardwareController State:");
|
|
pw.println(" mAutoContrast=" + mAutoContrast);
|
|
pw.println(" mColorEnhancement=" + mColorEnhancement);
|
|
pw.println(" mCABC=" + mCABC);
|
|
pw.println(" mColorAdjustment=" + Arrays.toString(mColorAdjustment));
|
|
pw.println(" mAdditionalAdjustment=" + Arrays.toString(mAdditionalAdjustment));
|
|
pw.println(" mRGB=" + Arrays.toString(mRGB));
|
|
}
|
|
|
|
boolean hasColorAdjustment() {
|
|
return mUseColorAdjustment;
|
|
}
|
|
|
|
/**
|
|
* Additional adjustments provided by night mode
|
|
*
|
|
* @param adj
|
|
*/
|
|
synchronized void setAdditionalAdjustment(float[] adj) {
|
|
if (DEBUG) {
|
|
Slog.d(TAG, "setAdditionalAdjustment: " + Arrays.toString(adj));
|
|
}
|
|
// Sanity check this so we don't mangle the display
|
|
if (adj != null && adj.length == 3 &&
|
|
!(adj[0] <= 0.0f && adj[1] <= 0.0f && adj[2] <= 0.0f)) {
|
|
for (int i = 0; i < 3; i++) {
|
|
if (adj[i] > 1.0f) {
|
|
adj[i] = 1.0f;
|
|
}
|
|
}
|
|
System.arraycopy(adj, 0, mAdditionalAdjustment, 0, 3);
|
|
updateColorAdjustment();
|
|
} else {
|
|
mAdditionalAdjustment[0] = 1.0f;
|
|
mAdditionalAdjustment[1] = 1.0f;
|
|
mAdditionalAdjustment[2] = 1.0f;
|
|
}
|
|
|
|
}
|
|
|
|
/**
|
|
* Automatic contrast optimization
|
|
*/
|
|
private synchronized void updateAutoContrast() {
|
|
if (!mUseAutoContrast) {
|
|
return;
|
|
}
|
|
|
|
boolean value = getInt(CMSettings.System.DISPLAY_AUTO_CONTRAST,
|
|
(mDefaultAutoContrast ? 1 : 0)) == 1;
|
|
|
|
boolean enabled = !isLowPowerMode() && value;
|
|
|
|
if (enabled == mAutoContrast) {
|
|
return;
|
|
}
|
|
|
|
mHardware.set(CMHardwareManager.FEATURE_AUTO_CONTRAST, enabled);
|
|
mAutoContrast = enabled;
|
|
}
|
|
|
|
/**
|
|
* Color enhancement is optional
|
|
*/
|
|
private synchronized void updateColorEnhancement() {
|
|
if (!mUseColorEnhancement) {
|
|
return;
|
|
}
|
|
|
|
boolean value = getInt(CMSettings.System.DISPLAY_COLOR_ENHANCE,
|
|
(mDefaultColorEnhancement ? 1 : 0)) == 1;
|
|
|
|
boolean enabled = !isLowPowerMode() && value;
|
|
|
|
if (enabled == mColorEnhancement) {
|
|
return;
|
|
}
|
|
|
|
mHardware.set(CMHardwareManager.FEATURE_COLOR_ENHANCEMENT, enabled);
|
|
mColorEnhancement = enabled;
|
|
}
|
|
|
|
/**
|
|
* Adaptive backlight / low power mode. Turn it off when under very bright light.
|
|
*/
|
|
private synchronized void updateCABCMode() {
|
|
if (!mUseCABC) {
|
|
return;
|
|
}
|
|
|
|
boolean value = getInt(CMSettings.System.DISPLAY_CABC,
|
|
(mDefaultCABC ? 1 : 0)) == 1;
|
|
|
|
boolean enabled = !isLowPowerMode() && value;
|
|
|
|
if (enabled == mCABC) {
|
|
return;
|
|
}
|
|
|
|
mHardware.set(CMHardwareManager.FEATURE_ADAPTIVE_BACKLIGHT, value);
|
|
mCABC = value;
|
|
}
|
|
|
|
private synchronized void updateColorAdjustment() {
|
|
if (!mUseColorAdjustment) {
|
|
return;
|
|
}
|
|
|
|
final float[] rgb = new float[] { 1.0f, 1.0f, 1.0f };
|
|
|
|
if (!isLowPowerMode()) {
|
|
|
|
System.arraycopy(mAdditionalAdjustment, 0, rgb, 0, 3);
|
|
rgb[0] *= mColorAdjustment[0];
|
|
rgb[1] *= mColorAdjustment[1];
|
|
rgb[2] *= mColorAdjustment[2];
|
|
}
|
|
|
|
if (rgb[0] == mRGB[0] && rgb[1] == mRGB[1] && rgb[2] == mRGB[2]) {
|
|
// no changes
|
|
return;
|
|
}
|
|
|
|
if (DEBUG) {
|
|
Slog.d(TAG, "updateColorAdjustment: " + Arrays.toString(rgb));
|
|
}
|
|
|
|
int max = mHardware.getDisplayColorCalibrationMax();
|
|
mHardware.setDisplayColorCalibration(new int[] {
|
|
(int) Math.ceil(rgb[0] * max),
|
|
(int) Math.ceil(rgb[1] * max),
|
|
(int) Math.ceil(rgb[2] * max)
|
|
});
|
|
System.arraycopy(rgb, 0, mRGB, 0, 3);
|
|
|
|
screenRefresh();
|
|
}
|
|
|
|
/**
|
|
* 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);
|
|
}
|
|
}
|
|
|
|
boolean getDefaultCABC() {
|
|
return mDefaultCABC;
|
|
}
|
|
|
|
boolean getDefaultAutoContrast() {
|
|
return mDefaultAutoContrast;
|
|
}
|
|
|
|
boolean getDefaultColorEnhancement() {
|
|
return mDefaultColorEnhancement;
|
|
}
|
|
|
|
boolean isAutoContrastEnabled() {
|
|
return mUseAutoContrast &&
|
|
getInt(CMSettings.System.DISPLAY_AUTO_CONTRAST,
|
|
(mDefaultAutoContrast ? 1 : 0)) == 1;
|
|
}
|
|
|
|
boolean setAutoContrastEnabled(boolean enabled) {
|
|
if (!mUseAutoContrast) {
|
|
return false;
|
|
}
|
|
putInt(CMSettings.System.DISPLAY_AUTO_CONTRAST, enabled ? 1 : 0);
|
|
return true;
|
|
}
|
|
|
|
boolean isCABCEnabled() {
|
|
return mUseCABC &&
|
|
getInt(CMSettings.System.DISPLAY_CABC,
|
|
(mDefaultCABC ? 1 : 0)) == 1;
|
|
}
|
|
|
|
boolean setCABCEnabled(boolean enabled) {
|
|
if (!mUseCABC) {
|
|
return false;
|
|
}
|
|
putInt(CMSettings.System.DISPLAY_CABC, enabled ? 1 : 0);
|
|
return true;
|
|
}
|
|
|
|
boolean isColorEnhancementEnabled() {
|
|
return mUseColorEnhancement &&
|
|
getInt(CMSettings.System.DISPLAY_COLOR_ENHANCE,
|
|
(mDefaultColorEnhancement ? 1 : 0)) == 1;
|
|
}
|
|
|
|
boolean setColorEnhancementEnabled(boolean enabled) {
|
|
if (!mUseColorEnhancement) {
|
|
return false;
|
|
}
|
|
putInt(CMSettings.System.DISPLAY_COLOR_ENHANCE, enabled ? 1 : 0);
|
|
return true;
|
|
}
|
|
|
|
|
|
float[] getColorAdjustment() {
|
|
if (!mUseColorAdjustment) {
|
|
return new float[] { 1.0f, 1.0f, 1.0f };
|
|
}
|
|
return parseColorAdjustment(getString(CMSettings.System.DISPLAY_COLOR_ADJUSTMENT));
|
|
}
|
|
|
|
boolean setColorAdjustment(float[] adj) {
|
|
// sanity check
|
|
if (!mUseColorAdjustment || adj.length != 3 ||
|
|
adj[0] < 0 || adj[0] > 1.0f ||
|
|
adj[1] < 0 || adj[1] > 1.0f ||
|
|
adj[2] < 0 || adj[2] > 1.0f) {
|
|
return false;
|
|
}
|
|
StringBuilder sb = new StringBuilder();
|
|
sb.append(adj[0]).append(" ").append(adj[1]).append(" ").append(adj[2]);
|
|
|
|
putString(CMSettings.System.DISPLAY_COLOR_ADJUSTMENT, sb.toString());
|
|
return true;
|
|
}
|
|
|
|
/**
|
|
* Parse and sanity check an RGB triplet from a string.
|
|
*/
|
|
private float[] parseColorAdjustment(String rgbString) {
|
|
String[] adj = rgbString == null ? null : rgbString.split(" ");
|
|
float[] parsed = new float[3];
|
|
|
|
if (adj == null || adj.length != 3) {
|
|
adj = new String[] { "1.0", "1.0", "1.0" };
|
|
}
|
|
|
|
try {
|
|
parsed[0] = Float.parseFloat(adj[0]);
|
|
parsed[1] = Float.parseFloat(adj[1]);
|
|
parsed[2] = Float.parseFloat(adj[2]);
|
|
} catch (NumberFormatException e) {
|
|
Slog.e(TAG, e.getMessage(), e);
|
|
parsed[0] = 1.0f;
|
|
parsed[1] = 1.0f;
|
|
parsed[2] = 1.0f;
|
|
}
|
|
|
|
// sanity check
|
|
for (int i = 0; i < parsed.length; i++) {
|
|
if (parsed[i] <= 0.0f || parsed[i] > 1.0f) {
|
|
parsed[i] = 1.0f;
|
|
}
|
|
}
|
|
return parsed;
|
|
}
|
|
}
|