KeyboardSwitcher.java revision ad1f88081190ad3c5569b2774c03e644786770d2
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 (mKeyboardLayoutSet == null) { 265 return; 266 } 267 if (isShowingEmojiPalettes()) { 268 setAlphabetKeyboard(); 269 } else { 270 setEmojiKeyboard(); 271 } 272 } 273 274 // Implements {@link KeyboardState.SwitchActions}. 275 @Override 276 public void setSymbolsShiftedKeyboard() { 277 setKeyboard(mKeyboardLayoutSet.getKeyboard(KeyboardId.ELEMENT_SYMBOLS_SHIFTED)); 278 } 279 280 // Future method for requesting an updating to the shift state. 281 public void requestUpdatingShiftState(final int currentAutoCapsState, 282 final int currentRecapitalizeState) { 283 mState.onUpdateShiftState(currentAutoCapsState, currentRecapitalizeState); 284 } 285 286 // Implements {@link KeyboardState.SwitchActions}. 287 @Override 288 public void startDoubleTapShiftKeyTimer() { 289 final MainKeyboardView keyboardView = getMainKeyboardView(); 290 if (keyboardView != null) { 291 keyboardView.startDoubleTapShiftKeyTimer(); 292 } 293 } 294 295 // Implements {@link KeyboardState.SwitchActions}. 296 @Override 297 public void cancelDoubleTapShiftKeyTimer() { 298 final MainKeyboardView keyboardView = getMainKeyboardView(); 299 if (keyboardView != null) { 300 keyboardView.cancelDoubleTapShiftKeyTimer(); 301 } 302 } 303 304 // Implements {@link KeyboardState.SwitchActions}. 305 @Override 306 public boolean isInDoubleTapShiftKeyTimeout() { 307 final MainKeyboardView keyboardView = getMainKeyboardView(); 308 return keyboardView != null && keyboardView.isInDoubleTapShiftKeyTimeout(); 309 } 310 311 /** 312 * Updates state machine to figure out when to automatically switch back to the previous mode. 313 */ 314 public void onCodeInput(final int code, final int currentAutoCapsState, 315 final int currentRecapitalizeState) { 316 mState.onCodeInput(code, currentAutoCapsState, currentRecapitalizeState); 317 } 318 319 public boolean isShowingEmojiPalettes() { 320 return mEmojiPalettesView != null && mEmojiPalettesView.isShown(); 321 } 322 323 public boolean isShowingMoreKeysPanel() { 324 if (isShowingEmojiPalettes()) { 325 return false; 326 } 327 return mKeyboardView.isShowingMoreKeysPanel(); 328 } 329 330 public View getVisibleKeyboardView() { 331 if (isShowingEmojiPalettes()) { 332 return mEmojiPalettesView; 333 } 334 return mKeyboardView; 335 } 336 337 public MainKeyboardView getMainKeyboardView() { 338 return mKeyboardView; 339 } 340 341 public void deallocateMemory() { 342 if (mKeyboardView != null) { 343 mKeyboardView.cancelAllOngoingEvents(); 344 mKeyboardView.deallocateMemory(); 345 } 346 if (mEmojiPalettesView != null) { 347 mEmojiPalettesView.stopEmojiPalettes(); 348 } 349 } 350 351 public View onCreateInputView(final boolean isHardwareAcceleratedDrawingEnabled) { 352 if (mKeyboardView != null) { 353 mKeyboardView.closing(); 354 } 355 356 updateKeyboardThemeAndContextThemeWrapper( 357 mLatinIME, KeyboardTheme.getKeyboardTheme(mPrefs)); 358 mCurrentInputView = (InputView)LayoutInflater.from(mThemeContext).inflate( 359 R.layout.input_view, null); 360 mMainKeyboardFrame = mCurrentInputView.findViewById(R.id.main_keyboard_frame); 361 mEmojiPalettesView = (EmojiPalettesView)mCurrentInputView.findViewById( 362 R.id.emoji_keyboard_view); 363 364 mKeyboardView = (MainKeyboardView) mCurrentInputView.findViewById(R.id.keyboard_view); 365 mKeyboardView.setHardwareAcceleratedDrawingEnabled(isHardwareAcceleratedDrawingEnabled); 366 mKeyboardView.setKeyboardActionListener(mLatinIME); 367 mEmojiPalettesView.setHardwareAcceleratedDrawingEnabled( 368 isHardwareAcceleratedDrawingEnabled); 369 mEmojiPalettesView.setKeyboardActionListener(mLatinIME); 370 return mCurrentInputView; 371 } 372 373 public void onNetworkStateChanged() { 374 if (mKeyboardView != null) { 375 mKeyboardView.updateShortcutKey(mSubtypeSwitcher.isShortcutImeReady()); 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 public int getCurrentKeyboardScriptId() { 398 if (null == mKeyboardLayoutSet) { 399 return ScriptUtils.SCRIPT_UNKNOWN; 400 } 401 return mKeyboardLayoutSet.getScriptId(); 402 } 403} 404