Add captioning preferences screen

BUG: 9926077
Change-Id: Iea141d5d6fd0e4f134c36c51d89830b3c31abd09
This commit is contained in:
Alan Viverette
2013-08-06 13:53:58 -07:00
parent 279a8dfc40
commit cc0e782871
28 changed files with 1939 additions and 12 deletions

View File

@@ -95,6 +95,8 @@ public class AccessibilitySettings extends SettingsPreferenceFragment implements
"select_long_press_timeout_preference";
private static final String ENABLE_ACCESSIBILITY_GESTURE_PREFERENCE_SCREEN =
"enable_global_gesture_preference_screen";
private static final String CAPTIONING_PREFERENCE_SCREEN =
"captioning_preference_screen";
private static final String DISPLAY_MAGNIFICATION_PREFERENCE_SCREEN =
"screen_magnification_preference_screen";
@@ -189,6 +191,7 @@ public class AccessibilitySettings extends SettingsPreferenceFragment implements
private CheckBoxPreference mToggleSpeakPasswordPreference;
private ListPreference mSelectLongPressTimeoutPreference;
private Preference mNoServicesMessagePreference;
private PreferenceScreen mCaptioningPreferenceScreen;
private PreferenceScreen mDisplayMagnificationPreferenceScreen;
private PreferenceScreen mGlobalGesturePreferenceScreen;
@@ -360,6 +363,10 @@ public class AccessibilitySettings extends SettingsPreferenceFragment implements
}
}
// Captioning.
mCaptioningPreferenceScreen = (PreferenceScreen) findPreference(
CAPTIONING_PREFERENCE_SCREEN);
// Display magnification.
mDisplayMagnificationPreferenceScreen = (PreferenceScreen) findPreference(
DISPLAY_MAGNIFICATION_PREFERENCE_SCREEN);
@@ -507,6 +514,15 @@ public class AccessibilitySettings extends SettingsPreferenceFragment implements
mSelectLongPressTimeoutPreference.setValue(value);
mSelectLongPressTimeoutPreference.setSummary(mLongPressTimeoutValuetoTitleMap.get(value));
// Captioning.
final boolean captioningEnabled = Settings.Secure.getInt(getContentResolver(),
Settings.Secure.ACCESSIBILITY_CAPTIONING_ENABLED, 0) == 1;
if (captioningEnabled) {
mCaptioningPreferenceScreen.setSummary(R.string.accessibility_feature_state_on);
} else {
mCaptioningPreferenceScreen.setSummary(R.string.accessibility_feature_state_off);
}
// Screen magnification.
final boolean magnificationEnabled = Settings.Secure.getInt(getContentResolver(),
Settings.Secure.ACCESSIBILITY_DISPLAY_MAGNIFICATION_ENABLED, 0) == 1;

View File

