SubtypeSwitcher.java revision 6a7019ff5db19b1e3f8d7afbba71af813cab9a37
1/* 2 * Copyright (C) 2010 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.inputmethod.latin; 18 19import static com.android.inputmethod.latin.Constants.Subtype.ExtraValue.REQ_NETWORK_CONNECTIVITY; 20 21import android.content.Context; 22import android.content.Intent; 23import android.content.res.Configuration; 24import android.content.res.Resources; 25import android.net.ConnectivityManager; 26import android.net.NetworkInfo; 27import android.os.AsyncTask; 28import android.os.IBinder; 29import android.util.Log; 30import android.view.inputmethod.InputMethodInfo; 31import android.view.inputmethod.InputMethodManager; 32import android.view.inputmethod.InputMethodSubtype; 33 34import com.android.inputmethod.keyboard.KeyboardSwitcher; 35 36import java.util.List; 37import java.util.Locale; 38import java.util.Map; 39 40public class SubtypeSwitcher { 41 private static boolean DBG = LatinImeLogger.sDBG; 42 private static final String TAG = SubtypeSwitcher.class.getSimpleName(); 43 44 private static final SubtypeSwitcher sInstance = new SubtypeSwitcher(); 45 private /* final */ LatinIME mService; 46 private /* final */ InputMethodManager mImm; 47 private /* final */ Resources mResources; 48 private /* final */ ConnectivityManager mConnectivityManager; 49 50 /*-----------------------------------------------------------*/ 51 // Variants which should be changed only by reload functions. 52 private NeedsToDisplayLanguage mNeedsToDisplayLanguage = new NeedsToDisplayLanguage(); 53 private InputMethodInfo mShortcutInputMethodInfo; 54 private InputMethodSubtype mShortcutSubtype; 55 private InputMethodSubtype mNoLanguageSubtype; 56 // Note: This variable is always non-null after {@link #initialize(LatinIME)}. 57 private InputMethodSubtype mCurrentSubtype; 58 private Locale mCurrentSystemLocale; 59 /*-----------------------------------------------------------*/ 60 61 private boolean mIsNetworkConnected; 62 63 static class NeedsToDisplayLanguage { 64 private int mEnabledSubtypeCount; 65 private boolean mIsSystemLanguageSameAsInputLanguage; 66 67 public boolean getValue() { 68 return mEnabledSubtypeCount >= 2 || !mIsSystemLanguageSameAsInputLanguage; 69 } 70 71 public void updateEnabledSubtypeCount(int count) { 72 mEnabledSubtypeCount = count; 73 } 74 75 public void updateIsSystemLanguageSameAsInputLanguage(boolean isSame) { 76 mIsSystemLanguageSameAsInputLanguage = isSame; 77 } 78 } 79 80 public static SubtypeSwitcher getInstance() { 81 return sInstance; 82 } 83 84 public static void init(LatinIME service) { 85 SubtypeLocale.init(service); 86 sInstance.initialize(service); 87 sInstance.updateAllParameters(); 88 } 89 90 private SubtypeSwitcher() { 91 // Intentional empty constructor for singleton. 92 } 93 94 private void initialize(LatinIME service) { 95 mService = service; 96 mResources = service.getResources(); 97 mImm = ImfUtils.getInputMethodManager(service); 98 mConnectivityManager = (ConnectivityManager) service.getSystemService( 99 Context.CONNECTIVITY_SERVICE); 100 mCurrentSystemLocale = mResources.getConfiguration().locale; 101 mCurrentSubtype = mImm.getCurrentInputMethodSubtype(); 102 mNoLanguageSubtype = ImfUtils.findSubtypeByLocaleAndKeyboardLayoutSet( 103 service, SubtypeLocale.NO_LANGUAGE, AdditionalSubtype.QWERTY); 104 105 final NetworkInfo info = mConnectivityManager.getActiveNetworkInfo(); 106 mIsNetworkConnected = (info != null && info.isConnected()); 107 } 108 109 // Update all parameters stored in SubtypeSwitcher. 110 // Only configuration changed event is allowed to call this because this is heavy. 111 private void updateAllParameters() { 112 mCurrentSystemLocale = mResources.getConfiguration().locale; 113 updateSubtype(mImm.getCurrentInputMethodSubtype()); 114 updateParametersOnStartInputView(); 115 } 116 117 // Update parameters which are changed outside LatinIME. This parameters affect UI so they 118 // should be updated every time onStartInputview. 119 public void updateParametersOnStartInputView() { 120 updateEnabledSubtypes(); 121 updateShortcutIME(); 122 } 123 124 // Reload enabledSubtypes from the framework. 125 private void updateEnabledSubtypes() { 126 final InputMethodSubtype currentSubtype = mCurrentSubtype; 127 boolean foundCurrentSubtypeBecameDisabled = true; 128 final List<InputMethodSubtype> enabledSubtypesOfThisIme = 129 mImm.getEnabledInputMethodSubtypeList(null, true); 130 for (InputMethodSubtype ims : enabledSubtypesOfThisIme) { 131 if (ims.equals(currentSubtype)) { 132 foundCurrentSubtypeBecameDisabled = false; 133 } 134 } 135 mNeedsToDisplayLanguage.updateEnabledSubtypeCount(enabledSubtypesOfThisIme.size()); 136 if (foundCurrentSubtypeBecameDisabled) { 137 if (DBG) { 138 Log.w(TAG, "Last subtype: " 139 + currentSubtype.getLocale() + "/" + currentSubtype.getExtraValue()); 140 Log.w(TAG, "Last subtype was disabled. Update to the current one."); 141 } 142 updateSubtype(mImm.getCurrentInputMethodSubtype()); 143 } 144 } 145 146 private void updateShortcutIME() { 147 if (DBG) { 148 Log.d(TAG, "Update shortcut IME from : " 149 + (mShortcutInputMethodInfo == null 150 ? "<null>" : mShortcutInputMethodInfo.getId()) + ", " 151 + (mShortcutSubtype == null ? "<null>" : ( 152 mShortcutSubtype.getLocale() + ", " + mShortcutSubtype.getMode()))); 153 } 154 // TODO: Update an icon for shortcut IME 155 final Map<InputMethodInfo, List<InputMethodSubtype>> shortcuts = 156 mImm.getShortcutInputMethodsAndSubtypes(); 157 mShortcutInputMethodInfo = null; 158 mShortcutSubtype = null; 159 for (InputMethodInfo imi : shortcuts.keySet()) { 160 List<InputMethodSubtype> subtypes = shortcuts.get(imi); 161 // TODO: Returns the first found IMI for now. Should handle all shortcuts as 162 // appropriate. 163 mShortcutInputMethodInfo = imi; 164 // TODO: Pick up the first found subtype for now. Should handle all subtypes 165 // as appropriate. 166 mShortcutSubtype = subtypes.size() > 0 ? subtypes.get(0) : null; 167 break; 168 } 169 if (DBG) { 170 Log.d(TAG, "Update shortcut IME to : " 171 + (mShortcutInputMethodInfo == null 172 ? "<null>" : mShortcutInputMethodInfo.getId()) + ", " 173 + (mShortcutSubtype == null ? "<null>" : ( 174 mShortcutSubtype.getLocale() + ", " + mShortcutSubtype.getMode()))); 175 } 176 } 177 178 // Update the current subtype. LatinIME.onCurrentInputMethodSubtypeChanged calls this function. 179 public void updateSubtype(InputMethodSubtype newSubtype) { 180 if (DBG) { 181 Log.w(TAG, "onCurrentInputMethodSubtypeChanged: to: " 182 + newSubtype.getLocale() + "/" + newSubtype.getExtraValue() + ", from: " 183 + mCurrentSubtype.getLocale() + "/" + mCurrentSubtype.getExtraValue()); 184 } 185 if (newSubtype.equals(mCurrentSubtype)) return; 186 187 final Locale newLocale = SubtypeLocale.getSubtypeLocale(newSubtype); 188 mNeedsToDisplayLanguage.updateIsSystemLanguageSameAsInputLanguage( 189 mCurrentSystemLocale.equals(newLocale)); 190 191 mCurrentSubtype = newSubtype; 192 updateShortcutIME(); 193 mService.onRefreshKeyboard(); 194 } 195 196 //////////////////////////// 197 // Shortcut IME functions // 198 //////////////////////////// 199 200 public void switchToShortcutIME() { 201 if (mShortcutInputMethodInfo == null) { 202 return; 203 } 204 205 final String imiId = mShortcutInputMethodInfo.getId(); 206 switchToTargetIME(imiId, mShortcutSubtype); 207 } 208 209 private void switchToTargetIME(final String imiId, final InputMethodSubtype subtype) { 210 final IBinder token = mService.getWindow().getWindow().getAttributes().token; 211 if (token == null) { 212 return; 213 } 214 final InputMethodManager imm = mImm; 215 new AsyncTask<Void, Void, Void>() { 216 @Override 217 protected Void doInBackground(Void... params) { 218 imm.setInputMethodAndSubtype(token, imiId, subtype); 219 return null; 220 } 221 }.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR); 222 } 223 224 public boolean isShortcutImeEnabled() { 225 if (mShortcutInputMethodInfo == null) { 226 return false; 227 } 228 if (mShortcutSubtype == null) { 229 return true; 230 } 231 final boolean allowsImplicitlySelectedSubtypes = true; 232 for (final InputMethodSubtype enabledSubtype : mImm.getEnabledInputMethodSubtypeList( 233 mShortcutInputMethodInfo, allowsImplicitlySelectedSubtypes)) { 234 if (enabledSubtype.equals(mShortcutSubtype)) { 235 return true; 236 } 237 } 238 return false; 239 } 240 241 public boolean isShortcutImeReady() { 242 if (mShortcutInputMethodInfo == null) 243 return false; 244 if (mShortcutSubtype == null) 245 return true; 246 if (mShortcutSubtype.containsExtraValueKey(REQ_NETWORK_CONNECTIVITY)) { 247 return mIsNetworkConnected; 248 } 249 return true; 250 } 251 252 public void onNetworkStateChanged(Intent intent) { 253 final boolean noConnection = intent.getBooleanExtra( 254 ConnectivityManager.EXTRA_NO_CONNECTIVITY, false); 255 mIsNetworkConnected = !noConnection; 256 257 KeyboardSwitcher.getInstance().onNetworkStateChanged(); 258 } 259 260 ////////////////////////////////// 261 // Subtype Switching functions // 262 ////////////////////////////////// 263 264 public boolean needsToDisplayLanguage(Locale keyboardLocale) { 265 if (keyboardLocale.toString().equals(SubtypeLocale.NO_LANGUAGE)) { 266 return true; 267 } 268 if (!keyboardLocale.equals(getCurrentSubtypeLocale())) { 269 return false; 270 } 271 return mNeedsToDisplayLanguage.getValue(); 272 } 273 274 public Locale getCurrentSubtypeLocale() { 275 return SubtypeLocale.getSubtypeLocale(mCurrentSubtype); 276 } 277 278 public void onConfigurationChanged(Configuration conf) { 279 final Locale systemLocale = conf.locale; 280 // If system configuration was changed, update all parameters. 281 if (!systemLocale.equals(mCurrentSystemLocale)) { 282 updateAllParameters(); 283 } 284 } 285 286 public InputMethodSubtype getCurrentSubtype() { 287 return mCurrentSubtype; 288 } 289 290 public InputMethodSubtype getNoLanguageSubtype() { 291 return mNoLanguageSubtype; 292 } 293} 294