From 225e7896b032e56dafb6f409e1e8156e79aaa680 Mon Sep 17 00:00:00 2001 From: Jens Doll Date: Wed, 10 Apr 2013 10:07:03 +0200 Subject: [PATCH] User defined colours for pie controls (2/2) This is the settings part of the commit. For more information look at the framework/base commit. Change-Id: Iaf486114db08cd6b002a3e5f25d6e4a9d915a7ae --- res/layout/dialog_pie_colors.xml | 41 ++++ res/layout/preference_widget_pie_color.xml | 10 + res/values/cm_strings.xml | 8 + res/xml/pie_control.xml | 37 ++- .../settings/cyanogenmod/PieColorDialog.java | 117 +++++++++ .../cyanogenmod/PieColorPreference.java | 232 ++++++++++++++++++ .../settings/cyanogenmod/PieControl.java | 112 ++++++++- 7 files changed, 552 insertions(+), 5 deletions(-) create mode 100644 res/layout/dialog_pie_colors.xml create mode 100644 res/layout/preference_widget_pie_color.xml create mode 100644 src/com/android/settings/cyanogenmod/PieColorDialog.java create mode 100644 src/com/android/settings/cyanogenmod/PieColorPreference.java diff --git a/res/layout/dialog_pie_colors.xml b/res/layout/dialog_pie_colors.xml new file mode 100644 index 00000000000..e90b33582b2 --- /dev/null +++ b/res/layout/dialog_pie_colors.xml @@ -0,0 +1,41 @@ + + + + + + + + + + + + + diff --git a/res/layout/preference_widget_pie_color.xml b/res/layout/preference_widget_pie_color.xml new file mode 100644 index 00000000000..a7ffd89338e --- /dev/null +++ b/res/layout/preference_widget_pie_color.xml @@ -0,0 +1,10 @@ + + + diff --git a/res/values/cm_strings.xml b/res/values/cm_strings.xml index b519edb388f..af757677a2e 100755 --- a/res/values/cm_strings.xml +++ b/res/values/cm_strings.xml @@ -943,6 +943,14 @@ two in order to insert additional control points. \'Remove\' deletes the selecte Right screen border Top screen border Only navigation will be displayed at top + Pie Color Settings + Normal background + Selected background + Long pressed background + Icon color + Show outline + Edit color setting + Reset Stylus gestures diff --git a/res/xml/pie_control.xml b/res/xml/pie_control.xml index ce8a40a415f..5b19a3c0da4 100755 --- a/res/xml/pie_control.xml +++ b/res/xml/pie_control.xml @@ -51,5 +51,40 @@ android:title="@string/pie_control_trigger_top" android:summary="@string/pie_control_trigger_top_summary" android:defaultValue="false" /> - + + + + + + + + + + + + + + + diff --git a/src/com/android/settings/cyanogenmod/PieColorDialog.java b/src/com/android/settings/cyanogenmod/PieColorDialog.java new file mode 100644 index 00000000000..e254c034218 --- /dev/null +++ b/src/com/android/settings/cyanogenmod/PieColorDialog.java @@ -0,0 +1,117 @@ +package com.android.settings.cyanogenmod; + +import android.app.Activity; +import android.app.AlertDialog; +import android.content.Context; +import android.graphics.Color; +import android.graphics.PixelFormat; +import android.text.Editable; +import android.text.TextWatcher; +import android.view.LayoutInflater; +import android.view.View; +import android.view.inputmethod.InputMethodManager; +import android.widget.EditText; +import android.widget.LinearLayout; +import android.widget.Spinner; + +import com.android.settings.R; +import com.android.settings.notificationlight.ColorPanelView; +import com.android.settings.notificationlight.ColorPickerView; +import com.android.settings.notificationlight.ColorPickerView.OnColorChangedListener; + +import java.util.Locale; + +public class PieColorDialog extends AlertDialog implements + ColorPickerView.OnColorChangedListener, TextWatcher, View.OnFocusChangeListener { + + private ColorPickerView mColorPicker; + private EditText mHexColorInput; + + private ColorPanelView mColorPanel; + + protected PieColorDialog(Context context, int initialColor) { + super(context); + + init(initialColor); + } + + private void init(int color) { + // To fight color banding. + getWindow().setFormat(PixelFormat.RGBA_8888); + setup(color); + } + + private void setup(int color) { + final LayoutInflater inflater = (LayoutInflater) getContext() + .getSystemService(Context.LAYOUT_INFLATER_SERVICE); + View layout = inflater.inflate(R.layout.dialog_pie_colors, null); + + mColorPicker = (ColorPickerView) layout.findViewById(R.id.color_picker_view); + mColorPanel = (ColorPanelView) layout.findViewById(R.id.color_panel); + mHexColorInput = (EditText) layout.findViewById(R.id.hex_color_input); + + mColorPanel.setColor(color); + mColorPicker.setOnColorChangedListener(this); + mColorPicker.setColor(color, true); + mHexColorInput.setOnFocusChangeListener(this); + + setView(layout); + setTitle(R.string.pie_control_color_title); + } + + @Override + public void onColorChanged(int color) { + final boolean hasAlpha = mColorPicker.isAlphaSliderVisible(); + final String format = hasAlpha ? "%08x" : "%06x"; + final int mask = hasAlpha ? 0xFFFFFFFF : 0x00FFFFFF; + + mColorPanel.setColor(color); + mHexColorInput.setText(String.format(Locale.US, format, color & mask)); + } + + public void setAlphaSliderVisible(boolean visible) { + mColorPicker.setAlphaSliderVisible(visible); + } + + public int getColor() { + return mColorPicker.getColor(); + } + + @Override + public void onFocusChange(View v, boolean hasFocus) { + if (!hasFocus) { + mHexColorInput.removeTextChangedListener(this); + InputMethodManager inputMethodManager = (InputMethodManager) getContext() + .getSystemService(Activity.INPUT_METHOD_SERVICE); + inputMethodManager.hideSoftInputFromWindow(v.getWindowToken(), 0); + } else { + mHexColorInput.addTextChangedListener(this); + } + } + + @Override + public void beforeTextChanged(CharSequence s, int start, int count, int after) { + } + + @Override + public void onTextChanged(CharSequence s, int start, int before, int count) { + } + + @Override + public void afterTextChanged(Editable s) { + String hexColor = mHexColorInput.getText().toString(); + if (!hexColor.isEmpty()) { + try { + int color = Color.parseColor(hexColor.indexOf('#') < 0 ? '#' + hexColor : hexColor); + if (!mColorPicker.isAlphaSliderVisible()) { + color |= 0xFF000000; // set opaque + } + mColorPicker.setColor(color); + mColorPanel.setColor(color); + } catch (IllegalArgumentException ex) { + // Number format is incorrect, ignore + } + } + } + +} diff --git a/src/com/android/settings/cyanogenmod/PieColorPreference.java b/src/com/android/settings/cyanogenmod/PieColorPreference.java new file mode 100644 index 00000000000..edf48ca46d7 --- /dev/null +++ b/src/com/android/settings/cyanogenmod/PieColorPreference.java @@ -0,0 +1,232 @@ +package com.android.settings.cyanogenmod; + +import android.app.AlertDialog; +import android.content.Context; +import android.content.DialogInterface; +import android.content.res.Resources; +import android.content.res.TypedArray; +import android.graphics.drawable.PaintDrawable; +import android.graphics.drawable.ShapeDrawable; +import android.graphics.drawable.shapes.RectShape; +import android.os.Parcel; +import android.os.Parcelable; +import android.preference.Preference; +import android.util.AttributeSet; +import android.util.Slog; +import android.view.View; +import android.view.ViewGroup; +import android.widget.ImageView; +import android.widget.LinearLayout; + +import com.android.settings.R; + +public class PieColorPreference extends Preference { + public static final String TAG = "PieColorPreference"; + + private ImageView mColorView; + private Integer mDefaultColor; + private int mColorValue; + + public PieColorPreference(Context context, AttributeSet attrs, int defStyle) { + super(context, attrs, defStyle); + setWidgetLayoutResource(R.layout.preference_widget_pie_color); + } + + public PieColorPreference(Context context, AttributeSet attrs) { + super(context, attrs); + setWidgetLayoutResource(R.layout.preference_widget_pie_color); + } + + public PieColorPreference(Context context) { + this(context, null); + } + + @Override + protected Object onGetDefaultValue(TypedArray a, int index) { + try { + mDefaultColor = (int) Long.parseLong(a.getString(index), 16); + } catch (NumberFormatException e) { + Slog.w(TAG, "Unexpected default value during inflate", e); + } + return mDefaultColor; + } + + @Override + protected void onSetInitialValue(boolean restoreValue, Object defaultValue) { + if (restoreValue) { + mColorValue = getPersistedInt(0xff000000); + } else { + mColorValue = (Integer) defaultValue; + } + } + + @Override + protected void onBindView(View view) { + super.onBindView(view); + mColorView = (ImageView) view.findViewById(R.id.pie_color); + updateColor(mColorValue, false); + } + + private void updateColor(int color, boolean notify) { + // persist value when notify && callChangeListener returns true, otherwise skip it + if (notify && !callChangeListener(color)) { + return; + } + mColorValue = color; + if (mColorView != null) { + mColorView.setEnabled(true); + mColorView.setImageDrawable(createRectShape(0xff000000 | mColorValue)); + } + persistInt(mColorValue); + } + + @Override + public void onClick() { + editPreferenceValues(); + } + + private void editPreferenceValues() { + final Resources resources = getContext().getResources(); + final PieColorDialog d = new PieColorDialog(getContext(), mColorValue); + d.setAlphaSliderVisible(true); + + d.setButton(AlertDialog.BUTTON_POSITIVE, resources.getString(R.string.ok), new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialog, int which) { + updateColor(d.getColor(), true); + } + }); + // show a reset button if we have a default value to set to + if (getDefaultColor() != null) { + d.setButton(AlertDialog.BUTTON_NEUTRAL, resources.getString(R.string.pie_control_color_reset), new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialog, int which) { + updateColor(getDefaultColor(), true); + } + }); + } + d.setButton(AlertDialog.BUTTON_NEGATIVE, resources.getString(R.string.cancel), (DialogInterface.OnClickListener) null); + d.show(); + } + + public int getColor() { + return mColorValue; + } + + public void setColor(int color) { + setColor(color, true); + } + + public void setColor(int color, boolean notifyChange) { + updateColor(color, notifyChange); + } + + public Integer getDefaultColor() { + return mDefaultColor; + } + + public void setDefaultColor(Integer color) { + mDefaultColor = color; + } + + private ShapeDrawable createRectShape(int color) { + ShapeDrawable shape = new ShapeDrawable(new RectShape()); + final Resources resources = getContext().getResources(); + // hacky hacky hacky + final int width = (int) resources.getDimension(R.dimen.device_memory_usage_button_width); + final int height = (int) resources.getDimension(R.dimen.device_memory_usage_button_height); + + shape.setIntrinsicHeight(height); + shape.setIntrinsicWidth(width); + shape.getPaint().setColor(color); + return shape; + } + + @Override + protected Parcelable onSaveInstanceState() { + /* + * Suppose a client uses this preference type without persisting. We + * must save the instance state so it is able to, for example, survive + * orientation changes. + */ + + final Parcelable superState = super.onSaveInstanceState(); + if (isPersistent()) { + // No need to save instance state since it's persistent + return superState; + } + + // Save the instance state + final SavedState myState = new SavedState(superState); + myState.color = mColorValue; + myState.defaultColor = mDefaultColor; + return myState; + } + + @Override + protected void onRestoreInstanceState(Parcelable state) { + if (!state.getClass().equals(SavedState.class)) { + // Didn't save state for us in onSaveInstanceState + super.onRestoreInstanceState(state); + return; + } + + // Restore the instance state + SavedState myState = (SavedState) state; + super.onRestoreInstanceState(myState.getSuperState()); + mColorValue = myState.color; + mDefaultColor = myState.defaultColor; + notifyChanged(); + } + + /** + * SavedState, a subclass of {@link BaseSavedState}, will store the state + * of MyPreference, a subclass of Preference. + *