@@ -1,37 +1,77 @@
/*
* Copyright (C) 2013 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.settings.accessibility;
import android.content.ComponentName;
import android.content.Context;
import android.content.res.Configuration;
import android.content.res.Resources;
import android.provider.Settings;
import android.provider.Settings.Secure;
import android.text.TextUtils.SimpleStringSplitter;
import java.util.Collections;
import java.util.HashSet;
import java.util.Locale;
import java.util.Set;
/**
* TODO: Insert description here. (generated by alanv)
* Utility methods used within accessibility settings.
*/
public class AccessibilityUtils {
class AccessibilityUtils {
/**
* @return the set of enabled accessibility services
*/
static Set<ComponentName> getEnabledServicesFromSettings(Context context) {
String enabledServicesSetting = Settings.Secure.getString(context.getContentResolver(),
Settings.Secure.ENABLED_ACCESSIBILITY_SERVICES);
final String enabledServicesSetting = Settings.Secure.getString(
context.getContentResolver(), Settings.Secure.ENABLED_ACCESSIBILITY_SERVICES);
if (enabledServicesSetting == null) {
enabledServicesSetting = "";
return Collections.emptySet();
}
Set<ComponentName> enabledServices = new HashSet<ComponentName>();
SimpleStringSplitter colonSplitter = AccessibilitySettings.sStringColonSplitter;
final Set<ComponentName> enabledServices = new HashSet<ComponentName>();
final SimpleStringSplitter colonSplitter = AccessibilitySettings.sStringColonSplitter;
colonSplitter.setString(enabledServicesSetting);
while (colonSplitter.hasNext()) {
String componentNameString = colonSplitter.next();
ComponentName enabledService = ComponentName.unflattenFromString(
final String componentNameString = colonSplitter.next();
final ComponentName enabledService = ComponentName.unflattenFromString(
componentNameString);
if (enabledService != null) {
enabledServices.add(enabledService);
}
}
return enabledServices;
}
/**
* @return a localized version of the text resource specified by resId
*/
static CharSequence getTextForLocale(Context context, Locale locale, int resId) {
final Resources res = context.getResources();
final Configuration config = res.getConfiguration();
final Locale prevLocale = config.locale;
try {
config.locale = locale;
res.updateConfiguration(config, null);
return res.getText(resId);
} finally {
config.locale = prevLocale;
res.updateConfiguration(config, null);
}
}
}

View File

@@ -0,0 +1,208 @@
/*
* Copyright (C) 2013 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.settings.accessibility;
import android.content.ContentResolver;
import android.content.res.Resources;
import android.graphics.Color;
import android.os.Bundle;
import android.preference.ListPreference;
import android.preference.Preference;
import android.preference.Preference.OnPreferenceChangeListener;
import android.provider.Settings;
import android.view.accessibility.CaptioningManager;
import android.view.accessibility.CaptioningManager.CaptionStyle;
import com.android.settings.R;
import com.android.settings.SettingsPreferenceFragment;
import com.android.settings.accessibility.ListDialogPreference.OnValueChangedListener;
/**
* Settings fragment containing captioning properties.
*/
public class CaptionPropertiesFragment extends SettingsPreferenceFragment
implements OnPreferenceChangeListener, OnValueChangedListener {
private ToggleCaptioningPreferenceFragment mParent;
// Standard options.
private LocalePreference mLocale;
private ListPreference mFontSize;
private PresetPreference mPreset;
// Custom options.
private ListPreference mTypeface;
private ColorPreference mForegroundColor;
private EdgeTypePreference mEdgeType;
private ColorPreference mEdgeColor;
private ColorPreference mBackgroundColor;
private ColorPreference mBackgroundOpacity;
@Override
public void onCreate(Bundle icicle) {
super.onCreate(icicle);
addPreferencesFromResource(R.xml.captioning_settings);
initializeAllPreferences();
updateAllPreferences();
installUpdateListeners();
}
/**
* Sets the parent fragment, which is used to update the live preview.
*
* @param parent the parent fragment
*/
public void setParent(ToggleCaptioningPreferenceFragment parent) {
mParent = parent;
}
private void initializeAllPreferences() {
final Resources res = getResources();
final int[] presetValues = res.getIntArray(R.array.captioning_preset_selector_values);
final String[] presetTitles = res.getStringArray(R.array.captioning_preset_selector_titles);
mPreset = (PresetPreference) findPreference("captioning_preset");
mPreset.setValues(presetValues);
mPreset.setTitles(presetTitles);
final int[] colorValues = res.getIntArray(R.array.captioning_color_selector_values);
final String[] colorTitles = res.getStringArray(R.array.captioning_color_selector_titles);
mForegroundColor = (ColorPreference) findPreference("captioning_foreground_color");
mForegroundColor.setTitles(colorTitles);
mForegroundColor.setValues(colorValues);
mEdgeColor = (ColorPreference) findPreference("captioning_edge_color");
mEdgeColor.setTitles(colorTitles);
mEdgeColor.setValues(colorValues);
final int[] bgColorValues = res.getIntArray(
R.array.captioning_background_color_selector_values);
final String[] bgColorTitles = res.getStringArray(
R.array.captioning_background_color_selector_titles);
mBackgroundColor = (ColorPreference) findPreference("captioning_background_color");
mBackgroundColor.setTitles(bgColorTitles);
mBackgroundColor.setValues(bgColorValues);
final int[] opacityValues = res.getIntArray(R.array.captioning_opacity_selector_values);
final String[] opacityTitles = res.getStringArray(
R.array.captioning_opacity_selector_titles);
mBackgroundOpacity = (ColorPreference) findPreference("captioning_background_opacity");
mBackgroundOpacity.setTitles(opacityTitles);
mBackgroundOpacity.setValues(opacityValues);
mEdgeType = (EdgeTypePreference) findPreference("captioning_edge_type");
mTypeface = (ListPreference) findPreference("captioning_typeface");
mFontSize = (ListPreference) findPreference("captioning_font_size");
mLocale = (LocalePreference) findPreference("captioning_locale");
}
private void installUpdateListeners() {
mPreset.setOnValueChangedListener(this);
mForegroundColor.setOnValueChangedListener(this);
mEdgeColor.setOnValueChangedListener(this);
mBackgroundColor.setOnValueChangedListener(this);
mBackgroundOpacity.setOnValueChangedListener(this);
mEdgeType.setOnValueChangedListener(this);
mTypeface.setOnPreferenceChangeListener(this);
mFontSize.setOnPreferenceChangeListener(this);
mLocale.setOnPreferenceChangeListener(this);
}
private void updateAllPreferences() {
final ContentResolver cr = getContentResolver();
final int preset = CaptionStyle.getRawPreset(cr);
mPreset.setValue(preset);
final float fontSize = CaptioningManager.getFontSize(cr);
mFontSize.setValue(Float.toString(fontSize));
final CaptionStyle attrs = CaptionStyle.getCustomStyle(cr);
mForegroundColor.setValue(attrs.foregroundColor);
mEdgeType.setValue(attrs.edgeType);
mEdgeColor.setValue(attrs.edgeColor);
final int backgroundColor = attrs.backgroundColor;
final int bgColor;
final int bgAlpha;
if (Color.alpha(backgroundColor) == 0) {
bgColor = Color.TRANSPARENT;
bgAlpha = (backgroundColor & 0xFF) << 24;
} else {
bgColor = backgroundColor | 0xFF000000;
bgAlpha = backgroundColor & 0xFF000000;
}
mBackgroundColor.setValue(bgColor);
mBackgroundOpacity.setValue(bgAlpha | 0xFFFFFF);
final String rawTypeface = attrs.mRawTypeface;
mTypeface.setValue(rawTypeface == null ? "" : rawTypeface);
final String rawLocale = CaptioningManager.getRawLocale(cr);
mLocale.setValue(rawLocale == null ? "" : rawLocale);
}
private void refreshPreviewText() {
if (mParent != null) {
mParent.refreshPreviewText();
}
}
@Override
public void onValueChanged(ListDialogPreference preference, int value) {
final ContentResolver cr = getActivity().getContentResolver();
if (mForegroundColor == preference) {
Settings.Secure.putInt(
cr, Settings.Secure.ACCESSIBILITY_CAPTIONING_FOREGROUND_COLOR, value);
} else if (mBackgroundColor == preference || mBackgroundOpacity == preference) {
final int bgColor = mBackgroundColor.getValue();
final int bgAlpha = mBackgroundOpacity.getValue();
final int argb;
if (Color.alpha(bgColor) == 0) {
argb = Color.alpha(bgAlpha);
} else {
argb = bgColor & 0x00FFFFFF | bgAlpha & 0xFF000000;
}
Settings.Secure.putInt(
cr, Settings.Secure.ACCESSIBILITY_CAPTIONING_BACKGROUND_COLOR, argb);
} else if (mEdgeColor == preference) {
Settings.Secure.putInt(cr, Settings.Secure.ACCESSIBILITY_CAPTIONING_EDGE_COLOR, value);
} else if (mPreset == preference) {
Settings.Secure.putInt(cr, Settings.Secure.ACCESSIBILITY_CAPTIONING_PRESET, value);
} else if (mEdgeType == preference) {
Settings.Secure.putInt(cr, Settings.Secure.ACCESSIBILITY_CAPTIONING_EDGE_TYPE, value);
}
refreshPreviewText();
}
@Override
public boolean onPreferenceChange(Preference preference, Object value) {
final ContentResolver cr = getActivity().getContentResolver();
if (mTypeface == preference) {
Settings.Secure.putString(
cr, Settings.Secure.ACCESSIBILITY_CAPTIONING_TYPEFACE, (String) value);
} else if (mFontSize == preference) {
Settings.Secure.putFloat(
cr, Settings.Secure.ACCESSIBILITY_CAPTIONING_FONT_SIZE,
Float.parseFloat((String) value));
} else if (mLocale == preference) {
Settings.Secure.putString(
cr, Settings.Secure.ACCESSIBILITY_CAPTIONING_LOCALE, (String) value);
}
refreshPreviewText();
return true;
}
}

View File

@@ -0,0 +1,309 @@
/*
* Copyright (C) 2013 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.settings.accessibility;
import android.content.ContentResolver;
import android.content.Context;
import android.content.res.ColorStateList;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Paint.Cap;
import android.graphics.Paint.Join;
import android.graphics.Paint.Style;
import android.os.Parcel;
import android.support.v4.view.ViewCompat;
import android.text.Editable;
import android.text.ParcelableSpan;
import android.text.TextPaint;
import android.text.TextUtils;
import android.text.style.CharacterStyle;
import android.text.style.UpdateAppearance;
import android.util.AttributeSet;
import android.view.accessibility.CaptioningManager;
import android.view.accessibility.CaptioningManager.CaptionStyle;
import android.widget.TextView;
public class CaptioningTextView extends TextView {
private MutableBackgroundColorSpan mBackgroundSpan;
private ColorStateList mOutlineColorState;
private float mOutlineWidth;
private int mOutlineColor;
private int mEdgeType = CaptionStyle.EDGE_TYPE_NONE;
private int mEdgeColor = Color.TRANSPARENT;
private float mEdgeWidth = 0;
private boolean mHasBackground = false;
public CaptioningTextView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
}
public CaptioningTextView(Context context, AttributeSet attrs) {
super(context, attrs);
}
public CaptioningTextView(Context context) {
super(context);
}
public void applyStyleAndFontSize(int styleId) {
final Context context = mContext;
final ContentResolver cr = context.getContentResolver();
final CaptionStyle style;
if (styleId == CaptionStyle.PRESET_CUSTOM) {
style = CaptionStyle.getCustomStyle(cr);
} else {
style = CaptionStyle.PRESETS[styleId];
}
setTextColor(style.foregroundColor);
setBackgroundColor(style.backgroundColor);
setTypeface(style.getTypeface());
// Clears all outlines.
applyEdge(style.edgeType, style.edgeColor, 4.0f);
final float fontSize = CaptioningManager.getFontSize(cr);
if (fontSize != 0) {
setTextSize(fontSize);
}
}
/**
* Applies an edge preset using a combination of {@link #setOutlineLayer}
* and {@link #setShadowLayer}. Any subsequent calls to either of these
* methods will invalidate the applied preset.
*
* @param type Type of edge to apply, one of:
* <ul>
* <li>{@link CaptionStyle#EDGE_TYPE_NONE}
* <li>{@link CaptionStyle#EDGE_TYPE_OUTLINE}
* <li>{@link CaptionStyle#EDGE_TYPE_DROP_SHADOW}
* </ul>
* @param color Edge color as a packed 32-bit ARGB color.
* @param width Width of the edge in pixels.
*/
public void applyEdge(int type, int color, float width) {
if (mEdgeType != type || mEdgeColor != color || mEdgeWidth != width) {
final int textColor = getTextColors().getDefaultColor();
switch (type) {
case CaptionStyle.EDGE_TYPE_DROP_SHADOW:
setOutlineLayer(0, 0);
super.setShadowLayer(width, width, width, color);
break;
case CaptionStyle.EDGE_TYPE_OUTLINE:
setOutlineLayer(width, color);
super.setShadowLayer(0, 0, 0, 0);
break;
default:
super.setShadowLayer(0, 0, 0, 0);
setOutlineLayer(0, 0);
}
mEdgeType = type;
mEdgeColor = color;
mEdgeWidth = width;
}
}
@Override
public void setShadowLayer(float radius, float dx, float dy, int color) {
mEdgeType = CaptionStyle.EDGE_TYPE_NONE;
super.setShadowLayer(radius, dx, dy, color);
}
/**
* Gives the text an outline of the specified pixel width and color.
*/
public void setOutlineLayer(float width, int color) {
width *= 2.0f;
mEdgeType = CaptionStyle.EDGE_TYPE_NONE;
if (mOutlineColor != color || mOutlineWidth != width) {
mOutlineColorState = ColorStateList.valueOf(color);
mOutlineColor = color;
mOutlineWidth = width;
invalidate();
// TODO: Remove after display list bug is fixed.
if (width > 0 && Color.alpha(color) != 0) {
setLayerType(ViewCompat.LAYER_TYPE_SOFTWARE, null);
} else {
setLayerType(ViewCompat.LAYER_TYPE_HARDWARE, null);
}
}
}
/**
* @return the color of the outline layer
* @see #setOutlineLayer(float, int)
*/
public int getOutlineColor() {
return mOutlineColor;
}
/**
* @return the width of the outline layer
* @see #setOutlineLayer(float, int)
*/
public float getOutlineWidth() {
return mOutlineWidth;
}
@Override
public Editable getEditableText() {
final CharSequence text = getText();
if (text instanceof Editable) {
return (Editable) text;
}
setText(text, BufferType.EDITABLE);
return (Editable) getText();
}
@Override
public void setBackgroundColor(int color) {
if (Color.alpha(color) == 0) {
if (mHasBackground) {
mHasBackground = false;
getEditableText().removeSpan(mBackgroundSpan);
}
} else {
if (mBackgroundSpan == null) {
mBackgroundSpan = new MutableBackgroundColorSpan(color);
} else {
mBackgroundSpan.setColor(color);
}
if (mHasBackground) {
invalidate();
} else {
mHasBackground = true;
getEditableText().setSpan(mBackgroundSpan, 0, length(), 0);
}
}
}
@Override
protected void onTextChanged(CharSequence text, int start, int lengthBefore, int lengthAfter) {
super.onTextChanged(text, start, lengthBefore, lengthAfter);
if (mBackgroundSpan != null) {
getEditableText().setSpan(mBackgroundSpan, 0, lengthAfter, 0);
}
}
@Override
protected void onDraw(Canvas c) {
if (mOutlineWidth > 0 && Color.alpha(mOutlineColor) > 0) {
final TextPaint textPaint = getPaint();
final Paint.Style previousStyle = textPaint.getStyle();
final ColorStateList previousColors = getTextColors();
textPaint.setStyle(Style.STROKE);
textPaint.setStrokeWidth(mOutlineWidth);
textPaint.setStrokeCap(Cap.ROUND);
textPaint.setStrokeJoin(Join.ROUND);
setTextColor(mOutlineColorState);
// Remove the shadow.
final float shadowRadius = getShadowRadius();
final float shadowDx = getShadowDx();
final float shadowDy = getShadowDy();
final int shadowColor = getShadowColor();
if (shadowRadius > 0) {
setShadowLayer(0, 0, 0, 0);
}
// Draw outline and background only.
super.onDraw(c);
// Restore the shadow.
if (shadowRadius > 0) {
setShadowLayer(shadowRadius, shadowDx, shadowDy, shadowColor);
}
// Restore original settings.
textPaint.setStyle(previousStyle);
setTextColor(previousColors);
// Remove the background.
final int color;
if (mBackgroundSpan != null) {
color = mBackgroundSpan.getBackgroundColor();
mBackgroundSpan.setColor(Color.TRANSPARENT);
} else {
color = 0;
}
// Draw foreground only.
super.onDraw(c);
// Restore the background.
if (mBackgroundSpan != null) {
mBackgroundSpan.setColor(color);
}
} else {
super.onDraw(c);
}
}
public static class MutableBackgroundColorSpan extends CharacterStyle
implements UpdateAppearance, ParcelableSpan {
private int mColor;
public MutableBackgroundColorSpan(int color) {
mColor = color;
}
public MutableBackgroundColorSpan(Parcel src) {
mColor = src.readInt();
}
public void setColor(int color) {
mColor = color;
}
@Override
public int getSpanTypeId() {
return TextUtils.BACKGROUND_COLOR_SPAN;
}
@Override
public int describeContents() {
return 0;
}
@Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeInt(mColor);
}
public int getBackgroundColor() {
return mColor;
}
@Override
public void updateDrawState(TextPaint ds) {
ds.bgColor = mColor;
}
}
}

