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