KeyboardSwitcher.java revision 59c3ef1ff8df23e3c3e3f549c0289c479553c666
1/* 2 * Copyright (C) 2008 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.keyboard; 18 19import android.content.Context; 20import android.content.SharedPreferences; 21import android.content.res.Resources; 22import android.preference.PreferenceManager; 23import android.util.Log; 24import android.view.ContextThemeWrapper; 25import android.view.LayoutInflater; 26import android.view.View; 27import android.view.inputmethod.EditorInfo; 28 29import com.android.inputmethod.compat.InputMethodServiceCompatUtils; 30import com.android.inputmethod.keyboard.KeyboardLayoutSet.KeyboardLayoutSetException; 31import com.android.inputmethod.keyboard.internal.KeyboardState; 32import com.android.inputmethod.keyboard.internal.KeyboardTextsSet; 33import com.android.inputmethod.latin.InputView; 34import com.android.inputmethod.latin.LatinIME; 35import com.android.inputmethod.latin.LatinImeLogger; 36import com.android.inputmethod.latin.R; 37import com.android.inputmethod.latin.RichInputMethodManager; 38import com.android.inputmethod.latin.SubtypeSwitcher; 39import com.android.inputmethod.latin.WordComposer; 40import com.android.inputmethod.latin.settings.SettingsValues; 41import com.android.inputmethod.latin.utils.ResourceUtils; 42 43public final class KeyboardSwitcher implements KeyboardState.SwitchActions { 44 private static final String TAG = KeyboardSwitcher.class.getSimpleName(); 45 46 private SubtypeSwitcher mSubtypeSwitcher; 47 private SharedPreferences mPrefs; 48 49 private InputView mCurrentInputView; 50 private View mMainKeyboardFrame; 51 private MainKeyboardView mKeyboardView; 52 private EmojiPalettesView mEmojiPalettesView; 53 private LatinIME mLatinIME; 54 private boolean mIsHardwareAcceleratedDrawingEnabled; 55 56 private KeyboardState mState; 57 58 private KeyboardLayoutSet mKeyboardLayoutSet; 59 // TODO: The following {@link KeyboardTextsSet} should be in {@link KeyboardLayoutSet}. 60 private final KeyboardTextsSet mKeyboardTextsSet = new KeyboardTextsSet(); 61 private SettingsValues mCurrentSettingsValues; 62 63 /** mIsAutoCorrectionActive indicates that auto corrected word will be input instead of 64 * what user actually typed. */ 65 private boolean mIsAutoCorrectionActive; 66 67 private KeyboardTheme mKeyboardTheme; 68 private Context mThemeContext; 69 70 private static final KeyboardSwitcher sInstance = new KeyboardSwitcher(); 71 72 public static KeyboardSwitcher getInstance() { 73 return sInstance; 74 } 75 76 private KeyboardSwitcher() { 77 // Intentional empty constructor for singleton. 78 } 79 80 public static void init(final LatinIME latinIme) { 81 final SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(latinIme); 82 sInstance.initInternal(latinIme, prefs); 83 } 84 85 private void initInternal(final LatinIME latinIme, final SharedPreferences prefs) { 86 mLatinIME = latinIme; 87 mPrefs = prefs; 88 mSubtypeSwitcher = SubtypeSwitcher.getInstance(); 89 mState = new KeyboardState(this); 90 mIsHardwareAcceleratedDrawingEnabled = 91 InputMethodServiceCompatUtils.enableHardwareAcceleration(mLatinIME); 92 } 93 94 public void updateKeyboardTheme() { 95 final boolean themeUpdated = updateKeyboardThemeAndContextThemeWrapper( 96 mLatinIME, KeyboardTheme.getKeyboardTheme(mPrefs)); 97 if (themeUpdated && mKeyboardView != null) { 98 mLatinIME.setInputView(onCreateInputView(mIsHardwareAcceleratedDrawingEnabled)); 99 } 100 } 101 102 private boolean updateKeyboardThemeAndContextThemeWrapper(final Context context, 103 final KeyboardTheme keyboardTheme) { 104 if (mThemeContext == null || !keyboardTheme.equals(mKeyboardTheme)) { 105 mKeyboardTheme = keyboardTheme; 106 mThemeContext = new ContextThemeWrapper(context, keyboardTheme.mStyleId); 107 KeyboardLayoutSet.clearKeyboardCache(); 108 return true; 109 } 110 return false; 111 } 112 113 public void loadKeyboard(final EditorInfo editorInfo, final SettingsValues settingsValues, 114 final int currentAutoCapsState, final int currentRecapitalizeState) { 115 final KeyboardLayoutSet.Builder builder = new KeyboardLayoutSet.Builder( 116 mThemeContext, editorInfo); 117 final Resources res = mThemeContext.getResources(); 118 final int keyboardWidth = ResourceUtils.getDefaultKeyboardWidth(res); 119 final int keyboardHeight = ResourceUtils.getDefaultKeyboardHeight(res); 120 builder.setKeyboardGeometry(keyboardWidth, keyboardHeight); 121 builder.setSubtype(mSubtypeSwitcher.getCurrentSubtype()); 122 builder.setOptions( 123 mSubtypeSwitcher.isShortcutImeEnabled(), 124 settingsValues.mShowsVoiceInputKey, 125 mLatinIME.shouldShowLanguageSwitchKey()); 126 mKeyboardLayoutSet = builder.build(); 127 mCurrentSettingsValues = settingsValues; 128 try { 129 mState.onLoadKeyboard(currentAutoCapsState, currentRecapitalizeState); 130 mKeyboardTextsSet.setLocale(mSubtypeSwitcher.getCurrentSubtypeLocale(), mThemeContext); 131 } catch (KeyboardLayoutSetException e) { 132 Log.w(TAG, "loading keyboard failed: " + e.mKeyboardId, e.getCause()); 133 LatinImeLogger.logOnException(e.mKeyboardId.toString(), e.getCause()); 134 return; 135 } 136 } 137 138 public void saveKeyboardState() { 139 if (getKeyboard() != null || isShowingEmojiPalettes()) { 140 mState.onSaveKeyboardState(); 141 } 142 } 143 144 public void onFinishInputView() { 145 mIsAutoCorrectionActive = false; 146 } 147 148 public void onHideWindow() { 149 mIsAutoCorrectionActive = false; 150 if (mKeyboardView != null) { 151 mKeyboardView.onHideWindow(); 152 } 153 } 154 155 private void setKeyboard(final Keyboard keyboard) { 156 // Make {@link MainKeyboardView} visible and hide {@link EmojiPalettesView}. 157 setMainKeyboardFrame(); 158 final MainKeyboardView keyboardView = mKeyboardView; 159 final Keyboard oldKeyboard = keyboardView.getKeyboard(); 160 keyboardView.setKeyboard(keyboard); 161 mCurrentInputView.setKeyboardTopPadding(keyboard.mTopPadding); 162 keyboardView.setKeyPreviewPopupEnabled( 163 mCurrentSettingsValues.mKeyPreviewPopupOn, 164 mCurrentSettingsValues.mKeyPreviewPopupDismissDelay); 165 keyboardView.setKeyPreviewAnimationParams( 166 mCurrentSettingsValues.mKeyPreviewShowUpStartScale, 167 mCurrentSettingsValues.mKeyPreviewShowUpDuration, 168 mCurrentSettingsValues.mKeyPreviewDismissEndScale, 169 mCurrentSettingsValues.mKeyPreviewDismissDuration); 170 keyboardView.updateAutoCorrectionState(mIsAutoCorrectionActive); 171 keyboardView.updateShortcutKey(mSubtypeSwitcher.isShortcutImeReady()); 172 final boolean subtypeChanged = (oldKeyboard == null) 173 || !keyboard.mId.mLocale.equals(oldKeyboard.mId.mLocale); 174 final int languageOnSpacebarFormatType = mSubtypeSwitcher.getLanguageOnSpacebarFormatType( 175 keyboard.mId.mSubtype); 176 final boolean hasMultipleEnabledIMEsOrSubtypes = RichInputMethodManager.getInstance() 177 .hasMultipleEnabledIMEsOrSubtypes(true /* shouldIncludeAuxiliarySubtypes */); 178 keyboardView.startDisplayLanguageOnSpacebar(subtypeChanged, languageOnSpacebarFormatType, 179 hasMultipleEnabledIMEsOrSubtypes); 180 } 181 182 public Keyboard getKeyboard() { 183 if (mKeyboardView != null) { 184 return mKeyboardView.getKeyboard(); 185 } 186 return null; 187 } 188 189 // TODO: Remove this method. Come up with a more comprehensive way to reset the keyboard layout 190 // when a keyboard layout set doesn't get reloaded in LatinIME.onStartInputViewInternal(). 191 public void resetKeyboardStateToAlphabet(final int currentAutoCapsState, 192 final int currentRecapitalizeState) { 193 mState.onResetKeyboardStateToAlphabet(currentAutoCapsState, currentRecapitalizeState); 194 } 195 196 public void onPressKey(final int code, final boolean isSinglePointer, 197 final int currentAutoCapsState, final int currentRecapitalizeState) { 198 mState.onPressKey(code, isSinglePointer, currentAutoCapsState, currentRecapitalizeState); 199 } 200 201 public void onReleaseKey(final int code, final boolean withSliding, 202 final int currentAutoCapsState, final int currentRecapitalizeState) { 203 mState.onReleaseKey(code, withSliding, currentAutoCapsState, currentRecapitalizeState); 204 } 205 206 public void onFinishSlidingInput(final int currentAutoCapsState, 207 final int currentRecapitalizeState) { 208 mState.onFinishSlidingInput(currentAutoCapsState, currentRecapitalizeState); 209 } 210 211 // Implements {@link KeyboardState.SwitchActions}. 212 @Override 213 public void setAlphabetKeyboard() { 214 setKeyboard(mKeyboardLayoutSet.getKeyboard(KeyboardId.ELEMENT_ALPHABET)); 215 } 216 217 // Implements {@link KeyboardState.SwitchActions}. 218 @Override 219 public void setAlphabetManualShiftedKeyboard() { 220 setKeyboard(mKeyboardLayoutSet.getKeyboard(KeyboardId.ELEMENT_ALPHABET_MANUAL_SHIFTED)); 221 } 222 223 // Implements {@link KeyboardState.SwitchActions}. 224 @Override 225 public void setAlphabetAutomaticShiftedKeyboard() { 226 setKeyboard(mKeyboardLayoutSet.getKeyboard(KeyboardId.ELEMENT_ALPHABET_AUTOMATIC_SHIFTED)); 227 } 228 229 // Implements {@link KeyboardState.SwitchActions}. 230 @Override 231 public void setAlphabetShiftLockedKeyboard() { 232 setKeyboard(mKeyboardLayoutSet.getKeyboard(KeyboardId.ELEMENT_ALPHABET_SHIFT_LOCKED)); 233 } 234 235 // Implements {@link KeyboardState.SwitchActions}. 236 @Override 237 public void setAlphabetShiftLockShiftedKeyboard() { 238 setKeyboard(mKeyboardLayoutSet.getKeyboard(KeyboardId.ELEMENT_ALPHABET_SHIFT_LOCK_SHIFTED)); 239 } 240 241 // Implements {@link KeyboardState.SwitchActions}. 242 @Override 243 public void setSymbolsKeyboard() { 244 setKeyboard(mKeyboardLayoutSet.getKeyboard(KeyboardId.ELEMENT_SYMBOLS)); 245 } 246 247 private void setMainKeyboardFrame() { 248 mMainKeyboardFrame.setVisibility(View.VISIBLE); 249 mEmojiPalettesView.setVisibility(View.GONE); 250 mEmojiPalettesView.stopEmojiPalettes(); 251 } 252 253 // Implements {@link KeyboardState.SwitchActions}. 254 @Override 255 public void setEmojiKeyboard() { 256 mMainKeyboardFrame.setVisibility(View.GONE); 257 mEmojiPalettesView.startEmojiPalettes( 258 mKeyboardTextsSet.getText(KeyboardTextsSet.SWITCH_TO_ALPHA_KEY_LABEL), 259 mKeyboardView.getKeyVisualAttribute()); 260 mEmojiPalettesView.setVisibility(View.VISIBLE); 261 } 262 263 // Implements {@link KeyboardState.SwitchActions}. 264 @Override 265 public void setSymbolsShiftedKeyboard() { 266 setKeyboard(mKeyboardLayoutSet.getKeyboard(KeyboardId.ELEMENT_SYMBOLS_SHIFTED)); 267 } 268 269 // Future method for requesting an updating to the shift state. 270 public void requestUpdatingShiftState(final int currentAutoCapsState, 271 final int currentRecapitalizeState) { 272 mState.onUpdateShiftState(currentAutoCapsState, currentRecapitalizeState); 273 } 274 275 // Implements {@link KeyboardState.SwitchActions}. 276 @Override 277 public void startDoubleTapShiftKeyTimer() { 278 final MainKeyboardView keyboardView = getMainKeyboardView(); 279 if (keyboardView != null) { 280 keyboardView.startDoubleTapShiftKeyTimer(); 281 } 282 } 283 284 // Implements {@link KeyboardState.SwitchActions}. 285 @Override 286 public void cancelDoubleTapShiftKeyTimer() { 287 final MainKeyboardView keyboardView = getMainKeyboardView(); 288 if (keyboardView != null) { 289 keyboardView.cancelDoubleTapShiftKeyTimer(); 290 } 291 } 292 293 // Implements {@link KeyboardState.SwitchActions}. 294 @Override 295 public boolean isInDoubleTapShiftKeyTimeout() { 296 final MainKeyboardView keyboardView = getMainKeyboardView(); 297 return keyboardView != null && keyboardView.isInDoubleTapShiftKeyTimeout(); 298 } 299 300 /** 301 * Updates state machine to figure out when to automatically switch back to the previous mode. 302 */ 303 public void onCodeInput(final int code, final int currentAutoCapsState, 304 final int currentRecapitalizeState) { 305 mState.onCodeInput(code, currentAutoCapsState, currentRecapitalizeState); 306 } 307 308 public boolean isShowingEmojiPalettes() { 309 return mEmojiPalettesView != null && mEmojiPalettesView.isShown(); 310 } 311 312 public boolean isShowingMoreKeysPanel() { 313 if (isShowingEmojiPalettes()) { 314 return false; 315 } 316 return mKeyboardView.isShowingMoreKeysPanel(); 317 } 318 319 public View getVisibleKeyboardView() { 320 if (isShowingEmojiPalettes()) { 321 return mEmojiPalettesView; 322 } 323 return mKeyboardView; 324 } 325 326 public MainKeyboardView getMainKeyboardView() { 327 return mKeyboardView; 328 } 329 330 public void deallocateMemory() { 331 if (mKeyboardView != null) { 332 mKeyboardView.cancelAllOngoingEvents(); 333 mKeyboardView.deallocateMemory(); 334 } 335 if (mEmojiPalettesView != null) { 336 mEmojiPalettesView.stopEmojiPalettes(); 337 } 338 } 339 340 public View onCreateInputView(final boolean isHardwareAcceleratedDrawingEnabled) { 341 if (mKeyboardView != null) { 342 mKeyboardView.closing(); 343 } 344 345 updateKeyboardThemeAndContextThemeWrapper( 346 mLatinIME, KeyboardTheme.getKeyboardTheme(mPrefs)); 347 mCurrentInputView = (InputView)LayoutInflater.from(mThemeContext).inflate( 348 R.layout.input_view, null); 349 mMainKeyboardFrame = mCurrentInputView.findViewById(R.id.main_keyboard_frame); 350 mEmojiPalettesView = (EmojiPalettesView)mCurrentInputView.findViewById( 351 R.id.emoji_keyboard_view); 352 353 mKeyboardView = (MainKeyboardView) mCurrentInputView.findViewById(R.id.keyboard_view); 354 mKeyboardView.setHardwareAcceleratedDrawingEnabled(isHardwareAcceleratedDrawingEnabled); 355 mKeyboardView.setKeyboardActionListener(mLatinIME); 356 mEmojiPalettesView.setHardwareAcceleratedDrawingEnabled( 357 isHardwareAcceleratedDrawingEnabled); 358 mEmojiPalettesView.setKeyboardActionListener(mLatinIME); 359 return mCurrentInputView; 360 } 361 362 public void onNetworkStateChanged() { 363 if (mKeyboardView != null) { 364 mKeyboardView.updateShortcutKey(mSubtypeSwitcher.isShortcutImeReady()); 365 } 366 } 367 368 public void onAutoCorrectionStateChanged(final boolean isAutoCorrection) { 369 if (mIsAutoCorrectionActive != isAutoCorrection) { 370 mIsAutoCorrectionActive = isAutoCorrection; 371 if (mKeyboardView != null) { 372 mKeyboardView.updateAutoCorrectionState(isAutoCorrection); 373 } 374 } 375 } 376 377 public int getKeyboardShiftMode() { 378 final Keyboard keyboard = getKeyboard(); 379 if (keyboard == null) { 380 return WordComposer.CAPS_MODE_OFF; 381 } 382 switch (keyboard.mId.mElementId) { 383 case KeyboardId.ELEMENT_ALPHABET_SHIFT_LOCKED: 384 case KeyboardId.ELEMENT_ALPHABET_SHIFT_LOCK_SHIFTED: 385 return WordComposer.CAPS_MODE_MANUAL_SHIFT_LOCKED; 386 case KeyboardId.ELEMENT_ALPHABET_MANUAL_SHIFTED: 387 return WordComposer.CAPS_MODE_MANUAL_SHIFTED; 388 case KeyboardId.ELEMENT_ALPHABET_AUTOMATIC_SHIFTED: 389 return WordComposer.CAPS_MODE_AUTO_SHIFTED; 390 default: 391 return WordComposer.CAPS_MODE_OFF; 392 } 393 } 394} 395