View File

@@ -0,0 +1,122 @@
/*
* Copyright (C) 2013 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.settings.accessibility;
import android.content.Context;
import android.graphics.Color;
import android.graphics.drawable.ColorDrawable;
import android.graphics.drawable.Drawable;
import android.text.TextUtils;
import android.util.AttributeSet;
import android.view.View;
import android.widget.ImageView;
import android.widget.TextView;
import com.android.settings.R;
/**
* Grid preference that allows the user to pick a color from a predefined set of
* colors. Optionally shows a preview in the preference item.
*/
public class ColorPreference extends ListDialogPreference {
private ColorDrawable mPreviewColor;
private boolean mPreviewEnabled;
public ColorPreference(Context context, AttributeSet attrs) {
super(context, attrs);
setDialogLayoutResource(R.layout.grid_picker_dialog);
setListItemLayoutResource(R.layout.color_picker_item);
}
/**
* @param enabled whether to show a preview in the preference item
*/
public void setPreviewEnabled(boolean enabled) {
if (mPreviewEnabled != enabled) {
mPreviewEnabled = enabled;
if (enabled) {
setWidgetLayoutResource(R.layout.preference_color);
} else {
setWidgetLayoutResource(0);
}
}
}
@Override
public boolean shouldDisableDependents() {
return getValue() == Color.TRANSPARENT || super.shouldDisableDependents();
}
@Override
protected void onBindView(View view) {
super.onBindView(view);
if (mPreviewEnabled) {
final ImageView previewImage = (ImageView) view.findViewById(R.id.color_preview);
final int argb = getValue();
if (Color.alpha(argb) < 255) {
previewImage.setBackgroundResource(R.drawable.transparency_tileable);
} else {
previewImage.setBackground(null);
}
if (mPreviewColor == null) {
mPreviewColor = new ColorDrawable(argb);
previewImage.setImageDrawable(mPreviewColor);
} else {
mPreviewColor.setColor(argb);
}
final CharSequence summary = getSummary();
if (!TextUtils.isEmpty(summary)) {
previewImage.setContentDescription(summary);
} else {
previewImage.setContentDescription(null);
}
previewImage.setAlpha(isEnabled() ? 1f : 0.2f);
}
}
@Override
protected void onBindListItem(View view, int index) {
final int argb = getValueAt(index);
final int alpha = Color.alpha(argb);
final ImageView swatch = (ImageView) view.findViewById(R.id.color_swatch);
if (alpha < 255) {
swatch.setBackgroundResource(R.drawable.transparency_tileable);
} else {
swatch.setBackground(null);
}
final Drawable foreground = swatch.getDrawable();
if (foreground instanceof ColorDrawable) {
((ColorDrawable) foreground).setColor(argb);
} else {
swatch.setImageDrawable(new ColorDrawable(argb));
}
final CharSequence title = getTitleAt(index);
if (title != null) {
final TextView summary = (TextView) view.findViewById(R.id.summary);
summary.setText(title);
}
}
}

