1/*
2 * Copyright (C) 2014 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.tv.settings.system;
18
19import android.content.ContentResolver;
20import android.content.Context;
21import android.content.res.Resources;
22import android.content.res.TypedArray;
23import android.os.Bundle;
24import android.provider.Settings;
25import android.text.TextUtils;
26import android.view.accessibility.CaptioningManager;
27
28import com.android.tv.settings.ActionBehavior;
29import com.android.tv.settings.ActionKey;
30import com.android.tv.settings.BaseSettingsActivity;
31import com.android.tv.settings.R;
32import com.android.tv.settings.dialog.old.Action;
33import com.android.tv.settings.dialog.old.ActionAdapter;
34import com.android.tv.settings.dialog.old.ActionFragment;
35
36import java.text.Collator;
37import java.util.ArrayList;
38import java.util.Arrays;
39import java.util.Locale;
40
41public class CaptionSetupActivity extends BaseSettingsActivity implements ActionAdapter.Listener,
42                                  ActionAdapter.OnFocusListener {
43
44    private static final String TAG = "CaptionSetupActivity";
45    private static final boolean DEBUG = false;
46
47    private Resources mResources;
48    private boolean mDisplayEnabled;
49    private String mNone;
50
51    private String mLanguage;
52    private String mLanguageName;
53    private String[] mLanguageLocales;
54    private String[] mLanguageNames;
55
56    private String mTextSize;
57    private String mTextSizeName;
58    private String[] mTextSizes;
59    private String[] mTextSizeNames;
60
61    private String mStyle;
62    private String mStyleName;
63    private String[] mStyles;
64    private String[] mStyleNames;
65
66    private String mFontFamily;
67    private String mFontFamilyName;
68    private String[] mFontFamilies;
69    private String[] mFontFamilyNames;
70
71    private int[] mColorResIds;
72    private int[] mColorRGBs;
73    private String[] mColorNames;
74
75    private int mTextColor;
76    private String mTextColorName;
77
78    private String mEdgeType;
79    private String mEdgeTypeName;
80    private String[] mEdgeTypes;
81    private String[] mEdgeTypeNames;
82
83    private int mEdgeColor;
84    private String mEdgeColorName;
85
86    private int mBackgroundColor;
87    private String mBackgroundColorName;
88
89    private String mBackgroundOpacity;
90    private String mBackgroundOpacityName;
91    private String[] mOpacities;
92    private String[] mOpacityNames;
93
94    private String mTextOpacity;
95    private String mTextOpacityName;
96
97    private boolean mWindowEnabled;
98    private int mWindowColor;
99    private String mWindowColorName;
100
101    private String mWindowOpacity;
102    private String mWindowOpacityName;
103
104    private CaptioningManager mCaptioningManager;
105
106    @Override
107    protected void onCreate(Bundle savedInstanceState) {
108        mResources = getResources();
109        mActions = new ArrayList<>();
110        mCaptioningManager = (CaptioningManager) getSystemService(Context.CAPTIONING_SERVICE);
111
112        mStyles = getIntArrayAsStringArray(R.array.captioning_preset_selector_values);
113
114        mStyleNames = mResources.getStringArray(R.array.captioning_preset_selector_titles);
115
116        mTextSizes = mResources.getStringArray(R.array.captioning_font_size_selector_values);
117        mTextSizeNames = mResources.getStringArray(R.array.captioning_font_size_selector_titles);
118
119        getLanguages();
120
121        mFontFamilies = mResources.getStringArray(R.array.captioning_typeface_selector_values);
122        mFontFamilyNames = mResources.getStringArray(R.array.captioning_typeface_selector_titles);
123
124        getColorSelection();
125
126        mEdgeTypes = getIntArrayAsStringArray (R.array.captioning_edge_type_selector_values);
127        mEdgeTypeNames = mResources.getStringArray(R.array.captioning_edge_type_selector_titles);
128
129        mOpacities = getIntArrayAsStringArray(R.array.captioning_opacity_selector_values);
130        mOpacityNames = mResources.getStringArray(R.array.captioning_opacity_selector_titles);
131
132        mNone = mResources.getString(R.string.accessibility_none);
133
134        getCaptionSettings ();
135
136        super.onCreate(savedInstanceState);
137
138        mContentFragment = CaptionPreviewFragment.newInstance();
139        setContentFragment (mContentFragment);
140    }
141
142    private String[] getIntArrayAsStringArray(int resourceId) {
143        int[] a = mResources.getIntArray(resourceId);
144        String[] s = new String[a.length];
145        for (int i = 0; i < a.length; ++i)
146            s[i] = String.valueOf(a[i]);
147        return s;
148    }
149
150    private void getColorSelection() {
151        // Load the resource ids of the selectable colors.
152        TypedArray ar =
153            getApplicationContext().getResources().obtainTypedArray
154                (R.array.captioning_color_selector_ids);
155        int len = ar.length();
156        mColorResIds = new int [len];
157        for (int i = 0; i < len; ++i)
158            mColorResIds [i] = ar.getResourceId(i, 0);
159        ar.recycle();
160        // Load the RGB values of the colors.
161        mColorRGBs = new int[len];
162        for (int i = 0; i < len; ++i)
163            mColorRGBs[i] = mResources.getColor(mColorResIds[i]) & 0xffffff;
164        // Initialize the color names that will be displayed to the user.
165        String[] colorNames = mResources.getStringArray(R.array.captioning_color_selector_titles);
166        mColorNames = new String[len];
167        for (int i = 0; i < colorNames.length; ++i) {
168            mColorNames[i] = colorNames[i];
169        }
170        for (int i = colorNames.length; i < len; ++i) {
171            mColorNames[i] = String.format("#%06X", mColorRGBs[i]);
172        }
173    }
174
175    private String getColorName(int color) {
176        for (int x = 0; x < mColorRGBs.length; ++x)
177            if (mColorRGBs[x] == color)
178                return mColorNames[x];
179        return "";
180    }
181
182    private void getCaptionSettings() {
183
184        mDisplayEnabled = mCaptioningManager.isEnabled();
185
186        mLanguage = mCaptioningManager.getRawLocale();
187        if (mLanguage != null)
188            mLanguageName = getLanguageName(mLanguage);
189
190        mTextSize = getClosestValue(mCaptioningManager.getFontScale(), mTextSizes);
191        mTextSizeName = getTextSizeName(mTextSize);
192
193        int style = mCaptioningManager.getRawUserStyle();
194        mStyle = String.valueOf (style);
195        mStyleName = getStyleName(mStyle);
196
197        if (style == CaptioningManager.CaptionStyle.PRESET_CUSTOM) {
198            getCustomCaptionStyle();
199        }
200    }
201
202    private String getClosestValue(float value, String[] values) {
203        int ndx = -1;
204        float delta = 0;
205        for (int i = 0; i < values.length; ++i) {
206            float d = Math.abs(value - Float.parseFloat(values [i]));
207            if (ndx == -1 || d < delta) {
208                ndx = i;
209                delta = d;
210            }
211        }
212        if (ndx == -1) {
213            return "";
214        } else {
215            return values [ndx];
216        }
217    }
218
219    private void getCustomCaptionStyle() {
220        CaptioningManager.CaptionStyle cs = mCaptioningManager.getUserStyle();
221
222        mFontFamily = cs.mRawTypeface;
223        mFontFamilyName = getFontFamilyName(mFontFamily);
224
225        mTextColor = cs.foregroundColor & 0xffffff;
226        mTextColorName = getColorName(mTextColor);
227
228        mTextOpacity = getClosestValue(cs.foregroundColor | 0xffffff, mOpacities);
229        mTextOpacityName = getOpacityName(mTextOpacity);
230
231        mEdgeType = Integer.toString (cs.edgeType);
232        mEdgeTypeName = getEdgeTypeName(mEdgeType);
233
234        mEdgeColor = cs.edgeColor & 0xffffff;
235        mEdgeColorName = getColorName(mEdgeColor);
236
237        mBackgroundColor = cs.backgroundColor & 0xffffff;
238        mBackgroundColorName = getColorName(mBackgroundColor);
239
240        mBackgroundOpacity = getClosestValue(cs.backgroundColor | 0xffffff, mOpacities);
241        mBackgroundOpacityName = getOpacityName(mBackgroundOpacity);
242
243        mWindowEnabled = cs.hasWindowColor() && (cs.windowColor & 0xff000000) != 0;
244        mWindowColor = cs.windowColor & 0xffffff;
245        if (mWindowEnabled) {
246            mWindowColorName = getColorName(mWindowColor);
247        } else {
248            mWindowColorName = mNone;
249        }
250        mWindowOpacity = getClosestValue(cs.windowColor | 0xffffff, mOpacities);
251        if (mWindowEnabled) {
252            mWindowOpacityName = getOpacityName(mWindowOpacity);
253        } else {
254            mWindowOpacityName = mNone;
255        }
256    }
257
258    private void colorsToActions(int selectedColor) {
259        mActions.clear();
260        for (int i = 0; i < mColorResIds.length; ++i) {
261            mActions.add(
262                new Action.Builder().key(Integer.toString(mColorRGBs[i]))
263                                    .drawableResource(mColorResIds[i])
264                                    .title(mColorNames[i])
265                                    .checked(selectedColor == mColorRGBs[i]).build());
266        }
267    }
268
269    @Override
270    protected void refreshActionList() {
271        if(mContentFragment instanceof CaptionPreviewFragment) {
272            ((CaptionPreviewFragment)mContentFragment).resetLivePreview();
273        }
274        mActions.clear();
275        switch ((ActionType) mState) {
276            case CAPTIONS_OVERVIEW:
277                int statusResource = mDisplayEnabled ?
278                        R.string.captions_display_on : R.string.captions_display_off;
279                mActions.add(ActionType.CAPTIONS_DISPLAY.toAction(
280                             mResources, mResources.getString(statusResource)));
281                mActions.add(ActionType.CAPTIONS_CONFIGURE.toAction(mResources,
282                             mResources.getString(R.string.display_options)));
283                break;
284            case CAPTIONS_DISPLAY:
285                mActions.add(ActionBehavior.ON.toAction(ActionBehavior.getOnKey(
286                             ActionType.CAPTIONS_DISPLAY.name()), mResources, mDisplayEnabled));
287                mActions.add(ActionBehavior.OFF.toAction(ActionBehavior.getOffKey(
288                             ActionType.CAPTIONS_DISPLAY.name()), mResources, ! mDisplayEnabled));
289                break;
290            case CAPTIONS_CONFIGURE:
291                mActions.add(ActionType.CAPTIONS_LANGUAGE.toAction(mResources, mLanguageName));
292                mActions.add(ActionType.CAPTIONS_TEXTSIZE.toAction(mResources, mTextSizeName));
293                mActions.add(ActionType.CAPTIONS_CAPTIONSTYLE.toAction(mResources, mStyleName));
294                break;
295            case CAPTIONS_TEXTSIZE:
296                mActions = Action.createActionsFromArrays(mTextSizes, mTextSizeNames);
297                for (Action action : mActions) {
298                    action.setChecked(action.getKey().equals(mTextSize));
299                }
300                break;
301            case CAPTIONS_CAPTIONSTYLE:
302                mActions = Action.createActionsFromArrays(mStyles, mStyleNames);
303                for (Action action : mActions) {
304                    action.setChecked(action.getKey().equals(mStyle));
305                }
306                break;
307            case CAPTIONS_CUSTOMOPTIONS:
308                mActions.add(ActionType.CAPTIONS_FONTFAMILY.toAction(mResources, mFontFamilyName));
309                mActions.add(ActionType.CAPTIONS_TEXTCOLOR.toAction(mResources, mTextColorName));
310                mActions.add(ActionType.CAPTIONS_TEXTOPACITY.toAction(mResources,
311                        mTextOpacityName));
312                mActions.add(ActionType.CAPTIONS_EDGETYPE.toAction(mResources, mEdgeTypeName));
313                mActions.add(ActionType.CAPTIONS_EDGECOLOR.toAction(mResources, mEdgeColorName));
314                mActions.add(ActionType.CAPTIONS_BACKGROUNDCOLOR.toAction(mResources,
315                               mBackgroundColorName));
316                mActions.add(ActionType.CAPTIONS_BACKGROUNDOPACITY.toAction(mResources,
317                               mBackgroundOpacityName));
318                mActions.add(ActionType.CAPTIONS_WINDOWCOLOR.toAction(mResources,
319                        mWindowColorName));
320                mActions.add(ActionType.CAPTIONS_WINDOWOPACITY.toAction(mResources,
321                        mWindowOpacityName, mWindowEnabled));
322                break;
323            case CAPTIONS_LANGUAGE:
324                mActions = Action.createActionsFromArrays(mLanguageLocales, mLanguageNames);
325                for (Action action : mActions) {
326                    action.setChecked(action.getKey().equals(mLanguage));
327                }
328                break;
329            case CAPTIONS_FONTFAMILY:
330                mActions = Action.createActionsFromArrays(mFontFamilies, mFontFamilyNames);
331                for (Action action : mActions) {
332                    action.setChecked(action.getKey().equals(mFontFamily));
333                }
334                break;
335            case CAPTIONS_TEXTCOLOR:
336                colorsToActions(mTextColor);
337                break;
338            case CAPTIONS_TEXTOPACITY:
339                mActions = Action.createActionsFromArrays(mOpacities, mOpacityNames);
340                for (Action action : mActions) {
341                    action.setChecked(action.getKey().equals(mTextOpacity));
342                }
343                break;
344            case CAPTIONS_EDGETYPE:
345                mActions = Action.createActionsFromArrays(mEdgeTypes, mEdgeTypeNames);
346               for (Action action : mActions) {
347                    action.setChecked(action.getKey().equals(mEdgeType));
348                }
349                break;
350            case CAPTIONS_EDGECOLOR:
351                colorsToActions(mEdgeColor);
352                break;
353            case CAPTIONS_BACKGROUNDCOLOR:
354                colorsToActions(mBackgroundColor);
355                break;
356            case CAPTIONS_BACKGROUNDOPACITY:
357                mActions = Action.createActionsFromArrays(mOpacities, mOpacityNames);
358                for (Action action : mActions) {
359                    action.setChecked(action.getKey().equals(mBackgroundOpacity));
360                }
361                break;
362            case CAPTIONS_WINDOWCOLOR:
363                mActions.clear();
364                mActions.add(
365                    new Action.Builder().key(mNone)
366                                        .drawableResource(mColorResIds[1])
367                                        .title(mNone)
368                                        .checked(!mWindowEnabled).build());
369                for (int i = 0; i < mColorResIds.length; ++i) {
370                    mActions.add(
371                        new Action.Builder().key(Integer.toString(mColorRGBs[i]))
372                                            .drawableResource(mColorResIds[i])
373                                            .title(mColorNames[i])
374                                            .checked(mWindowEnabled && mWindowColor ==
375                                                    mColorRGBs[i]).build());
376                }
377                break;
378            case CAPTIONS_WINDOWOPACITY:
379                mActions = Action.createActionsFromArrays(mOpacities, mOpacityNames);
380                for (Action action : mActions) {
381                    action.setChecked(action.getKey().equals(mWindowOpacity));
382                }
383                break;
384        }
385    }
386
387    @Override
388    protected void updateView() {
389        refreshActionList();
390        mActionFragment = ActionFragment.newInstance(mActions);
391        setActionFragment (mActionFragment);
392    }
393
394    @Override
395    public void onActionFocused(Action action) {
396        final String key = action.getKey();
397        switch ((ActionType) mState) {
398            case CAPTIONS_LANGUAGE:
399                if(mContentFragment instanceof CaptionPreviewFragment) {
400                    ((CaptionPreviewFragment)mContentFragment).
401                        livePreviewLanguage(key);
402                }
403                break;
404            case CAPTIONS_TEXTSIZE:
405                if(mContentFragment instanceof CaptionPreviewFragment) {
406                    ((CaptionPreviewFragment)mContentFragment).
407                        livePreviewFontScale(Float.parseFloat(key));
408                }
409                break;
410            case CAPTIONS_CAPTIONSTYLE:
411                if(mContentFragment instanceof CaptionPreviewFragment) {
412                    ((CaptionPreviewFragment)mContentFragment).
413                        livePreviewCaptionStyle(Integer.parseInt(key));
414                }
415                break;
416            case CAPTIONS_FONTFAMILY:
417                if(mContentFragment instanceof CaptionPreviewFragment) {
418                    ((CaptionPreviewFragment)mContentFragment).
419                        livePreviewFontFamily(key);
420                }
421                break;
422            case CAPTIONS_TEXTCOLOR:
423                if(mContentFragment instanceof CaptionPreviewFragment) {
424                    ((CaptionPreviewFragment)mContentFragment).
425                        livePreviewTextColor(Integer.parseInt(key));
426                }
427                break;
428            case CAPTIONS_TEXTOPACITY:
429                if(mContentFragment instanceof CaptionPreviewFragment) {
430                    ((CaptionPreviewFragment)mContentFragment).
431                        livePreviewTextOpacity(key);
432                }
433                break;
434            case CAPTIONS_EDGETYPE:
435                if(mContentFragment instanceof CaptionPreviewFragment) {
436                    ((CaptionPreviewFragment)mContentFragment).
437                        livePreviewEdgeType(Integer.parseInt(key));
438                }
439                break;
440            case CAPTIONS_EDGECOLOR:
441                if(mContentFragment instanceof CaptionPreviewFragment) {
442                    ((CaptionPreviewFragment)mContentFragment).
443                        livePreviewEdgeColor(Integer.parseInt(key));
444                }
445                break;
446            case CAPTIONS_BACKGROUNDCOLOR:
447                if(mContentFragment instanceof CaptionPreviewFragment) {
448                    ((CaptionPreviewFragment)mContentFragment).
449                        livePreviewBackgroundColor(Integer.parseInt(key));
450                }
451                break;
452            case CAPTIONS_BACKGROUNDOPACITY:
453                if(mContentFragment instanceof CaptionPreviewFragment) {
454                    ((CaptionPreviewFragment)mContentFragment).
455                        livePreviewBackgroundOpacity(key);
456                }
457                break;
458            case CAPTIONS_WINDOWCOLOR:
459                if(mContentFragment instanceof CaptionPreviewFragment) {
460                    if (TextUtils.equals(key, mNone)) {
461                        ((CaptionPreviewFragment)mContentFragment).
462                            livePreviewWindowColorNone();
463                    } else {
464                        ((CaptionPreviewFragment)mContentFragment).
465                            livePreviewWindowColor(Integer.parseInt(key));
466                    }
467                }
468                break;
469            case CAPTIONS_WINDOWOPACITY:
470                if(mContentFragment instanceof CaptionPreviewFragment) {
471                    ((CaptionPreviewFragment)mContentFragment).
472                        livePreviewWindowOpacity(key);
473                }
474                break;
475        }
476    }
477
478    @Override
479    public void onActionClicked(Action action) {
480        final String key = action.getKey();
481        switch ((ActionType) mState) {
482            case CAPTIONS_LANGUAGE:
483                setLanguage(key);
484                goBack();
485                break;
486            case CAPTIONS_TEXTSIZE:
487                setTextSize(key);
488                goBack();
489                break;
490            case CAPTIONS_CAPTIONSTYLE:
491                setStyle(key);
492                if (Integer.parseInt(key) == CaptioningManager.CaptionStyle.PRESET_CUSTOM) {
493                    setState(ActionType.CAPTIONS_CUSTOMOPTIONS, true);
494                } else {
495                    goBack();
496                }
497                break;
498            case CAPTIONS_FONTFAMILY:
499                setFontFamily(key);
500                goBack();
501                break;
502            case CAPTIONS_TEXTCOLOR:
503                setTextColor(key);
504                goBack();
505                break;
506            case CAPTIONS_TEXTOPACITY:
507                setTextOpacity(key);
508                goBack();
509                break;
510            case CAPTIONS_EDGETYPE:
511                setEdgeType(key);
512                goBack();
513                break;
514            case CAPTIONS_EDGECOLOR:
515                setEdgeColor(key);
516                goBack();
517                break;
518            case CAPTIONS_BACKGROUNDCOLOR:
519                setBackgroundColor(key);
520                goBack();
521                break;
522            case CAPTIONS_BACKGROUNDOPACITY:
523                setBackgroundOpacity(key);
524                goBack();
525                break;
526            case CAPTIONS_WINDOWCOLOR:
527                setWindowColor(key);
528                goBack();
529                break;
530            case CAPTIONS_WINDOWOPACITY:
531                setWindowOpacity(key);
532                goBack();
533                break;
534            default:
535                ActionKey<ActionType, ActionBehavior> actionKey =
536                    new ActionKey<>(
537                        ActionType.class, ActionBehavior.class, action.getKey());
538                final ActionType type = actionKey.getType();
539                final ActionBehavior behavior = actionKey.getBehavior();
540                if (behavior == null) {
541                    return;
542                }
543                switch (behavior) {
544                    case ON:
545                        setProperty(true);
546                        break;
547                    case OFF:
548                        setProperty(false);
549                        break;
550                    case INIT:
551                        setState(type, true);
552                        break;
553                }
554                break;
555        }
556    }
557
558    @Override
559    protected Object getInitialState() {
560        return ActionType.CAPTIONS_OVERVIEW;
561    }
562
563    @Override
564    protected void setProperty(boolean enable) {
565        switch ((ActionType) mState) {
566            case CAPTIONS_DISPLAY:
567                setEnabled(enable);
568                break;
569        }
570        goBack();
571    }
572
573    private String getTextSizeName(String textSize) {
574        for (int i = 0; i < mTextSizes.length; ++i) {
575            if (mTextSizes [i] == textSize) {
576                return mTextSizeNames [i];
577            }
578        }
579        return "";
580    }
581
582    private String getStyleName(String style) {
583        for (int i = 0; i < mStyles.length; ++i) {
584            if (mStyles [i] == style) {
585                return mStyleNames [i];
586            }
587        }
588        return "";
589    }
590
591    private void setEnabled(boolean enabled) {
592        mDisplayEnabled = enabled;
593        final ContentResolver cr = getContentResolver();
594        Settings.Secure.putInt(cr, Settings.Secure.ACCESSIBILITY_CAPTIONING_ENABLED,
595                               enabled ? 1 : 0);
596    }
597
598    private void setStyle(String style) {
599        mStyle = style;
600        mStyleName = getStyleName(style);
601        final ContentResolver cr = getContentResolver();
602        int s = Integer.parseInt(style);
603        Settings.Secure.putInt(cr, Settings.Secure.ACCESSIBILITY_CAPTIONING_PRESET, s);
604        if (s == CaptioningManager.CaptionStyle.PRESET_CUSTOM) {
605            getCustomCaptionStyle();
606        }
607        if(mContentFragment instanceof CaptionPreviewFragment) {
608            ((CaptionPreviewFragment)mContentFragment).refreshPreviewText();
609        }
610    }
611
612    private void setTextSize(String textSize) {
613        mTextSize = textSize;
614        mTextSizeName = getTextSizeName(textSize);
615        final ContentResolver cr = getContentResolver();
616        Settings.Secure.putFloat(cr, Settings.Secure.ACCESSIBILITY_CAPTIONING_FONT_SCALE,
617                                 Float.parseFloat(textSize));
618    }
619
620    private void setLanguage(String language) {
621        mLanguage = language;
622        mLanguageName = getLanguageName(language);
623        final ContentResolver cr = getContentResolver();
624        Settings.Secure.putString(cr, Settings.Secure.ACCESSIBILITY_CAPTIONING_LOCALE, language);
625    }
626
627    private void setFontFamily(String fontFamily) {
628        mFontFamily = fontFamily;
629        mFontFamilyName = getFontFamilyName(fontFamily);
630        final ContentResolver cr = getContentResolver();
631        Settings.Secure.putString(cr, Settings.Secure.ACCESSIBILITY_CAPTIONING_TYPEFACE,
632                                  fontFamily);
633    }
634
635    private void setTextColor(String textColor) {
636        mTextColor = Integer.parseInt(textColor);
637        mTextColorName = getColorName(mTextColor);
638        updateCaptioningTextColor();
639    }
640
641    private void setTextOpacity(String textOpacity) {
642        mTextOpacity = textOpacity;
643        mTextOpacityName = getOpacityName(textOpacity);
644        updateCaptioningTextColor();
645    }
646
647    private void updateCaptioningTextColor() {
648        int opacity = Integer.parseInt(mTextOpacity) & 0xff000000;
649        final ContentResolver cr = getContentResolver();
650        Settings.Secure.putInt(cr, Settings.Secure.ACCESSIBILITY_CAPTIONING_FOREGROUND_COLOR,
651                                opacity | mTextColor);
652    }
653
654    private void setWindowColor(String windowColor) {
655        if (TextUtils.equals(windowColor, mNone)) {
656            mWindowEnabled = false;
657            mWindowColorName = mNone;
658            mWindowOpacityName = mNone;
659        } else {
660            mWindowEnabled = true;
661            mWindowColor = Integer.parseInt(windowColor);
662            mWindowColorName = getColorName(mWindowColor);
663            mWindowOpacityName = getOpacityName(mWindowOpacity);
664        }
665        updateCaptioningWindowColor();
666    }
667
668    private void setWindowOpacity(String windowOpacity) {
669        mWindowOpacity = windowOpacity;
670        mWindowOpacityName = getOpacityName(windowOpacity);
671        updateCaptioningWindowColor();
672    }
673
674    private void updateCaptioningWindowColor() {
675        int opacity = mWindowEnabled ? Integer.parseInt(mWindowOpacity) & 0xff000000 : 0;
676        final ContentResolver cr = getContentResolver();
677        Settings.Secure.putInt(cr, Settings.Secure.ACCESSIBILITY_CAPTIONING_WINDOW_COLOR,
678                                opacity | mWindowColor);
679    }
680
681    private void setEdgeType(String edgeType) {
682        mEdgeType = edgeType;
683        mEdgeTypeName = getEdgeTypeName(edgeType);
684        final ContentResolver cr = getContentResolver();
685        Settings.Secure.putInt(cr, Settings.Secure.ACCESSIBILITY_CAPTIONING_EDGE_TYPE,
686                                Integer.parseInt(edgeType));
687    }
688
689    private void setEdgeColor(String edgeColor) {
690        mEdgeColor = Integer.parseInt(edgeColor);
691        mEdgeColorName = getColorName(mEdgeColor);
692        final ContentResolver cr = getContentResolver();
693        Settings.Secure.putInt(cr, Settings.Secure.ACCESSIBILITY_CAPTIONING_EDGE_COLOR,
694                                0xff000000 | mEdgeColor);
695    }
696
697    private void updateCaptioningBackgroundColor() {
698        int opacity = Integer.parseInt(mBackgroundOpacity) & 0xff000000;
699        final ContentResolver cr = getContentResolver();
700        Settings.Secure.putInt(cr, Settings.Secure.ACCESSIBILITY_CAPTIONING_BACKGROUND_COLOR,
701                                opacity | mBackgroundColor);
702    }
703
704    private void setBackgroundColor(String backgroundColor) {
705        mBackgroundColor = Integer.parseInt(backgroundColor);
706        mBackgroundColorName = getColorName(mBackgroundColor);
707        updateCaptioningBackgroundColor();
708    }
709
710    private void setBackgroundOpacity(String backgroundOpacity) {
711        mBackgroundOpacity = backgroundOpacity;
712        mBackgroundOpacityName = getOpacityName(backgroundOpacity);
713        updateCaptioningBackgroundColor();
714    }
715
716    private String getLanguageName(String language) {
717        for (int i = 0; i < mLanguageLocales.length; ++i) {
718            if (language.equals(mLanguageLocales [i])) {
719                return mLanguageNames [i];
720            }
721        }
722        return "";
723    }
724
725    private static String getDisplayName(
726            Locale l, String[] specialLocaleCodes, String[] specialLocaleNames) {
727        String code = l.toString();
728        for (int i = 0; i < specialLocaleCodes.length; i++) {
729            if (specialLocaleCodes[i].equals(code)) {
730                return specialLocaleNames[i];
731            }
732        }
733        return l.getDisplayName(l);
734    }
735
736    private String getFontFamilyName(String fontFamily) {
737        int x = indexOf(mFontFamilies, fontFamily);
738        if (x == -1) {
739            return "";
740        } else {
741            return mFontFamilyNames [x];
742        }
743    }
744
745    private String getOpacityName(String opacity) {
746        int x = indexOf(mOpacities, opacity);
747        if (x == -1) {
748            return "";
749        } else {
750            return mOpacityNames [x];
751        }
752    }
753
754    private int indexOf(String[] a, String s) {
755        if (s != null) {
756            for (int i = 0; i < a.length; ++i) {
757                if (s.equals(a [i])) {
758                    return i;
759                }
760            }
761        }
762        return -1;
763    }
764
765    private String getEdgeTypeName(String edgeType) {
766        int x = indexOf(mEdgeTypes, edgeType);
767        if (x == -1) {
768            return "";
769        } else {
770            return mEdgeTypeNames [x];
771        }
772    }
773
774    private static class LocaleInfo implements Comparable<LocaleInfo> {
775        private static final Collator sCollator = Collator.getInstance();
776
777        public String label;
778        public final Locale locale;
779
780        public LocaleInfo(String label, Locale locale) {
781            this.label = label;
782            this.locale = locale;
783        }
784
785        @Override
786        public String toString() {
787            return label;
788        }
789
790        @Override
791        public int compareTo(LocaleInfo another) {
792            return sCollator.compare(this.label, another.label);
793        }
794    }
795
796    private void getLanguages() {
797        final String[] systemLocales = Resources.getSystem().getAssets().getLocales();
798        Arrays.sort(systemLocales);
799
800        final Context context = getApplicationContext();
801        final Resources resources = context.getResources();
802        final String[] specialLocaleCodes = resources.getStringArray(
803                com.android.internal.R.array.special_locale_codes);
804        final String[] specialLocaleNames = resources.getStringArray(
805                com.android.internal.R.array.special_locale_names);
806
807        int finalSize = 0;
808
809        final int origSize = systemLocales.length;
810        final LocaleInfo[] localeInfos = new LocaleInfo[origSize];
811        for (int i = 0; i < origSize; i++) {
812            final String localeStr = systemLocales[i];
813            final Locale locale = Locale.forLanguageTag(localeStr.replace('_', '-'));
814            // "und" means undefined.
815            if ("und".equals(locale.getLanguage()) || locale.getLanguage().isEmpty() ||
816                    locale.getCountry().isEmpty()) {
817                continue;
818            }
819
820            if (finalSize == 0) {
821                localeInfos[finalSize++] =
822                       new LocaleInfo(locale.getDisplayLanguage(locale), locale);
823            } else {
824                // check previous entry:
825                // same lang and a country -> upgrade to full name and
826                // insert ours with full name
827                // diff lang -> insert ours with lang-only name
828                final LocaleInfo previous = localeInfos[finalSize - 1];
829                if (previous.locale.getLanguage().equals(locale.getLanguage())
830                        && !previous.locale.getLanguage().equals("zz")) {
831                    previous.label = getDisplayName(
832                            localeInfos[finalSize - 1].locale, specialLocaleCodes,
833                            specialLocaleNames);
834                    localeInfos[finalSize++] = new LocaleInfo(getDisplayName(locale,
835                            specialLocaleCodes, specialLocaleNames), locale);
836                } else {
837                    final String displayName;
838                    if (localeStr.equals("zz_ZZ")) {
839                        displayName = "[Developer] Accented English";
840                    } else if (localeStr.equals("zz_ZY")) {
841                        displayName = "[Developer] Fake Bi-Directional";
842                    } else {
843                        displayName = locale.getDisplayLanguage(locale);
844                    }
845                    localeInfos[finalSize++] = new LocaleInfo(displayName, locale);
846                }
847            }
848        }
849
850        mLanguageLocales = new String [finalSize];
851        mLanguageNames = new String [finalSize];
852
853        Arrays.sort(localeInfos, 0, finalSize);
854        for (int i = 0; i < finalSize; i++) {
855            final LocaleInfo info = localeInfos[i];
856            mLanguageLocales[i] = info.locale.toString();
857            mLanguageNames[i] = info.toString();
858        }
859    }
860}
861
862