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