View File

@@ -0,0 +1,66 @@
/*
* Copyright (C) 2013 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.settings.accessibility;
import android.content.Context;
import android.content.res.Resources;
import android.graphics.Color;
import android.util.AttributeSet;
import android.view.View;
import android.view.accessibility.CaptioningManager;
import android.view.accessibility.CaptioningManager.CaptionStyle;
import android.widget.TextView;
import com.android.settings.R;
/**
* Grid preference that allows the user to pick a captioning edge type.
*/
public class EdgeTypePreference extends ListDialogPreference {
public EdgeTypePreference(Context context, AttributeSet attrs) {
super(context, attrs);
final Resources res = context.getResources();
setValues(res.getIntArray(R.array.captioning_edge_type_selector_values));
setTitles(res.getStringArray(R.array.captioning_edge_type_selector_titles));
setDialogLayoutResource(R.layout.grid_picker_dialog);
setListItemLayoutResource(R.layout.preset_picker_item);
}
@Override
public boolean shouldDisableDependents() {
return getValue() == CaptionStyle.EDGE_TYPE_NONE || super.shouldDisableDependents();
}
@Override
protected void onBindListItem(View view, int index) {
final float fontSize = CaptioningManager.getFontSize(getContext().getContentResolver());
final CaptioningTextView preview = (CaptioningTextView) view.findViewById(R.id.preview);
preview.setTextColor(Color.WHITE);
preview.setBackgroundColor(Color.TRANSPARENT);
preview.setTextSize(fontSize);
final int value = getValueAt(index);
preview.applyEdge(value, Color.BLACK, 4.0f);
final CharSequence title = getTitleAt(index);
if (title != null) {
final TextView summary = (TextView) view.findViewById(R.id.summary);
summary.setText(title);
}
}
}

