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