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