View File

@@ -0,0 +1,322 @@
/*
* Copyright (C) 2013 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.settings.accessibility;
import android.app.AlertDialog.Builder;
import android.app.Dialog;
import android.content.Context;
import android.content.res.TypedArray;
import android.os.Parcel;
import android.os.Parcelable;
import android.preference.DialogPreference;
import android.util.AttributeSet;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.AbsListView;
import android.widget.AdapterView;
import android.widget.AdapterView.OnItemClickListener;
import android.widget.BaseAdapter;
/**
* Abstract dialog preference that displays a set of values and optional titles.
*/
public abstract class ListDialogPreference extends DialogPreference {
private CharSequence[] mEntryTitles;
private int[] mEntryValues;
private OnValueChangedListener mOnValueChangedListener;
/** The layout resource to use for grid items. */
private int mListItemLayout;
/** The current value of this preference. */
private int mValue;
/** The index within the value set of the current value. */
private int mValueIndex;
/** Whether the value had been set using {@link #setValue}. */
private boolean mValueSet;
public ListDialogPreference(Context context, AttributeSet attrs) {
super(context, attrs);
}
/**
* Sets a listened to invoke when the value of this preference changes.
*
* @param listener the listener to invoke
*/
public void setOnValueChangedListener(OnValueChangedListener listener) {
mOnValueChangedListener = listener;
}
/**
* Sets the layout to use for grid items.
*
* @param layoutResId the layout to use for displaying grid items
*/
public void setListItemLayoutResource(int layoutResId) {
mListItemLayout = layoutResId;
}
/**
* Sets the list of item values. Values must be distinct.
*
* @param values the list of item values
*/
public void setValues(int[] values) {
mEntryValues = values;
}
/**
* Sets the list of item titles. May be null if no titles are specified, or
* may be shorter than the list of values to leave some titles unspecified.
*
* @param titles the list of item titles
*/
public void setTitles(CharSequence[] titles) {
mEntryTitles = titles;
}
/**
* Populates a list item view with data for the specified index.
*
* @param view the view to populate
* @param index the index for which to populate the view
* @see #setListItemLayoutResource(int)
* @see #getValueAt(int)
* @see #getTitleAt(int)
*/
protected abstract void onBindListItem(View view, int index);
/**
* @return the title at the specified index, or null if none specified
*/
protected CharSequence getTitleAt(int index) {
if (mEntryTitles == null || mEntryTitles.length <= index) {
return null;
}
return mEntryTitles[index];
}
/**
* @return the value at the specified index
*/
protected int getValueAt(int index) {
return mEntryValues[index];
}
@Override
public CharSequence getSummary() {
if (mValueIndex >= 0) {
return getTitleAt(mValueIndex);
}
return null;
}
@Override
protected void onPrepareDialogBuilder(Builder builder) {
super.onPrepareDialogBuilder(builder);
final Context context = getContext();
final int dialogLayout = getDialogLayoutResource();
final View picker = LayoutInflater.from(context).inflate(dialogLayout, null);
final ListPreferenceAdapter adapter = new ListPreferenceAdapter();
final AbsListView list = (AbsListView) picker.findViewById(android.R.id.list);
list.setAdapter(adapter);
list.setOnItemClickListener(new OnItemClickListener() {
@Override
public void onItemClick(AdapterView<?> adapter, View v, int position, long id) {
if (callChangeListener((int) id)) {
setValue((int) id);
}
final Dialog dialog = getDialog();
if (dialog != null) {
dialog.dismiss();
}
}
});
// Set initial selection.
final int selectedPosition = getIndexForValue(mValue);
if (selectedPosition != AbsListView.INVALID_POSITION) {
list.setSelection(selectedPosition);
}
builder.setView(picker);
builder.setPositiveButton(null, null);
}
/**
* @return the index of the specified value within the list of entry values,
* or {@link AbsListView#INVALID_POSITION} if not found
*/
protected int getIndexForValue(int value) {
final int[] values = mEntryValues;
final int count = values.length;
for (int i = 0; i < count; i++) {
if (values[i] == value) {
return i;
}
}
return AbsListView.INVALID_POSITION;
}
/**
* Sets the current value. If the value exists within the set of entry
* values, updates the selection index.
*
* @param value the value to set
*/
public void setValue(int value) {
final boolean changed = mValue != value;
if (changed || !mValueSet) {
mValue = value;
mValueIndex = getIndexForValue(value);
mValueSet = true;
persistInt(value);
if (changed) {
notifyDependencyChange(shouldDisableDependents());
notifyChanged();
}
if (mOnValueChangedListener != null) {
mOnValueChangedListener.onValueChanged(this, value);
}
}
}
/**
* @return the current value
*/
public int getValue() {
return mValue;
}
@Override
protected Object onGetDefaultValue(TypedArray a, int index) {
return a.getInt(index, 0);
}
@Override
protected void onSetInitialValue(boolean restoreValue, Object defaultValue) {
setValue(restoreValue ? getPersistedInt(mValue) : (Integer) defaultValue);
}
@Override
protected Parcelable onSaveInstanceState() {
final Parcelable superState = super.onSaveInstanceState();
if (isPersistent()) {
// No need to save instance state since it's persistent
return superState;
}
final SavedState myState = new SavedState(superState);
myState.value = getValue();
return myState;
}
@Override
protected void onRestoreInstanceState(Parcelable state) {
if (state == null || !state.getClass().equals(SavedState.class)) {
// Didn't save state for us in onSaveInstanceState
super.onRestoreInstanceState(state);
return;
}
SavedState myState = (SavedState) state;
super.onRestoreInstanceState(myState.getSuperState());
setValue(myState.value);
}
private class ListPreferenceAdapter extends BaseAdapter {
private LayoutInflater mInflater;
@Override
public int getCount() {
return mEntryValues.length;
}
@Override
public Integer getItem(int position) {
return mEntryValues[position];
}
@Override
public long getItemId(int position) {
return mEntryValues[position];
}
@Override
public boolean hasStableIds() {
return true;
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
if (convertView == null) {
if (mInflater == null) {
mInflater = LayoutInflater.from(parent.getContext());
}
convertView = mInflater.inflate(mListItemLayout, parent, false);
}
onBindListItem(convertView, position);
return convertView;
}
}
private static class SavedState extends BaseSavedState {
public int value;
public SavedState(Parcel source) {
super(source);
value = source.readInt();
}
@Override
public void writeToParcel(Parcel dest, int flags) {
super.writeToParcel(dest, flags);
dest.writeInt(value);
}
public SavedState(Parcelable superState) {
super(superState);
}
@SuppressWarnings({ "hiding", "unused" })
public static final Creator<SavedState> CREATOR = new Creator<SavedState>() {
@Override
public SavedState createFromParcel(Parcel in) {
return new SavedState(in);
}
@Override
public SavedState[] newArray(int size) {
return new SavedState[size];
}
};
}
public interface OnValueChangedListener {
public void onValueChanged(ListDialogPreference preference, int value);
}
}

