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