KeyboardSwitcher.java revision ac88f3d8459e17236654aa38debea749ecb631d1
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.SettingsValues; 42import com.android.inputmethod.latin.utils.ResourceUtils; 43import com.android.inputmethod.latin.utils.ScriptUtils; 44 45public final class KeyboardSwitcher implements KeyboardState.SwitchActions { 46 private static final String TAG = KeyboardSwitcher.class.getSimpleName(); 47 48 private SubtypeSwitcher mSubtypeSwitcher; 49 private SharedPreferences mPrefs; 50 51 private InputView mCurrentInputView; 52 private View mMainKeyboardFrame; 53 private MainKeyboardView mKeyboardView; 54 private EmojiPalettesView mEmojiPalettesView; 55 private LatinIME mLatinIME; 56 private boolean mIsHardwareAcceleratedDrawingEnabled; 57 58 private KeyboardState mState; 59 60 private KeyboardLayoutSet mKeyboardLayoutSet; 61 // TODO: The following {@link KeyboardTextsSet} should be in {@link KeyboardLayoutSet}. 62 private final KeyboardTextsSet mKeyboardTextsSet = new KeyboardTextsSet(); 63 private SettingsValues mCurrentSettingsValues; 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 mCurrentSettingsValues = settingsValues; 124 try { 125 mState.onLoadKeyboard(currentAutoCapsState, currentRecapitalizeState); 126 mKeyboardTextsSet.setLocale(mSubtypeSwitcher.getCurrentSubtypeLocale(), mThemeContext); 127 } catch (KeyboardLayoutSetException e) { 128 Log.w(TAG, "loading keyboard failed: " + e.mKeyboardId, e.getCause()); 129 return; 130 } 131 } 132 133 public void saveKeyboardState() { 134 if (getKeyboard() != null || isShowingEmojiPalettes()) { 135 mState.onSaveKeyboardState(); 136 } 137 } 138 139 public void onHideWindow() { 140 if (mKeyboardView != null) { 141 mKeyboardView.onHideWindow(); 142 } 143 } 144 145 private void setKeyboard(final Keyboard keyboard) { 146 // Make {@link MainKeyboardView} visible and hide {@link EmojiPalettesView}. 147 setMainKeyboardFrame(); 148 final MainKeyboardView keyboardView = mKeyboardView; 149 final Keyboard oldKeyboard = keyboardView.getKeyboard(); 150 keyboardView.setKeyboard(keyboard); 151 mCurrentInputView.setKeyboardTopPadding(keyboard.mTopPadding); 152 keyboardView.setKeyPreviewPopupEnabled( 153 mCurrentSettingsValues.mKeyPreviewPopupOn, 154 mCurrentSettingsValues.mKeyPreviewPopupDismissDelay); 155 keyboardView.setKeyPreviewAnimationParams( 156 mCurrentSettingsValues.mHasCustomKeyPreviewAnimationParams, 157 mCurrentSettingsValues.mKeyPreviewShowUpStartXScale, 158 mCurrentSettingsValues.mKeyPreviewShowUpStartYScale, 159 mCurrentSettingsValues.mKeyPreviewShowUpDuration, 160 mCurrentSettingsValues.mKeyPreviewDismissEndXScale, 161 mCurrentSettingsValues.mKeyPreviewDismissEndYScale, 162 mCurrentSettingsValues.mKeyPreviewDismissDuration); 163 keyboardView.updateShortcutKey(mSubtypeSwitcher.isShortcutImeReady()); 164 final boolean subtypeChanged = (oldKeyboard == null) 165 || !keyboard.mId.mLocale.equals(oldKeyboard.mId.mLocale); 166 final int languageOnSpacebarFormatType = mSubtypeSwitcher.getLanguageOnSpacebarFormatType( 167 keyboard.mId.mSubtype); 168 final boolean hasMultipleEnabledIMEsOrSubtypes = RichInputMethodManager.getInstance() 169 .hasMultipleEnabledIMEsOrSubtypes(true /* shouldIncludeAuxiliarySubtypes */); 170 keyboardView.startDisplayLanguageOnSpacebar(subtypeChanged, languageOnSpacebarFormatType, 171 hasMultipleEnabledIMEsOrSubtypes); 172 } 173 174 public Keyboard getKeyboard() { 175 if (mKeyboardView != null) { 176 return mKeyboardView.getKeyboard(); 177 } 178 return null; 179 } 180 181 // TODO: Remove this method. Come up with a more comprehensive way to reset the keyboard layout 182 // when a keyboard layout set doesn't get reloaded in LatinIME.onStartInputViewInternal(). 183 public void resetKeyboardStateToAlphabet(final int currentAutoCapsState, 184 final int currentRecapitalizeState) { 185 mState.onResetKeyboardStateToAlphabet(currentAutoCapsState, currentRecapitalizeState); 186 } 187 188 public void onPressKey(final int code, final boolean isSinglePointer, 189 final int currentAutoCapsState, final int currentRecapitalizeState) { 190 mState.onPressKey(code, isSinglePointer, currentAutoCapsState, currentRecapitalizeState); 191 } 192 193 public void onReleaseKey(final int code, final boolean withSliding, 194 final int currentAutoCapsState, final int currentRecapitalizeState) { 195 mState.onReleaseKey(code, withSliding, currentAutoCapsState, currentRecapitalizeState); 196 } 197 198 public void onFinishSlidingInput(final int currentAutoCapsState, 199 final int currentRecapitalizeState) { 200 mState.onFinishSlidingInput(currentAutoCapsState, currentRecapitalizeState); 201 } 202 203 // Implements {@link KeyboardState.SwitchActions}. 204 @Override 205 public void setAlphabetKeyboard() { 206 setKeyboard(mKeyboardLayoutSet.getKeyboard(KeyboardId.ELEMENT_ALPHABET)); 207 } 208 209 // Implements {@link KeyboardState.SwitchActions}. 210 @Override 211 public void setAlphabetManualShiftedKeyboard() { 212 setKeyboard(mKeyboardLayoutSet.getKeyboard(KeyboardId.ELEMENT_ALPHABET_MANUAL_SHIFTED)); 213 } 214 215 // Implements {@link KeyboardState.SwitchActions}. 216 @Override 217 public void setAlphabetAutomaticShiftedKeyboard() { 218 setKeyboard(mKeyboardLayoutSet.getKeyboard(KeyboardId.ELEMENT_ALPHABET_AUTOMATIC_SHIFTED)); 219 } 220 221 // Implements {@link KeyboardState.SwitchActions}. 222 @Override 223 public void setAlphabetShiftLockedKeyboard() { 224 setKeyboard(mKeyboardLayoutSet.getKeyboard(KeyboardId.ELEMENT_ALPHABET_SHIFT_LOCKED)); 225 } 226 227 // Implements {@link KeyboardState.SwitchActions}. 228 @Override 229 public void setAlphabetShiftLockShiftedKeyboard() { 230 setKeyboard(mKeyboardLayoutSet.getKeyboard(KeyboardId.ELEMENT_ALPHABET_SHIFT_LOCK_SHIFTED)); 231 } 232 233 // Implements {@link KeyboardState.SwitchActions}. 234 @Override 235 public void setSymbolsKeyboard() { 236 setKeyboard(mKeyboardLayoutSet.getKeyboard(KeyboardId.ELEMENT_SYMBOLS)); 237 } 238 239 private void setMainKeyboardFrame() { 240 mMainKeyboardFrame.setVisibility(hasHardwareKeyboard() ? View.GONE : View.VISIBLE); 241 mEmojiPalettesView.setVisibility(View.GONE); 242 mEmojiPalettesView.stopEmojiPalettes(); 243 } 244 245 // TODO: Move this boolean to a member of {@link SettingsValues} and reset it 246 // at {@link LatinIME#onConfigurationChanged(Configuration)}. 247 public boolean hasHardwareKeyboard() { 248 // Copied from {@link InputMethodServce#onEvaluateInputViewShown()}. 249 final Configuration config = mLatinIME.getResources().getConfiguration(); 250 final boolean noHardwareKeyboard = config.keyboard == Configuration.KEYBOARD_NOKEYS 251 || config.hardKeyboardHidden == Configuration.HARDKEYBOARDHIDDEN_YES; 252 return !noHardwareKeyboard; 253 } 254 255 // Implements {@link KeyboardState.SwitchActions}. 256 @Override 257 public void setEmojiKeyboard() { 258 final Keyboard keyboard = mKeyboardLayoutSet.getKeyboard(KeyboardId.ELEMENT_ALPHABET); 259 mMainKeyboardFrame.setVisibility(View.GONE); 260 mEmojiPalettesView.startEmojiPalettes( 261 mKeyboardTextsSet.getText(KeyboardTextsSet.SWITCH_TO_ALPHA_KEY_LABEL), 262 mKeyboardView.getKeyVisualAttribute(), keyboard.mIconsSet); 263 mEmojiPalettesView.setVisibility(View.VISIBLE); 264 } 265 266 public void onToggleEmojiKeyboard() { 267 if (mKeyboardLayoutSet == null) { 268 return; 269 } 270 if (isShowingEmojiPalettes()) { 271 setAlphabetKeyboard(); 272 } else { 273 setEmojiKeyboard(); 274 } 275 } 276 277 // Implements {@link KeyboardState.SwitchActions}. 278 @Override 279 public void setSymbolsShiftedKeyboard() { 280 setKeyboard(mKeyboardLayoutSet.getKeyboard(KeyboardId.ELEMENT_SYMBOLS_SHIFTED)); 281 } 282 283 // Future method for requesting an updating to the shift state. 284 public void requestUpdatingShiftState(final int currentAutoCapsState, 285 final int currentRecapitalizeState) { 286 mState.onUpdateShiftState(currentAutoCapsState, currentRecapitalizeState); 287 } 288 289 // Implements {@link KeyboardState.SwitchActions}. 290 @Override 291 public void startDoubleTapShiftKeyTimer() { 292 final MainKeyboardView keyboardView = getMainKeyboardView(); 293 if (keyboardView != null) { 294 keyboardView.startDoubleTapShiftKeyTimer(); 295 } 296 } 297 298 // Implements {@link KeyboardState.SwitchActions}. 299 @Override 300 public void cancelDoubleTapShiftKeyTimer() { 301 final MainKeyboardView keyboardView = getMainKeyboardView(); 302 if (keyboardView != null) { 303 keyboardView.cancelDoubleTapShiftKeyTimer(); 304 } 305 } 306 307 // Implements {@link KeyboardState.SwitchActions}. 308 @Override 309 public boolean isInDoubleTapShiftKeyTimeout() { 310 final MainKeyboardView keyboardView = getMainKeyboardView(); 311 return keyboardView != null && keyboardView.isInDoubleTapShiftKeyTimeout(); 312 } 313 314 /** 315 * Updates state machine to figure out when to automatically switch back to the previous mode. 316 */ 317 public void onCodeInput(final int code, final int currentAutoCapsState, 318 final int currentRecapitalizeState) { 319 mState.onCodeInput(code, currentAutoCapsState, currentRecapitalizeState); 320 } 321 322 public boolean isShowingEmojiPalettes() { 323 return mEmojiPalettesView != null && mEmojiPalettesView.isShown(); 324 } 325 326 public boolean isShowingMoreKeysPanel() { 327 if (isShowingEmojiPalettes()) { 328 return false; 329 } 330 return mKeyboardView.isShowingMoreKeysPanel(); 331 } 332 333 public View getVisibleKeyboardView() { 334 if (isShowingEmojiPalettes()) { 335 return mEmojiPalettesView; 336 } 337 return mKeyboardView; 338 } 339 340 public MainKeyboardView getMainKeyboardView() { 341 return mKeyboardView; 342 } 343 344 public void deallocateMemory() { 345 if (mKeyboardView != null) { 346 mKeyboardView.cancelAllOngoingEvents(); 347 mKeyboardView.deallocateMemory(); 348 } 349 if (mEmojiPalettesView != null) { 350 mEmojiPalettesView.stopEmojiPalettes(); 351 } 352 } 353 354 public View onCreateInputView(final boolean isHardwareAcceleratedDrawingEnabled) { 355 if (mKeyboardView != null) { 356 mKeyboardView.closing(); 357 } 358 359 updateKeyboardThemeAndContextThemeWrapper( 360 mLatinIME, KeyboardTheme.getKeyboardTheme(mPrefs)); 361 mCurrentInputView = (InputView)LayoutInflater.from(mThemeContext).inflate( 362 R.layout.input_view, null); 363 mMainKeyboardFrame = mCurrentInputView.findViewById(R.id.main_keyboard_frame); 364 mEmojiPalettesView = (EmojiPalettesView)mCurrentInputView.findViewById( 365 R.id.emoji_palettes_view); 366 367 mKeyboardView = (MainKeyboardView) mCurrentInputView.findViewById(R.id.keyboard_view); 368 mKeyboardView.setHardwareAcceleratedDrawingEnabled(isHardwareAcceleratedDrawingEnabled); 369 mKeyboardView.setKeyboardActionListener(mLatinIME); 370 mEmojiPalettesView.setHardwareAcceleratedDrawingEnabled( 371 isHardwareAcceleratedDrawingEnabled); 372 mEmojiPalettesView.setKeyboardActionListener(mLatinIME); 373 return mCurrentInputView; 374 } 375 376 public void onNetworkStateChanged() { 377 if (mKeyboardView != null) { 378 mKeyboardView.updateShortcutKey(mSubtypeSwitcher.isShortcutImeReady()); 379 } 380 } 381 382 public int getKeyboardShiftMode() { 383 final Keyboard keyboard = getKeyboard(); 384 if (keyboard == null) { 385 return WordComposer.CAPS_MODE_OFF; 386 } 387 switch (keyboard.mId.mElementId) { 388 case KeyboardId.ELEMENT_ALPHABET_SHIFT_LOCKED: 389 case KeyboardId.ELEMENT_ALPHABET_SHIFT_LOCK_SHIFTED: 390 return WordComposer.CAPS_MODE_MANUAL_SHIFT_LOCKED; 391 case KeyboardId.ELEMENT_ALPHABET_MANUAL_SHIFTED: 392 return WordComposer.CAPS_MODE_MANUAL_SHIFTED; 393 case KeyboardId.ELEMENT_ALPHABET_AUTOMATIC_SHIFTED: 394 return WordComposer.CAPS_MODE_AUTO_SHIFTED; 395 default: 396 return WordComposer.CAPS_MODE_OFF; 397 } 398 } 399 400 public int getCurrentKeyboardScriptId() { 401 if (null == mKeyboardLayoutSet) { 402 return ScriptUtils.SCRIPT_UNKNOWN; 403 } 404 return mKeyboardLayoutSet.getScriptId(); 405 } 406} 407