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 
17 package com.android.inputmethod.keyboard;
18 
19 import android.content.Context;
20 import android.content.res.Resources;
21 import android.util.Log;
22 import android.view.ContextThemeWrapper;
23 import android.view.LayoutInflater;
24 import android.view.View;
25 import android.view.inputmethod.EditorInfo;
26 
27 import androidx.annotation.NonNull;
28 
29 import com.android.inputmethod.compat.InputMethodServiceCompatUtils;
30 import com.android.inputmethod.event.Event;
31 import com.android.inputmethod.keyboard.KeyboardLayoutSet.KeyboardLayoutSetException;
32 import com.android.inputmethod.keyboard.emoji.EmojiPalettesView;
33 import com.android.inputmethod.keyboard.internal.KeyboardState;
34 import com.android.inputmethod.keyboard.internal.KeyboardTextsSet;
35 import com.android.inputmethod.latin.InputView;
36 import com.android.inputmethod.latin.LatinIME;
37 import com.android.inputmethod.latin.R;
38 import com.android.inputmethod.latin.RichInputMethodManager;
39 import com.android.inputmethod.latin.WordComposer;
40 import com.android.inputmethod.latin.define.ProductionFlags;
41 import com.android.inputmethod.latin.settings.Settings;
42 import com.android.inputmethod.latin.settings.SettingsValues;
43 import com.android.inputmethod.latin.utils.CapsModeUtils;
44 import com.android.inputmethod.latin.utils.LanguageOnSpacebarUtils;
45 import com.android.inputmethod.latin.utils.RecapitalizeStatus;
46 import com.android.inputmethod.latin.utils.ResourceUtils;
47 import com.android.inputmethod.latin.utils.ScriptUtils;
48 
49 import javax.annotation.Nonnull;
50 
51 public final class KeyboardSwitcher implements KeyboardState.SwitchActions {
52     private static final String TAG = KeyboardSwitcher.class.getSimpleName();
53 
54     private InputView mCurrentInputView;
55     private View mMainKeyboardFrame;
56     private MainKeyboardView mKeyboardView;
57     private EmojiPalettesView mEmojiPalettesView;
58     private LatinIME mLatinIME;
59     private RichInputMethodManager mRichImm;
60     private boolean mIsHardwareAcceleratedDrawingEnabled;
61 
62     private KeyboardState mState;
63 
64     private KeyboardLayoutSet mKeyboardLayoutSet;
65     // TODO: The following {@link KeyboardTextsSet} should be in {@link KeyboardLayoutSet}.
66     private final KeyboardTextsSet mKeyboardTextsSet = new KeyboardTextsSet();
67 
68     private KeyboardTheme mKeyboardTheme;
69     private Context mThemeContext;
70 
71     private static final KeyboardSwitcher sInstance = new KeyboardSwitcher();
72 
getInstance()73     public static KeyboardSwitcher getInstance() {
74         return sInstance;
75     }
76 
KeyboardSwitcher()77     private KeyboardSwitcher() {
78         // Intentional empty constructor for singleton.
79     }
80 
init(final LatinIME latinIme)81     public static void init(final LatinIME latinIme) {
82         sInstance.initInternal(latinIme);
83     }
84 
initInternal(final LatinIME latinIme)85     private void initInternal(final LatinIME latinIme) {
86         mLatinIME = latinIme;
87         mRichImm = RichInputMethodManager.getInstance();
88         mState = new KeyboardState(this);
89         mIsHardwareAcceleratedDrawingEnabled =
90                 InputMethodServiceCompatUtils.enableHardwareAcceleration(mLatinIME);
91     }
92 
updateKeyboardTheme(@onNull Context displayContext)93     public void updateKeyboardTheme(@NonNull Context displayContext) {
94         final boolean themeUpdated = updateKeyboardThemeAndContextThemeWrapper(
95                 displayContext, KeyboardTheme.getKeyboardTheme(displayContext /* context */));
96         if (themeUpdated && mKeyboardView != null) {
97             mLatinIME.setInputView(
98                     onCreateInputView(displayContext, mIsHardwareAcceleratedDrawingEnabled));
99         }
100     }
101 
updateKeyboardThemeAndContextThemeWrapper(final Context context, final KeyboardTheme keyboardTheme)102     private boolean updateKeyboardThemeAndContextThemeWrapper(final Context context,
103             final KeyboardTheme keyboardTheme) {
104         if (mThemeContext == null || !keyboardTheme.equals(mKeyboardTheme)
105                 || !mThemeContext.getResources().equals(context.getResources())) {
106             mKeyboardTheme = keyboardTheme;
107             mThemeContext = new ContextThemeWrapper(context, keyboardTheme.mStyleId);
108             KeyboardLayoutSet.onKeyboardThemeChanged();
109             return true;
110         }
111         return false;
112     }
113 
loadKeyboard(final EditorInfo editorInfo, final SettingsValues settingsValues, final int currentAutoCapsState, final int currentRecapitalizeState)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.getKeyboardHeight(res, settingsValues);
121         builder.setKeyboardGeometry(keyboardWidth, keyboardHeight);
122         builder.setSubtype(mRichImm.getCurrentSubtype());
123         builder.setVoiceInputKeyEnabled(settingsValues.mShowsVoiceInputKey);
124         builder.setLanguageSwitchKeyEnabled(mLatinIME.shouldShowLanguageSwitchKey());
125         builder.setSplitLayoutEnabledByUser(ProductionFlags.IS_SPLIT_KEYBOARD_SUPPORTED
126                 && settingsValues.mIsSplitKeyboardEnabled);
127         mKeyboardLayoutSet = builder.build();
128         try {
129             mState.onLoadKeyboard(currentAutoCapsState, currentRecapitalizeState);
130             mKeyboardTextsSet.setLocale(mRichImm.getCurrentSubtypeLocale(), mThemeContext);
131         } catch (KeyboardLayoutSetException e) {
132             Log.w(TAG, "loading keyboard failed: " + e.mKeyboardId, e.getCause());
133         }
134     }
135 
saveKeyboardState()136     public void saveKeyboardState() {
137         if (getKeyboard() != null || isShowingEmojiPalettes()) {
138             mState.onSaveKeyboardState();
139         }
140     }
141 
onHideWindow()142     public void onHideWindow() {
143         if (mKeyboardView != null) {
144             mKeyboardView.onHideWindow();
145         }
146     }
147 
setKeyboard( @onnull final int keyboardId, @Nonnull final KeyboardSwitchState toggleState)148     private void setKeyboard(
149             @Nonnull final int keyboardId,
150             @Nonnull final KeyboardSwitchState toggleState) {
151         // Make {@link MainKeyboardView} visible and hide {@link EmojiPalettesView}.
152         final SettingsValues currentSettingsValues = Settings.getInstance().getCurrent();
153         setMainKeyboardFrame(currentSettingsValues, toggleState);
154         // TODO: pass this object to setKeyboard instead of getting the current values.
155         final MainKeyboardView keyboardView = mKeyboardView;
156         final Keyboard oldKeyboard = keyboardView.getKeyboard();
157         final Keyboard newKeyboard = mKeyboardLayoutSet.getKeyboard(keyboardId);
158         keyboardView.setKeyboard(newKeyboard);
159         mCurrentInputView.setKeyboardTopPadding(newKeyboard.mTopPadding);
160         keyboardView.setKeyPreviewPopupEnabled(
161                 currentSettingsValues.mKeyPreviewPopupOn,
162                 currentSettingsValues.mKeyPreviewPopupDismissDelay);
163         keyboardView.setKeyPreviewAnimationParams(
164                 currentSettingsValues.mHasCustomKeyPreviewAnimationParams,
165                 currentSettingsValues.mKeyPreviewShowUpStartXScale,
166                 currentSettingsValues.mKeyPreviewShowUpStartYScale,
167                 currentSettingsValues.mKeyPreviewShowUpDuration,
168                 currentSettingsValues.mKeyPreviewDismissEndXScale,
169                 currentSettingsValues.mKeyPreviewDismissEndYScale,
170                 currentSettingsValues.mKeyPreviewDismissDuration);
171         keyboardView.updateShortcutKey(mRichImm.isShortcutImeReady());
172         final boolean subtypeChanged = (oldKeyboard == null)
173                 || !newKeyboard.mId.mSubtype.equals(oldKeyboard.mId.mSubtype);
174         final int languageOnSpacebarFormatType = LanguageOnSpacebarUtils
175                 .getLanguageOnSpacebarFormatType(newKeyboard.mId.mSubtype);
176         final boolean hasMultipleEnabledIMEsOrSubtypes = mRichImm
177                 .hasMultipleEnabledIMEsOrSubtypes(true /* shouldIncludeAuxiliarySubtypes */);
178         keyboardView.startDisplayLanguageOnSpacebar(subtypeChanged, languageOnSpacebarFormatType,
179                 hasMultipleEnabledIMEsOrSubtypes);
180     }
181 
getKeyboard()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().
resetKeyboardStateToAlphabet(final int currentAutoCapsState, final int currentRecapitalizeState)191     public void resetKeyboardStateToAlphabet(final int currentAutoCapsState,
192             final int currentRecapitalizeState) {
193         mState.onResetKeyboardStateToAlphabet(currentAutoCapsState, currentRecapitalizeState);
194     }
195 
onPressKey(final int code, final boolean isSinglePointer, final int currentAutoCapsState, final int currentRecapitalizeState)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 
onReleaseKey(final int code, final boolean withSliding, final int currentAutoCapsState, final int currentRecapitalizeState)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 
onFinishSlidingInput(final int currentAutoCapsState, final int currentRecapitalizeState)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
setAlphabetKeyboard()213     public void setAlphabetKeyboard() {
214         if (DEBUG_ACTION) {
215             Log.d(TAG, "setAlphabetKeyboard");
216         }
217         setKeyboard(KeyboardId.ELEMENT_ALPHABET, KeyboardSwitchState.OTHER);
218     }
219 
220     // Implements {@link KeyboardState.SwitchActions}.
221     @Override
setAlphabetManualShiftedKeyboard()222     public void setAlphabetManualShiftedKeyboard() {
223         if (DEBUG_ACTION) {
224             Log.d(TAG, "setAlphabetManualShiftedKeyboard");
225         }
226         setKeyboard(KeyboardId.ELEMENT_ALPHABET_MANUAL_SHIFTED, KeyboardSwitchState.OTHER);
227     }
228 
229     // Implements {@link KeyboardState.SwitchActions}.
230     @Override
setAlphabetAutomaticShiftedKeyboard()231     public void setAlphabetAutomaticShiftedKeyboard() {
232         if (DEBUG_ACTION) {
233             Log.d(TAG, "setAlphabetAutomaticShiftedKeyboard");
234         }
235         setKeyboard(KeyboardId.ELEMENT_ALPHABET_AUTOMATIC_SHIFTED, KeyboardSwitchState.OTHER);
236     }
237 
238     // Implements {@link KeyboardState.SwitchActions}.
239     @Override
setAlphabetShiftLockedKeyboard()240     public void setAlphabetShiftLockedKeyboard() {
241         if (DEBUG_ACTION) {
242             Log.d(TAG, "setAlphabetShiftLockedKeyboard");
243         }
244         setKeyboard(KeyboardId.ELEMENT_ALPHABET_SHIFT_LOCKED, KeyboardSwitchState.OTHER);
245     }
246 
247     // Implements {@link KeyboardState.SwitchActions}.
248     @Override
setAlphabetShiftLockShiftedKeyboard()249     public void setAlphabetShiftLockShiftedKeyboard() {
250         if (DEBUG_ACTION) {
251             Log.d(TAG, "setAlphabetShiftLockShiftedKeyboard");
252         }
253         setKeyboard(KeyboardId.ELEMENT_ALPHABET_SHIFT_LOCK_SHIFTED, KeyboardSwitchState.OTHER);
254     }
255 
256     // Implements {@link KeyboardState.SwitchActions}.
257     @Override
setSymbolsKeyboard()258     public void setSymbolsKeyboard() {
259         if (DEBUG_ACTION) {
260             Log.d(TAG, "setSymbolsKeyboard");
261         }
262         setKeyboard(KeyboardId.ELEMENT_SYMBOLS, KeyboardSwitchState.OTHER);
263     }
264 
265     // Implements {@link KeyboardState.SwitchActions}.
266     @Override
setSymbolsShiftedKeyboard()267     public void setSymbolsShiftedKeyboard() {
268         if (DEBUG_ACTION) {
269             Log.d(TAG, "setSymbolsShiftedKeyboard");
270         }
271         setKeyboard(KeyboardId.ELEMENT_SYMBOLS_SHIFTED, KeyboardSwitchState.SYMBOLS_SHIFTED);
272     }
273 
isImeSuppressedByHardwareKeyboard( @onnull final SettingsValues settingsValues, @Nonnull final KeyboardSwitchState toggleState)274     public boolean isImeSuppressedByHardwareKeyboard(
275             @Nonnull final SettingsValues settingsValues,
276             @Nonnull final KeyboardSwitchState toggleState) {
277         return settingsValues.mHasHardwareKeyboard && toggleState == KeyboardSwitchState.HIDDEN;
278     }
279 
setMainKeyboardFrame( @onnull final SettingsValues settingsValues, @Nonnull final KeyboardSwitchState toggleState)280     private void setMainKeyboardFrame(
281             @Nonnull final SettingsValues settingsValues,
282             @Nonnull final KeyboardSwitchState toggleState) {
283         final int visibility =  isImeSuppressedByHardwareKeyboard(settingsValues, toggleState)
284                 ? View.GONE : View.VISIBLE;
285         mKeyboardView.setVisibility(visibility);
286         // The visibility of {@link #mKeyboardView} must be aligned with {@link #MainKeyboardFrame}.
287         // @see #getVisibleKeyboardView() and
288         // @see LatinIME#onComputeInset(android.inputmethodservice.InputMethodService.Insets)
289         mMainKeyboardFrame.setVisibility(visibility);
290         mEmojiPalettesView.setVisibility(View.GONE);
291         mEmojiPalettesView.stopEmojiPalettes();
292     }
293 
294     // Implements {@link KeyboardState.SwitchActions}.
295     @Override
setEmojiKeyboard()296     public void setEmojiKeyboard() {
297         if (DEBUG_ACTION) {
298             Log.d(TAG, "setEmojiKeyboard");
299         }
300         final Keyboard keyboard = mKeyboardLayoutSet.getKeyboard(KeyboardId.ELEMENT_ALPHABET);
301         mMainKeyboardFrame.setVisibility(View.GONE);
302         // The visibility of {@link #mKeyboardView} must be aligned with {@link #MainKeyboardFrame}.
303         // @see #getVisibleKeyboardView() and
304         // @see LatinIME#onComputeInset(android.inputmethodservice.InputMethodService.Insets)
305         mKeyboardView.setVisibility(View.GONE);
306         mEmojiPalettesView.startEmojiPalettes(
307                 mKeyboardTextsSet.getText(KeyboardTextsSet.SWITCH_TO_ALPHA_KEY_LABEL),
308                 mKeyboardView.getKeyVisualAttribute(), keyboard.mIconsSet);
309         mEmojiPalettesView.setVisibility(View.VISIBLE);
310     }
311 
312     public enum KeyboardSwitchState {
313         HIDDEN(-1),
314         SYMBOLS_SHIFTED(KeyboardId.ELEMENT_SYMBOLS_SHIFTED),
315         EMOJI(KeyboardId.ELEMENT_EMOJI_RECENTS),
316         OTHER(-1);
317 
318         final int mKeyboardId;
319 
KeyboardSwitchState(int keyboardId)320         KeyboardSwitchState(int keyboardId) {
321             mKeyboardId = keyboardId;
322         }
323     }
324 
getKeyboardSwitchState()325     public KeyboardSwitchState getKeyboardSwitchState() {
326         boolean hidden = !isShowingEmojiPalettes()
327                 && (mKeyboardLayoutSet == null
328                 || mKeyboardView == null
329                 || !mKeyboardView.isShown());
330         KeyboardSwitchState state;
331         if (hidden) {
332             return KeyboardSwitchState.HIDDEN;
333         } else if (isShowingEmojiPalettes()) {
334             return KeyboardSwitchState.EMOJI;
335         } else if (isShowingKeyboardId(KeyboardId.ELEMENT_SYMBOLS_SHIFTED)) {
336             return KeyboardSwitchState.SYMBOLS_SHIFTED;
337         }
338         return KeyboardSwitchState.OTHER;
339     }
340 
onToggleKeyboard(@onnull final KeyboardSwitchState toggleState)341     public void onToggleKeyboard(@Nonnull final KeyboardSwitchState toggleState) {
342         KeyboardSwitchState currentState = getKeyboardSwitchState();
343         Log.w(TAG, "onToggleKeyboard() : Current = " + currentState + " : Toggle = " + toggleState);
344         if (currentState == toggleState) {
345             mLatinIME.stopShowingInputView();
346             mLatinIME.hideWindow();
347             setAlphabetKeyboard();
348         } else {
349             mLatinIME.startShowingInputView(true);
350             if (toggleState == KeyboardSwitchState.EMOJI) {
351                 setEmojiKeyboard();
352             } else {
353                 mEmojiPalettesView.stopEmojiPalettes();
354                 mEmojiPalettesView.setVisibility(View.GONE);
355 
356                 mMainKeyboardFrame.setVisibility(View.VISIBLE);
357                 mKeyboardView.setVisibility(View.VISIBLE);
358                 setKeyboard(toggleState.mKeyboardId, toggleState);
359             }
360         }
361     }
362 
363     // Future method for requesting an updating to the shift state.
364     @Override
requestUpdatingShiftState(final int autoCapsFlags, final int recapitalizeMode)365     public void requestUpdatingShiftState(final int autoCapsFlags, final int recapitalizeMode) {
366         if (DEBUG_ACTION) {
367             Log.d(TAG, "requestUpdatingShiftState: "
368                     + " autoCapsFlags=" + CapsModeUtils.flagsToString(autoCapsFlags)
369                     + " recapitalizeMode=" + RecapitalizeStatus.modeToString(recapitalizeMode));
370         }
371         mState.onUpdateShiftState(autoCapsFlags, recapitalizeMode);
372     }
373 
374     // Implements {@link KeyboardState.SwitchActions}.
375     @Override
startDoubleTapShiftKeyTimer()376     public void startDoubleTapShiftKeyTimer() {
377         if (DEBUG_TIMER_ACTION) {
378             Log.d(TAG, "startDoubleTapShiftKeyTimer");
379         }
380         final MainKeyboardView keyboardView = getMainKeyboardView();
381         if (keyboardView != null) {
382             keyboardView.startDoubleTapShiftKeyTimer();
383         }
384     }
385 
386     // Implements {@link KeyboardState.SwitchActions}.
387     @Override
cancelDoubleTapShiftKeyTimer()388     public void cancelDoubleTapShiftKeyTimer() {
389         if (DEBUG_TIMER_ACTION) {
390             Log.d(TAG, "setAlphabetKeyboard");
391         }
392         final MainKeyboardView keyboardView = getMainKeyboardView();
393         if (keyboardView != null) {
394             keyboardView.cancelDoubleTapShiftKeyTimer();
395         }
396     }
397 
398     // Implements {@link KeyboardState.SwitchActions}.
399     @Override
isInDoubleTapShiftKeyTimeout()400     public boolean isInDoubleTapShiftKeyTimeout() {
401         if (DEBUG_TIMER_ACTION) {
402             Log.d(TAG, "isInDoubleTapShiftKeyTimeout");
403         }
404         final MainKeyboardView keyboardView = getMainKeyboardView();
405         return keyboardView != null && keyboardView.isInDoubleTapShiftKeyTimeout();
406     }
407 
408     /**
409      * Updates state machine to figure out when to automatically switch back to the previous mode.
410      */
onEvent(final Event event, final int currentAutoCapsState, final int currentRecapitalizeState)411     public void onEvent(final Event event, final int currentAutoCapsState,
412             final int currentRecapitalizeState) {
413         mState.onEvent(event, currentAutoCapsState, currentRecapitalizeState);
414     }
415 
isShowingKeyboardId(@onnull int... keyboardIds)416     public boolean isShowingKeyboardId(@Nonnull int... keyboardIds) {
417         if (mKeyboardView == null || !mKeyboardView.isShown()) {
418             return false;
419         }
420         int activeKeyboardId = mKeyboardView.getKeyboard().mId.mElementId;
421         for (int keyboardId : keyboardIds) {
422             if (activeKeyboardId == keyboardId) {
423                 return true;
424             }
425         }
426         return false;
427     }
428 
isShowingEmojiPalettes()429     public boolean isShowingEmojiPalettes() {
430         return mEmojiPalettesView != null && mEmojiPalettesView.isShown();
431     }
432 
isShowingMoreKeysPanel()433     public boolean isShowingMoreKeysPanel() {
434         if (isShowingEmojiPalettes()) {
435             return false;
436         }
437         return mKeyboardView.isShowingMoreKeysPanel();
438     }
439 
getVisibleKeyboardView()440     public View getVisibleKeyboardView() {
441         if (isShowingEmojiPalettes()) {
442             return mEmojiPalettesView;
443         }
444         return mKeyboardView;
445     }
446 
getMainKeyboardView()447     public MainKeyboardView getMainKeyboardView() {
448         return mKeyboardView;
449     }
450 
deallocateMemory()451     public void deallocateMemory() {
452         if (mKeyboardView != null) {
453             mKeyboardView.cancelAllOngoingEvents();
454             mKeyboardView.deallocateMemory();
455         }
456         if (mEmojiPalettesView != null) {
457             mEmojiPalettesView.stopEmojiPalettes();
458         }
459     }
460 
onCreateInputView(@onNull Context displayContext, final boolean isHardwareAcceleratedDrawingEnabled)461     public View onCreateInputView(@NonNull Context displayContext,
462             final boolean isHardwareAcceleratedDrawingEnabled) {
463         if (mKeyboardView != null) {
464             mKeyboardView.closing();
465         }
466 
467         updateKeyboardThemeAndContextThemeWrapper(
468                 displayContext, KeyboardTheme.getKeyboardTheme(displayContext /* context */));
469         mCurrentInputView = (InputView)LayoutInflater.from(mThemeContext).inflate(
470                 R.layout.input_view, null);
471         mMainKeyboardFrame = mCurrentInputView.findViewById(R.id.main_keyboard_frame);
472         mEmojiPalettesView = (EmojiPalettesView)mCurrentInputView.findViewById(
473                 R.id.emoji_palettes_view);
474 
475         mKeyboardView = (MainKeyboardView) mCurrentInputView.findViewById(R.id.keyboard_view);
476         mKeyboardView.setHardwareAcceleratedDrawingEnabled(isHardwareAcceleratedDrawingEnabled);
477         mKeyboardView.setKeyboardActionListener(mLatinIME);
478         mEmojiPalettesView.setHardwareAcceleratedDrawingEnabled(
479                 isHardwareAcceleratedDrawingEnabled);
480         mEmojiPalettesView.setKeyboardActionListener(mLatinIME);
481         return mCurrentInputView;
482     }
483 
getKeyboardShiftMode()484     public int getKeyboardShiftMode() {
485         final Keyboard keyboard = getKeyboard();
486         if (keyboard == null) {
487             return WordComposer.CAPS_MODE_OFF;
488         }
489         switch (keyboard.mId.mElementId) {
490         case KeyboardId.ELEMENT_ALPHABET_SHIFT_LOCKED:
491         case KeyboardId.ELEMENT_ALPHABET_SHIFT_LOCK_SHIFTED:
492             return WordComposer.CAPS_MODE_MANUAL_SHIFT_LOCKED;
493         case KeyboardId.ELEMENT_ALPHABET_MANUAL_SHIFTED:
494             return WordComposer.CAPS_MODE_MANUAL_SHIFTED;
495         case KeyboardId.ELEMENT_ALPHABET_AUTOMATIC_SHIFTED:
496             return WordComposer.CAPS_MODE_AUTO_SHIFTED;
497         default:
498             return WordComposer.CAPS_MODE_OFF;
499         }
500     }
501 
getCurrentKeyboardScriptId()502     public int getCurrentKeyboardScriptId() {
503         if (null == mKeyboardLayoutSet) {
504             return ScriptUtils.SCRIPT_UNKNOWN;
505         }
506         return mKeyboardLayoutSet.getScriptId();
507     }
508 }
509