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