summaryrefslogtreecommitdiffstats
path: root/src/com/android/settings/inputmethod/InputMethodPreference.java
diff options
context:
space:
mode:
Diffstat (limited to 'src/com/android/settings/inputmethod/InputMethodPreference.java')
-rwxr-xr-x[-rw-r--r--]src/com/android/settings/inputmethod/InputMethodPreference.java422
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;
}
}