2b25f674f2
Change-Id: I7bd71f1d4ef0fc0fe21ddfd9f3e11463f53ac4e7
452 lines
18 KiB
Java
452 lines
18 KiB
Java
/*
|
|
* Copyright (C) 2008 The Android Open Source Project
|
|
*
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
* you may not use this file except in compliance with the License.
|
|
* You may obtain a copy of the License at
|
|
*
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
*
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
* See the License for the specific language governing permissions and
|
|
* limitations under the License.
|
|
*/
|
|
|
|
package com.android.inputmethod.keyboard;
|
|
|
|
import android.content.Context;
|
|
import android.content.res.Resources;
|
|
import android.util.Log;
|
|
import android.view.ContextThemeWrapper;
|
|
import android.view.LayoutInflater;
|
|
import android.view.View;
|
|
import android.view.inputmethod.EditorInfo;
|
|
|
|
import com.android.inputmethod.compat.InputMethodServiceCompatUtils;
|
|
import com.android.inputmethod.event.Event;
|
|
import com.android.inputmethod.keyboard.KeyboardLayoutSet.KeyboardLayoutSetException;
|
|
import com.android.inputmethod.keyboard.emoji.EmojiPalettesView;
|
|
import com.android.inputmethod.keyboard.internal.KeyboardState;
|
|
import com.android.inputmethod.keyboard.internal.KeyboardTextsSet;
|
|
import com.android.inputmethod.latin.InputView;
|
|
import com.android.inputmethod.latin.LatinIME;
|
|
import com.android.inputmethod.latin.R;
|
|
import com.android.inputmethod.latin.RichInputMethodManager;
|
|
import com.android.inputmethod.latin.SubtypeSwitcher;
|
|
import com.android.inputmethod.latin.WordComposer;
|
|
import com.android.inputmethod.latin.define.ProductionFlags;
|
|
import com.android.inputmethod.latin.settings.Settings;
|
|
import com.android.inputmethod.latin.settings.SettingsValues;
|
|
import com.android.inputmethod.latin.utils.CapsModeUtils;
|
|
import com.android.inputmethod.latin.utils.NetworkConnectivityUtils;
|
|
import com.android.inputmethod.latin.utils.RecapitalizeStatus;
|
|
import com.android.inputmethod.latin.utils.ResourceUtils;
|
|
import com.android.inputmethod.latin.utils.ScriptUtils;
|
|
|
|
public final class KeyboardSwitcher implements KeyboardState.SwitchActions,
|
|
NetworkConnectivityUtils.NetworkStateChangeListener {
|
|
private static final String TAG = KeyboardSwitcher.class.getSimpleName();
|
|
|
|
private SubtypeSwitcher mSubtypeSwitcher;
|
|
|
|
private InputView mCurrentInputView;
|
|
private View mMainKeyboardFrame;
|
|
private MainKeyboardView mKeyboardView;
|
|
private EmojiPalettesView mEmojiPalettesView;
|
|
private LatinIME mLatinIME;
|
|
private boolean mIsHardwareAcceleratedDrawingEnabled;
|
|
|
|
private KeyboardState mState;
|
|
|
|
private KeyboardLayoutSet mKeyboardLayoutSet;
|
|
// TODO: The following {@link KeyboardTextsSet} should be in {@link KeyboardLayoutSet}.
|
|
private final KeyboardTextsSet mKeyboardTextsSet = new KeyboardTextsSet();
|
|
|
|
private KeyboardTheme mKeyboardTheme;
|
|
private Context mThemeContext;
|
|
|
|
private static final KeyboardSwitcher sInstance = new KeyboardSwitcher();
|
|
|
|
public static KeyboardSwitcher getInstance() {
|
|
return sInstance;
|
|
}
|
|
|
|
private KeyboardSwitcher() {
|
|
// Intentional empty constructor for singleton.
|
|
}
|
|
|
|
public static void init(final LatinIME latinIme) {
|
|
sInstance.initInternal(latinIme);
|
|
}
|
|
|
|
private void initInternal(final LatinIME latinIme) {
|
|
mLatinIME = latinIme;
|
|
mSubtypeSwitcher = SubtypeSwitcher.getInstance();
|
|
mState = new KeyboardState(this);
|
|
mIsHardwareAcceleratedDrawingEnabled =
|
|
InputMethodServiceCompatUtils.enableHardwareAcceleration(mLatinIME);
|
|
}
|
|
|
|
public void updateKeyboardTheme() {
|
|
final boolean themeUpdated = updateKeyboardThemeAndContextThemeWrapper(
|
|
mLatinIME, KeyboardTheme.getKeyboardTheme(mLatinIME /* context */));
|
|
if (themeUpdated && mKeyboardView != null) {
|
|
mLatinIME.setInputView(onCreateInputView(mIsHardwareAcceleratedDrawingEnabled));
|
|
}
|
|
}
|
|
|
|
private boolean updateKeyboardThemeAndContextThemeWrapper(final Context context,
|
|
final KeyboardTheme keyboardTheme) {
|
|
if (mThemeContext == null || !keyboardTheme.equals(mKeyboardTheme)) {
|
|
mKeyboardTheme = keyboardTheme;
|
|
mThemeContext = new ContextThemeWrapper(context, keyboardTheme.mStyleId);
|
|
KeyboardLayoutSet.onKeyboardThemeChanged();
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
public void loadKeyboard(final EditorInfo editorInfo, final SettingsValues settingsValues,
|
|
final int currentAutoCapsState, final int currentRecapitalizeState) {
|
|
final KeyboardLayoutSet.Builder builder = new KeyboardLayoutSet.Builder(
|
|
mThemeContext, editorInfo);
|
|
final Resources res = mThemeContext.getResources();
|
|
final int keyboardWidth = ResourceUtils.getDefaultKeyboardWidth(res);
|
|
final int keyboardHeight = ResourceUtils.getKeyboardHeight(res, settingsValues);
|
|
builder.setKeyboardGeometry(keyboardWidth, keyboardHeight);
|
|
builder.setSubtype(RichInputMethodManager.getInstance().getCurrentSubtype());
|
|
builder.setVoiceInputKeyEnabled(settingsValues.mShowsVoiceInputKey);
|
|
builder.setLanguageSwitchKeyEnabled(mLatinIME.shouldShowLanguageSwitchKey());
|
|
builder.setSplitLayoutEnabledByUser(ProductionFlags.IS_SPLIT_KEYBOARD_SUPPORTED
|
|
&& settingsValues.mIsSplitKeyboardEnabled);
|
|
mKeyboardLayoutSet = builder.build();
|
|
try {
|
|
mState.onLoadKeyboard(currentAutoCapsState, currentRecapitalizeState);
|
|
// TODO: revisit this for multi-lingual input
|
|
mKeyboardTextsSet.setLocale(
|
|
RichInputMethodManager.getInstance().getCurrentSubtypeLocales()[0],
|
|
mThemeContext);
|
|
} catch (KeyboardLayoutSetException e) {
|
|
Log.w(TAG, "loading keyboard failed: " + e.mKeyboardId, e.getCause());
|
|
return;
|
|
}
|
|
}
|
|
|
|
public void saveKeyboardState() {
|
|
if (getKeyboard() != null || isShowingEmojiPalettes()) {
|
|
mState.onSaveKeyboardState();
|
|
}
|
|
}
|
|
|
|
public void onHideWindow() {
|
|
if (mKeyboardView != null) {
|
|
mKeyboardView.onHideWindow();
|
|
}
|
|
}
|
|
|
|
private void setKeyboard(final Keyboard keyboard) {
|
|
// Make {@link MainKeyboardView} visible and hide {@link EmojiPalettesView}.
|
|
final SettingsValues currentSettingsValues = Settings.getInstance().getCurrent();
|
|
setMainKeyboardFrame(currentSettingsValues);
|
|
// TODO: pass this object to setKeyboard instead of getting the current values.
|
|
final MainKeyboardView keyboardView = mKeyboardView;
|
|
final Keyboard oldKeyboard = keyboardView.getKeyboard();
|
|
keyboardView.setKeyboard(keyboard);
|
|
mCurrentInputView.setKeyboardTopPadding(keyboard.mTopPadding);
|
|
keyboardView.setKeyPreviewPopupEnabled(
|
|
currentSettingsValues.mKeyPreviewPopupOn,
|
|
currentSettingsValues.mKeyPreviewPopupDismissDelay);
|
|
keyboardView.setKeyPreviewAnimationParams(
|
|
currentSettingsValues.mHasCustomKeyPreviewAnimationParams,
|
|
currentSettingsValues.mKeyPreviewShowUpStartXScale,
|
|
currentSettingsValues.mKeyPreviewShowUpStartYScale,
|
|
currentSettingsValues.mKeyPreviewShowUpDuration,
|
|
currentSettingsValues.mKeyPreviewDismissEndXScale,
|
|
currentSettingsValues.mKeyPreviewDismissEndYScale,
|
|
currentSettingsValues.mKeyPreviewDismissDuration);
|
|
keyboardView.updateShortcutKey(RichInputMethodManager.getInstance().isShortcutImeReady());
|
|
final boolean subtypeChanged = (oldKeyboard == null)
|
|
|| !keyboard.mId.mSubtype.equals(oldKeyboard.mId.mSubtype);
|
|
final int languageOnSpacebarFormatType = mSubtypeSwitcher.getLanguageOnSpacebarFormatType(
|
|
keyboard.mId.mSubtype);
|
|
final boolean hasMultipleEnabledIMEsOrSubtypes = RichInputMethodManager.getInstance()
|
|
.hasMultipleEnabledIMEsOrSubtypes(true /* shouldIncludeAuxiliarySubtypes */);
|
|
keyboardView.startDisplayLanguageOnSpacebar(subtypeChanged, languageOnSpacebarFormatType,
|
|
hasMultipleEnabledIMEsOrSubtypes);
|
|
}
|
|
|
|
public Keyboard getKeyboard() {
|
|
if (mKeyboardView != null) {
|
|
return mKeyboardView.getKeyboard();
|
|
}
|
|
return null;
|
|
}
|
|
|
|
// TODO: Remove this method. Come up with a more comprehensive way to reset the keyboard layout
|
|
// when a keyboard layout set doesn't get reloaded in LatinIME.onStartInputViewInternal().
|
|
public void resetKeyboardStateToAlphabet(final int currentAutoCapsState,
|
|
final int currentRecapitalizeState) {
|
|
mState.onResetKeyboardStateToAlphabet(currentAutoCapsState, currentRecapitalizeState);
|
|
}
|
|
|
|
public void onPressKey(final int code, final boolean isSinglePointer,
|
|
final int currentAutoCapsState, final int currentRecapitalizeState) {
|
|
mState.onPressKey(code, isSinglePointer, currentAutoCapsState, currentRecapitalizeState);
|
|
}
|
|
|
|
public void onReleaseKey(final int code, final boolean withSliding,
|
|
final int currentAutoCapsState, final int currentRecapitalizeState) {
|
|
mState.onReleaseKey(code, withSliding, currentAutoCapsState, currentRecapitalizeState);
|
|
}
|
|
|
|
public void onFinishSlidingInput(final int currentAutoCapsState,
|
|
final int currentRecapitalizeState) {
|
|
mState.onFinishSlidingInput(currentAutoCapsState, currentRecapitalizeState);
|
|
}
|
|
|
|
// Implements {@link KeyboardState.SwitchActions}.
|
|
@Override
|
|
public void setAlphabetKeyboard() {
|
|
if (DEBUG_ACTION) {
|
|
Log.d(TAG, "setAlphabetKeyboard");
|
|
}
|
|
setKeyboard(mKeyboardLayoutSet.getKeyboard(KeyboardId.ELEMENT_ALPHABET));
|
|
}
|
|
|
|
// Implements {@link KeyboardState.SwitchActions}.
|
|
@Override
|
|
public void setAlphabetManualShiftedKeyboard() {
|
|
if (DEBUG_ACTION) {
|
|
Log.d(TAG, "setAlphabetManualShiftedKeyboard");
|
|
}
|
|
setKeyboard(mKeyboardLayoutSet.getKeyboard(KeyboardId.ELEMENT_ALPHABET_MANUAL_SHIFTED));
|
|
}
|
|
|
|
// Implements {@link KeyboardState.SwitchActions}.
|
|
@Override
|
|
public void setAlphabetAutomaticShiftedKeyboard() {
|
|
if (DEBUG_ACTION) {
|
|
Log.d(TAG, "setAlphabetAutomaticShiftedKeyboard");
|
|
}
|
|
setKeyboard(mKeyboardLayoutSet.getKeyboard(KeyboardId.ELEMENT_ALPHABET_AUTOMATIC_SHIFTED));
|
|
}
|
|
|
|
// Implements {@link KeyboardState.SwitchActions}.
|
|
@Override
|
|
public void setAlphabetShiftLockedKeyboard() {
|
|
if (DEBUG_ACTION) {
|
|
Log.d(TAG, "setAlphabetShiftLockedKeyboard");
|
|
}
|
|
setKeyboard(mKeyboardLayoutSet.getKeyboard(KeyboardId.ELEMENT_ALPHABET_SHIFT_LOCKED));
|
|
}
|
|
|
|
// Implements {@link KeyboardState.SwitchActions}.
|
|
@Override
|
|
public void setAlphabetShiftLockShiftedKeyboard() {
|
|
if (DEBUG_ACTION) {
|
|
Log.d(TAG, "setAlphabetShiftLockShiftedKeyboard");
|
|
}
|
|
setKeyboard(mKeyboardLayoutSet.getKeyboard(KeyboardId.ELEMENT_ALPHABET_SHIFT_LOCK_SHIFTED));
|
|
}
|
|
|
|
// Implements {@link KeyboardState.SwitchActions}.
|
|
@Override
|
|
public void setSymbolsKeyboard() {
|
|
if (DEBUG_ACTION) {
|
|
Log.d(TAG, "setSymbolsKeyboard");
|
|
}
|
|
setKeyboard(mKeyboardLayoutSet.getKeyboard(KeyboardId.ELEMENT_SYMBOLS));
|
|
}
|
|
|
|
private void setMainKeyboardFrame(final SettingsValues settingsValues) {
|
|
final int visibility = settingsValues.mHasHardwareKeyboard ? View.GONE : View.VISIBLE;
|
|
mKeyboardView.setVisibility(visibility);
|
|
// The visibility of {@link #mKeyboardView} must be aligned with {@link #MainKeyboardFrame}.
|
|
// @see #getVisibleKeyboardView() and
|
|
// @see LatinIME#onComputeInset(android.inputmethodservice.InputMethodService.Insets)
|
|
mMainKeyboardFrame.setVisibility(visibility);
|
|
mEmojiPalettesView.setVisibility(View.GONE);
|
|
mEmojiPalettesView.stopEmojiPalettes();
|
|
}
|
|
|
|
// Implements {@link KeyboardState.SwitchActions}.
|
|
@Override
|
|
public void setEmojiKeyboard() {
|
|
if (DEBUG_ACTION) {
|
|
Log.d(TAG, "setEmojiKeyboard");
|
|
}
|
|
final Keyboard keyboard = mKeyboardLayoutSet.getKeyboard(KeyboardId.ELEMENT_ALPHABET);
|
|
mMainKeyboardFrame.setVisibility(View.GONE);
|
|
// The visibility of {@link #mKeyboardView} must be aligned with {@link #MainKeyboardFrame}.
|
|
// @see #getVisibleKeyboardView() and
|
|
// @see LatinIME#onComputeInset(android.inputmethodservice.InputMethodService.Insets)
|
|
mKeyboardView.setVisibility(View.GONE);
|
|
mEmojiPalettesView.startEmojiPalettes(
|
|
mKeyboardTextsSet.getText(KeyboardTextsSet.SWITCH_TO_ALPHA_KEY_LABEL),
|
|
mKeyboardView.getKeyVisualAttribute(), keyboard.mIconsSet);
|
|
mEmojiPalettesView.setVisibility(View.VISIBLE);
|
|
}
|
|
|
|
public void onToggleEmojiKeyboard() {
|
|
final boolean needsToLoadKeyboard = (mKeyboardLayoutSet == null);
|
|
if (needsToLoadKeyboard || !isShowingEmojiPalettes()) {
|
|
mLatinIME.startShowingInputView(needsToLoadKeyboard);
|
|
setEmojiKeyboard();
|
|
} else {
|
|
mLatinIME.stopShowingInputView();
|
|
setAlphabetKeyboard();
|
|
}
|
|
}
|
|
|
|
// Implements {@link KeyboardState.SwitchActions}.
|
|
@Override
|
|
public void setSymbolsShiftedKeyboard() {
|
|
if (DEBUG_ACTION) {
|
|
Log.d(TAG, "setSymbolsShiftedKeyboard");
|
|
}
|
|
setKeyboard(mKeyboardLayoutSet.getKeyboard(KeyboardId.ELEMENT_SYMBOLS_SHIFTED));
|
|
}
|
|
|
|
// Future method for requesting an updating to the shift state.
|
|
@Override
|
|
public void requestUpdatingShiftState(final int autoCapsFlags, final int recapitalizeMode) {
|
|
if (DEBUG_ACTION) {
|
|
Log.d(TAG, "requestUpdatingShiftState: "
|
|
+ " autoCapsFlags=" + CapsModeUtils.flagsToString(autoCapsFlags)
|
|
+ " recapitalizeMode=" + RecapitalizeStatus.modeToString(recapitalizeMode));
|
|
}
|
|
mState.onUpdateShiftState(autoCapsFlags, recapitalizeMode);
|
|
}
|
|
|
|
// Implements {@link KeyboardState.SwitchActions}.
|
|
@Override
|
|
public void startDoubleTapShiftKeyTimer() {
|
|
if (DEBUG_TIMER_ACTION) {
|
|
Log.d(TAG, "startDoubleTapShiftKeyTimer");
|
|
}
|
|
final MainKeyboardView keyboardView = getMainKeyboardView();
|
|
if (keyboardView != null) {
|
|
keyboardView.startDoubleTapShiftKeyTimer();
|
|
}
|
|
}
|
|
|
|
// Implements {@link KeyboardState.SwitchActions}.
|
|
@Override
|
|
public void cancelDoubleTapShiftKeyTimer() {
|
|
if (DEBUG_TIMER_ACTION) {
|
|
Log.d(TAG, "setAlphabetKeyboard");
|
|
}
|
|
final MainKeyboardView keyboardView = getMainKeyboardView();
|
|
if (keyboardView != null) {
|
|
keyboardView.cancelDoubleTapShiftKeyTimer();
|
|
}
|
|
}
|
|
|
|
// Implements {@link KeyboardState.SwitchActions}.
|
|
@Override
|
|
public boolean isInDoubleTapShiftKeyTimeout() {
|
|
if (DEBUG_TIMER_ACTION) {
|
|
Log.d(TAG, "isInDoubleTapShiftKeyTimeout");
|
|
}
|
|
final MainKeyboardView keyboardView = getMainKeyboardView();
|
|
return keyboardView != null && keyboardView.isInDoubleTapShiftKeyTimeout();
|
|
}
|
|
|
|
/**
|
|
* Updates state machine to figure out when to automatically switch back to the previous mode.
|
|
*/
|
|
public void onEvent(final Event event, final int currentAutoCapsState,
|
|
final int currentRecapitalizeState) {
|
|
mState.onEvent(event, currentAutoCapsState, currentRecapitalizeState);
|
|
}
|
|
|
|
public boolean isShowingEmojiPalettes() {
|
|
return mEmojiPalettesView != null && mEmojiPalettesView.isShown();
|
|
}
|
|
|
|
public boolean isShowingMoreKeysPanel() {
|
|
if (isShowingEmojiPalettes()) {
|
|
return false;
|
|
}
|
|
return mKeyboardView.isShowingMoreKeysPanel();
|
|
}
|
|
|
|
public View getVisibleKeyboardView() {
|
|
if (isShowingEmojiPalettes()) {
|
|
return mEmojiPalettesView;
|
|
}
|
|
return mKeyboardView;
|
|
}
|
|
|
|
public MainKeyboardView getMainKeyboardView() {
|
|
return mKeyboardView;
|
|
}
|
|
|
|
public void deallocateMemory() {
|
|
if (mKeyboardView != null) {
|
|
mKeyboardView.cancelAllOngoingEvents();
|
|
mKeyboardView.deallocateMemory();
|
|
}
|
|
if (mEmojiPalettesView != null) {
|
|
mEmojiPalettesView.stopEmojiPalettes();
|
|
}
|
|
}
|
|
|
|
public View onCreateInputView(final boolean isHardwareAcceleratedDrawingEnabled) {
|
|
if (mKeyboardView != null) {
|
|
mKeyboardView.closing();
|
|
}
|
|
|
|
updateKeyboardThemeAndContextThemeWrapper(
|
|
mLatinIME, KeyboardTheme.getKeyboardTheme(mLatinIME /* context */));
|
|
mCurrentInputView = (InputView)LayoutInflater.from(mThemeContext).inflate(
|
|
R.layout.input_view, null);
|
|
mMainKeyboardFrame = mCurrentInputView.findViewById(R.id.main_keyboard_frame);
|
|
mEmojiPalettesView = (EmojiPalettesView)mCurrentInputView.findViewById(
|
|
R.id.emoji_palettes_view);
|
|
|
|
mKeyboardView = (MainKeyboardView) mCurrentInputView.findViewById(R.id.keyboard_view);
|
|
mKeyboardView.setHardwareAcceleratedDrawingEnabled(isHardwareAcceleratedDrawingEnabled);
|
|
mKeyboardView.setKeyboardActionListener(mLatinIME);
|
|
mEmojiPalettesView.setHardwareAcceleratedDrawingEnabled(
|
|
isHardwareAcceleratedDrawingEnabled);
|
|
mEmojiPalettesView.setKeyboardActionListener(mLatinIME);
|
|
return mCurrentInputView;
|
|
}
|
|
|
|
// {@link NetworkConnectivityUtils.NetworkStateChangeListener#onNetworkStateChanged(boolean)}.
|
|
@Override
|
|
public void onNetworkStateChanged() {
|
|
if (mKeyboardView == null) {
|
|
return;
|
|
}
|
|
mKeyboardView.updateShortcutKey(RichInputMethodManager.getInstance().isShortcutImeReady());
|
|
}
|
|
|
|
public int getKeyboardShiftMode() {
|
|
final Keyboard keyboard = getKeyboard();
|
|
if (keyboard == null) {
|
|
return WordComposer.CAPS_MODE_OFF;
|
|
}
|
|
switch (keyboard.mId.mElementId) {
|
|
case KeyboardId.ELEMENT_ALPHABET_SHIFT_LOCKED:
|
|
case KeyboardId.ELEMENT_ALPHABET_SHIFT_LOCK_SHIFTED:
|
|
return WordComposer.CAPS_MODE_MANUAL_SHIFT_LOCKED;
|
|
case KeyboardId.ELEMENT_ALPHABET_MANUAL_SHIFTED:
|
|
return WordComposer.CAPS_MODE_MANUAL_SHIFTED;
|
|
case KeyboardId.ELEMENT_ALPHABET_AUTOMATIC_SHIFTED:
|
|
return WordComposer.CAPS_MODE_AUTO_SHIFTED;
|
|
default:
|
|
return WordComposer.CAPS_MODE_OFF;
|
|
}
|
|
}
|
|
|
|
public int getCurrentKeyboardScriptId() {
|
|
if (null == mKeyboardLayoutSet) {
|
|
return ScriptUtils.SCRIPT_UNKNOWN;
|
|
}
|
|
return mKeyboardLayoutSet.getScriptId();
|
|
}
|
|
}
|