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