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