KeyboardSwitcher.java revision 8fdff5a11129827e88ce9f5bc462e18f613c19a3
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.clearKeyboardCache(); 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.mKeyPreviewShowUpStartScale, 157 mCurrentSettingsValues.mKeyPreviewShowUpDuration, 158 mCurrentSettingsValues.mKeyPreviewDismissEndScale, 159 mCurrentSettingsValues.mKeyPreviewDismissDuration); 160 keyboardView.updateShortcutKey(mSubtypeSwitcher.isShortcutImeReady()); 161 final boolean subtypeChanged = (oldKeyboard == null) 162 || !keyboard.mId.mLocale.equals(oldKeyboard.mId.mLocale); 163 final int languageOnSpacebarFormatType = mSubtypeSwitcher.getLanguageOnSpacebarFormatType( 164 keyboard.mId.mSubtype); 165 final boolean hasMultipleEnabledIMEsOrSubtypes = RichInputMethodManager.getInstance() 166 .hasMultipleEnabledIMEsOrSubtypes(true /* shouldIncludeAuxiliarySubtypes */); 167 keyboardView.startDisplayLanguageOnSpacebar(subtypeChanged, languageOnSpacebarFormatType, 168 hasMultipleEnabledIMEsOrSubtypes); 169 } 170 171 public Keyboard getKeyboard() { 172 if (mKeyboardView != null) { 173 return mKeyboardView.getKeyboard(); 174 } 175 return null; 176 } 177 178 // TODO: Remove this method. Come up with a more comprehensive way to reset the keyboard layout 179 // when a keyboard layout set doesn't get reloaded in LatinIME.onStartInputViewInternal(). 180 public void resetKeyboardStateToAlphabet(final int currentAutoCapsState, 181 final int currentRecapitalizeState) { 182 mState.onResetKeyboardStateToAlphabet(currentAutoCapsState, currentRecapitalizeState); 183 } 184 185 public void onPressKey(final int code, final boolean isSinglePointer, 186 final int currentAutoCapsState, final int currentRecapitalizeState) { 187 mState.onPressKey(code, isSinglePointer, currentAutoCapsState, currentRecapitalizeState); 188 } 189 190 public void onReleaseKey(final int code, final boolean withSliding, 191 final int currentAutoCapsState, final int currentRecapitalizeState) { 192 mState.onReleaseKey(code, withSliding, currentAutoCapsState, currentRecapitalizeState); 193 } 194 195 public void onFinishSlidingInput(final int currentAutoCapsState, 196 final int currentRecapitalizeState) { 197 mState.onFinishSlidingInput(currentAutoCapsState, currentRecapitalizeState); 198 } 199 200 // Implements {@link KeyboardState.SwitchActions}. 201 @Override 202 public void setAlphabetKeyboard() { 203 setKeyboard(mKeyboardLayoutSet.getKeyboard(KeyboardId.ELEMENT_ALPHABET)); 204 } 205 206 // Implements {@link KeyboardState.SwitchActions}. 207 @Override 208 public void setAlphabetManualShiftedKeyboard() { 209 setKeyboard(mKeyboardLayoutSet.getKeyboard(KeyboardId.ELEMENT_ALPHABET_MANUAL_SHIFTED)); 210 } 211 212 // Implements {@link KeyboardState.SwitchActions}. 213 @Override 214 public void setAlphabetAutomaticShiftedKeyboard() { 215 setKeyboard(mKeyboardLayoutSet.getKeyboard(KeyboardId.ELEMENT_ALPHABET_AUTOMATIC_SHIFTED)); 216 } 217 218 // Implements {@link KeyboardState.SwitchActions}. 219 @Override 220 public void setAlphabetShiftLockedKeyboard() { 221 setKeyboard(mKeyboardLayoutSet.getKeyboard(KeyboardId.ELEMENT_ALPHABET_SHIFT_LOCKED)); 222 } 223 224 // Implements {@link KeyboardState.SwitchActions}. 225 @Override 226 public void setAlphabetShiftLockShiftedKeyboard() { 227 setKeyboard(mKeyboardLayoutSet.getKeyboard(KeyboardId.ELEMENT_ALPHABET_SHIFT_LOCK_SHIFTED)); 228 } 229 230 // Implements {@link KeyboardState.SwitchActions}. 231 @Override 232 public void setSymbolsKeyboard() { 233 setKeyboard(mKeyboardLayoutSet.getKeyboard(KeyboardId.ELEMENT_SYMBOLS)); 234 } 235 236 private void setMainKeyboardFrame() { 237 mMainKeyboardFrame.setVisibility(hasHardwareKeyboard() ? View.GONE : View.VISIBLE); 238 mEmojiPalettesView.setVisibility(View.GONE); 239 mEmojiPalettesView.stopEmojiPalettes(); 240 } 241 242 // TODO: Move this boolean to a member of {@link SettingsValues} and reset it 243 // at {@link LatinIME#onConfigurationChanged(Configuration)}. 244 public boolean hasHardwareKeyboard() { 245 // Copied from {@link InputMethodServce#onEvaluateInputViewShown()}. 246 final Configuration config = mLatinIME.getResources().getConfiguration(); 247 final boolean noHardwareKeyboard = config.keyboard == Configuration.KEYBOARD_NOKEYS 248 || config.hardKeyboardHidden == Configuration.HARDKEYBOARDHIDDEN_YES; 249 return !noHardwareKeyboard; 250 } 251 252 // Implements {@link KeyboardState.SwitchActions}. 253 @Override 254 public void setEmojiKeyboard() { 255 final Keyboard keyboard = mKeyboardLayoutSet.getKeyboard(KeyboardId.ELEMENT_ALPHABET); 256 mMainKeyboardFrame.setVisibility(View.GONE); 257 mEmojiPalettesView.startEmojiPalettes( 258 mKeyboardTextsSet.getText(KeyboardTextsSet.SWITCH_TO_ALPHA_KEY_LABEL), 259 mKeyboardView.getKeyVisualAttribute(), keyboard.mIconsSet); 260 mEmojiPalettesView.setVisibility(View.VISIBLE); 261 } 262 263 public void onToggleEmojiKeyboard() { 264 if (isShowingEmojiPalettes()) { 265 setAlphabetKeyboard(); 266 } else { 267 setEmojiKeyboard(); 268 } 269 } 270 271 // Implements {@link KeyboardState.SwitchActions}. 272 @Override 273 public void setSymbolsShiftedKeyboard() { 274 setKeyboard(mKeyboardLayoutSet.getKeyboard(KeyboardId.ELEMENT_SYMBOLS_SHIFTED)); 275 } 276 277 // Future method for requesting an updating to the shift state. 278 public void requestUpdatingShiftState(final int currentAutoCapsState, 279 final int currentRecapitalizeState) { 280 mState.onUpdateShiftState(currentAutoCapsState, currentRecapitalizeState); 281 } 282 283 // Implements {@link KeyboardState.SwitchActions}. 284 @Override 285 public void startDoubleTapShiftKeyTimer() { 286 final MainKeyboardView keyboardView = getMainKeyboardView(); 287 if (keyboardView != null) { 288 keyboardView.startDoubleTapShiftKeyTimer(); 289 } 290 } 291 292 // Implements {@link KeyboardState.SwitchActions}. 293 @Override 294 public void cancelDoubleTapShiftKeyTimer() { 295 final MainKeyboardView keyboardView = getMainKeyboardView(); 296 if (keyboardView != null) { 297 keyboardView.cancelDoubleTapShiftKeyTimer(); 298 } 299 } 300 301 // Implements {@link KeyboardState.SwitchActions}. 302 @Override 303 public boolean isInDoubleTapShiftKeyTimeout() { 304 final MainKeyboardView keyboardView = getMainKeyboardView(); 305 return keyboardView != null && keyboardView.isInDoubleTapShiftKeyTimeout(); 306 } 307 308 /** 309 * Updates state machine to figure out when to automatically switch back to the previous mode. 310 */ 311 public void onCodeInput(final int code, final int currentAutoCapsState, 312 final int currentRecapitalizeState) { 313 mState.onCodeInput(code, currentAutoCapsState, currentRecapitalizeState); 314 } 315 316 public boolean isShowingEmojiPalettes() { 317 return mEmojiPalettesView != null && mEmojiPalettesView.isShown(); 318 } 319 320 public boolean isShowingMoreKeysPanel() { 321 if (isShowingEmojiPalettes()) { 322 return false; 323 } 324 return mKeyboardView.isShowingMoreKeysPanel(); 325 } 326 327 public View getVisibleKeyboardView() { 328 if (isShowingEmojiPalettes()) { 329 return mEmojiPalettesView; 330 } 331 return mKeyboardView; 332 } 333 334 public MainKeyboardView getMainKeyboardView() { 335 return mKeyboardView; 336 } 337 338 public void deallocateMemory() { 339 if (mKeyboardView != null) { 340 mKeyboardView.cancelAllOngoingEvents(); 341 mKeyboardView.deallocateMemory(); 342 } 343 if (mEmojiPalettesView != null) { 344 mEmojiPalettesView.stopEmojiPalettes(); 345 } 346 } 347 348 public View onCreateInputView(final boolean isHardwareAcceleratedDrawingEnabled) { 349 if (mKeyboardView != null) { 350 mKeyboardView.closing(); 351 } 352 353 updateKeyboardThemeAndContextThemeWrapper( 354 mLatinIME, KeyboardTheme.getKeyboardTheme(mPrefs)); 355 mCurrentInputView = (InputView)LayoutInflater.from(mThemeContext).inflate( 356 R.layout.input_view, null); 357 mMainKeyboardFrame = mCurrentInputView.findViewById(R.id.main_keyboard_frame); 358 mEmojiPalettesView = (EmojiPalettesView)mCurrentInputView.findViewById( 359 R.id.emoji_keyboard_view); 360 361 mKeyboardView = (MainKeyboardView) mCurrentInputView.findViewById(R.id.keyboard_view); 362 mKeyboardView.setHardwareAcceleratedDrawingEnabled(isHardwareAcceleratedDrawingEnabled); 363 mKeyboardView.setKeyboardActionListener(mLatinIME); 364 mEmojiPalettesView.setHardwareAcceleratedDrawingEnabled( 365 isHardwareAcceleratedDrawingEnabled); 366 mEmojiPalettesView.setKeyboardActionListener(mLatinIME); 367 return mCurrentInputView; 368 } 369 370 public void onNetworkStateChanged() { 371 if (mKeyboardView != null) { 372 mKeyboardView.updateShortcutKey(mSubtypeSwitcher.isShortcutImeReady()); 373 } 374 } 375 376 public int getKeyboardShiftMode() { 377 final Keyboard keyboard = getKeyboard(); 378 if (keyboard == null) { 379 return WordComposer.CAPS_MODE_OFF; 380 } 381 switch (keyboard.mId.mElementId) { 382 case KeyboardId.ELEMENT_ALPHABET_SHIFT_LOCKED: 383 case KeyboardId.ELEMENT_ALPHABET_SHIFT_LOCK_SHIFTED: 384 return WordComposer.CAPS_MODE_MANUAL_SHIFT_LOCKED; 385 case KeyboardId.ELEMENT_ALPHABET_MANUAL_SHIFTED: 386 return WordComposer.CAPS_MODE_MANUAL_SHIFTED; 387 case KeyboardId.ELEMENT_ALPHABET_AUTOMATIC_SHIFTED: 388 return WordComposer.CAPS_MODE_AUTO_SHIFTED; 389 default: 390 return WordComposer.CAPS_MODE_OFF; 391 } 392 } 393 394 public int getCurrentKeyboardScriptId() { 395 if (null == mKeyboardLayoutSet) { 396 return ScriptUtils.SCRIPT_UNKNOWN; 397 } 398 return mKeyboardLayoutSet.getScriptId(); 399 } 400} 401