View File

@@ -0,0 +1,150 @@
/*
* Copyright (C) 2013 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.settings.accessibility;
import android.content.Context;
import android.content.res.Resources;
import android.preference.ListPreference;
import android.util.AttributeSet;
import com.android.settings.R;
import java.text.Collator;
import java.util.Arrays;
import java.util.Locale;
/**
* List preference that allows the user to pick a locale from the list of
* supported device locales.
*/
public class LocalePreference extends ListPreference {
public LocalePreference(Context context, AttributeSet attrs) {
super(context, attrs);
init(context);
}
public LocalePreference(Context context) {
super(context);
init(context);
}
public void init(Context context) {
final String[] systemLocales = Resources.getSystem().getAssets().getLocales();
Arrays.sort(systemLocales);
final Resources resources = context.getResources();
final String[] specialLocaleCodes = resources.getStringArray(
com.android.internal.R.array.special_locale_codes);
final String[] specialLocaleNames = resources.getStringArray(
com.android.internal.R.array.special_locale_names);
int finalSize = 0;
final int origSize = systemLocales.length;
final LocaleInfo[] localeInfos = new LocaleInfo[origSize];
for (int i = 0; i < origSize; i++) {
final String localeStr = systemLocales[i];
final int len = localeStr.length();
if (len != 5) {
continue;
}
final String language = localeStr.substring(0, 2);
final String country = localeStr.substring(3, 5);
final Locale l = new Locale(language, country);
if (finalSize == 0) {
localeInfos[finalSize++] = new LocaleInfo(l.getDisplayLanguage(l), l);
} else {
// check previous entry:
// same lang and a country -> upgrade to full name and
// insert ours with full name
// diff lang -> insert ours with lang-only name
final LocaleInfo previous = localeInfos[finalSize - 1];
if (previous.locale.getLanguage().equals(language)
&& !previous.locale.getLanguage().equals("zz")) {
previous.label = getDisplayName(
localeInfos[finalSize - 1].locale, specialLocaleCodes,
specialLocaleNames);
localeInfos[finalSize++] = new LocaleInfo(getDisplayName(l,
specialLocaleCodes, specialLocaleNames), l);
} else {
final String displayName;
if (localeStr.equals("zz_ZZ")) {
displayName = "[Developer] Accented English";
} else if (localeStr.equals("zz_ZY")) {
displayName = "[Developer] Fake Bi-Directional";
} else {
displayName = l.getDisplayLanguage(l);
}
localeInfos[finalSize++] = new LocaleInfo(displayName, l);
}
}
}
final CharSequence[] entries = new CharSequence[finalSize + 1];
final CharSequence[] entryValues = new CharSequence[finalSize + 1];
Arrays.sort(localeInfos, 0, finalSize);
entries[0] = resources.getString(R.string.locale_default);
entryValues[0] = "";
for (int i = 0; i < finalSize; i++) {
final LocaleInfo info = localeInfos[i];
entries[i + 1] = info.toString();
entryValues[i + 1] = info.locale.toString();
}
setEntries(entries);
setEntryValues(entryValues);
}
private static String getDisplayName(
Locale l, String[] specialLocaleCodes, String[] specialLocaleNames) {
String code = l.toString();
for (int i = 0; i < specialLocaleCodes.length; i++) {
if (specialLocaleCodes[i].equals(code)) {
return specialLocaleNames[i];
}
}
return l.getDisplayName(l);
}
private static class LocaleInfo implements Comparable<LocaleInfo> {
private static final Collator sCollator = Collator.getInstance();
public String label;
public Locale locale;
public LocaleInfo(String label, Locale locale) {
this.label = label;
this.locale = locale;
}
@Override
public String toString() {
return label;
}
@Override
public int compareTo(LocaleInfo another) {
return sCollator.compare(this.label, another.label);
}
}
}

