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