1/* 2 * Copyright (C) 2013 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17package com.android.settings.accessibility; 18 19import android.app.ActionBar; 20import android.app.Activity; 21import android.content.ContentResolver; 22import android.content.Context; 23import android.content.res.Resources; 24import android.graphics.Color; 25import android.os.Bundle; 26import android.preference.ListPreference; 27import android.preference.Preference; 28import android.preference.PreferenceCategory; 29import android.preference.PreferenceFrameLayout; 30import android.preference.Preference.OnPreferenceChangeListener; 31import android.provider.Settings; 32import android.view.Gravity; 33import android.view.LayoutInflater; 34import android.view.View; 35import android.view.ViewGroup; 36import android.view.ViewGroup.LayoutParams; 37import android.view.accessibility.CaptioningManager; 38import android.view.accessibility.CaptioningManager.CaptionStyle; 39 40import com.android.internal.widget.SubtitleView; 41import com.android.settings.R; 42import com.android.settings.SettingsPreferenceFragment; 43import com.android.settings.accessibility.ListDialogPreference.OnValueChangedListener; 44import com.android.settings.accessibility.ToggleSwitch.OnBeforeCheckedChangeListener; 45 46import java.util.Locale; 47 48/** 49 * Settings fragment containing captioning properties. 50 */ 51public class CaptionPropertiesFragment extends SettingsPreferenceFragment 52 implements OnPreferenceChangeListener, OnValueChangedListener { 53 private static final String PREF_BACKGROUND_COLOR = "captioning_background_color"; 54 private static final String PREF_BACKGROUND_OPACITY = "captioning_background_opacity"; 55 private static final String PREF_FOREGROUND_COLOR = "captioning_foreground_color"; 56 private static final String PREF_FOREGROUND_OPACITY = "captioning_foreground_opacity"; 57 private static final String PREF_EDGE_COLOR = "captioning_edge_color"; 58 private static final String PREF_EDGE_TYPE = "captioning_edge_type"; 59 private static final String PREF_FONT_SIZE = "captioning_font_size"; 60 private static final String PREF_TYPEFACE = "captioning_typeface"; 61 private static final String PREF_LOCALE = "captioning_locale"; 62 private static final String PREF_PRESET = "captioning_preset"; 63 private static final String PREF_CUSTOM = "custom"; 64 65 private static final float DEFAULT_FONT_SIZE = 48f; 66 67 private CaptioningManager mCaptioningManager; 68 private SubtitleView mPreviewText; 69 70 // Standard options. 71 private LocalePreference mLocale; 72 private ListPreference mFontSize; 73 private PresetPreference mPreset; 74 75 // Custom options. 76 private ListPreference mTypeface; 77 private ColorPreference mForegroundColor; 78 private ColorPreference mForegroundOpacity; 79 private EdgeTypePreference mEdgeType; 80 private ColorPreference mEdgeColor; 81 private ColorPreference mBackgroundColor; 82 private ColorPreference mBackgroundOpacity; 83 private PreferenceCategory mCustom; 84 85 private boolean mShowingCustom; 86 87 @Override 88 public void onCreate(Bundle icicle) { 89 super.onCreate(icicle); 90 91 mCaptioningManager = (CaptioningManager) getSystemService(Context.CAPTIONING_SERVICE); 92 93 addPreferencesFromResource(R.xml.captioning_settings); 94 initializeAllPreferences(); 95 updateAllPreferences(); 96 refreshShowingCustom(); 97 installUpdateListeners(); 98 } 99 100 @Override 101 public View onCreateView( 102 LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { 103 final View rootView = inflater.inflate(R.layout.captioning_preview, container, false); 104 105 // We have to do this now because PreferenceFrameLayout looks at it 106 // only when the view is added. 107 if (container instanceof PreferenceFrameLayout) { 108 ((PreferenceFrameLayout.LayoutParams) rootView.getLayoutParams()).removeBorders = true; 109 } 110 111 final View content = super.onCreateView(inflater, container, savedInstanceState); 112 ((ViewGroup) rootView.findViewById(R.id.properties_fragment)).addView( 113 content, LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT); 114 115 return rootView; 116 } 117 118 @Override 119 public void onViewCreated(View view, Bundle savedInstanceState) { 120 super.onViewCreated(view, savedInstanceState); 121 122 mPreviewText = (SubtitleView) view.findViewById(R.id.preview_text); 123 124 installActionBarToggleSwitch(); 125 refreshPreviewText(); 126 } 127 128 private void refreshPreviewText() { 129 final Context context = getActivity(); 130 if (context == null) { 131 // We've been destroyed, abort! 132 return; 133 } 134 135 final SubtitleView preview = mPreviewText; 136 if (preview != null) { 137 final int styleId = mCaptioningManager.getRawUserStyle(); 138 applyCaptionProperties(mCaptioningManager, preview, styleId); 139 140 final Locale locale = mCaptioningManager.getLocale(); 141 if (locale != null) { 142 final CharSequence localizedText = AccessibilityUtils.getTextForLocale( 143 context, locale, R.string.captioning_preview_text); 144 preview.setText(localizedText); 145 } else { 146 preview.setText(R.string.captioning_preview_text); 147 } 148 } 149 } 150 151 public static void applyCaptionProperties( 152 CaptioningManager manager, SubtitleView previewText, int styleId) { 153 previewText.setStyle(styleId); 154 155 final Context context = previewText.getContext(); 156 final ContentResolver cr = context.getContentResolver(); 157 final float fontScale = manager.getFontScale(); 158 previewText.setTextSize(fontScale * DEFAULT_FONT_SIZE); 159 160 final Locale locale = manager.getLocale(); 161 if (locale != null) { 162 final CharSequence localizedText = AccessibilityUtils.getTextForLocale( 163 context, locale, R.string.captioning_preview_characters); 164 previewText.setText(localizedText); 165 } else { 166 previewText.setText(R.string.captioning_preview_characters); 167 } 168 } 169 170 private void installActionBarToggleSwitch() { 171 final Activity activity = getActivity(); 172 final ToggleSwitch toggleSwitch = new ToggleSwitch(activity); 173 174 final int padding = getResources().getDimensionPixelSize( 175 R.dimen.action_bar_switch_padding); 176 toggleSwitch.setPaddingRelative(0, 0, padding, 0); 177 178 final ActionBar actionBar = activity.getActionBar(); 179 actionBar.setDisplayOptions(ActionBar.DISPLAY_SHOW_CUSTOM, ActionBar.DISPLAY_SHOW_CUSTOM); 180 181 final ActionBar.LayoutParams params = new ActionBar.LayoutParams( 182 ActionBar.LayoutParams.WRAP_CONTENT, ActionBar.LayoutParams.WRAP_CONTENT, 183 Gravity.CENTER_VERTICAL | Gravity.END); 184 actionBar.setCustomView(toggleSwitch, params); 185 186 final boolean enabled = mCaptioningManager.isEnabled(); 187 getPreferenceScreen().setEnabled(enabled); 188 mPreviewText.setVisibility(enabled ? View.VISIBLE : View.INVISIBLE); 189 toggleSwitch.setCheckedInternal(enabled); 190 toggleSwitch.setOnBeforeCheckedChangeListener(new OnBeforeCheckedChangeListener() { 191 @Override 192 public boolean onBeforeCheckedChanged(ToggleSwitch toggleSwitch, boolean checked) { 193 toggleSwitch.setCheckedInternal(checked); 194 Settings.Secure.putInt(getActivity().getContentResolver(), 195 Settings.Secure.ACCESSIBILITY_CAPTIONING_ENABLED, checked ? 1 : 0); 196 getPreferenceScreen().setEnabled(checked); 197 mPreviewText.setVisibility(checked ? View.VISIBLE : View.INVISIBLE); 198 return false; 199 } 200 }); 201 } 202 203 private void initializeAllPreferences() { 204 mLocale = (LocalePreference) findPreference(PREF_LOCALE); 205 mFontSize = (ListPreference) findPreference(PREF_FONT_SIZE); 206 207 final Resources res = getResources(); 208 final int[] presetValues = res.getIntArray(R.array.captioning_preset_selector_values); 209 final String[] presetTitles = res.getStringArray(R.array.captioning_preset_selector_titles); 210 mPreset = (PresetPreference) findPreference(PREF_PRESET); 211 mPreset.setValues(presetValues); 212 mPreset.setTitles(presetTitles); 213 214 mCustom = (PreferenceCategory) findPreference(PREF_CUSTOM); 215 mShowingCustom = true; 216 217 final int[] colorValues = res.getIntArray(R.array.captioning_color_selector_values); 218 final String[] colorTitles = res.getStringArray(R.array.captioning_color_selector_titles); 219 mForegroundColor = (ColorPreference) mCustom.findPreference(PREF_FOREGROUND_COLOR); 220 mForegroundColor.setTitles(colorTitles); 221 mForegroundColor.setValues(colorValues); 222 223 final int[] opacityValues = res.getIntArray(R.array.captioning_opacity_selector_values); 224 final String[] opacityTitles = res.getStringArray( 225 R.array.captioning_opacity_selector_titles); 226 mForegroundOpacity = (ColorPreference) mCustom.findPreference(PREF_FOREGROUND_OPACITY); 227 mForegroundOpacity.setTitles(opacityTitles); 228 mForegroundOpacity.setValues(opacityValues); 229 230 mEdgeColor = (ColorPreference) mCustom.findPreference(PREF_EDGE_COLOR); 231 mEdgeColor.setTitles(colorTitles); 232 mEdgeColor.setValues(colorValues); 233 234 // Add "none" as an additional option for backgrounds. 235 final int[] bgColorValues = new int[colorValues.length + 1]; 236 final String[] bgColorTitles = new String[colorTitles.length + 1]; 237 System.arraycopy(colorValues, 0, bgColorValues, 1, colorValues.length); 238 System.arraycopy(colorTitles, 0, bgColorTitles, 1, colorTitles.length); 239 bgColorValues[0] = Color.TRANSPARENT; 240 bgColorTitles[0] = getString(R.string.color_none); 241 mBackgroundColor = (ColorPreference) mCustom.findPreference(PREF_BACKGROUND_COLOR); 242 mBackgroundColor.setTitles(bgColorTitles); 243 mBackgroundColor.setValues(bgColorValues); 244 245 mBackgroundOpacity = (ColorPreference) mCustom.findPreference(PREF_BACKGROUND_OPACITY); 246 mBackgroundOpacity.setTitles(opacityTitles); 247 mBackgroundOpacity.setValues(opacityValues); 248 249 mEdgeType = (EdgeTypePreference) mCustom.findPreference(PREF_EDGE_TYPE); 250 mTypeface = (ListPreference) mCustom.findPreference(PREF_TYPEFACE); 251 } 252 253 private void installUpdateListeners() { 254 mPreset.setOnValueChangedListener(this); 255 mForegroundColor.setOnValueChangedListener(this); 256 mForegroundOpacity.setOnValueChangedListener(this); 257 mEdgeColor.setOnValueChangedListener(this); 258 mBackgroundColor.setOnValueChangedListener(this); 259 mBackgroundOpacity.setOnValueChangedListener(this); 260 mEdgeType.setOnValueChangedListener(this); 261 262 mTypeface.setOnPreferenceChangeListener(this); 263 mFontSize.setOnPreferenceChangeListener(this); 264 mLocale.setOnPreferenceChangeListener(this); 265 } 266 267 private void updateAllPreferences() { 268 final int preset = mCaptioningManager.getRawUserStyle(); 269 mPreset.setValue(preset); 270 271 final float fontSize = mCaptioningManager.getFontScale(); 272 mFontSize.setValue(Float.toString(fontSize)); 273 274 final ContentResolver cr = getContentResolver(); 275 final CaptionStyle attrs = CaptionStyle.getCustomStyle(cr); 276 mEdgeType.setValue(attrs.edgeType); 277 mEdgeColor.setValue(attrs.edgeColor); 278 279 parseColorOpacity(mForegroundColor, mForegroundOpacity, attrs.foregroundColor); 280 parseColorOpacity(mBackgroundColor, mBackgroundOpacity, attrs.backgroundColor); 281 282 final String rawTypeface = attrs.mRawTypeface; 283 mTypeface.setValue(rawTypeface == null ? "" : rawTypeface); 284 285 final String rawLocale = mCaptioningManager.getRawLocale(); 286 mLocale.setValue(rawLocale == null ? "" : rawLocale); 287 } 288 289 private void parseColorOpacity(ColorPreference color, ColorPreference opacity, int value) { 290 final int colorValue; 291 final int opacityValue; 292 if (Color.alpha(value) == 0) { 293 colorValue = Color.TRANSPARENT; 294 opacityValue = (value & 0xFF) << 24; 295 } else { 296 colorValue = value | 0xFF000000; 297 opacityValue = value & 0xFF000000; 298 } 299 color.setValue(colorValue); 300 opacity.setValue(opacityValue | 0xFFFFFF); 301 } 302 303 private int mergeColorOpacity(ColorPreference color, ColorPreference opacity) { 304 final int colorValue = color.getValue(); 305 final int opacityValue = opacity.getValue(); 306 final int value; 307 if (Color.alpha(colorValue) == 0) { 308 value = Color.alpha(opacityValue); 309 } else { 310 value = colorValue & 0x00FFFFFF | opacityValue & 0xFF000000; 311 } 312 return value; 313 } 314 315 private void refreshShowingCustom() { 316 final boolean customPreset = mPreset.getValue() == CaptionStyle.PRESET_CUSTOM; 317 if (!customPreset && mShowingCustom) { 318 getPreferenceScreen().removePreference(mCustom); 319 mShowingCustom = false; 320 } else if (customPreset && !mShowingCustom) { 321 getPreferenceScreen().addPreference(mCustom); 322 mShowingCustom = true; 323 } 324 } 325 326 @Override 327 public void onValueChanged(ListDialogPreference preference, int value) { 328 final ContentResolver cr = getActivity().getContentResolver(); 329 if (mForegroundColor == preference || mForegroundOpacity == preference) { 330 final int merged = mergeColorOpacity(mForegroundColor, mForegroundOpacity); 331 Settings.Secure.putInt( 332 cr, Settings.Secure.ACCESSIBILITY_CAPTIONING_FOREGROUND_COLOR, merged); 333 } else if (mBackgroundColor == preference || mBackgroundOpacity == preference) { 334 final int merged = mergeColorOpacity(mBackgroundColor, mBackgroundOpacity); 335 Settings.Secure.putInt( 336 cr, Settings.Secure.ACCESSIBILITY_CAPTIONING_BACKGROUND_COLOR, merged); 337 } else if (mEdgeColor == preference) { 338 Settings.Secure.putInt(cr, Settings.Secure.ACCESSIBILITY_CAPTIONING_EDGE_COLOR, value); 339 } else if (mPreset == preference) { 340 Settings.Secure.putInt(cr, Settings.Secure.ACCESSIBILITY_CAPTIONING_PRESET, value); 341 refreshShowingCustom(); 342 } else if (mEdgeType == preference) { 343 Settings.Secure.putInt(cr, Settings.Secure.ACCESSIBILITY_CAPTIONING_EDGE_TYPE, value); 344 } 345 346 refreshPreviewText(); 347 } 348 349 @Override 350 public boolean onPreferenceChange(Preference preference, Object value) { 351 final ContentResolver cr = getActivity().getContentResolver(); 352 if (mTypeface == preference) { 353 Settings.Secure.putString( 354 cr, Settings.Secure.ACCESSIBILITY_CAPTIONING_TYPEFACE, (String) value); 355 } else if (mFontSize == preference) { 356 Settings.Secure.putFloat( 357 cr, Settings.Secure.ACCESSIBILITY_CAPTIONING_FONT_SCALE, 358 Float.parseFloat((String) value)); 359 } else if (mLocale == preference) { 360 Settings.Secure.putString( 361 cr, Settings.Secure.ACCESSIBILITY_CAPTIONING_LOCALE, (String) value); 362 } 363 364 refreshPreviewText(); 365 return true; 366 } 367} 368