/* * Copyright (C) 2011 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.android.settings.inputmethod; import android.app.settings.SettingsEnums; import android.content.Context; import android.content.DialogInterface; import android.content.pm.ApplicationInfo; import android.os.Bundle; import android.provider.Settings; import android.util.Log; import android.view.textservice.SpellCheckerInfo; import android.view.textservice.SpellCheckerSubtype; import android.view.textservice.TextServicesManager; import android.widget.Switch; import androidx.appcompat.app.AlertDialog; import androidx.preference.Preference; import androidx.preference.Preference.OnPreferenceChangeListener; import androidx.preference.Preference.OnPreferenceClickListener; import androidx.preference.PreferenceScreen; import com.android.settings.R; import com.android.settings.SettingsActivity; import com.android.settings.SettingsPreferenceFragment; import com.android.settings.widget.SwitchBar; import com.android.settings.widget.SwitchBar.OnSwitchChangeListener; public class SpellCheckersSettings extends SettingsPreferenceFragment implements OnSwitchChangeListener, OnPreferenceClickListener, OnPreferenceChangeListener { private static final String TAG = SpellCheckersSettings.class.getSimpleName(); private static final boolean DBG = false; private static final String KEY_SPELL_CHECKER_LANGUAGE = "spellchecker_language"; private static final String KEY_DEFAULT_SPELL_CHECKER = "default_spellchecker"; private static final int ITEM_ID_USE_SYSTEM_LANGUAGE = 0; private SwitchBar mSwitchBar; private Preference mSpellCheckerLanaguagePref; private AlertDialog mDialog = null; private SpellCheckerInfo mCurrentSci; private SpellCheckerInfo[] mEnabledScis; private TextServicesManager mTsm; @Override public int getMetricsCategory() { return SettingsEnums.INPUTMETHOD_SPELL_CHECKERS; } @Override public void onCreate(final Bundle icicle) { super.onCreate(icicle); addPreferencesFromResource(R.xml.spellchecker_prefs); mSpellCheckerLanaguagePref = findPreference(KEY_SPELL_CHECKER_LANGUAGE); mSpellCheckerLanaguagePref.setOnPreferenceClickListener(this); mTsm = (TextServicesManager) getSystemService(Context.TEXT_SERVICES_MANAGER_SERVICE); mCurrentSci = mTsm.getCurrentSpellChecker(); mEnabledScis = mTsm.getEnabledSpellCheckers(); populatePreferenceScreen(); } private void populatePreferenceScreen() { final SpellCheckerPreference pref = new SpellCheckerPreference(getPrefContext(), mEnabledScis); pref.setTitle(R.string.default_spell_checker); final int count = (mEnabledScis == null) ? 0 : mEnabledScis.length; if (count > 0) { pref.setSummary("%s"); } else { pref.setSummary(R.string.spell_checker_not_selected); } pref.setKey(KEY_DEFAULT_SPELL_CHECKER); pref.setOnPreferenceChangeListener(this); getPreferenceScreen().addPreference(pref); } @Override public void onResume() { super.onResume(); mSwitchBar = ((SettingsActivity) getActivity()).getSwitchBar(); mSwitchBar.setSwitchBarText( R.string.spell_checker_master_switch_title, R.string.spell_checker_master_switch_title); mSwitchBar.show(); mSwitchBar.addOnSwitchChangeListener(this); updatePreferenceScreen(); } @Override public void onPause() { super.onPause(); mSwitchBar.removeOnSwitchChangeListener(this); } @Override public void onSwitchChanged(final Switch switchView, final boolean isChecked) { Settings.Secure.putInt(getContentResolver(), Settings.Secure.SPELL_CHECKER_ENABLED, isChecked ? 1 : 0); updatePreferenceScreen(); } private void updatePreferenceScreen() { mCurrentSci = mTsm.getCurrentSpellChecker(); final boolean isSpellCheckerEnabled = mTsm.isSpellCheckerEnabled(); mSwitchBar.setChecked(isSpellCheckerEnabled); final SpellCheckerSubtype currentScs; if (mCurrentSci != null) { currentScs = mTsm.getCurrentSpellCheckerSubtype( false /* allowImplicitlySelectedSubtype */); } else { currentScs = null; } mSpellCheckerLanaguagePref.setSummary(getSpellCheckerSubtypeLabel(mCurrentSci, currentScs)); final PreferenceScreen screen = getPreferenceScreen(); final int count = screen.getPreferenceCount(); for (int index = 0; index < count; index++) { final Preference preference = screen.getPreference(index); preference.setEnabled(isSpellCheckerEnabled); if (preference instanceof SpellCheckerPreference) { final SpellCheckerPreference pref = (SpellCheckerPreference) preference; pref.setSelected(mCurrentSci); } } mSpellCheckerLanaguagePref.setEnabled(isSpellCheckerEnabled && mCurrentSci != null); } private CharSequence getSpellCheckerSubtypeLabel(final SpellCheckerInfo sci, final SpellCheckerSubtype subtype) { if (sci == null) { return getString(R.string.spell_checker_not_selected); } if (subtype == null) { return getString(R.string.use_system_language_to_select_input_method_subtypes); } return subtype.getDisplayName( getActivity(), sci.getPackageName(), sci.getServiceInfo().applicationInfo); } @Override public boolean onPreferenceClick(final Preference pref) { if (pref == mSpellCheckerLanaguagePref) { showChooseLanguageDialog(); return true; } return false; } @Override public boolean onPreferenceChange(Preference preference, Object newValue) { final SpellCheckerInfo sci = (SpellCheckerInfo) newValue; final boolean isSystemApp = (sci.getServiceInfo().applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) != 0; if (isSystemApp) { changeCurrentSpellChecker(sci); return true; } else { showSecurityWarnDialog(sci); return false; } } private static int convertSubtypeIndexToDialogItemId(final int index) { return index + 1; } private static int convertDialogItemIdToSubtypeIndex(final int item) { return item - 1; } private void showChooseLanguageDialog() { if (mDialog != null && mDialog.isShowing()) { mDialog.dismiss(); } final SpellCheckerInfo currentSci = mTsm.getCurrentSpellChecker(); if (currentSci == null) { // This can happen in some situations. One example is that the package that the current // spell checker belongs to was uninstalled or being in background. return; } final SpellCheckerSubtype currentScs = mTsm.getCurrentSpellCheckerSubtype( false /* allowImplicitlySelectedSubtype */); final AlertDialog.Builder builder = new AlertDialog.Builder(getActivity()); builder.setTitle(R.string.phone_language); final int subtypeCount = currentSci.getSubtypeCount(); final CharSequence[] items = new CharSequence[subtypeCount + 1 /* default */]; items[ITEM_ID_USE_SYSTEM_LANGUAGE] = getSpellCheckerSubtypeLabel(currentSci, null); int checkedItemId = ITEM_ID_USE_SYSTEM_LANGUAGE; for (int index = 0; index < subtypeCount; ++index) { final SpellCheckerSubtype subtype = currentSci.getSubtypeAt(index); final int itemId = convertSubtypeIndexToDialogItemId(index); items[itemId] = getSpellCheckerSubtypeLabel(currentSci, subtype); if (subtype.equals(currentScs)) { checkedItemId = itemId; } } builder.setSingleChoiceItems(items, checkedItemId, new AlertDialog.OnClickListener() { @Override public void onClick(final DialogInterface dialog, final int item) { final int subtypeId; if (item == ITEM_ID_USE_SYSTEM_LANGUAGE) { subtypeId = SpellCheckerSubtype.SUBTYPE_ID_NONE; } else { final int index = convertDialogItemIdToSubtypeIndex(item); subtypeId = currentSci.getSubtypeAt(index).hashCode(); } Settings.Secure.putInt(getContentResolver(), Settings.Secure.SELECTED_SPELL_CHECKER_SUBTYPE, subtypeId); if (DBG) { final SpellCheckerSubtype subtype = mTsm.getCurrentSpellCheckerSubtype( true /* allowImplicitlySelectedSubtype */); Log.d(TAG, "Current spell check locale is " + subtype == null ? "null" : subtype.getLocale()); } dialog.dismiss(); updatePreferenceScreen(); } }); mDialog = builder.create(); mDialog.show(); } private void showSecurityWarnDialog(final SpellCheckerInfo sci) { if (mDialog != null && mDialog.isShowing()) { mDialog.dismiss(); } final AlertDialog.Builder builder = new AlertDialog.Builder(getActivity()); builder.setTitle(android.R.string.dialog_alert_title); builder.setMessage(getString(R.string.spellchecker_security_warning, sci.loadLabel(getPackageManager()))); builder.setCancelable(true); builder.setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() { @Override public void onClick(final DialogInterface dialog, final int which) { changeCurrentSpellChecker(sci); } }); builder.setNegativeButton(android.R.string.cancel, new DialogInterface.OnClickListener() { @Override public void onClick(final DialogInterface dialog, final int which) { } }); mDialog = builder.create(); mDialog.show(); } private void changeCurrentSpellChecker(final SpellCheckerInfo sci) { Settings.Secure.putString(getContentResolver(), Settings.Secure.SELECTED_SPELL_CHECKER, sci.getId()); // Reset the spell checker subtype Settings.Secure.putInt(getContentResolver(), Settings.Secure.SELECTED_SPELL_CHECKER_SUBTYPE, SpellCheckerSubtype.SUBTYPE_ID_NONE); if (DBG) { Log.d(TAG, "Current spell check is " + mTsm.getCurrentSpellChecker().getId()); } updatePreferenceScreen(); } }