• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 com.android.internal.inputmethod.InputMethodUtils;
20 import com.android.settings.R;
21 import com.android.settings.SettingsPreferenceFragment;
22 import com.android.settings.Utils;
23 
24 import android.app.AlertDialog;
25 import android.app.Fragment;
26 import android.content.ActivityNotFoundException;
27 import android.content.Context;
28 import android.content.DialogInterface;
29 import android.content.Intent;
30 import android.content.res.Configuration;
31 import android.os.Bundle;
32 import android.preference.CheckBoxPreference;
33 import android.preference.Preference;
34 import android.preference.PreferenceActivity;
35 import android.provider.Settings;
36 import android.text.TextUtils;
37 import android.util.Log;
38 import android.view.View;
39 import android.view.View.OnClickListener;
40 import android.view.View.OnLongClickListener;
41 import android.view.inputmethod.InputMethodInfo;
42 import android.view.inputmethod.InputMethodManager;
43 import android.view.inputmethod.InputMethodSubtype;
44 import android.widget.ImageView;
45 import android.widget.TextView;
46 import android.widget.Toast;
47 
48 import java.text.Collator;
49 import java.util.List;
50 
51 public class InputMethodPreference extends CheckBoxPreference {
52     private static final String TAG = InputMethodPreference.class.getSimpleName();
53     private final SettingsPreferenceFragment mFragment;
54     private final InputMethodInfo mImi;
55     private final InputMethodManager mImm;
56     private final boolean mIsValidSystemNonAuxAsciiCapableIme;
57     private final Intent mSettingsIntent;
58     private final boolean mIsSystemIme;
59     private final Collator mCollator;
60 
61     private AlertDialog mDialog = null;
62     private ImageView mInputMethodSettingsButton;
63     private TextView mTitleText;
64     private TextView mSummaryText;
65     private View mInputMethodPref;
66     private OnPreferenceChangeListener mOnImePreferenceChangeListener;
67 
68     private final OnClickListener mPrefOnclickListener = new OnClickListener() {
69         @Override
70         public void onClick(View arg0) {
71             if (!isEnabled()) {
72                 return;
73             }
74             if (isChecked()) {
75                 setChecked(false, true /* save */);
76             } else {
77                 if (mIsSystemIme) {
78                     setChecked(true, true /* save */);
79                 } else {
80                     showSecurityWarnDialog(mImi, InputMethodPreference.this);
81                 }
82             }
83         }
84     };
85 
InputMethodPreference(SettingsPreferenceFragment fragment, Intent settingsIntent, InputMethodManager imm, InputMethodInfo imi)86     public InputMethodPreference(SettingsPreferenceFragment fragment, Intent settingsIntent,
87             InputMethodManager imm, InputMethodInfo imi) {
88         super(fragment.getActivity(), null, R.style.InputMethodPreferenceStyle);
89         setLayoutResource(R.layout.preference_inputmethod);
90         setWidgetLayoutResource(R.layout.preference_inputmethod_widget);
91         mFragment = fragment;
92         mSettingsIntent = settingsIntent;
93         mImm = imm;
94         mImi = imi;
95         mIsSystemIme = InputMethodUtils.isSystemIme(imi);
96         mCollator = Collator.getInstance(fragment.getResources().getConfiguration().locale);
97         final Context context = fragment.getActivity();
98         mIsValidSystemNonAuxAsciiCapableIme = InputMethodSettingValuesWrapper
99                 .getInstance(context).isValidSystemNonAuxAsciiCapableIme(imi, context);
100         updatePreferenceViews();
101     }
102 
103     @Override
onBindView(View view)104     protected void onBindView(View view) {
105         super.onBindView(view);
106         mInputMethodPref = view.findViewById(R.id.inputmethod_pref);
107         mInputMethodPref.setOnClickListener(mPrefOnclickListener);
108         mInputMethodSettingsButton = (ImageView)view.findViewById(R.id.inputmethod_settings);
109         mTitleText = (TextView)view.findViewById(android.R.id.title);
110         mSummaryText = (TextView)view.findViewById(android.R.id.summary);
111         final boolean hasSubtypes = mImi.getSubtypeCount() > 1;
112         final String imiId = mImi.getId();
113         if (hasSubtypes) {
114             mInputMethodPref.setOnLongClickListener(new OnLongClickListener() {
115                 @Override
116                 public boolean onLongClick(View arg0) {
117                     final Bundle bundle = new Bundle();
118                     bundle.putString(Settings.EXTRA_INPUT_METHOD_ID, imiId);
119                     startFragment(mFragment, InputMethodAndSubtypeEnabler.class.getName(),
120                             0, bundle);
121                     return true;
122                 }
123             });
124         }
125 
126         if (mSettingsIntent != null) {
127             mInputMethodSettingsButton.setOnClickListener(
128                     new OnClickListener() {
129                         @Override
130                         public void onClick(View arg0) {
131                             try {
132                                 mFragment.startActivity(mSettingsIntent);
133                             } catch (ActivityNotFoundException e) {
134                                 Log.d(TAG, "IME's Settings Activity Not Found: " + e);
135                                 final String msg = mFragment.getString(
136                                         R.string.failed_to_open_app_settings_toast,
137                                         mImi.loadLabel(
138                                                 mFragment.getActivity().getPackageManager()));
139                                 Toast.makeText(
140                                         mFragment.getActivity(), msg, Toast.LENGTH_LONG).show();
141                             }
142                         }
143                     });
144         }
145         if (hasSubtypes) {
146             final OnLongClickListener listener = new OnLongClickListener() {
147                 @Override
148                 public boolean onLongClick(View arg0) {
149                     final Bundle bundle = new Bundle();
150                     bundle.putString(Settings.EXTRA_INPUT_METHOD_ID, imiId);
151                     startFragment(mFragment, InputMethodAndSubtypeEnabler.class.getName(),
152                             0, bundle);
153                     return true;
154                 }
155             };
156             mInputMethodSettingsButton.setOnLongClickListener(listener);
157         }
158         if (mSettingsIntent == null) {
159             mInputMethodSettingsButton.setVisibility(View.GONE);
160         }
161         updatePreferenceViews();
162     }
163 
164     @Override
setEnabled(boolean enabled)165     public void setEnabled(boolean enabled) {
166         super.setEnabled(enabled);
167         updatePreferenceViews();
168     }
169 
updatePreferenceViews()170     public void updatePreferenceViews() {
171         final boolean isAlwaysChecked =
172                 InputMethodSettingValuesWrapper.getInstance(getContext()).isAlwaysCheckedIme(
173                         mImi, getContext());
174         if (isAlwaysChecked) {
175             super.setChecked(true);
176             super.setEnabled(false);
177         } else {
178             super.setEnabled(true);
179         }
180         final boolean checked = isChecked();
181         if (mInputMethodSettingsButton != null) {
182             mInputMethodSettingsButton.setEnabled(checked);
183             mInputMethodSettingsButton.setClickable(checked);
184             mInputMethodSettingsButton.setFocusable(checked);
185             if (!checked) {
186                 mInputMethodSettingsButton.setAlpha(Utils.DISABLED_ALPHA);
187             }
188         }
189         if (mTitleText != null) {
190             mTitleText.setEnabled(true);
191         }
192         if (mSummaryText != null) {
193             mSummaryText.setEnabled(checked);
194         }
195         if (mInputMethodPref != null) {
196             mInputMethodPref.setEnabled(true);
197             mInputMethodPref.setLongClickable(checked);
198             final boolean enabled = isEnabled();
199             mInputMethodPref.setOnClickListener(enabled ? mPrefOnclickListener : null);
200             if (!enabled) {
201                 mInputMethodPref.setBackgroundColor(0);
202             }
203         }
204         updateSummary();
205     }
206 
startFragment( Fragment fragment, String fragmentClass, int requestCode, Bundle extras)207     public static boolean startFragment(
208             Fragment fragment, String fragmentClass, int requestCode, Bundle extras) {
209         if (fragment.getActivity() instanceof PreferenceActivity) {
210             PreferenceActivity preferenceActivity = (PreferenceActivity)fragment.getActivity();
211             preferenceActivity.startPreferencePanel(fragmentClass, extras, 0, null, fragment,
212                     requestCode);
213             return true;
214         } else {
215             Log.w(TAG, "Parent isn't PreferenceActivity, thus there's no way to launch the "
216                     + "given Fragment (name: " + fragmentClass + ", requestCode: " + requestCode
217                     + ")");
218             return false;
219         }
220     }
221 
getSummaryString()222     private String getSummaryString() {
223         final StringBuilder builder = new StringBuilder();
224         final List<InputMethodSubtype> subtypes = mImm.getEnabledInputMethodSubtypeList(mImi, true);
225         for (InputMethodSubtype subtype : subtypes) {
226             if (builder.length() > 0) {
227                 builder.append(", ");
228             }
229             final CharSequence subtypeLabel = subtype.getDisplayName(mFragment.getActivity(),
230                     mImi.getPackageName(), mImi.getServiceInfo().applicationInfo);
231             builder.append(subtypeLabel);
232         }
233         return builder.toString();
234     }
235 
updateSummary()236     private void updateSummary() {
237         final String summary = getSummaryString();
238         if (TextUtils.isEmpty(summary)) {
239             return;
240         }
241         setSummary(summary);
242     }
243 
244     /**
245      * Sets the checkbox state and optionally saves the settings.
246      * @param checked whether to check the box
247      * @param save whether to save IME settings
248      */
setChecked(boolean checked, boolean save)249     private void setChecked(boolean checked, boolean save) {
250         final boolean wasChecked = isChecked();
251         super.setChecked(checked);
252         if (save) {
253             saveImeSettings();
254             if (wasChecked != checked && mOnImePreferenceChangeListener != null) {
255                 mOnImePreferenceChangeListener.onPreferenceChange(this, checked);
256             }
257         }
258     }
259 
setOnImePreferenceChangeListener(OnPreferenceChangeListener listener)260     public void setOnImePreferenceChangeListener(OnPreferenceChangeListener listener) {
261         mOnImePreferenceChangeListener = listener;
262     }
263 
showSecurityWarnDialog(InputMethodInfo imi, final InputMethodPreference chkPref)264     private void showSecurityWarnDialog(InputMethodInfo imi, final InputMethodPreference chkPref) {
265         if (mDialog != null && mDialog.isShowing()) {
266             mDialog.dismiss();
267         }
268         mDialog = (new AlertDialog.Builder(mFragment.getActivity()))
269                 .setTitle(android.R.string.dialog_alert_title)
270                 .setIconAttribute(android.R.attr.alertDialogIcon)
271                 .setCancelable(true)
272                 .setPositiveButton(android.R.string.ok,
273                         new DialogInterface.OnClickListener() {
274                     @Override
275                     public void onClick(DialogInterface dialog, int which) {
276                         chkPref.setChecked(true, true);
277                     }
278                 })
279                 .setNegativeButton(android.R.string.cancel,
280                         new DialogInterface.OnClickListener() {
281                     @Override
282                     public void onClick(DialogInterface dialog, int which) {
283                     }
284                 })
285                 .create();
286         mDialog.setMessage(mFragment.getResources().getString(R.string.ime_security_warning,
287                 imi.getServiceInfo().applicationInfo.loadLabel(
288                         mFragment.getActivity().getPackageManager())));
289         mDialog.show();
290     }
291 
292     @Override
compareTo(Preference p)293     public int compareTo(Preference p) {
294         if (!(p instanceof InputMethodPreference)) {
295             return super.compareTo(p);
296         }
297         final InputMethodPreference imp = (InputMethodPreference) p;
298         final boolean priority0 = mIsSystemIme && mIsValidSystemNonAuxAsciiCapableIme;
299         final boolean priority1 = imp.mIsSystemIme && imp.mIsValidSystemNonAuxAsciiCapableIme;
300         if (priority0 == priority1) {
301             final CharSequence t0 = getTitle();
302             final CharSequence t1 = imp.getTitle();
303             if (TextUtils.isEmpty(t0)) {
304                 return 1;
305             }
306             if (TextUtils.isEmpty(t1)) {
307                 return -1;
308             }
309             return mCollator.compare(t0.toString(), t1.toString());
310         }
311         // Prefer always checked system IMEs
312         return priority0 ? -1 : 1;
313     }
314 
saveImeSettings()315     private void saveImeSettings() {
316         InputMethodAndSubtypeUtil.saveInputMethodSubtypeList(
317                 mFragment, mFragment.getActivity().getContentResolver(), mImm.getInputMethodList(),
318                 mFragment.getResources().getConfiguration().keyboard
319                         == Configuration.KEYBOARD_QWERTY);
320     }
321 }
322