Color transforms for the tuner
Change-Id: I615be65e2b020acd5520f93c04f426c4006221c5
diff --git a/core/java/com/android/internal/logging/MetricsLogger.java b/core/java/com/android/internal/logging/MetricsLogger.java
index e276bc6..bfc56db 100644
--- a/core/java/com/android/internal/logging/MetricsLogger.java
+++ b/core/java/com/android/internal/logging/MetricsLogger.java
@@ -35,6 +35,7 @@
public static final int ACTION_ZEN_ALLOW_LIGHTS = 262;
public static final int NOTIFICATION_TOPIC_NOTIFICATION = 263;
public static final int ACTION_DEFAULT_SMS_APP_CHANGED = 264;
+ public static final int QS_COLOR_MATRIX = 265;
/**
* Logged when the user docks a window from recents by longpressing a task and dragging it to
diff --git a/packages/SystemUI/res/drawable/ic_colorize.xml b/packages/SystemUI/res/drawable/ic_colorize.xml
new file mode 100644
index 0000000..79fd6d9
--- /dev/null
+++ b/packages/SystemUI/res/drawable/ic_colorize.xml
@@ -0,0 +1,24 @@
+<!--
+ Copyright (C) 2015 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.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24.0dp"
+ android:height="24.0dp"
+ android:viewportWidth="24.0"
+ android:viewportHeight="24.0">
+ <path
+ android:fillColor="#FFFFFFFF"
+ android:pathData="M20.71,5.63l-2.34,-2.34c-0.39,-0.39 -1.02,-0.39 -1.41,0.0l-3.12,3.12 -1.93,-1.91 -1.41,1.41 1.42,1.42L3.0,16.25L3.0,21.0l4.75,0.0l8.92,-8.92 1.42,1.42 1.41,-1.41 -1.92,-1.92 3.12,-3.12c0.4,0.0 0.4,-1.0 0.01,-1.42zM6.92,19.0L5.0,17.08l8.06,-8.06 1.92,1.92L6.92,19.0z"/>
+</vector>
diff --git a/packages/SystemUI/res/layout/preference_matrix.xml b/packages/SystemUI/res/layout/preference_matrix.xml
new file mode 100644
index 0000000..ebf486f
--- /dev/null
+++ b/packages/SystemUI/res/layout/preference_matrix.xml
@@ -0,0 +1,100 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright (C) 2015 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.
+-->
+
+<LinearLayout
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:orientation="horizontal">
+ <Space
+ android:layout_width="0dp"
+ android:layout_height="wrap_content"
+ android:layout_weight="1" />
+ <GridLayout
+ android:id="@+id/edit_group"
+ android:layout_height="wrap_content"
+ android:layout_width="wrap_content"
+ android:rowCount="5"
+ android:columnCount="5">
+
+ <Space android:layout_width="40dp" />
+
+ <TextView
+ android:layout_width="40dp"
+ android:text="@string/color_modification_r"
+ android:gravity="center"
+ android:textAppearance="?android:attr/textAppearanceMedium" />
+
+ <TextView
+ android:layout_width="40dp"
+ android:text="@string/color_modification_g"
+ android:gravity="center"
+ android:textAppearance="?android:attr/textAppearanceMedium" />
+
+ <TextView
+ android:layout_width="40dp"
+ android:text="@string/color_modification_b"
+ android:gravity="center"
+ android:textAppearance="?android:attr/textAppearanceMedium" />
+
+ <Space android:layout_width="40dp" />
+
+ <TextView
+ android:layout_width="40dp"
+ android:text="@string/color_modification_r"
+ android:gravity="center"
+ android:textAppearance="?android:attr/textAppearanceMedium" />
+ <EditText android:inputType="numberDecimal" android:layout_width="40dp" />
+ <EditText android:inputType="numberDecimal" android:layout_width="40dp" />
+ <EditText android:inputType="numberDecimal" android:layout_width="40dp" />
+ <EditText android:inputType="numberDecimal" android:layout_width="40dp" />
+
+ <TextView
+ android:layout_width="40dp"
+ android:text="@string/color_modification_g"
+ android:gravity="center"
+ android:textAppearance="?android:attr/textAppearanceMedium" />
+ <EditText android:inputType="numberDecimal" android:layout_width="40dp" />
+ <EditText android:inputType="numberDecimal" android:layout_width="40dp" />
+ <EditText android:inputType="numberDecimal" android:layout_width="40dp" />
+ <EditText android:inputType="numberDecimal" android:layout_width="40dp" />
+
+ <TextView
+ android:layout_width="40dp"
+ android:text="@string/color_modification_b"
+ android:gravity="center"
+ android:textAppearance="?android:attr/textAppearanceMedium" />
+ <EditText android:inputType="numberDecimal" android:layout_width="40dp" />
+ <EditText android:inputType="numberDecimal" android:layout_width="40dp" />
+ <EditText android:inputType="numberDecimal" android:layout_width="40dp" />
+ <EditText android:inputType="numberDecimal" android:layout_width="40dp" />
+
+ <Space android:layout_width="40dp" />
+ <EditText android:inputType="numberDecimal" android:layout_width="40dp" />
+ <EditText android:inputType="numberDecimal" android:layout_width="40dp" />
+ <EditText android:inputType="numberDecimal" android:layout_width="40dp" />
+ <EditText android:inputType="numberDecimal" android:layout_width="40dp" />
+
+ </GridLayout>
+ <Button
+ android:id="@+id/apply"
+ android:layout_width="0dp"
+ android:layout_height="wrap_content"
+ android:layout_weight="1"
+ android:layout_gravity="bottom"
+ android:text="@string/color_apply" />
+</LinearLayout>
diff --git a/packages/SystemUI/res/layout/preference_widget_settings.xml b/packages/SystemUI/res/layout/preference_widget_settings.xml
new file mode 100644
index 0000000..082a295
--- /dev/null
+++ b/packages/SystemUI/res/layout/preference_widget_settings.xml
@@ -0,0 +1,44 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright (C) 2015 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.
+-->
+
+<LinearLayout
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_height="wrap_content"
+ android:layout_width="wrap_content">
+
+ <RadioButton
+ android:id="@+id/radio_button"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginEnd="4dp"
+ android:clickable="false"
+ android:focusable="false" />
+
+ <View
+ android:layout_width="1dp"
+ android:layout_height="match_parent"
+ android:background="?android:attr/listDivider" />
+
+ <ImageView
+ android:id="@+id/widget_icon"
+ android:layout_width="50dp"
+ android:layout_height="24dp"
+ android:tint="@android:color/black"
+ android:src="@drawable/ic_settings"
+ android:layout_gravity="center_vertical" />
+
+</LinearLayout>
diff --git a/packages/SystemUI/res/layout/preference_widget_switch.xml b/packages/SystemUI/res/layout/preference_widget_switch.xml
new file mode 100644
index 0000000..49610de
--- /dev/null
+++ b/packages/SystemUI/res/layout/preference_widget_switch.xml
@@ -0,0 +1,44 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright (C) 2015 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.
+-->
+
+<LinearLayout
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_height="wrap_content"
+ android:layout_width="wrap_content">
+
+ <RadioButton
+ android:id="@+id/radio_button"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:clickable="false"
+ android:focusable="false"
+ android:layout_marginEnd="4dp" />
+
+ <View
+ android:layout_width="1dp"
+ android:layout_height="match_parent"
+ android:background="?android:attr/listDivider" />
+
+ <Switch
+ android:id="@*android:id/switch_widget"
+ android:layout_width="50dp"
+ android:layout_height="wrap_content"
+ android:focusable="false"
+ android:clickable="false"
+ android:background="@null" />
+
+</LinearLayout>
diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml
index 6658cfe..45ddd50 100644
--- a/packages/SystemUI/res/values/strings.xml
+++ b/packages/SystemUI/res/values/strings.xml
@@ -1228,4 +1228,40 @@
<!-- [CHAR LIMIT=100] Notification Importance slider: max importance level description -->
<string name="notification_importance_max">Peek onto the screen and make sound</string>
+ <!-- Label for no color transform [CHAR LIMIT=30] -->
+ <string name="color_matrix_none">Normal colors</string>
+
+ <!-- Label for night color transform [CHAR LIMIT=30] -->
+ <string name="color_matrix_night">Night colors</string>
+
+ <!-- Label for custom color transform [CHAR LIMIT=30] -->
+ <string name="color_matrix_custom">Custom colors</string>
+
+ <!-- Label for unknown color transform [CHAR LIMIT=30] -->
+ <string name="color_matrix_unknown">Unknown colors</string>
+
+ <!-- Title for color transform [CHAR LIMIT=30] -->
+ <string name="color_transform">Color modification</string>
+
+ <!-- Title for setting to show Quick Settings tile [CHAR LIMIT=60] -->
+ <string name="color_matrix_show_qs">Show Quick Settings tile</string>
+
+ <!-- Title for switch to enable custom color transform [CHAR LIMIT=60] -->
+ <string name="color_enable_custom">Enable custom transform</string>
+
+ <!-- Button to apply settings [CHAR LIMIT=30] -->
+ <string name="color_apply">Apply</string>
+
+ <!-- Title of warning dialog about bad color settings. [CHAR LIMIT=30] -->
+ <string name="color_revert_title">Confirm settings</string>
+
+ <!-- Message warning user about custom color settings [CHAR LIMIT=NONE] -->
+ <string name="color_revert_message">Some color settings can make this
+ device unusable. Click OK to confirm these color settings,
+ otherwise these settings will reset after 10 seconds.</string>
+
+ <string name="color_modification_r" translatable="false">R</string>
+ <string name="color_modification_g" translatable="false">G</string>
+ <string name="color_modification_b" translatable="false">B</string>
+
</resources>
diff --git a/packages/SystemUI/res/values/styles.xml b/packages/SystemUI/res/values/styles.xml
index 7e01866..a9176e0 100644
--- a/packages/SystemUI/res/values/styles.xml
+++ b/packages/SystemUI/res/values/styles.xml
@@ -310,7 +310,11 @@
</style>
<style name="TunerSettings" parent="@android:style/Theme.Material.Settings">
- <item name="preferenceTheme">@android:style/Theme.Material.Settings</item>
+ <item name="preferenceTheme">@style/TunerPreferenceTheme</item>
+ </style>
+
+ <style name="TunerPreferenceTheme" parent="@android:style/Theme.Material.Settings">
+ <item name="@dropdownPreferenceStyle">@style/Preference.DropDown.Material</item>
</style>
</resources>
diff --git a/packages/SystemUI/res/xml/tuner_prefs.xml b/packages/SystemUI/res/xml/tuner_prefs.xml
index 6103216..f02f763 100644
--- a/packages/SystemUI/res/xml/tuner_prefs.xml
+++ b/packages/SystemUI/res/xml/tuner_prefs.xml
@@ -102,6 +102,11 @@
android:title="@string/demo_mode"
android:fragment="com.android.systemui.tuner.DemoModeFragment" />
+ <Preference
+ android:key="color_transform"
+ android:title="@string/color_transform"
+ android:fragment="com.android.systemui.tuner.ColorMatrixFragment" />
+
<!-- Warning, this goes last. -->
<Preference
android:summary="@string/tuner_persistent_warning"
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/QSTileHost.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/QSTileHost.java
index 7f27ba7..e6d837a 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/QSTileHost.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/QSTileHost.java
@@ -64,6 +64,7 @@
import com.android.systemui.statusbar.policy.UserInfoController;
import com.android.systemui.statusbar.policy.UserSwitcherController;
import com.android.systemui.statusbar.policy.ZenModeController;
+import com.android.systemui.tuner.ColorMatrixTile;
import com.android.systemui.tuner.TunerService;
import com.android.systemui.tuner.TunerService.Tunable;
@@ -368,6 +369,8 @@
else if (tileSpec.equals("hotspot")) return new HotspotTile(this);
else if (tileSpec.equals("user")) return new UserTile(this);
else if (tileSpec.equals("battery")) return new BatteryTile(this);
+ else if (tileSpec.equals(ColorMatrixTile.COLOR_MATRIX_SPEC))
+ return new ColorMatrixTile(this);
// Intent tiles.
else if (tileSpec.startsWith(IntentTile.PREFIX)) return IntentTile.create(this,tileSpec);
else if (tileSpec.startsWith(CustomTile.PREFIX)) return CustomTile.create(this,tileSpec);
diff --git a/packages/SystemUI/src/com/android/systemui/tuner/ColorMatrixFragment.java b/packages/SystemUI/src/com/android/systemui/tuner/ColorMatrixFragment.java
new file mode 100644
index 0000000..8ed1b06
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/tuner/ColorMatrixFragment.java
@@ -0,0 +1,355 @@
+/**
+ * Copyright (c) 2015, 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.systemui.tuner;
+
+import android.annotation.Nullable;
+import android.app.AlertDialog;
+import android.app.Dialog;
+import android.app.DialogFragment;
+import android.content.Context;
+import android.content.DialogInterface;
+import android.os.Bundle;
+import android.provider.Settings;
+import android.support.v14.preference.PreferenceFragment;
+import android.support.v14.preference.SwitchPreference;
+import android.support.v7.preference.DropDownPreference;
+import android.support.v7.preference.Preference;
+import android.support.v7.preference.PreferenceViewHolder;
+import android.text.Editable;
+import android.text.TextUtils;
+import android.text.TextWatcher;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.Button;
+import android.widget.EditText;
+import com.android.systemui.R;
+import com.android.systemui.statusbar.phone.QSTileHost;
+
+import java.util.Objects;
+
+public class ColorMatrixFragment extends PreferenceFragment implements TunerService.Tunable {
+
+ private static final String TAG = "ColorMatrixFragment";
+
+ public static final int CUSTOM_INDEX = 2;
+
+ // Night mode ~= 3400 K
+ private static final float[] NIGHT_VALUES = new float[] {
+ 1, 0, 0, 0,
+ 0, .754f, 0, 0,
+ 0, 0, .516f, 0,
+ 0, 0, 0, 1,
+ };
+ public static final float[] IDENTITY_MATRIX = new float[]{
+ 1, 0, 0, 0,
+ 0, 1, 0, 0,
+ 0, 0, 1, 0,
+ 0, 0, 0, 1,
+ };
+ private static final long RESET_DELAY = 10000;
+
+ private boolean mCustomEnabled;
+ private DropDownPreference mSelectPreference;
+ private String mCurrentValue;
+ private String mCustomValues;
+ private SwitchPreference mEnableCustomPreference;
+ private MatrixPreference mCustomPreference;
+ private SwitchPreference mShowQs;
+ private String mTiles;
+
+ @Override
+ public void onCreate(@Nullable Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+
+ Context context = getContext();
+ TunerService.get(context).addTunable(this, ColorMatrixTile.COLOR_MATRIX_CUSTOM_ENABLED,
+ ColorMatrixTile.COLOR_MATRIX_CUSTOM_VALUES, QSTileHost.TILES_SETTING,
+ Settings.Secure.ACCESSIBILITY_DISPLAY_COLOR_MATRIX);
+ }
+
+ @Override
+ public void onCreatePreferences(Bundle savedInstanceState, String rootKey) {
+ final Context context = getPreferenceManager().getContext();
+ setPreferenceScreen(getPreferenceManager().createPreferenceScreen(context));
+
+ mSelectPreference = new DropDownPreference(context);
+ mSelectPreference.setTitle(R.string.color_transform);
+ mSelectPreference.setSummary("%s");
+ mSelectPreference.setOnPreferenceChangeListener(new Preference.OnPreferenceChangeListener() {
+ @Override
+ public boolean onPreferenceChange(Preference preference, Object newValue) {
+ int index = Integer.parseInt((String) newValue);
+ Settings.Secure.putString(context.getContentResolver(),
+ Settings.Secure.ACCESSIBILITY_DISPLAY_COLOR_MATRIX, getValues()[index]);
+ return true;
+ }
+ });
+ getPreferenceScreen().addPreference(mSelectPreference);
+
+ mShowQs = new SwitchPreference(context);
+ mShowQs.setTitle(R.string.color_matrix_show_qs);
+ mShowQs.setOnPreferenceChangeListener(new Preference.OnPreferenceChangeListener() {
+ @Override
+ public boolean onPreferenceChange(Preference preference, Object newValue) {
+ boolean showTile = (Boolean) newValue;
+ String newTiles;
+ if (showTile) {
+ newTiles = mTiles != null ? mTiles + "," + ColorMatrixTile.COLOR_MATRIX_SPEC
+ : "default," + ColorMatrixTile.COLOR_MATRIX_SPEC;
+ } else {
+ newTiles =
+ mTiles.replace(mTiles.contains(ColorMatrixTile.COLOR_MATRIX_SPEC+ ",")
+ ? ColorMatrixTile.COLOR_MATRIX_SPEC + ","
+ : "," + ColorMatrixTile.COLOR_MATRIX_SPEC, "");
+ }
+ Settings.Secure.putString(context.getContentResolver(), QSTileHost.TILES_SETTING,
+ newTiles);
+ return true;
+ }
+ });
+ getPreferenceScreen().addPreference(mShowQs);
+
+ mEnableCustomPreference = new SwitchPreference(context);
+ mEnableCustomPreference.setTitle(R.string.color_enable_custom);
+ mEnableCustomPreference.setOnPreferenceChangeListener(
+ new Preference.OnPreferenceChangeListener() {
+ @Override
+ public boolean onPreferenceChange(Preference preference, Object newValue) {
+ boolean enabled = (Boolean) newValue;
+ Settings.Secure.putInt(context.getContentResolver(),
+ ColorMatrixTile.COLOR_MATRIX_CUSTOM_ENABLED, enabled ? 1 : 0);
+ return true;
+ }
+ });
+ getPreferenceScreen().addPreference(mEnableCustomPreference);
+
+ mCustomPreference = new MatrixPreference(context);
+ getPreferenceScreen().addPreference(mCustomPreference);
+ }
+
+ @Override
+ public void onDestroy() {
+ super.onDestroy();
+ TunerService.get(getContext()).removeTunable(this);
+ }
+
+ @Override
+ public void onTuningChanged(String key, String newValue) {
+ if (ColorMatrixTile.COLOR_MATRIX_CUSTOM_ENABLED.equals(key)) {
+ mCustomEnabled = newValue != null && Integer.parseInt(newValue) != 0;
+ mEnableCustomPreference.setChecked(mCustomEnabled);
+ mCustomPreference.setEnabled(mCustomEnabled);
+ updateSelectOptions();
+ } else if (ColorMatrixTile.COLOR_MATRIX_CUSTOM_VALUES.equals(key)) {
+ mCustomValues = newValue;
+ mCustomPreference.setValues(mCustomValues);
+ updateSelectOptions();
+ } else if (QSTileHost.TILES_SETTING.equals(key)) {
+ mTiles = newValue;
+ boolean hasTile = newValue != null
+ && newValue.contains(ColorMatrixTile.COLOR_MATRIX_SPEC);
+ mShowQs.setChecked(hasTile);
+ } else {
+ mCurrentValue = newValue;
+ updateSelectOptions();
+ }
+ }
+
+ private void updateSelectOptions() {
+ final int N = CUSTOM_INDEX + (mCustomEnabled ? 1 : 0);
+ String[] values = new String[N];
+ CharSequence[] totalNames = getColorTitles(getContext());
+ CharSequence[] names = new CharSequence[N];
+ for (int i = 0; i < N; i++) {
+ values[i] = String.valueOf(i);
+ names[i] = totalNames[i];
+ }
+ mSelectPreference.setEntries(names);
+ mSelectPreference.setEntryValues(values);
+ String[] entries = getValues();
+ for (int i = 0; i < values.length; i++) {
+ if (Objects.equals(entries[i], mCurrentValue)) {
+ mSelectPreference.setValueIndex(i);
+ return;
+ }
+ }
+ mSelectPreference.setSummary(R.string.color_matrix_unknown);
+ return;
+ }
+
+ private String[] getValues() {
+ String[] ret = getColorTransforms();
+ // Fill in custom based on tuner settings.
+ ret[CUSTOM_INDEX] = mCustomValues;
+ return ret;
+ }
+
+ private void startRevertTimer() {
+ getView().postDelayed(mResetColorMatrix, RESET_DELAY);
+ }
+
+ private void onApply() {
+ Settings.Secure.putString(getContext().getContentResolver(),
+ ColorMatrixTile.COLOR_MATRIX_CUSTOM_VALUES, mCurrentValue);
+ getView().removeCallbacks(mResetColorMatrix);
+ }
+
+ private void onRevert() {
+ getView().removeCallbacks(mResetColorMatrix);
+ mResetColorMatrix.run();
+ }
+
+ public static String[] getColorTransforms() {
+ return new String[] {
+ null,
+ toString(NIGHT_VALUES),
+ null, // Blank spot for custom values
+ null, // Unknown
+ };
+ }
+
+ public static CharSequence[] getColorTitles(Context context) {
+ return new CharSequence[] {
+ context.getString(R.string.color_matrix_none),
+ context.getString(R.string.color_matrix_night),
+ context.getString(R.string.color_matrix_custom),
+ context.getString(R.string.color_matrix_unknown),
+ };
+ }
+
+ private static String toString(float[] values) {
+ StringBuilder builder = new StringBuilder();
+ for (int i = 0; i < values.length; i++) {
+ if (builder.length() != 0) {
+ builder.append(',');
+ }
+ builder.append(values[i]);
+ }
+ return builder.toString();
+ }
+
+ private final Runnable mResetColorMatrix = new Runnable() {
+ @Override
+ public void run() {
+ ((DialogFragment) getFragmentManager().findFragmentByTag("RevertWarning")).dismiss();
+ Settings.Secure.putString(getContext().getContentResolver(),
+ Settings.Secure.ACCESSIBILITY_DISPLAY_COLOR_MATRIX, null);
+ }
+ };
+
+ private class MatrixPreference extends Preference implements View.OnClickListener {
+ private float[] mValues;
+
+ public MatrixPreference(Context context) {
+ super(context);
+ setLayoutResource(R.layout.preference_matrix);
+ }
+
+ public void setValues(String customValues) {
+ if (customValues == null) {
+ mValues = IDENTITY_MATRIX;
+ } else {
+ String[] strValues = customValues.split(",");
+ mValues = new float[strValues.length];
+ for (int i = 0; i < mValues.length; i++) {
+ mValues[i] = Float.parseFloat(strValues[i]);
+ }
+ }
+ notifyChanged();
+ }
+
+ @Override
+ public void onBindViewHolder(PreferenceViewHolder holder) {
+ super.onBindViewHolder(holder);
+ ViewGroup vg = (ViewGroup) holder.itemView.findViewById(R.id.edit_group);
+ if (mValues == null) {
+ return;
+ }
+ int childIndex = 0;
+ for (int i = 0; i < mValues.length; i++) {
+ final int index = i;
+ while (!(vg.getChildAt(childIndex) instanceof EditText)) {
+ childIndex++;
+ }
+ final EditText editText = (EditText) vg.getChildAt(childIndex++);
+ editText.setText(String.valueOf(mValues[i]));
+ editText.addTextChangedListener(new TextWatcher() {
+ @Override
+ public void afterTextChanged(Editable s) {
+ if (TextUtils.isEmpty(s.toString())) {
+ return;
+ }
+ try {
+ mValues[index] = Float.parseFloat(s.toString());
+ } catch (NumberFormatException e) {
+ mValues[index] = 0;
+ }
+ }
+
+ @Override
+ public void onTextChanged(CharSequence s, int start, int before, int count) {
+ }
+
+ @Override
+ public void beforeTextChanged(CharSequence s, int start, int count, int after) {
+ }
+ });
+ }
+ ((Button) holder.itemView.findViewById(R.id.apply)).setOnClickListener(this);
+ }
+
+ @Override
+ public void onClick(View v) {
+ Settings.Secure.putString(getContext().getContentResolver(),
+ Settings.Secure.ACCESSIBILITY_DISPLAY_COLOR_MATRIX,
+ ColorMatrixFragment.toString(mValues));
+ RevertWarning.show(ColorMatrixFragment.this);
+ }
+
+ }
+
+ public static class RevertWarning extends DialogFragment
+ implements DialogInterface.OnClickListener {
+
+ public static void show(ColorMatrixFragment fragment) {
+ RevertWarning warning = new RevertWarning();
+ warning.setTargetFragment(fragment, 0);
+ warning.show(fragment.getFragmentManager(), "RevertWarning");
+ }
+
+ @Override
+ public Dialog onCreateDialog(Bundle savedInstanceState) {
+ AlertDialog alertDialog = new AlertDialog.Builder(getContext())
+ .setTitle(R.string.color_revert_title)
+ .setMessage(R.string.color_revert_message)
+ .setPositiveButton(R.string.ok, this)
+ .create();
+ alertDialog.setCanceledOnTouchOutside(true);
+ return alertDialog;
+ }
+
+ @Override
+ public void onCancel(DialogInterface dialog) {
+ super.onCancel(dialog);
+ ((ColorMatrixFragment) getTargetFragment()).onRevert();
+ }
+
+ @Override
+ public void onClick(DialogInterface dialog, int which) {
+ ((ColorMatrixFragment) getTargetFragment()).onApply();
+ }
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/tuner/ColorMatrixTile.java b/packages/SystemUI/src/com/android/systemui/tuner/ColorMatrixTile.java
new file mode 100644
index 0000000..1fd2352
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/tuner/ColorMatrixTile.java
@@ -0,0 +1,107 @@
+/**
+ * Copyright (c) 2015, 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.systemui.tuner;
+
+import android.app.ActivityManager;
+import android.provider.Settings;
+import com.android.internal.logging.MetricsLogger;
+import com.android.systemui.R;
+import com.android.systemui.qs.QSTile;
+import libcore.util.Objects;
+
+public class ColorMatrixTile extends QSTile<QSTile.State> implements TunerService.Tunable {
+
+ public static final String COLOR_MATRIX_CUSTOM_ENABLED = "tuner_color_custom_enabled";
+ public static final String COLOR_MATRIX_CUSTOM_VALUES = "tuner_color_custom_values";
+
+ public static final String COLOR_MATRIX_SPEC = "colors";
+
+ private int mIndex;
+ private String mCurrentValue;
+
+ private boolean mCustomEnabled;
+ private String[] mValues;
+ private CharSequence[] mValueTitles;
+
+ public ColorMatrixTile(Host host) {
+ super(host);
+ }
+
+ @Override
+ public void setListening(boolean listening) {
+ if (listening) {
+ mValues = ColorMatrixFragment.getColorTransforms();
+ mValueTitles = ColorMatrixFragment.getColorTitles(mContext);
+ TunerService.get(mContext).addTunable(this, COLOR_MATRIX_CUSTOM_ENABLED,
+ COLOR_MATRIX_CUSTOM_VALUES,
+ Settings.Secure.ACCESSIBILITY_DISPLAY_COLOR_MATRIX);
+ } else {
+ TunerService.get(mContext).removeTunable(this);
+ }
+ }
+
+ @Override
+ protected State newTileState() {
+ return new State();
+ }
+
+ @Override
+ protected void handleClick() {
+ mIndex++;
+ if (!mCustomEnabled && (mIndex == ColorMatrixFragment.CUSTOM_INDEX)) {
+ mIndex++;
+ }
+ if (mIndex == mValues.length - 1) {
+ mIndex = 0;
+ }
+ Settings.Secure.putStringForUser(mContext.getContentResolver(),
+ Settings.Secure.ACCESSIBILITY_DISPLAY_COLOR_MATRIX, mValues[mIndex],
+ ActivityManager.getCurrentUser());
+ refreshState();
+ }
+
+ @Override
+ public void onTuningChanged(String key, String newValue) {
+ if (COLOR_MATRIX_CUSTOM_ENABLED.equals(key)) {
+ mCustomEnabled = newValue != null && Integer.parseInt(newValue) != 0;
+ } else if (COLOR_MATRIX_CUSTOM_VALUES.equals(key)) {
+ mValues[ColorMatrixFragment.CUSTOM_INDEX] = newValue;
+ } else {
+ mCurrentValue = newValue;
+ }
+ // Last value is unknown, default to that.
+ mIndex = mValues.length - 1;
+ for (int i = 0; i < mValues.length - 1; i++) {
+ if (Objects.equal(mCurrentValue, mValues[i])) {
+ mIndex = i;
+ break;
+ }
+ }
+ refreshState();
+ }
+
+ @Override
+ protected void handleUpdateState(State state, Object arg) {
+ state.icon = ResourceIcon.get(R.drawable.ic_colorize);
+ state.label = mValueTitles[mIndex];
+ state.contentDescription = mValueTitles[mIndex];
+ }
+
+ @Override
+ public int getMetricsCategory() {
+ return MetricsLogger.QS_COLOR_MATRIX;
+ }
+}