+ * It is important to always call through to super methods. + */ + private static class SavedState extends BaseSavedState { + int color; + Integer defaultColor; + + public SavedState(Parcel source) { + super(source); + + // Restore + color = source.readInt(); + if (source.readByte() == 1) { + defaultColor = source.readInt(); + } + } + + @Override + public void writeToParcel(Parcel dest, int flags) { + super.writeToParcel(dest, flags); + + // Save + dest.writeInt(color); + if (defaultColor != null) { + dest.writeByte((byte) 1); + dest.writeInt(color); + } else { + dest.writeByte((byte) 0); + } + } + + public SavedState(Parcelable superState) { + super(superState); + } + + @SuppressWarnings("unused") + public static final Parcelable.Creator CREATOR = + new Parcelable.Creator() { + public SavedState createFromParcel(Parcel in) { + return new SavedState(in); + } + + public SavedState[] newArray(int size) { + return new SavedState[size]; + } + }; + } +} diff --git a/src/com/android/settings/cyanogenmod/PieControl.java b/src/com/android/settings/cyanogenmod/PieControl.java index da2ee13792c..728b02b1eaf 100755 --- a/src/com/android/settings/cyanogenmod/PieControl.java +++ b/src/com/android/settings/cyanogenmod/PieControl.java @@ -1,6 +1,5 @@ package com.android.settings.cyanogenmod; -import android.content.ContentResolver; import android.database.ContentObserver; import android.os.Bundle; import android.os.Handler; @@ -10,6 +9,9 @@ import android.preference.SeekBarDialogPreference; import android.provider.Settings; +import com.android.internal.util.pie.PieColorUtils; +import com.android.internal.util.pie.PieColorUtils.PieColor; +import com.android.internal.util.pie.PieColorUtils.PieColorSettings; import com.android.settings.R; import com.android.settings.SettingsPreferenceFragment; @@ -26,10 +28,26 @@ public class PieControl extends SettingsPreferenceFragment "pie_control_trigger_right", "pie_control_trigger_top" }; + // You want this to be in sync with COLOR_MAPPINGS! + private static final String[] COLORS = { + "pie_control_color_normal", + "pie_control_color_selected", + "pie_control_color_longpressed", + "pie_control_color_icon", + }; + private static final PieColor[] COLOR_MAPPING = { + PieColorUtils.COLOR_NORMAL, + PieColorUtils.COLOR_SELECTED, + PieColorUtils.COLOR_LONG_PRESSED, + PieColorUtils.COLOR_ICON, + }; + private static final String PIE_OUTLINE = "pie_control_outline"; private CheckBoxPreference mPieControl; private SeekBarDialogPreference mPieSize; - private CheckBoxPreference[] mTrigger = new CheckBoxPreference[4]; + private CheckBoxPreference[] mTrigger = new CheckBoxPreference[TRIGGER.length]; + private PieColorPreference[] mColor = new PieColorPreference[COLORS.length]; + private CheckBoxPreference mPieOutline; private ContentObserver mPieTriggerObserver = new ContentObserver(new Handler()) { @Override @@ -38,6 +56,9 @@ public void onChange(boolean selfChange) { } }; + private PieColorSettings mColorDefaults; + private boolean mOutlineByDefault; + @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); @@ -53,6 +74,17 @@ public void onCreate(Bundle savedInstanceState) { mTrigger[i] = (CheckBoxPreference) prefSet.findPreference(TRIGGER[i]); mTrigger[i].setOnPreferenceChangeListener(this); } + + mColorDefaults = PieColorUtils.loadDefaultPieColors(getActivity()); + for (int i = 0; i < COLORS.length; i++) { + mColor[i] = (PieColorPreference) prefSet.findPreference(COLORS[i]); + mColor[i].setOnPreferenceChangeListener(this); + mColor[i].setDefaultColor(mColorDefaults.getColor(COLOR_MAPPING[i])); + } + mPieOutline = (CheckBoxPreference) prefSet.findPreference(PIE_OUTLINE); + mPieOutline.setOnPreferenceChangeListener(this); + mOutlineByDefault = mColorDefaults.getColor(PieColorUtils.COLOR_OUTLINE) + != mColorDefaults.getColor(PieColorUtils.COLOR_NORMAL); } @Override @@ -64,7 +96,28 @@ public boolean onPreferenceChange(Preference preference, Object newValue) { Settings.System.PIE_CONTROLS, newState ? 1 : 0); propagatePieControl(newState); - } else { + } else if (isColorPreference(preference)) { + PieColorSettings colorSettings = PieColorUtils.loadPieColors(getActivity(), false); + for (int i = 0; i < mColor.length; i++) { + if (preference == mColor[i]) { + // only store color settings that are non default values + if ((Integer) newValue != ((PieColorPreference) preference).getDefaultColor()) { + colorSettings.setColor(COLOR_MAPPING[i], (Integer) newValue); + } else { + colorSettings.removeColor(COLOR_MAPPING[i]); + } + } + } + // correct outline color if appropriate + applyOutlineColor(colorSettings, mPieOutline.isChecked()); + PieColorUtils.storePieColors(getActivity(), colorSettings); + } else if (preference == mPieOutline) { + boolean newState = (Boolean) newValue; + + PieColorSettings colorSettings = PieColorUtils.loadPieColors(getActivity(), false); + applyOutlineColor(colorSettings, newState); + PieColorUtils.storePieColors(getActivity(), colorSettings); + } else if (isTriggerPreference(preference)) { int triggerSlots = 0; for (int i = 0; i < mTrigger.length; i++) { boolean checked = preference == mTrigger[i] @@ -79,6 +132,44 @@ public boolean onPreferenceChange(Preference preference, Object newValue) { return true; } + private void applyOutlineColor(PieColorSettings colorSettings, boolean state) { + PieColor sourceColor = state ? PieColorUtils.COLOR_ICON : PieColorUtils.COLOR_NORMAL; + // if state and byDefault is equal and source is default, fall back to default outline color + if ((state == mOutlineByDefault) && !colorSettings.isColorPresent(sourceColor)) { + colorSettings.removeColor(PieColorUtils.COLOR_OUTLINE); + return; + } + // otherwise get the color from settings or default and set the color + int newColorValue = mColorDefaults.getColor(sourceColor); + if (colorSettings.isColorPresent(sourceColor)) { + newColorValue = colorSettings.getColor(sourceColor); + } + // set the color only if it is different from the default + if (newColorValue != mColorDefaults.getColor(PieColorUtils.COLOR_OUTLINE)) { + colorSettings.setColor(PieColorUtils.COLOR_OUTLINE, newColorValue); + } else { + colorSettings.removeColor(PieColorUtils.COLOR_OUTLINE); + } + } + + private boolean isColorPreference(Preference preference) { + for (int i = 0; i < mColor.length; i++) { + if (mColor[i] == preference) { + return true; + } + } + return false; + } + + private boolean isTriggerPreference(Preference preference) { + for (int i = 0; i < mTrigger.length; i++) { + if (mTrigger[i] == preference) { + return true; + } + } + return false; + } + @Override public void onResume() { super.onResume(); @@ -91,6 +182,7 @@ public void onResume() { Settings.System.getUriFor(Settings.System.PIE_POSITIONS), true, mPieTriggerObserver); + updatePieColors(); updatePieTriggers(); } @@ -101,12 +193,24 @@ public void onPause() { } private void propagatePieControl(boolean value) { + for (int i = 0; i < mTrigger.length; i++) { + mColor[i].setEnabled(value); + } for (int i = 0; i < mTrigger.length; i++) { mTrigger[i].setEnabled(value); } mPieSize.setEnabled(value); } + private void updatePieColors() { + PieColorSettings colorSettings = PieColorUtils.loadPieColors(getActivity(), true); + mPieOutline.setChecked(colorSettings.getColor(PieColorUtils.COLOR_OUTLINE) + != colorSettings.getColor(PieColorUtils.COLOR_NORMAL)); + for (int i = 0; i < mColor.length; i++) { + mColor[i].setColor(colorSettings.getColor(COLOR_MAPPING[i]), false); + } + } + private void updatePieTriggers() { int triggerSlots = Settings.System.getInt(getContentResolver(), Settings.System.PIE_POSITIONS, DEFAULT_POSITION); @@ -120,4 +224,4 @@ private void updatePieTriggers() { } } -} +} \ No newline at end of file