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