1/*
2 * Copyright (C) 2011 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.inputmethod;
18
19import android.app.AlertDialog;
20import android.content.Context;
21import android.content.DialogInterface;
22import android.content.pm.ApplicationInfo;
23import android.os.Bundle;
24import android.preference.Preference;
25import android.preference.Preference.OnPreferenceClickListener;
26import android.preference.PreferenceScreen;
27import android.util.Log;
28import android.view.textservice.SpellCheckerInfo;
29import android.view.textservice.SpellCheckerSubtype;
30import android.view.textservice.TextServicesManager;
31import android.widget.Switch;
32
33import com.android.internal.logging.MetricsLogger;
34import com.android.settings.R;
35import com.android.settings.SettingsActivity;
36import com.android.settings.SettingsPreferenceFragment;
37import com.android.settings.inputmethod.SpellCheckerPreference.OnRadioButtonPreferenceListener;
38import com.android.settings.widget.SwitchBar;
39import com.android.settings.widget.SwitchBar.OnSwitchChangeListener;
40
41public class SpellCheckersSettings extends SettingsPreferenceFragment
42        implements OnSwitchChangeListener, OnPreferenceClickListener,
43        OnRadioButtonPreferenceListener {
44    private static final String TAG = SpellCheckersSettings.class.getSimpleName();
45    private static final boolean DBG = false;
46
47    private static final String KEY_SPELL_CHECKER_LANGUAGE = "spellchecker_language";
48    private static final int ITEM_ID_USE_SYSTEM_LANGUAGE = 0;
49
50    private SwitchBar mSwitchBar;
51    private Preference mSpellCheckerLanaguagePref;
52    private AlertDialog mDialog = null;
53    private SpellCheckerInfo mCurrentSci;
54    private SpellCheckerInfo[] mEnabledScis;
55    private TextServicesManager mTsm;
56
57    @Override
58    protected int getMetricsCategory() {
59        return MetricsLogger.INPUTMETHOD_SPELL_CHECKERS;
60    }
61
62    @Override
63    public void onCreate(final Bundle icicle) {
64        super.onCreate(icicle);
65
66        addPreferencesFromResource(R.xml.spellchecker_prefs);
67        mSpellCheckerLanaguagePref = findPreference(KEY_SPELL_CHECKER_LANGUAGE);
68        mSpellCheckerLanaguagePref.setOnPreferenceClickListener(this);
69
70        mTsm = (TextServicesManager) getSystemService(Context.TEXT_SERVICES_MANAGER_SERVICE);
71        mCurrentSci = mTsm.getCurrentSpellChecker();
72        mEnabledScis = mTsm.getEnabledSpellCheckers();
73        populatePreferenceScreen();
74    }
75
76    private void populatePreferenceScreen() {
77        final PreferenceScreen screen = getPreferenceScreen();
78        final Context context = getActivity();
79        final int count = (mEnabledScis == null) ? 0 : mEnabledScis.length;
80        for (int index = 0; index < count; ++index) {
81            final SpellCheckerInfo sci = mEnabledScis[index];
82            final SpellCheckerPreference pref = new SpellCheckerPreference(context, sci, this);
83            screen.addPreference(pref);
84            InputMethodAndSubtypeUtil.removeUnnecessaryNonPersistentPreference(pref);
85        }
86    }
87
88    @Override
89    public void onResume() {
90        super.onResume();
91        mSwitchBar = ((SettingsActivity)getActivity()).getSwitchBar();
92        mSwitchBar.show();
93        mSwitchBar.addOnSwitchChangeListener(this);
94        updatePreferenceScreen();
95    }
96
97    @Override
98    public void onPause() {
99        super.onPause();
100        mSwitchBar.removeOnSwitchChangeListener(this);
101    }
102
103    @Override
104    public void onSwitchChanged(final Switch switchView, final boolean isChecked) {
105        mTsm.setSpellCheckerEnabled(isChecked);
106        updatePreferenceScreen();
107    }
108
109    private void updatePreferenceScreen() {
110        mCurrentSci = mTsm.getCurrentSpellChecker();
111        final boolean isSpellCheckerEnabled = mTsm.isSpellCheckerEnabled();
112        mSwitchBar.setChecked(isSpellCheckerEnabled);
113
114        final SpellCheckerSubtype currentScs = mTsm.getCurrentSpellCheckerSubtype(
115                false /* allowImplicitlySelectedSubtype */);
116        mSpellCheckerLanaguagePref.setSummary(getSpellCheckerSubtypeLabel(mCurrentSci, currentScs));
117
118        final PreferenceScreen screen = getPreferenceScreen();
119        final int count = screen.getPreferenceCount();
120        for (int index = 0; index < count; index++) {
121            final Preference preference = screen.getPreference(index);
122            preference.setEnabled(isSpellCheckerEnabled);
123            if (preference instanceof SpellCheckerPreference) {
124                final SpellCheckerPreference pref = (SpellCheckerPreference)preference;
125                final SpellCheckerInfo sci = pref.getSpellCheckerInfo();
126                pref.setSelected(mCurrentSci != null && mCurrentSci.getId().equals(sci.getId()));
127            }
128        }
129    }
130
131    private CharSequence getSpellCheckerSubtypeLabel(final SpellCheckerInfo sci,
132            final SpellCheckerSubtype subtype) {
133        if (sci == null) {
134            return null;
135        }
136        if (subtype == null) {
137            return getString(R.string.use_system_language_to_select_input_method_subtypes);
138        }
139        return subtype.getDisplayName(
140                getActivity(), sci.getPackageName(), sci.getServiceInfo().applicationInfo);
141    }
142
143    @Override
144    public boolean onPreferenceClick(final Preference pref) {
145        if (pref == mSpellCheckerLanaguagePref) {
146            showChooseLanguageDialog();
147            return true;
148        }
149        return false;
150    }
151
152    @Override
153    public void onRadioButtonClicked(final SpellCheckerPreference pref) {
154        final SpellCheckerInfo sci = pref.getSpellCheckerInfo();
155        final boolean isSystemApp =
156                (sci.getServiceInfo().applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) != 0;
157        if (isSystemApp) {
158            changeCurrentSpellChecker(sci);
159        } else {
160            showSecurityWarnDialog(pref);
161        }
162    }
163
164    private static int convertSubtypeIndexToDialogItemId(final int index) { return index + 1; }
165    private static int convertDialogItemIdToSubtypeIndex(final int item) { return item - 1; }
166
167    private void showChooseLanguageDialog() {
168        if (mDialog != null && mDialog.isShowing()) {
169            mDialog.dismiss();
170        }
171        final SpellCheckerInfo currentSci = mTsm.getCurrentSpellChecker();
172        final SpellCheckerSubtype currentScs = mTsm.getCurrentSpellCheckerSubtype(
173                false /* allowImplicitlySelectedSubtype */);
174        final AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
175        builder.setTitle(R.string.phone_language);
176        final int subtypeCount = currentSci.getSubtypeCount();
177        final CharSequence[] items = new CharSequence[subtypeCount + 1 /* default */ ];
178        items[ITEM_ID_USE_SYSTEM_LANGUAGE] = getSpellCheckerSubtypeLabel(currentSci, null);
179        int checkedItemId = ITEM_ID_USE_SYSTEM_LANGUAGE;
180        for (int index = 0; index < subtypeCount; ++index) {
181            final SpellCheckerSubtype subtype = currentSci.getSubtypeAt(index);
182            final int itemId = convertSubtypeIndexToDialogItemId(index);
183            items[itemId] = getSpellCheckerSubtypeLabel(currentSci, subtype);
184            if (subtype.equals(currentScs)) {
185                checkedItemId = itemId;
186            }
187        }
188        builder.setSingleChoiceItems(items, checkedItemId, new AlertDialog.OnClickListener() {
189            @Override
190            public void onClick(final DialogInterface dialog, final int item) {
191                if (item == ITEM_ID_USE_SYSTEM_LANGUAGE) {
192                    mTsm.setSpellCheckerSubtype(null);
193                } else {
194                    final int index = convertDialogItemIdToSubtypeIndex(item);
195                    mTsm.setSpellCheckerSubtype(currentSci.getSubtypeAt(index));
196                }
197                if (DBG) {
198                    final SpellCheckerSubtype subtype = mTsm.getCurrentSpellCheckerSubtype(
199                            true /* allowImplicitlySelectedSubtype */);
200                    Log.d(TAG, "Current spell check locale is "
201                            + subtype == null ? "null" : subtype.getLocale());
202                }
203                dialog.dismiss();
204                updatePreferenceScreen();
205            }
206        });
207        mDialog = builder.create();
208        mDialog.show();
209    }
210
211    private void showSecurityWarnDialog(final SpellCheckerPreference pref) {
212        if (mDialog != null && mDialog.isShowing()) {
213            mDialog.dismiss();
214        }
215        final SpellCheckerInfo sci = pref.getSpellCheckerInfo();
216        final AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
217        builder.setTitle(android.R.string.dialog_alert_title);
218        builder.setMessage(getString(R.string.spellchecker_security_warning, pref.getTitle()));
219        builder.setCancelable(true);
220        builder.setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() {
221            @Override
222            public void onClick(final DialogInterface dialog, final int which) {
223                changeCurrentSpellChecker(sci);
224            }
225        });
226        builder.setNegativeButton(android.R.string.cancel, new DialogInterface.OnClickListener() {
227            @Override
228            public void onClick(final DialogInterface dialog, final int which) {
229            }
230        });
231        mDialog = builder.create();
232        mDialog.show();
233    }
234
235    private void changeCurrentSpellChecker(final SpellCheckerInfo sci) {
236        mTsm.setCurrentSpellChecker(sci);
237        if (DBG) {
238            Log.d(TAG, "Current spell check is " + mTsm.getCurrentSpellChecker().getId());
239        }
240        updatePreferenceScreen();
241    }
242}
243