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