diff options
Diffstat (limited to 'src/com/android/settings/inputmethod/InputMethodPreference.java')
-rwxr-xr-x[-rw-r--r--] | src/com/android/settings/inputmethod/InputMethodPreference.java | 422 |
1 files changed, 182 insertions, 240 deletions
diff --git a/src/com/android/settings/inputmethod/InputMethodPreference.java b/src/com/android/settings/inputmethod/InputMethodPreference.java index aa6430f..5cf5d6a 100644..100755 --- a/src/com/android/settings/inputmethod/InputMethodPreference.java +++ b/src/com/android/settings/inputmethod/InputMethodPreference.java @@ -16,306 +16,248 @@ package com.android.settings.inputmethod; -import com.android.internal.inputmethod.InputMethodUtils; -import com.android.settings.R; -import com.android.settings.SettingsPreferenceFragment; -import com.android.settings.Utils; - import android.app.AlertDialog; -import android.app.Fragment; import android.content.ActivityNotFoundException; import android.content.Context; import android.content.DialogInterface; import android.content.Intent; -import android.content.res.Configuration; -import android.os.Bundle; -import android.preference.CheckBoxPreference; import android.preference.Preference; -import android.preference.PreferenceActivity; -import android.provider.Settings; +import android.preference.Preference.OnPreferenceChangeListener; +import android.preference.Preference.OnPreferenceClickListener; +import android.preference.SwitchPreference; import android.text.TextUtils; import android.util.Log; -import android.view.View; -import android.view.View.OnClickListener; -import android.view.View.OnLongClickListener; import android.view.inputmethod.InputMethodInfo; import android.view.inputmethod.InputMethodManager; import android.view.inputmethod.InputMethodSubtype; -import android.widget.ImageView; -import android.widget.TextView; import android.widget.Toast; +import com.android.internal.inputmethod.InputMethodUtils; +import com.android.settings.R; + import java.text.Collator; +import java.util.ArrayList; import java.util.List; -public class InputMethodPreference extends CheckBoxPreference { +/** + * Input method preference. + * + * This preference represents an IME. It is used for two purposes. 1) An instance with a switch + * is used to enable or disable the IME. 2) An instance without a switch is used to invoke the + * setting activity of the IME. + */ +class InputMethodPreference extends SwitchPreference implements OnPreferenceClickListener, + OnPreferenceChangeListener { private static final String TAG = InputMethodPreference.class.getSimpleName(); - private final SettingsPreferenceFragment mFragment; + private static final String EMPTY_TEXT = ""; + + interface OnSavePreferenceListener { + /** + * Called when this preference needs to be saved its state. + * + * Note that this preference is non-persistent and needs explicitly to be saved its state. + * Because changing one IME state may change other IMEs' state, this is a place to update + * other IMEs' state as well. + * + * @param pref This preference. + */ + public void onSaveInputMethodPreference(InputMethodPreference pref); + } + private final InputMethodInfo mImi; - private final InputMethodManager mImm; - private final boolean mIsValidSystemNonAuxAsciiCapableIme; - private final Intent mSettingsIntent; - private final boolean mIsSystemIme; - private final Collator mCollator; + private final boolean mHasPriorityInSorting; + private final OnSavePreferenceListener mOnSaveListener; + private final InputMethodSettingValuesWrapper mInputMethodSettingValues; + private final boolean mIsAllowedByOrganization; private AlertDialog mDialog = null; - private ImageView mInputMethodSettingsButton; - private TextView mTitleText; - private TextView mSummaryText; - private View mInputMethodPref; - private OnPreferenceChangeListener mOnImePreferenceChangeListener; - - private final OnClickListener mPrefOnclickListener = new OnClickListener() { - @Override - public void onClick(View arg0) { - if (!isEnabled()) { - return; - } - if (isChecked()) { - setChecked(false, true /* save */); - } else { - if (mIsSystemIme) { - setChecked(true, true /* save */); - } else { - showSecurityWarnDialog(mImi, InputMethodPreference.this); - } - } - } - }; - public InputMethodPreference(SettingsPreferenceFragment fragment, Intent settingsIntent, - InputMethodManager imm, InputMethodInfo imi) { - super(fragment.getActivity(), null, R.style.InputMethodPreferenceStyle); - setLayoutResource(R.layout.preference_inputmethod); - setWidgetLayoutResource(R.layout.preference_inputmethod_widget); - mFragment = fragment; - mSettingsIntent = settingsIntent; - mImm = imm; + /** + * A preference entry of an input method. + * + * @param context The Context this is associated with. + * @param imi The {@link InputMethodInfo} of this preference. + * @param isImeEnabler true if this preference is the IME enabler that has enable/disable + * switches for all available IMEs, not the list of enabled IMEs. + * @param isAllowedByOrganization false if the IME has been disabled by a device or profile + owner. + * @param onSaveListener The listener called when this preference has been changed and needs + * to save the state to shared preference. + */ + InputMethodPreference(final Context context, final InputMethodInfo imi, + final boolean isImeEnabler, final boolean isAllowedByOrganization, + final OnSavePreferenceListener onSaveListener) { + super(context); + setPersistent(false); mImi = imi; - mIsSystemIme = InputMethodUtils.isSystemIme(imi); - mCollator = Collator.getInstance(fragment.getResources().getConfiguration().locale); - final Context context = fragment.getActivity(); - mIsValidSystemNonAuxAsciiCapableIme = InputMethodSettingValuesWrapper - .getInstance(context).isValidSystemNonAuxAsciiCapableIme(imi, context); - updatePreferenceViews(); - } - - @Override - protected void onBindView(View view) { - super.onBindView(view); - mInputMethodPref = view.findViewById(R.id.inputmethod_pref); - mInputMethodPref.setOnClickListener(mPrefOnclickListener); - mInputMethodSettingsButton = (ImageView)view.findViewById(R.id.inputmethod_settings); - mTitleText = (TextView)view.findViewById(android.R.id.title); - mSummaryText = (TextView)view.findViewById(android.R.id.summary); - final boolean hasSubtypes = mImi.getSubtypeCount() > 1; - final String imiId = mImi.getId(); - if (hasSubtypes) { - mInputMethodPref.setOnLongClickListener(new OnLongClickListener() { - @Override - public boolean onLongClick(View arg0) { - final Bundle bundle = new Bundle(); - bundle.putString(Settings.EXTRA_INPUT_METHOD_ID, imiId); - startFragment(mFragment, InputMethodAndSubtypeEnabler.class.getName(), - 0, bundle); - return true; - } - }); - } - - if (mSettingsIntent != null) { - mInputMethodSettingsButton.setOnClickListener( - new OnClickListener() { - @Override - public void onClick(View arg0) { - try { - mFragment.startActivity(mSettingsIntent); - } catch (ActivityNotFoundException e) { - Log.d(TAG, "IME's Settings Activity Not Found: " + e); - final String msg = mFragment.getString( - R.string.failed_to_open_app_settings_toast, - mImi.loadLabel( - mFragment.getActivity().getPackageManager())); - Toast.makeText( - mFragment.getActivity(), msg, Toast.LENGTH_LONG).show(); - } - } - }); - } - if (hasSubtypes) { - final OnLongClickListener listener = new OnLongClickListener() { - @Override - public boolean onLongClick(View arg0) { - final Bundle bundle = new Bundle(); - bundle.putString(Settings.EXTRA_INPUT_METHOD_ID, imiId); - startFragment(mFragment, InputMethodAndSubtypeEnabler.class.getName(), - 0, bundle); - return true; - } - }; - mInputMethodSettingsButton.setOnLongClickListener(listener); + mIsAllowedByOrganization = isAllowedByOrganization; + mOnSaveListener = onSaveListener; + if (!isImeEnabler) { + // Hide switch widget. + setWidgetLayoutResource(0 /* widgetLayoutResId */); } - if (mSettingsIntent == null) { - mInputMethodSettingsButton.setVisibility(View.GONE); + // Disable on/off switch texts. + setSwitchTextOn(EMPTY_TEXT); + setSwitchTextOff(EMPTY_TEXT); + setKey(imi.getId()); + setTitle(imi.loadLabel(context.getPackageManager())); + final String settingsActivity = imi.getSettingsActivity(); + if (TextUtils.isEmpty(settingsActivity)) { + setIntent(null); + } else { + // Set an intent to invoke settings activity of an input method. + final Intent intent = new Intent(Intent.ACTION_MAIN); + intent.setClassName(imi.getPackageName(), settingsActivity); + setIntent(intent); } - updatePreferenceViews(); + mInputMethodSettingValues = InputMethodSettingValuesWrapper.getInstance(context); + mHasPriorityInSorting = InputMethodUtils.isSystemIme(imi) + && mInputMethodSettingValues.isValidSystemNonAuxAsciiCapableIme(imi, context); + setOnPreferenceClickListener(this); + setOnPreferenceChangeListener(this); } - @Override - public void setEnabled(boolean enabled) { - super.setEnabled(enabled); - updatePreferenceViews(); + public InputMethodInfo getInputMethodInfo() { + return mImi; } - public void updatePreferenceViews() { - final boolean isAlwaysChecked = - InputMethodSettingValuesWrapper.getInstance(getContext()).isAlwaysCheckedIme( - mImi, getContext()); - if (isAlwaysChecked) { - super.setChecked(true); - super.setEnabled(false); - } else { - super.setEnabled(true); - } - final boolean checked = isChecked(); - if (mInputMethodSettingsButton != null) { - mInputMethodSettingsButton.setEnabled(checked); - mInputMethodSettingsButton.setClickable(checked); - mInputMethodSettingsButton.setFocusable(checked); - if (!checked) { - mInputMethodSettingsButton.setAlpha(Utils.DISABLED_ALPHA); - } - } - if (mTitleText != null) { - mTitleText.setEnabled(true); + private boolean isImeEnabler() { + // If this {@link SwitchPreference} doesn't have a widget layout, we explicitly hide the + // switch widget at constructor. + return getWidgetLayoutResource() != 0; + } + + @Override + public boolean onPreferenceChange(final Preference preference, final Object newValue) { + // Always returns false to prevent default behavior. + // See {@link TwoStatePreference#onClick()}. + if (!isImeEnabler()) { + // Prevent disabling an IME because this preference is for invoking a settings activity. + return false; } - if (mSummaryText != null) { - mSummaryText.setEnabled(checked); + if (isChecked()) { + // Disable this IME. + setChecked(false); + mOnSaveListener.onSaveInputMethodPreference(this); + return false; } - if (mInputMethodPref != null) { - mInputMethodPref.setEnabled(true); - mInputMethodPref.setLongClickable(checked); - final boolean enabled = isEnabled(); - mInputMethodPref.setOnClickListener(enabled ? mPrefOnclickListener : null); - if (!enabled) { - mInputMethodPref.setBackgroundColor(0); - } + if (InputMethodUtils.isSystemIme(mImi)) { + // Enable a system IME. No need to show a security warning dialog. + setChecked(true); + mOnSaveListener.onSaveInputMethodPreference(this); + return false; } - updateSummary(); + // Enable a 3rd party IME. + showSecurityWarnDialog(mImi); + return false; } - public static boolean startFragment( - Fragment fragment, String fragmentClass, int requestCode, Bundle extras) { - if (fragment.getActivity() instanceof PreferenceActivity) { - PreferenceActivity preferenceActivity = (PreferenceActivity)fragment.getActivity(); - preferenceActivity.startPreferencePanel(fragmentClass, extras, 0, null, fragment, - requestCode); + @Override + public boolean onPreferenceClick(final Preference preference) { + // Always returns true to prevent invoking an intent without catching exceptions. + // See {@link Preference#performClick(PreferenceScreen)}/ + if (isImeEnabler()) { + // Prevent invoking a settings activity because this preference is for enabling and + // disabling an input method. return true; - } else { - Log.w(TAG, "Parent isn't PreferenceActivity, thus there's no way to launch the " - + "given Fragment (name: " + fragmentClass + ", requestCode: " + requestCode - + ")"); - return false; } - } - - private String getSummaryString() { - final StringBuilder builder = new StringBuilder(); - final List<InputMethodSubtype> subtypes = mImm.getEnabledInputMethodSubtypeList(mImi, true); - for (InputMethodSubtype subtype : subtypes) { - if (builder.length() > 0) { - builder.append(", "); + final Context context = getContext(); + try { + final Intent intent = getIntent(); + if (intent != null) { + // Invoke a settings activity of an input method. + context.startActivity(intent); } - final CharSequence subtypeLabel = subtype.getDisplayName(mFragment.getActivity(), - mImi.getPackageName(), mImi.getServiceInfo().applicationInfo); - builder.append(subtypeLabel); + } catch (final ActivityNotFoundException e) { + Log.d(TAG, "IME's Settings Activity Not Found", e); + final String message = context.getString( + R.string.failed_to_open_app_settings_toast, + mImi.loadLabel(context.getPackageManager())); + Toast.makeText(context, message, Toast.LENGTH_LONG).show(); } - return builder.toString(); + return true; } - private void updateSummary() { - final String summary = getSummaryString(); - if (TextUtils.isEmpty(summary)) { - return; - } - setSummary(summary); + void updatePreferenceViews() { + final boolean isAlwaysChecked = mInputMethodSettingValues.isAlwaysCheckedIme( + mImi, getContext()); + // Only when this preference has a switch and an input method should be always enabled, + // this preference should be disabled to prevent accidentally disabling an input method. + setEnabled(!((isAlwaysChecked && isImeEnabler()) || (!mIsAllowedByOrganization))); + setChecked(mInputMethodSettingValues.isEnabledImi(mImi)); + setSummary(getSummaryString()); } - /** - * Sets the checkbox state and optionally saves the settings. - * @param checked whether to check the box - * @param save whether to save IME settings - */ - private void setChecked(boolean checked, boolean save) { - final boolean wasChecked = isChecked(); - super.setChecked(checked); - if (save) { - saveImeSettings(); - if (wasChecked != checked && mOnImePreferenceChangeListener != null) { - mOnImePreferenceChangeListener.onPreferenceChange(this, checked); - } - } + private InputMethodManager getInputMethodManager() { + return (InputMethodManager)getContext().getSystemService(Context.INPUT_METHOD_SERVICE); } - public void setOnImePreferenceChangeListener(OnPreferenceChangeListener listener) { - mOnImePreferenceChangeListener = listener; + private String getSummaryString() { + final Context context = getContext(); + if (!mIsAllowedByOrganization) { + return context.getString(R.string.accessibility_feature_or_input_method_not_allowed); + } + final InputMethodManager imm = getInputMethodManager(); + final List<InputMethodSubtype> subtypes = imm.getEnabledInputMethodSubtypeList(mImi, true); + final ArrayList<CharSequence> subtypeLabels = new ArrayList<>(); + for (final InputMethodSubtype subtype : subtypes) { + final CharSequence label = subtype.getDisplayName( + context, mImi.getPackageName(), mImi.getServiceInfo().applicationInfo); + subtypeLabels.add(label); + } + // TODO: A delimiter of subtype labels should be localized. + return TextUtils.join(", ", subtypeLabels); } - private void showSecurityWarnDialog(InputMethodInfo imi, final InputMethodPreference chkPref) { + private void showSecurityWarnDialog(final InputMethodInfo imi) { if (mDialog != null && mDialog.isShowing()) { mDialog.dismiss(); } - mDialog = (new AlertDialog.Builder(mFragment.getActivity())) - .setTitle(android.R.string.dialog_alert_title) - .setIconAttribute(android.R.attr.alertDialogIcon) - .setCancelable(true) - .setPositiveButton(android.R.string.ok, - new DialogInterface.OnClickListener() { - @Override - public void onClick(DialogInterface dialog, int which) { - chkPref.setChecked(true, true); - } - }) - .setNegativeButton(android.R.string.cancel, - new DialogInterface.OnClickListener() { - @Override - public void onClick(DialogInterface dialog, int which) { - } - }) - .create(); - mDialog.setMessage(mFragment.getResources().getString(R.string.ime_security_warning, - imi.getServiceInfo().applicationInfo.loadLabel( - mFragment.getActivity().getPackageManager()))); + final Context context = getContext(); + final AlertDialog.Builder builder = new AlertDialog.Builder(context); + builder.setCancelable(true /* cancelable */); + builder.setTitle(android.R.string.dialog_alert_title); + final CharSequence label = imi.getServiceInfo().applicationInfo.loadLabel( + context.getPackageManager()); + builder.setMessage(context.getString(R.string.ime_security_warning, label)); + builder.setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() { + @Override + public void onClick(final DialogInterface dialog, final int which) { + // The user confirmed to enable a 3rd party IME. + setChecked(true); + mOnSaveListener.onSaveInputMethodPreference(InputMethodPreference.this); + notifyChanged(); + } + }); + builder.setNegativeButton(android.R.string.cancel, new DialogInterface.OnClickListener() { + @Override + public void onClick(final DialogInterface dialog, final int which) { + // The user canceled to enable a 3rd party IME. + setChecked(false); + mOnSaveListener.onSaveInputMethodPreference(InputMethodPreference.this); + notifyChanged(); + } + }); + mDialog = builder.create(); mDialog.show(); } - @Override - public int compareTo(Preference p) { - if (!(p instanceof InputMethodPreference)) { - return super.compareTo(p); + int compareTo(final InputMethodPreference rhs, final Collator collator) { + if (this == rhs) { + return 0; } - final InputMethodPreference imp = (InputMethodPreference) p; - final boolean priority0 = mIsSystemIme && mIsValidSystemNonAuxAsciiCapableIme; - final boolean priority1 = imp.mIsSystemIme && imp.mIsValidSystemNonAuxAsciiCapableIme; - if (priority0 == priority1) { + if (mHasPriorityInSorting == rhs.mHasPriorityInSorting) { final CharSequence t0 = getTitle(); - final CharSequence t1 = imp.getTitle(); + final CharSequence t1 = rhs.getTitle(); if (TextUtils.isEmpty(t0)) { return 1; } if (TextUtils.isEmpty(t1)) { return -1; } - return mCollator.compare(t0.toString(), t1.toString()); + return collator.compare(t0.toString(), t1.toString()); } // Prefer always checked system IMEs - return priority0 ? -1 : 1; - } - - private void saveImeSettings() { - InputMethodAndSubtypeUtil.saveInputMethodSubtypeList( - mFragment, mFragment.getActivity().getContentResolver(), mImm.getInputMethodList(), - mFragment.getResources().getConfiguration().keyboard - == Configuration.KEYBOARD_QWERTY); + return mHasPriorityInSorting ? -1 : 1; } } |