View File

@@ -0,0 +1,54 @@
/*
* Copyright (C) 2013 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.settings.accessibility;
import android.content.Context;
import android.util.AttributeSet;
import android.view.View;
import android.view.accessibility.CaptioningManager.CaptionStyle;
import android.widget.TextView;
import com.android.settings.R;
public class PresetPreference extends ListDialogPreference {
public PresetPreference(Context context, AttributeSet attrs) {
super(context, attrs);
setDialogLayoutResource(R.layout.grid_picker_dialog);
setListItemLayoutResource(R.layout.preset_picker_item);
}
@Override
public boolean shouldDisableDependents() {
return getValue() != CaptionStyle.PRESET_CUSTOM
|| super.shouldDisableDependents();
}
@Override
protected void onBindListItem(View view, int index) {
final CaptioningTextView previewText = (CaptioningTextView) view.findViewById(
R.id.preview);
final int value = getValueAt(index);
ToggleCaptioningPreferenceFragment.applyCaptionProperties(previewText, value);
final CharSequence title = getTitleAt(index);
if (title != null) {
final TextView summary = (TextView) view.findViewById(R.id.summary);
summary.setText(title);
}
}
}

View File

@@ -0,0 +1,133 @@
/*
* Copyright (C) 2013 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.settings.accessibility;
import android.app.ActionBar;
import android.app.Activity;
import android.app.Fragment;
import android.content.ContentResolver;
import android.content.Context;
import android.os.Bundle;
import android.preference.PreferenceFrameLayout;
import android.provider.Settings;
import android.view.Gravity;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.view.accessibility.CaptioningManager;
import android.view.accessibility.CaptioningManager.CaptionStyle;
import com.android.settings.R;
import com.android.settings.accessibility.ToggleSwitch.OnBeforeCheckedChangeListener;
import java.util.Locale;
public class ToggleCaptioningPreferenceFragment extends Fragment {
private CaptionPropertiesFragment mPropsFragment;
private CaptioningTextView mPreviewText;
@Override
public View onCreateView(
LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
final View rootView = inflater.inflate(R.layout.captioning_preview, container, false);
// We have to do this now because PreferenceFrameLayout looks at it
// only when the view is added.
if (container instanceof PreferenceFrameLayout) {
((PreferenceFrameLayout.LayoutParams) rootView.getLayoutParams()).removeBorders = true;
}
return rootView;
}
@Override
public void onViewCreated(View view, Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
mPropsFragment = ((CaptionPropertiesFragment) getFragmentManager()
.findFragmentById(R.id.properties_fragment));
mPropsFragment.setParent(this);
mPreviewText = (CaptioningTextView) view.findViewById(R.id.preview_text);
installActionBarToggleSwitch();
refreshPreviewText();
}
public void refreshPreviewText() {
final CaptioningTextView preview = mPreviewText;
if (preview != null) {
final Activity activity = getActivity();
final ContentResolver cr = activity.getContentResolver();
final int styleId = CaptionStyle.getRawPreset(cr);
applyCaptionProperties(preview, styleId);
final Locale locale = CaptioningManager.getLocale(cr);
if (locale != null) {
final CharSequence localizedText = AccessibilityUtils.getTextForLocale(
activity, locale, R.string.captioning_preview_text);
preview.setText(localizedText);
}
}
}
public static void applyCaptionProperties(CaptioningTextView previewText, int styleId) {
previewText.applyStyleAndFontSize(styleId);
final Context context = previewText.getContext();
final ContentResolver cr = context.getContentResolver();
final Locale locale = CaptioningManager.getLocale(cr);
if (locale != null) {
final CharSequence localizedText = AccessibilityUtils.getTextForLocale(
context, locale, R.string.captioning_preview_characters);
previewText.setText(localizedText);
}
}
private void installActionBarToggleSwitch() {
final Activity activity = getActivity();
final ToggleSwitch toggleSwitch = new ToggleSwitch(activity);
final int padding = getResources().getDimensionPixelSize(
R.dimen.action_bar_switch_padding);
toggleSwitch.setPaddingRelative(0, 0, padding, 0);
final ActionBar actionBar = activity.getActionBar();
actionBar.setDisplayOptions(ActionBar.DISPLAY_SHOW_CUSTOM, ActionBar.DISPLAY_SHOW_CUSTOM);
final ActionBar.LayoutParams params = new ActionBar.LayoutParams(
ActionBar.LayoutParams.WRAP_CONTENT, ActionBar.LayoutParams.WRAP_CONTENT,
Gravity.CENTER_VERTICAL | Gravity.END);
actionBar.setCustomView(toggleSwitch, params);
final boolean enabled = CaptioningManager.isEnabled(getActivity().getContentResolver());
mPropsFragment.getPreferenceScreen().setEnabled(enabled);
mPreviewText.setVisibility(enabled ? View.VISIBLE : View.INVISIBLE);
toggleSwitch.setCheckedInternal(enabled);
toggleSwitch.setOnBeforeCheckedChangeListener(new OnBeforeCheckedChangeListener() {
@Override
public boolean onBeforeCheckedChanged(ToggleSwitch toggleSwitch, boolean checked) {
toggleSwitch.setCheckedInternal(checked);
Settings.Secure.putInt(getActivity().getContentResolver(),
Settings.Secure.ACCESSIBILITY_CAPTIONING_ENABLED, checked ? 1 : 0);
mPropsFragment.getPreferenceScreen().setEnabled(checked);
mPreviewText.setVisibility(checked ? View.VISIBLE : View.INVISIBLE);
return false;
}
});
}
}