KeyboardSwitcher.java revision 889691eca1ad991a85fb721deb37ecba6a913762
1923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project/*
2443c360d0afdbab091994244f045f4756feaf2b4Jean-Baptiste Queru * Copyright (C) 2008 The Android Open Source Project
3923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project *
4923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project * Licensed under the Apache License, Version 2.0 (the "License"); you may not
5923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project * use this file except in compliance with the License. You may obtain a copy of
6923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project * the License at
7923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project *
8923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project * http://www.apache.org/licenses/LICENSE-2.0
9923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project *
10923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project * Unless required by applicable law or agreed to in writing, software
11923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
12923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
13923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project * License for the specific language governing permissions and limitations under
14923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project * the License.
15923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project */
16923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project
17923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Projectpackage com.android.inputmethod.latin;
18923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project
198b00bc4f3281c229ee830f34a78c0ec287902c3fTadashi G. Takaokaimport android.content.Context;
20979f8690967ff5409fe18f5085858ccdb8e0ccf1satokimport android.content.SharedPreferences;
2136fcf25833f7c8876cbc8286e0c159b052dc2626Amith Yamasaniimport android.content.res.Configuration;
2236fcf25833f7c8876cbc8286e0c159b052dc2626Amith Yamasaniimport android.content.res.Resources;
23979f8690967ff5409fe18f5085858ccdb8e0ccf1satokimport android.preference.PreferenceManager;
248b00bc4f3281c229ee830f34a78c0ec287902c3fTadashi G. Takaokaimport android.util.Log;
25979f8690967ff5409fe18f5085858ccdb8e0ccf1satokimport android.view.InflateException;
2636fcf25833f7c8876cbc8286e0c159b052dc2626Amith Yamasani
27681b676b0aecb30e644f25550018ce2b6cea3e15Tadashi G. Takaokaimport java.lang.ref.SoftReference;
287e1f5a2d5a96c74691b3b09fa986efb7161e5a12Tadashi G. Takaokaimport java.util.Arrays;
2912659d4c0ce04aaf3d8479e44f9230881b964000Tadashi G. Takaokaimport java.util.HashMap;
3012659d4c0ce04aaf3d8479e44f9230881b964000Tadashi G. Takaokaimport java.util.Locale;
3112659d4c0ce04aaf3d8479e44f9230881b964000Tadashi G. Takaoka
32979f8690967ff5409fe18f5085858ccdb8e0ccf1satokpublic class KeyboardSwitcher implements SharedPreferences.OnSharedPreferenceChangeListener {
338b00bc4f3281c229ee830f34a78c0ec287902c3fTadashi G. Takaoka    private static final String TAG = "KeyboardSwitcher";
348b00bc4f3281c229ee830f34a78c0ec287902c3fTadashi G. Takaoka    private static final boolean DEBUG = false;
35923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project
36e354a85ef44e13999aaefd735cef7f659090f6e8Ken Wakasa    public static final int MODE_TEXT = 0;
37e354a85ef44e13999aaefd735cef7f659090f6e8Ken Wakasa    public static final int MODE_URL = 1;
38e354a85ef44e13999aaefd735cef7f659090f6e8Ken Wakasa    public static final int MODE_EMAIL = 2;
39e354a85ef44e13999aaefd735cef7f659090f6e8Ken Wakasa    public static final int MODE_IM = 3;
40e354a85ef44e13999aaefd735cef7f659090f6e8Ken Wakasa    public static final int MODE_WEB = 4;
41e354a85ef44e13999aaefd735cef7f659090f6e8Ken Wakasa    public static final int MODE_PHONE = 5;
42e354a85ef44e13999aaefd735cef7f659090f6e8Ken Wakasa
4331adfa78e2edae188edb05e869f9f68798857582satok    public static final String DEFAULT_LAYOUT_ID = "4";
44a327485e595c9f7676989097c830ff452085d4c9satok    public static final String PREF_KEYBOARD_LAYOUT = "pref_keyboard_layout_20100902";
45979f8690967ff5409fe18f5085858ccdb8e0ccf1satok    private static final int[] THEMES = new int [] {
46979f8690967ff5409fe18f5085858ccdb8e0ccf1satok        R.layout.input_basic, R.layout.input_basic_highcontrast, R.layout.input_stone_normal,
4731adfa78e2edae188edb05e869f9f68798857582satok        R.layout.input_stone_bold, R.layout.input_gingerbread};
48979f8690967ff5409fe18f5085858ccdb8e0ccf1satok
49979f8690967ff5409fe18f5085858ccdb8e0ccf1satok    // Ids for each characters' color in the keyboard
50979f8690967ff5409fe18f5085858ccdb8e0ccf1satok    private static final int CHAR_THEME_COLOR_WHITE = 0;
51979f8690967ff5409fe18f5085858ccdb8e0ccf1satok    private static final int CHAR_THEME_COLOR_BLACK = 1;
52979f8690967ff5409fe18f5085858ccdb8e0ccf1satok
53979f8690967ff5409fe18f5085858ccdb8e0ccf1satok    // Tables which contains resource ids for each character theme color
54b0465116bd3786174ccd0034c8a165ebc723b60fTadashi G. Takaoka    private static final int[] KBD_PHONE = new int[] {
55b0465116bd3786174ccd0034c8a165ebc723b60fTadashi G. Takaoka            R.xml.kbd_phone, R.xml.kbd_phone_black
56b0465116bd3786174ccd0034c8a165ebc723b60fTadashi G. Takaoka    };
57979f8690967ff5409fe18f5085858ccdb8e0ccf1satok    private static final int[] KBD_PHONE_SYMBOLS = new int[] {
58b0465116bd3786174ccd0034c8a165ebc723b60fTadashi G. Takaoka            R.xml.kbd_phone_symbols, R.xml.kbd_phone_symbols_black
59b0465116bd3786174ccd0034c8a165ebc723b60fTadashi G. Takaoka    };
60979f8690967ff5409fe18f5085858ccdb8e0ccf1satok    private static final int[] KBD_SYMBOLS = new int[] {
61b0465116bd3786174ccd0034c8a165ebc723b60fTadashi G. Takaoka            R.xml.kbd_symbols, R.xml.kbd_symbols_black
62b0465116bd3786174ccd0034c8a165ebc723b60fTadashi G. Takaoka    };
63979f8690967ff5409fe18f5085858ccdb8e0ccf1satok    private static final int[] KBD_SYMBOLS_SHIFT = new int[] {
64b0465116bd3786174ccd0034c8a165ebc723b60fTadashi G. Takaoka            R.xml.kbd_symbols_shift, R.xml.kbd_symbols_shift_black
65b0465116bd3786174ccd0034c8a165ebc723b60fTadashi G. Takaoka    };
66b0465116bd3786174ccd0034c8a165ebc723b60fTadashi G. Takaoka    private static final int[] KBD_QWERTY = new int[] {
67b0465116bd3786174ccd0034c8a165ebc723b60fTadashi G. Takaoka            R.xml.kbd_qwerty, R.xml.kbd_qwerty_black
68b0465116bd3786174ccd0034c8a165ebc723b60fTadashi G. Takaoka    };
69979f8690967ff5409fe18f5085858ccdb8e0ccf1satok
70b19668cfc17ad30afcc3c8c0407d47238ce1a90dAmith Yamasani    private static final int SYMBOLS_MODE_STATE_NONE = 0;
71b19668cfc17ad30afcc3c8c0407d47238ce1a90dAmith Yamasani    private static final int SYMBOLS_MODE_STATE_BEGIN = 1;
72b19668cfc17ad30afcc3c8c0407d47238ce1a90dAmith Yamasani    private static final int SYMBOLS_MODE_STATE_SYMBOL = 2;
73b19668cfc17ad30afcc3c8c0407d47238ce1a90dAmith Yamasani
743a2896c80475094f751ef447fc9c97028bfc2265Tadashi G. Takaoka    private LatinKeyboardView mInputView;
753a2896c80475094f751ef447fc9c97028bfc2265Tadashi G. Takaoka    private final LatinIME mInputMethodService;
768b00bc4f3281c229ee830f34a78c0ec287902c3fTadashi G. Takaoka    private final LanguageSwitcher mLanguageSwitcher;
7731adfa78e2edae188edb05e869f9f68798857582satok
78889691eca1ad991a85fb721deb37ecba6a913762Tadashi G. Takaoka    private ShiftKeyState mShiftState = new ShiftKeyState();
796c92ee127df50509d364a2b6d428b223d2cbaa6eTadashi G. Takaoka    private ModifierKeyState mSymbolKeyState = new ModifierKeyState();
80889691eca1ad991a85fb721deb37ecba6a913762Tadashi G. Takaoka
81353da6d207bed3d32ec38b9ce52e4a136adbf060Brandon Ballinger    private KeyboardId mSymbolsId;
82353da6d207bed3d32ec38b9ce52e4a136adbf060Brandon Ballinger    private KeyboardId mSymbolsShiftedId;
83353da6d207bed3d32ec38b9ce52e4a136adbf060Brandon Ballinger
84353da6d207bed3d32ec38b9ce52e4a136adbf060Brandon Ballinger    private KeyboardId mCurrentId;
858b00bc4f3281c229ee830f34a78c0ec287902c3fTadashi G. Takaoka    private final HashMap<KeyboardId, SoftReference<LatinKeyboard>> mKeyboardCache =
868b00bc4f3281c229ee830f34a78c0ec287902c3fTadashi G. Takaoka            new HashMap<KeyboardId, SoftReference<LatinKeyboard>>();
87466741d8a78965b8509bf527344f289e50873092Mike LeBeau
888b00bc4f3281c229ee830f34a78c0ec287902c3fTadashi G. Takaoka    private int mMode = MODE_TEXT; /* default value */
89923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    private int mImeOptions;
90353da6d207bed3d32ec38b9ce52e4a136adbf060Brandon Ballinger    private boolean mIsSymbols;
9141feaaadb758a8b31d3e436063b4b5faed104d4dsatok    /** mIsAutoCompletionActive indicates that auto completed word will be input instead of
9241feaaadb758a8b31d3e436063b4b5faed104d4dsatok     * what user actually typed. */
9341feaaadb758a8b31d3e436063b4b5faed104d4dsatok    private boolean mIsAutoCompletionActive;
94507495efd57074994fdc2fda78db9d5345f4a3a8Tadashi G. Takaoka    private boolean mVoiceButtonEnabled;
95507495efd57074994fdc2fda78db9d5345f4a3a8Tadashi G. Takaoka    private boolean mVoiceButtonOnPrimary;
96b19668cfc17ad30afcc3c8c0407d47238ce1a90dAmith Yamasani    private int mSymbolsModeState = SYMBOLS_MODE_STATE_NONE;
97923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project
981508c0e84f0cd93ab6f5d46fea5026e833f299bcKen Wakasa    // Indicates whether or not we have the settings key
993a2896c80475094f751ef447fc9c97028bfc2265Tadashi G. Takaoka    private boolean mHasSettingsKey;
1001508c0e84f0cd93ab6f5d46fea5026e833f299bcKen Wakasa    private static final int SETTINGS_KEY_MODE_AUTO = R.string.settings_key_mode_auto;
101503797ae0e55c74068470d237fb47c4da13ec4fbTadashi G. Takaoka    private static final int SETTINGS_KEY_MODE_ALWAYS_SHOW =
102503797ae0e55c74068470d237fb47c4da13ec4fbTadashi G. Takaoka            R.string.settings_key_mode_always_show;
10317fcd719de9a0ddcf9fd712481b28038419eec4eKen Wakasa    // NOTE: No need to have SETTINGS_KEY_MODE_ALWAYS_HIDE here because it's not being referred to
10417fcd719de9a0ddcf9fd712481b28038419eec4eKen Wakasa    // in the source code now.
10517fcd719de9a0ddcf9fd712481b28038419eec4eKen Wakasa    // Default is SETTINGS_KEY_MODE_AUTO.
10617fcd719de9a0ddcf9fd712481b28038419eec4eKen Wakasa    private static final int DEFAULT_SETTINGS_KEY_MODE = SETTINGS_KEY_MODE_AUTO;
1071508c0e84f0cd93ab6f5d46fea5026e833f299bcKen Wakasa
108979f8690967ff5409fe18f5085858ccdb8e0ccf1satok    private int mLayoutId;
109979f8690967ff5409fe18f5085858ccdb8e0ccf1satok
1108b00bc4f3281c229ee830f34a78c0ec287902c3fTadashi G. Takaoka    public KeyboardSwitcher(LatinIME ims, LanguageSwitcher languageSwitcher) {
1111508c0e84f0cd93ab6f5d46fea5026e833f299bcKen Wakasa        mInputMethodService = ims;
1128b00bc4f3281c229ee830f34a78c0ec287902c3fTadashi G. Takaoka        mLanguageSwitcher = languageSwitcher;
113979f8690967ff5409fe18f5085858ccdb8e0ccf1satok
114979f8690967ff5409fe18f5085858ccdb8e0ccf1satok        final SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(ims);
115979f8690967ff5409fe18f5085858ccdb8e0ccf1satok        mLayoutId = Integer.valueOf(prefs.getString(PREF_KEYBOARD_LAYOUT, DEFAULT_LAYOUT_ID));
116979f8690967ff5409fe18f5085858ccdb8e0ccf1satok        prefs.registerOnSharedPreferenceChangeListener(this);
117979f8690967ff5409fe18f5085858ccdb8e0ccf1satok    }
118979f8690967ff5409fe18f5085858ccdb8e0ccf1satok
119e354a85ef44e13999aaefd735cef7f659090f6e8Ken Wakasa    private void makeSymbolsKeyboardIds() {
1208b00bc4f3281c229ee830f34a78c0ec287902c3fTadashi G. Takaoka        final Locale locale = mLanguageSwitcher.getInputLocale();
1218b00bc4f3281c229ee830f34a78c0ec287902c3fTadashi G. Takaoka        final int orientation = mInputMethodService.getResources().getConfiguration().orientation;
1228b00bc4f3281c229ee830f34a78c0ec287902c3fTadashi G. Takaoka        final int mode = mMode;
1238b00bc4f3281c229ee830f34a78c0ec287902c3fTadashi G. Takaoka        final int colorScheme = getCharColorId();
1248b00bc4f3281c229ee830f34a78c0ec287902c3fTadashi G. Takaoka        final boolean hasSettingsKey = mHasSettingsKey;
1258b00bc4f3281c229ee830f34a78c0ec287902c3fTadashi G. Takaoka        final boolean hasVoiceKey = mVoiceButtonEnabled && !mVoiceButtonOnPrimary;
1268b00bc4f3281c229ee830f34a78c0ec287902c3fTadashi G. Takaoka        final int imeOptions = mImeOptions;
127b0465116bd3786174ccd0034c8a165ebc723b60fTadashi G. Takaoka        mSymbolsId = new KeyboardId(locale, orientation, mode,
1288b00bc4f3281c229ee830f34a78c0ec287902c3fTadashi G. Takaoka                KBD_SYMBOLS, colorScheme, hasSettingsKey, hasVoiceKey, imeOptions, true);
129b0465116bd3786174ccd0034c8a165ebc723b60fTadashi G. Takaoka        mSymbolsShiftedId = new KeyboardId(locale, orientation, mode,
1308b00bc4f3281c229ee830f34a78c0ec287902c3fTadashi G. Takaoka                KBD_SYMBOLS_SHIFT, colorScheme, hasSettingsKey, hasVoiceKey, imeOptions, true);
131353da6d207bed3d32ec38b9ce52e4a136adbf060Brandon Ballinger    }
132353da6d207bed3d32ec38b9ce52e4a136adbf060Brandon Ballinger
133353da6d207bed3d32ec38b9ce52e4a136adbf060Brandon Ballinger    /**
134353da6d207bed3d32ec38b9ce52e4a136adbf060Brandon Ballinger     * Represents the parameters necessary to construct a new LatinKeyboard,
135353da6d207bed3d32ec38b9ce52e4a136adbf060Brandon Ballinger     * which also serve as a unique identifier for each keyboard type.
136353da6d207bed3d32ec38b9ce52e4a136adbf060Brandon Ballinger     */
137b0465116bd3786174ccd0034c8a165ebc723b60fTadashi G. Takaoka    public static class KeyboardId {
13848bc6b158bb2890c1e5cbfe63e93705476ce9673Tadashi G. Takaoka        public final Locale mLocale;
13948bc6b158bb2890c1e5cbfe63e93705476ce9673Tadashi G. Takaoka        public final int mOrientation;
14048bc6b158bb2890c1e5cbfe63e93705476ce9673Tadashi G. Takaoka        public final int mMode;
14148bc6b158bb2890c1e5cbfe63e93705476ce9673Tadashi G. Takaoka        public final int[] mXmlArray;
14248bc6b158bb2890c1e5cbfe63e93705476ce9673Tadashi G. Takaoka        public final int mColorScheme;
1438b00bc4f3281c229ee830f34a78c0ec287902c3fTadashi G. Takaoka        public final boolean mHasSettingsKey;
1448b00bc4f3281c229ee830f34a78c0ec287902c3fTadashi G. Takaoka        public final boolean mHasVoiceKey;
1458b00bc4f3281c229ee830f34a78c0ec287902c3fTadashi G. Takaoka        public final int mImeOptions;
14648bc6b158bb2890c1e5cbfe63e93705476ce9673Tadashi G. Takaoka        public final boolean mEnableShiftLock;
147353da6d207bed3d32ec38b9ce52e4a136adbf060Brandon Ballinger
1487e1f5a2d5a96c74691b3b09fa986efb7161e5a12Tadashi G. Takaoka        private final int mHashCode;
1497e1f5a2d5a96c74691b3b09fa986efb7161e5a12Tadashi G. Takaoka
150b0465116bd3786174ccd0034c8a165ebc723b60fTadashi G. Takaoka        public KeyboardId(Locale locale, int orientation, int mode,
1518b00bc4f3281c229ee830f34a78c0ec287902c3fTadashi G. Takaoka                int[] xmlArray, int colorScheme, boolean hasSettingsKey, boolean hasVoiceKey,
1528b00bc4f3281c229ee830f34a78c0ec287902c3fTadashi G. Takaoka                int imeOptions, boolean enableShiftLock) {
15348bc6b158bb2890c1e5cbfe63e93705476ce9673Tadashi G. Takaoka            this.mLocale = locale;
15448bc6b158bb2890c1e5cbfe63e93705476ce9673Tadashi G. Takaoka            this.mOrientation = orientation;
15548bc6b158bb2890c1e5cbfe63e93705476ce9673Tadashi G. Takaoka            this.mMode = mode;
15648bc6b158bb2890c1e5cbfe63e93705476ce9673Tadashi G. Takaoka            this.mXmlArray = xmlArray;
15748bc6b158bb2890c1e5cbfe63e93705476ce9673Tadashi G. Takaoka            this.mColorScheme = colorScheme;
1588b00bc4f3281c229ee830f34a78c0ec287902c3fTadashi G. Takaoka            this.mHasSettingsKey = hasSettingsKey;
1598b00bc4f3281c229ee830f34a78c0ec287902c3fTadashi G. Takaoka            this.mHasVoiceKey = hasVoiceKey;
1608b00bc4f3281c229ee830f34a78c0ec287902c3fTadashi G. Takaoka            this.mImeOptions = imeOptions;
16148bc6b158bb2890c1e5cbfe63e93705476ce9673Tadashi G. Takaoka            this.mEnableShiftLock = enableShiftLock;
1627e1f5a2d5a96c74691b3b09fa986efb7161e5a12Tadashi G. Takaoka
1637e1f5a2d5a96c74691b3b09fa986efb7161e5a12Tadashi G. Takaoka            this.mHashCode = Arrays.hashCode(new Object[] {
1648b00bc4f3281c229ee830f34a78c0ec287902c3fTadashi G. Takaoka                    locale,
1658b00bc4f3281c229ee830f34a78c0ec287902c3fTadashi G. Takaoka                    orientation,
1668b00bc4f3281c229ee830f34a78c0ec287902c3fTadashi G. Takaoka                    mode,
1678b00bc4f3281c229ee830f34a78c0ec287902c3fTadashi G. Takaoka                    xmlArray,
1688b00bc4f3281c229ee830f34a78c0ec287902c3fTadashi G. Takaoka                    colorScheme,
1698b00bc4f3281c229ee830f34a78c0ec287902c3fTadashi G. Takaoka                    hasSettingsKey,
1708b00bc4f3281c229ee830f34a78c0ec287902c3fTadashi G. Takaoka                    hasVoiceKey,
1718b00bc4f3281c229ee830f34a78c0ec287902c3fTadashi G. Takaoka                    imeOptions,
1728b00bc4f3281c229ee830f34a78c0ec287902c3fTadashi G. Takaoka                    enableShiftLock,
1737e1f5a2d5a96c74691b3b09fa986efb7161e5a12Tadashi G. Takaoka            });
174353da6d207bed3d32ec38b9ce52e4a136adbf060Brandon Ballinger        }
175353da6d207bed3d32ec38b9ce52e4a136adbf060Brandon Ballinger
176b0465116bd3786174ccd0034c8a165ebc723b60fTadashi G. Takaoka        public int getXmlId() {
177b0465116bd3786174ccd0034c8a165ebc723b60fTadashi G. Takaoka            return mXmlArray[mColorScheme];
178b0465116bd3786174ccd0034c8a165ebc723b60fTadashi G. Takaoka        }
179b0465116bd3786174ccd0034c8a165ebc723b60fTadashi G. Takaoka
180b0465116bd3786174ccd0034c8a165ebc723b60fTadashi G. Takaoka        public boolean isAlphabetMode() {
181b0465116bd3786174ccd0034c8a165ebc723b60fTadashi G. Takaoka            return mXmlArray == KBD_QWERTY;
182b0465116bd3786174ccd0034c8a165ebc723b60fTadashi G. Takaoka        }
183b0465116bd3786174ccd0034c8a165ebc723b60fTadashi G. Takaoka
184979f8690967ff5409fe18f5085858ccdb8e0ccf1satok        @Override
185353da6d207bed3d32ec38b9ce52e4a136adbf060Brandon Ballinger        public boolean equals(Object other) {
186353da6d207bed3d32ec38b9ce52e4a136adbf060Brandon Ballinger            return other instanceof KeyboardId && equals((KeyboardId) other);
187353da6d207bed3d32ec38b9ce52e4a136adbf060Brandon Ballinger        }
188353da6d207bed3d32ec38b9ce52e4a136adbf060Brandon Ballinger
189681b676b0aecb30e644f25550018ce2b6cea3e15Tadashi G. Takaoka        private boolean equals(KeyboardId other) {
19048bc6b158bb2890c1e5cbfe63e93705476ce9673Tadashi G. Takaoka            return other.mLocale.equals(this.mLocale)
19148bc6b158bb2890c1e5cbfe63e93705476ce9673Tadashi G. Takaoka                && other.mOrientation == this.mOrientation
19248bc6b158bb2890c1e5cbfe63e93705476ce9673Tadashi G. Takaoka                && other.mMode == this.mMode
19348bc6b158bb2890c1e5cbfe63e93705476ce9673Tadashi G. Takaoka                && other.mXmlArray == this.mXmlArray
19448bc6b158bb2890c1e5cbfe63e93705476ce9673Tadashi G. Takaoka                && other.mColorScheme == this.mColorScheme
1958b00bc4f3281c229ee830f34a78c0ec287902c3fTadashi G. Takaoka                && other.mHasSettingsKey == this.mHasSettingsKey
1968b00bc4f3281c229ee830f34a78c0ec287902c3fTadashi G. Takaoka                && other.mHasVoiceKey == this.mHasVoiceKey
1978b00bc4f3281c229ee830f34a78c0ec287902c3fTadashi G. Takaoka                && other.mImeOptions == this.mImeOptions
19848bc6b158bb2890c1e5cbfe63e93705476ce9673Tadashi G. Takaoka                && other.mEnableShiftLock == this.mEnableShiftLock;
199353da6d207bed3d32ec38b9ce52e4a136adbf060Brandon Ballinger        }
200353da6d207bed3d32ec38b9ce52e4a136adbf060Brandon Ballinger
201979f8690967ff5409fe18f5085858ccdb8e0ccf1satok        @Override
202353da6d207bed3d32ec38b9ce52e4a136adbf060Brandon Ballinger        public int hashCode() {
2037e1f5a2d5a96c74691b3b09fa986efb7161e5a12Tadashi G. Takaoka            return mHashCode;
204923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        }
2058b00bc4f3281c229ee830f34a78c0ec287902c3fTadashi G. Takaoka
2068b00bc4f3281c229ee830f34a78c0ec287902c3fTadashi G. Takaoka        @Override
2078b00bc4f3281c229ee830f34a78c0ec287902c3fTadashi G. Takaoka        public String toString() {
208b0465116bd3786174ccd0034c8a165ebc723b60fTadashi G. Takaoka            return String.format("[%s %s %5s imeOptions=0x%08x xml=0x%08x %s%s%s%s]",
209b0465116bd3786174ccd0034c8a165ebc723b60fTadashi G. Takaoka                    mLocale,
210b0465116bd3786174ccd0034c8a165ebc723b60fTadashi G. Takaoka                    (mOrientation == 1 ? "port" : "land"),
211b0465116bd3786174ccd0034c8a165ebc723b60fTadashi G. Takaoka                    modeName(mMode),
212b0465116bd3786174ccd0034c8a165ebc723b60fTadashi G. Takaoka                    mImeOptions,
213b0465116bd3786174ccd0034c8a165ebc723b60fTadashi G. Takaoka                    mXmlArray[0],
214b0465116bd3786174ccd0034c8a165ebc723b60fTadashi G. Takaoka                    (mColorScheme == CHAR_THEME_COLOR_WHITE ? "white" : "black"),
215b0465116bd3786174ccd0034c8a165ebc723b60fTadashi G. Takaoka                    (mHasSettingsKey ? " hasSettingsKey" : ""),
216b0465116bd3786174ccd0034c8a165ebc723b60fTadashi G. Takaoka                    (mHasVoiceKey ? " hasVoiceKey" : ""),
217b0465116bd3786174ccd0034c8a165ebc723b60fTadashi G. Takaoka                    (mEnableShiftLock ? " enableShiftLock" : ""));
2188b00bc4f3281c229ee830f34a78c0ec287902c3fTadashi G. Takaoka        }
2198b00bc4f3281c229ee830f34a78c0ec287902c3fTadashi G. Takaoka
2208b00bc4f3281c229ee830f34a78c0ec287902c3fTadashi G. Takaoka        private static String modeName(int mode) {
221b0465116bd3786174ccd0034c8a165ebc723b60fTadashi G. Takaoka            switch (mode) {
222b0465116bd3786174ccd0034c8a165ebc723b60fTadashi G. Takaoka            case MODE_TEXT: return "text";
223b0465116bd3786174ccd0034c8a165ebc723b60fTadashi G. Takaoka            case MODE_URL: return "url";
224b0465116bd3786174ccd0034c8a165ebc723b60fTadashi G. Takaoka            case MODE_EMAIL: return "email";
225b0465116bd3786174ccd0034c8a165ebc723b60fTadashi G. Takaoka            case MODE_IM: return "im";
226b0465116bd3786174ccd0034c8a165ebc723b60fTadashi G. Takaoka            case MODE_WEB: return "web";
227b0465116bd3786174ccd0034c8a165ebc723b60fTadashi G. Takaoka            case MODE_PHONE: return "phone";
2288b00bc4f3281c229ee830f34a78c0ec287902c3fTadashi G. Takaoka            }
2298b00bc4f3281c229ee830f34a78c0ec287902c3fTadashi G. Takaoka            return null;
2308b00bc4f3281c229ee830f34a78c0ec287902c3fTadashi G. Takaoka        }
231923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    }
232923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project
2338b00bc4f3281c229ee830f34a78c0ec287902c3fTadashi G. Takaoka    private boolean hasVoiceKey(boolean isSymbols) {
234507495efd57074994fdc2fda78db9d5345f4a3a8Tadashi G. Takaoka        return mVoiceButtonEnabled && (isSymbols != mVoiceButtonOnPrimary);
235466741d8a78965b8509bf527344f289e50873092Mike LeBeau    }
236466741d8a78965b8509bf527344f289e50873092Mike LeBeau
2378b00bc4f3281c229ee830f34a78c0ec287902c3fTadashi G. Takaoka    public void loadKeyboard(int mode, int imeOptions, boolean voiceButtonEnabled,
238507495efd57074994fdc2fda78db9d5345f4a3a8Tadashi G. Takaoka            boolean voiceButtonOnPrimary) {
239e3803800c53cc813e27dd1e7c31bdb4d075f0252Amith Yamasani        mSymbolsModeState = SYMBOLS_MODE_STATE_NONE;
240979f8690967ff5409fe18f5085858ccdb8e0ccf1satok        try {
2418b00bc4f3281c229ee830f34a78c0ec287902c3fTadashi G. Takaoka            loadKeyboardInternal(mode, imeOptions, voiceButtonEnabled, voiceButtonOnPrimary,
242507495efd57074994fdc2fda78db9d5345f4a3a8Tadashi G. Takaoka                    false);
243979f8690967ff5409fe18f5085858ccdb8e0ccf1satok        } catch (RuntimeException e) {
244b0465116bd3786174ccd0034c8a165ebc723b60fTadashi G. Takaoka            Log.w(TAG, e);
245e354a85ef44e13999aaefd735cef7f659090f6e8Ken Wakasa            LatinImeLogger.logOnException(mode + "," + imeOptions, e);
246979f8690967ff5409fe18f5085858ccdb8e0ccf1satok        }
247353da6d207bed3d32ec38b9ce52e4a136adbf060Brandon Ballinger    }
248353da6d207bed3d32ec38b9ce52e4a136adbf060Brandon Ballinger
2498b00bc4f3281c229ee830f34a78c0ec287902c3fTadashi G. Takaoka    private void loadKeyboardInternal(int mode, int imeOptions, boolean voiceButtonEnabled,
250507495efd57074994fdc2fda78db9d5345f4a3a8Tadashi G. Takaoka            boolean voiceButtonOnPrimary, boolean isSymbols) {
2516516d0fdfcbaa4eb809a8a69bd876293043a68a4Amith Yamasani        if (mInputView == null) return;
2528b00bc4f3281c229ee830f34a78c0ec287902c3fTadashi G. Takaoka        mInputView.setPreviewEnabled(mInputMethodService.getPopupOn());
2538b00bc4f3281c229ee830f34a78c0ec287902c3fTadashi G. Takaoka
254923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        mMode = mode;
255923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        mImeOptions = imeOptions;
2568b00bc4f3281c229ee830f34a78c0ec287902c3fTadashi G. Takaoka        mVoiceButtonEnabled = voiceButtonEnabled;
2578b00bc4f3281c229ee830f34a78c0ec287902c3fTadashi G. Takaoka        mVoiceButtonOnPrimary = voiceButtonOnPrimary;
258c5bb4591b67b165f007e29bd9424d319ac3c7c28Brandon Ballinger        mIsSymbols = isSymbols;
2598b00bc4f3281c229ee830f34a78c0ec287902c3fTadashi G. Takaoka        // Update the settings key state because number of enabled IMEs could have been changed
2608b00bc4f3281c229ee830f34a78c0ec287902c3fTadashi G. Takaoka        mHasSettingsKey = getSettingsKeyMode(
2618b00bc4f3281c229ee830f34a78c0ec287902c3fTadashi G. Takaoka                PreferenceManager.getDefaultSharedPreferences(mInputMethodService),
2628b00bc4f3281c229ee830f34a78c0ec287902c3fTadashi G. Takaoka                mInputMethodService);
2638b00bc4f3281c229ee830f34a78c0ec287902c3fTadashi G. Takaoka        makeSymbolsKeyboardIds();
264466741d8a78965b8509bf527344f289e50873092Mike LeBeau
265353da6d207bed3d32ec38b9ce52e4a136adbf060Brandon Ballinger        KeyboardId id = getKeyboardId(mode, imeOptions, isSymbols);
2668b00bc4f3281c229ee830f34a78c0ec287902c3fTadashi G. Takaoka        LatinKeyboard keyboard = getKeyboard(id);
267353da6d207bed3d32ec38b9ce52e4a136adbf060Brandon Ballinger
268353da6d207bed3d32ec38b9ce52e4a136adbf060Brandon Ballinger        if (mode == MODE_PHONE) {
269353da6d207bed3d32ec38b9ce52e4a136adbf060Brandon Ballinger            mInputView.setPhoneKeyboard(keyboard);
270353da6d207bed3d32ec38b9ce52e4a136adbf060Brandon Ballinger        }
271353da6d207bed3d32ec38b9ce52e4a136adbf060Brandon Ballinger
272353da6d207bed3d32ec38b9ce52e4a136adbf060Brandon Ballinger        mCurrentId = id;
273353da6d207bed3d32ec38b9ce52e4a136adbf060Brandon Ballinger        mInputView.setKeyboard(keyboard);
274353da6d207bed3d32ec38b9ce52e4a136adbf060Brandon Ballinger    }
275353da6d207bed3d32ec38b9ce52e4a136adbf060Brandon Ballinger
276353da6d207bed3d32ec38b9ce52e4a136adbf060Brandon Ballinger    private LatinKeyboard getKeyboard(KeyboardId id) {
2778b00bc4f3281c229ee830f34a78c0ec287902c3fTadashi G. Takaoka        final SoftReference<LatinKeyboard> ref = mKeyboardCache.get(id);
278681b676b0aecb30e644f25550018ce2b6cea3e15Tadashi G. Takaoka        LatinKeyboard keyboard = (ref == null) ? null : ref.get();
279681b676b0aecb30e644f25550018ce2b6cea3e15Tadashi G. Takaoka        if (keyboard == null) {
2808b00bc4f3281c229ee830f34a78c0ec287902c3fTadashi G. Takaoka            final Resources res = mInputMethodService.getResources();
2818b00bc4f3281c229ee830f34a78c0ec287902c3fTadashi G. Takaoka            final Configuration conf = res.getConfiguration();
2828b00bc4f3281c229ee830f34a78c0ec287902c3fTadashi G. Takaoka            final Locale saveLocale = conf.locale;
2838b00bc4f3281c229ee830f34a78c0ec287902c3fTadashi G. Takaoka            conf.locale = mLanguageSwitcher.getInputLocale();
28448bc6b158bb2890c1e5cbfe63e93705476ce9673Tadashi G. Takaoka            res.updateConfiguration(conf, null);
2858b00bc4f3281c229ee830f34a78c0ec287902c3fTadashi G. Takaoka
286b0465116bd3786174ccd0034c8a165ebc723b60fTadashi G. Takaoka            final int xml = id.getXmlId();
287b0465116bd3786174ccd0034c8a165ebc723b60fTadashi G. Takaoka            keyboard = new LatinKeyboard(mInputMethodService, id);
2888b00bc4f3281c229ee830f34a78c0ec287902c3fTadashi G. Takaoka            keyboard.setVoiceMode(
2898b00bc4f3281c229ee830f34a78c0ec287902c3fTadashi G. Takaoka                    hasVoiceKey(xml == R.xml.kbd_symbols || xml == R.xml.kbd_symbols_black),
2908b00bc4f3281c229ee830f34a78c0ec287902c3fTadashi G. Takaoka                    mVoiceButtonEnabled);
2918b00bc4f3281c229ee830f34a78c0ec287902c3fTadashi G. Takaoka            keyboard.setLanguageSwitcher(mLanguageSwitcher);
2928b00bc4f3281c229ee830f34a78c0ec287902c3fTadashi G. Takaoka            keyboard.setImeOptions(res, id.mMode, id.mImeOptions);
2938b00bc4f3281c229ee830f34a78c0ec287902c3fTadashi G. Takaoka            keyboard.setColorOfSymbolIcons(isBlackSym(id.mColorScheme));
294358e485b14938fbcb5af5be75aa29f2b73674100Amith Yamasani
295353da6d207bed3d32ec38b9ce52e4a136adbf060Brandon Ballinger            if (id.mEnableShiftLock) {
296353da6d207bed3d32ec38b9ce52e4a136adbf060Brandon Ballinger                keyboard.enableShiftLock();
297353da6d207bed3d32ec38b9ce52e4a136adbf060Brandon Ballinger            }
2988b00bc4f3281c229ee830f34a78c0ec287902c3fTadashi G. Takaoka
2998b00bc4f3281c229ee830f34a78c0ec287902c3fTadashi G. Takaoka            mKeyboardCache.put(id, new SoftReference<LatinKeyboard>(keyboard));
3008b00bc4f3281c229ee830f34a78c0ec287902c3fTadashi G. Takaoka            if (DEBUG)
3018b00bc4f3281c229ee830f34a78c0ec287902c3fTadashi G. Takaoka                Log.d(TAG, "keyboard cache size=" + mKeyboardCache.size() + ": "
3028b00bc4f3281c229ee830f34a78c0ec287902c3fTadashi G. Takaoka                        + ((ref == null) ? "LOAD" : "GCed") + " id=" + id);
30336fcf25833f7c8876cbc8286e0c159b052dc2626Amith Yamasani
30436fcf25833f7c8876cbc8286e0c159b052dc2626Amith Yamasani            conf.locale = saveLocale;
30548bc6b158bb2890c1e5cbfe63e93705476ce9673Tadashi G. Takaoka            res.updateConfiguration(conf, null);
3068b00bc4f3281c229ee830f34a78c0ec287902c3fTadashi G. Takaoka        } else if (DEBUG) {
3078b00bc4f3281c229ee830f34a78c0ec287902c3fTadashi G. Takaoka            Log.d(TAG, "keyboard cache size=" + mKeyboardCache.size() + ": HIT  id=" + id);
308353da6d207bed3d32ec38b9ce52e4a136adbf060Brandon Ballinger        }
3098b00bc4f3281c229ee830f34a78c0ec287902c3fTadashi G. Takaoka
3108b00bc4f3281c229ee830f34a78c0ec287902c3fTadashi G. Takaoka        keyboard.onAutoCompletionStateChanged(mIsAutoCompletionActive);
3118b00bc4f3281c229ee830f34a78c0ec287902c3fTadashi G. Takaoka        keyboard.setShifted(false);
312681b676b0aecb30e644f25550018ce2b6cea3e15Tadashi G. Takaoka        return keyboard;
313353da6d207bed3d32ec38b9ce52e4a136adbf060Brandon Ballinger    }
314353da6d207bed3d32ec38b9ce52e4a136adbf060Brandon Ballinger
315353da6d207bed3d32ec38b9ce52e4a136adbf060Brandon Ballinger    private KeyboardId getKeyboardId(int mode, int imeOptions, boolean isSymbols) {
3168b00bc4f3281c229ee830f34a78c0ec287902c3fTadashi G. Takaoka        final boolean hasVoiceKey = hasVoiceKey(isSymbols);
317e354a85ef44e13999aaefd735cef7f659090f6e8Ken Wakasa        final int charColorId = getCharColorId();
31848bc6b158bb2890c1e5cbfe63e93705476ce9673Tadashi G. Takaoka        final int[] xmlArray;
319e354a85ef44e13999aaefd735cef7f659090f6e8Ken Wakasa        final boolean enableShiftLock;
320e354a85ef44e13999aaefd735cef7f659090f6e8Ken Wakasa
321e354a85ef44e13999aaefd735cef7f659090f6e8Ken Wakasa        if (isSymbols) {
32248bc6b158bb2890c1e5cbfe63e93705476ce9673Tadashi G. Takaoka            xmlArray = mode == MODE_PHONE ? KBD_PHONE_SYMBOLS : KBD_SYMBOLS;
323e354a85ef44e13999aaefd735cef7f659090f6e8Ken Wakasa            enableShiftLock = false;
324e354a85ef44e13999aaefd735cef7f659090f6e8Ken Wakasa        } else {  // QWERTY
32548bc6b158bb2890c1e5cbfe63e93705476ce9673Tadashi G. Takaoka            xmlArray = mode == MODE_PHONE ? KBD_PHONE : KBD_QWERTY;
326e354a85ef44e13999aaefd735cef7f659090f6e8Ken Wakasa            enableShiftLock = mode == MODE_PHONE ? false : true;
327923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        }
3288b00bc4f3281c229ee830f34a78c0ec287902c3fTadashi G. Takaoka        final int orientation = mInputMethodService.getResources().getConfiguration().orientation;
3298b00bc4f3281c229ee830f34a78c0ec287902c3fTadashi G. Takaoka        final Locale locale = mLanguageSwitcher.getInputLocale();
330b0465116bd3786174ccd0034c8a165ebc723b60fTadashi G. Takaoka        return new KeyboardId(locale, orientation, mode, xmlArray,
3318b00bc4f3281c229ee830f34a78c0ec287902c3fTadashi G. Takaoka                charColorId, mHasSettingsKey, hasVoiceKey, imeOptions, enableShiftLock);
332923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    }
333923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project
3343a2896c80475094f751ef447fc9c97028bfc2265Tadashi G. Takaoka    public int getKeyboardMode() {
335923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        return mMode;
336923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    }
3371679432d1c8a8cfe6ff09be0a49792f4af91ab35Tadashi G. Takaoka
3383a2896c80475094f751ef447fc9c97028bfc2265Tadashi G. Takaoka    public boolean isAlphabetMode() {
339b0465116bd3786174ccd0034c8a165ebc723b60fTadashi G. Takaoka        return mCurrentId != null && mCurrentId.isAlphabetMode();
340923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    }
341923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project
3421679432d1c8a8cfe6ff09be0a49792f4af91ab35Tadashi G. Takaoka    public boolean isInputViewShown() {
3431679432d1c8a8cfe6ff09be0a49792f4af91ab35Tadashi G. Takaoka        return mInputView != null && mInputView.isShown();
3441679432d1c8a8cfe6ff09be0a49792f4af91ab35Tadashi G. Takaoka    }
3451679432d1c8a8cfe6ff09be0a49792f4af91ab35Tadashi G. Takaoka
3461679432d1c8a8cfe6ff09be0a49792f4af91ab35Tadashi G. Takaoka    public boolean isKeyboardAvailable() {
3471679432d1c8a8cfe6ff09be0a49792f4af91ab35Tadashi G. Takaoka        return mInputView != null && mInputView.getLatinKeyboard() != null;
3481679432d1c8a8cfe6ff09be0a49792f4af91ab35Tadashi G. Takaoka    }
3491679432d1c8a8cfe6ff09be0a49792f4af91ab35Tadashi G. Takaoka
3501679432d1c8a8cfe6ff09be0a49792f4af91ab35Tadashi G. Takaoka    public void setPreferredLetters(int[] frequencies) {
3511679432d1c8a8cfe6ff09be0a49792f4af91ab35Tadashi G. Takaoka        LatinKeyboard latinKeyboard;
3521679432d1c8a8cfe6ff09be0a49792f4af91ab35Tadashi G. Takaoka        if (mInputView != null && (latinKeyboard = mInputView.getLatinKeyboard()) != null)
3531679432d1c8a8cfe6ff09be0a49792f4af91ab35Tadashi G. Takaoka            latinKeyboard.setPreferredLetters(frequencies);
3541679432d1c8a8cfe6ff09be0a49792f4af91ab35Tadashi G. Takaoka    }
3551679432d1c8a8cfe6ff09be0a49792f4af91ab35Tadashi G. Takaoka
3561679432d1c8a8cfe6ff09be0a49792f4af91ab35Tadashi G. Takaoka    public void keyReleased() {
3571679432d1c8a8cfe6ff09be0a49792f4af91ab35Tadashi G. Takaoka        LatinKeyboard latinKeyboard;
3581679432d1c8a8cfe6ff09be0a49792f4af91ab35Tadashi G. Takaoka        if (mInputView != null && (latinKeyboard = mInputView.getLatinKeyboard()) != null)
3591679432d1c8a8cfe6ff09be0a49792f4af91ab35Tadashi G. Takaoka            latinKeyboard.keyReleased();
3601679432d1c8a8cfe6ff09be0a49792f4af91ab35Tadashi G. Takaoka    }
3611679432d1c8a8cfe6ff09be0a49792f4af91ab35Tadashi G. Takaoka
3621679432d1c8a8cfe6ff09be0a49792f4af91ab35Tadashi G. Takaoka    public boolean isShifted() {
3631679432d1c8a8cfe6ff09be0a49792f4af91ab35Tadashi G. Takaoka        LatinKeyboard latinKeyboard;
3641679432d1c8a8cfe6ff09be0a49792f4af91ab35Tadashi G. Takaoka        return mInputView != null && (latinKeyboard = mInputView.getLatinKeyboard()) != null
3651679432d1c8a8cfe6ff09be0a49792f4af91ab35Tadashi G. Takaoka                && latinKeyboard.isShifted();
3661679432d1c8a8cfe6ff09be0a49792f4af91ab35Tadashi G. Takaoka    }
3671679432d1c8a8cfe6ff09be0a49792f4af91ab35Tadashi G. Takaoka
3681679432d1c8a8cfe6ff09be0a49792f4af91ab35Tadashi G. Takaoka    public boolean isShiftLocked() {
3691679432d1c8a8cfe6ff09be0a49792f4af91ab35Tadashi G. Takaoka        LatinKeyboard latinKeyboard;
3701679432d1c8a8cfe6ff09be0a49792f4af91ab35Tadashi G. Takaoka        return mInputView != null && (latinKeyboard = mInputView.getLatinKeyboard()) != null
3711679432d1c8a8cfe6ff09be0a49792f4af91ab35Tadashi G. Takaoka                && latinKeyboard.isShiftLocked();
3721679432d1c8a8cfe6ff09be0a49792f4af91ab35Tadashi G. Takaoka    }
3731679432d1c8a8cfe6ff09be0a49792f4af91ab35Tadashi G. Takaoka
3743a2896c80475094f751ef447fc9c97028bfc2265Tadashi G. Takaoka    public void setShifted(boolean shifted) {
375276845c7a9ea90fd34289d060873c8e3a7ed342cKen Wakasa        if (mInputView == null) return;
376276845c7a9ea90fd34289d060873c8e3a7ed342cKen Wakasa        LatinKeyboard latinKeyboard = mInputView.getLatinKeyboard();
377276845c7a9ea90fd34289d060873c8e3a7ed342cKen Wakasa        if (latinKeyboard == null) return;
378276845c7a9ea90fd34289d060873c8e3a7ed342cKen Wakasa        if (latinKeyboard.setShifted(shifted)) {
379276845c7a9ea90fd34289d060873c8e3a7ed342cKen Wakasa            mInputView.invalidateAllKeys();
380979f8690967ff5409fe18f5085858ccdb8e0ccf1satok        }
381979f8690967ff5409fe18f5085858ccdb8e0ccf1satok    }
382979f8690967ff5409fe18f5085858ccdb8e0ccf1satok
3833a2896c80475094f751ef447fc9c97028bfc2265Tadashi G. Takaoka    public void setShiftLocked(boolean shiftLocked) {
384276845c7a9ea90fd34289d060873c8e3a7ed342cKen Wakasa        if (mInputView == null) return;
385276845c7a9ea90fd34289d060873c8e3a7ed342cKen Wakasa        mInputView.setShiftLocked(shiftLocked);
386979f8690967ff5409fe18f5085858ccdb8e0ccf1satok    }
387979f8690967ff5409fe18f5085858ccdb8e0ccf1satok
388889691eca1ad991a85fb721deb37ecba6a913762Tadashi G. Takaoka    public void onPressShift() {
389889691eca1ad991a85fb721deb37ecba6a913762Tadashi G. Takaoka        mShiftState.onPress();
390889691eca1ad991a85fb721deb37ecba6a913762Tadashi G. Takaoka    }
391889691eca1ad991a85fb721deb37ecba6a913762Tadashi G. Takaoka
392889691eca1ad991a85fb721deb37ecba6a913762Tadashi G. Takaoka    public void onPressShiftOnShifted() {
393889691eca1ad991a85fb721deb37ecba6a913762Tadashi G. Takaoka        mShiftState.onPressOnShifted();
394889691eca1ad991a85fb721deb37ecba6a913762Tadashi G. Takaoka    }
395889691eca1ad991a85fb721deb37ecba6a913762Tadashi G. Takaoka
396889691eca1ad991a85fb721deb37ecba6a913762Tadashi G. Takaoka    public void onReleaseShift() {
397889691eca1ad991a85fb721deb37ecba6a913762Tadashi G. Takaoka        mShiftState.onRelease();
398889691eca1ad991a85fb721deb37ecba6a913762Tadashi G. Takaoka    }
399889691eca1ad991a85fb721deb37ecba6a913762Tadashi G. Takaoka
400889691eca1ad991a85fb721deb37ecba6a913762Tadashi G. Takaoka    public boolean isShiftMomentary() {
401889691eca1ad991a85fb721deb37ecba6a913762Tadashi G. Takaoka        return mShiftState.isMomentary();
402889691eca1ad991a85fb721deb37ecba6a913762Tadashi G. Takaoka    }
403889691eca1ad991a85fb721deb37ecba6a913762Tadashi G. Takaoka
404889691eca1ad991a85fb721deb37ecba6a913762Tadashi G. Takaoka    public boolean isShiftPressingOnShifted() {
405889691eca1ad991a85fb721deb37ecba6a913762Tadashi G. Takaoka        return mShiftState.isPressingOnShifted();
406889691eca1ad991a85fb721deb37ecba6a913762Tadashi G. Takaoka    }
407889691eca1ad991a85fb721deb37ecba6a913762Tadashi G. Takaoka
408889691eca1ad991a85fb721deb37ecba6a913762Tadashi G. Takaoka    public boolean isShiftIgnoring() {
409889691eca1ad991a85fb721deb37ecba6a913762Tadashi G. Takaoka        return mShiftState.isIgnoring();
410889691eca1ad991a85fb721deb37ecba6a913762Tadashi G. Takaoka    }
411889691eca1ad991a85fb721deb37ecba6a913762Tadashi G. Takaoka
4126c92ee127df50509d364a2b6d428b223d2cbaa6eTadashi G. Takaoka    public void onPressSymbol() {
4136c92ee127df50509d364a2b6d428b223d2cbaa6eTadashi G. Takaoka        mSymbolKeyState.onPress();
4146c92ee127df50509d364a2b6d428b223d2cbaa6eTadashi G. Takaoka    }
4156c92ee127df50509d364a2b6d428b223d2cbaa6eTadashi G. Takaoka
4166c92ee127df50509d364a2b6d428b223d2cbaa6eTadashi G. Takaoka    public void onReleaseSymbol() {
4176c92ee127df50509d364a2b6d428b223d2cbaa6eTadashi G. Takaoka        mSymbolKeyState.onRelease();
4186c92ee127df50509d364a2b6d428b223d2cbaa6eTadashi G. Takaoka    }
4196c92ee127df50509d364a2b6d428b223d2cbaa6eTadashi G. Takaoka
4206c92ee127df50509d364a2b6d428b223d2cbaa6eTadashi G. Takaoka    public boolean isSymbolMomentary() {
4216c92ee127df50509d364a2b6d428b223d2cbaa6eTadashi G. Takaoka        return mSymbolKeyState.isMomentary();
4226c92ee127df50509d364a2b6d428b223d2cbaa6eTadashi G. Takaoka    }
4236c92ee127df50509d364a2b6d428b223d2cbaa6eTadashi G. Takaoka
4246c92ee127df50509d364a2b6d428b223d2cbaa6eTadashi G. Takaoka    public void onOtherKeyPressed() {
425889691eca1ad991a85fb721deb37ecba6a913762Tadashi G. Takaoka        mShiftState.onOtherKeyPressed();
4266c92ee127df50509d364a2b6d428b223d2cbaa6eTadashi G. Takaoka        mSymbolKeyState.onOtherKeyPressed();
4276c92ee127df50509d364a2b6d428b223d2cbaa6eTadashi G. Takaoka    }
4286c92ee127df50509d364a2b6d428b223d2cbaa6eTadashi G. Takaoka
4293a2896c80475094f751ef447fc9c97028bfc2265Tadashi G. Takaoka    public void toggleShift() {
4307e1f5a2d5a96c74691b3b09fa986efb7161e5a12Tadashi G. Takaoka        if (isAlphabetMode())
4317e1f5a2d5a96c74691b3b09fa986efb7161e5a12Tadashi G. Takaoka            return;
4328b00bc4f3281c229ee830f34a78c0ec287902c3fTadashi G. Takaoka        final LatinKeyboard keyboard;
4337e1f5a2d5a96c74691b3b09fa986efb7161e5a12Tadashi G. Takaoka        if (mCurrentId.equals(mSymbolsId) || !mCurrentId.equals(mSymbolsShiftedId)) {
434353da6d207bed3d32ec38b9ce52e4a136adbf060Brandon Ballinger            mCurrentId = mSymbolsShiftedId;
4358b00bc4f3281c229ee830f34a78c0ec287902c3fTadashi G. Takaoka            keyboard = getKeyboard(mCurrentId);
43612659d4c0ce04aaf3d8479e44f9230881b964000Tadashi G. Takaoka            // Symbol shifted keyboard has an ALT key that has a caps lock style indicator. To
43712659d4c0ce04aaf3d8479e44f9230881b964000Tadashi G. Takaoka            // enable the indicator, we need to call enableShiftLock() and setShiftLocked(true).
43812659d4c0ce04aaf3d8479e44f9230881b964000Tadashi G. Takaoka            // Thus we can keep the ALT key's Key.on value true while LatinKey.onRelease() is
43912659d4c0ce04aaf3d8479e44f9230881b964000Tadashi G. Takaoka            // called.
4408b00bc4f3281c229ee830f34a78c0ec287902c3fTadashi G. Takaoka            keyboard.setShiftLocked(true);
4417e1f5a2d5a96c74691b3b09fa986efb7161e5a12Tadashi G. Takaoka        } else {
442353da6d207bed3d32ec38b9ce52e4a136adbf060Brandon Ballinger            mCurrentId = mSymbolsId;
4438b00bc4f3281c229ee830f34a78c0ec287902c3fTadashi G. Takaoka            keyboard = getKeyboard(mCurrentId);
44412659d4c0ce04aaf3d8479e44f9230881b964000Tadashi G. Takaoka            // Symbol keyboard has an ALT key that has a caps lock style indicator. To disable the
44512659d4c0ce04aaf3d8479e44f9230881b964000Tadashi G. Takaoka            // indicator, we need to call enableShiftLock() and setShiftLocked(false).
4468b00bc4f3281c229ee830f34a78c0ec287902c3fTadashi G. Takaoka            keyboard.setShifted(false);
447923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        }
4488b00bc4f3281c229ee830f34a78c0ec287902c3fTadashi G. Takaoka        mInputView.setKeyboard(keyboard);
449923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    }
450923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project
4513a2896c80475094f751ef447fc9c97028bfc2265Tadashi G. Takaoka    public void toggleSymbols() {
4528b00bc4f3281c229ee830f34a78c0ec287902c3fTadashi G. Takaoka        loadKeyboardInternal(mMode, mImeOptions, mVoiceButtonEnabled, mVoiceButtonOnPrimary,
453507495efd57074994fdc2fda78db9d5345f4a3a8Tadashi G. Takaoka                !mIsSymbols);
454e354a85ef44e13999aaefd735cef7f659090f6e8Ken Wakasa        if (mIsSymbols) {
455b19668cfc17ad30afcc3c8c0407d47238ce1a90dAmith Yamasani            mSymbolsModeState = SYMBOLS_MODE_STATE_BEGIN;
456b19668cfc17ad30afcc3c8c0407d47238ce1a90dAmith Yamasani        } else {
457b19668cfc17ad30afcc3c8c0407d47238ce1a90dAmith Yamasani            mSymbolsModeState = SYMBOLS_MODE_STATE_NONE;
458b19668cfc17ad30afcc3c8c0407d47238ce1a90dAmith Yamasani        }
459b19668cfc17ad30afcc3c8c0407d47238ce1a90dAmith Yamasani    }
460b19668cfc17ad30afcc3c8c0407d47238ce1a90dAmith Yamasani
461c8b9afe0378e3f33c3f83271bd1df9678a70c2a2Tadashi G. Takaoka    public boolean hasDistinctMultitouch() {
462c8b9afe0378e3f33c3f83271bd1df9678a70c2a2Tadashi G. Takaoka        return mInputView != null && mInputView.hasDistinctMultitouch();
463c8b9afe0378e3f33c3f83271bd1df9678a70c2a2Tadashi G. Takaoka    }
464c8b9afe0378e3f33c3f83271bd1df9678a70c2a2Tadashi G. Takaoka
465b19668cfc17ad30afcc3c8c0407d47238ce1a90dAmith Yamasani    /**
466b19668cfc17ad30afcc3c8c0407d47238ce1a90dAmith Yamasani     * Updates state machine to figure out when to automatically switch back to alpha mode.
467b19668cfc17ad30afcc3c8c0407d47238ce1a90dAmith Yamasani     * Returns true if the keyboard needs to switch back
468b19668cfc17ad30afcc3c8c0407d47238ce1a90dAmith Yamasani     */
4693a2896c80475094f751ef447fc9c97028bfc2265Tadashi G. Takaoka    public boolean onKey(int key) {
470d67fe0e7583f1be18b35b33b7658e4427f1e3dedAmith Yamasani        // Switch back to alpha mode if user types one or more non-space/enter characters
471d67fe0e7583f1be18b35b33b7658e4427f1e3dedAmith Yamasani        // followed by a space/enter
472b19668cfc17ad30afcc3c8c0407d47238ce1a90dAmith Yamasani        switch (mSymbolsModeState) {
473b19668cfc17ad30afcc3c8c0407d47238ce1a90dAmith Yamasani            case SYMBOLS_MODE_STATE_BEGIN:
474d67fe0e7583f1be18b35b33b7658e4427f1e3dedAmith Yamasani                if (key != LatinIME.KEYCODE_SPACE && key != LatinIME.KEYCODE_ENTER && key > 0) {
475d67fe0e7583f1be18b35b33b7658e4427f1e3dedAmith Yamasani                    mSymbolsModeState = SYMBOLS_MODE_STATE_SYMBOL;
476d67fe0e7583f1be18b35b33b7658e4427f1e3dedAmith Yamasani                }
477b19668cfc17ad30afcc3c8c0407d47238ce1a90dAmith Yamasani                break;
478b19668cfc17ad30afcc3c8c0407d47238ce1a90dAmith Yamasani            case SYMBOLS_MODE_STATE_SYMBOL:
479d67fe0e7583f1be18b35b33b7658e4427f1e3dedAmith Yamasani                if (key == LatinIME.KEYCODE_ENTER || key == LatinIME.KEYCODE_SPACE) return true;
480b19668cfc17ad30afcc3c8c0407d47238ce1a90dAmith Yamasani                break;
481b19668cfc17ad30afcc3c8c0407d47238ce1a90dAmith Yamasani        }
482b19668cfc17ad30afcc3c8c0407d47238ce1a90dAmith Yamasani        return false;
483923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    }
484979f8690967ff5409fe18f5085858ccdb8e0ccf1satok
485979f8690967ff5409fe18f5085858ccdb8e0ccf1satok    public LatinKeyboardView getInputView() {
486979f8690967ff5409fe18f5085858ccdb8e0ccf1satok        return mInputView;
487979f8690967ff5409fe18f5085858ccdb8e0ccf1satok    }
488979f8690967ff5409fe18f5085858ccdb8e0ccf1satok
4898b00bc4f3281c229ee830f34a78c0ec287902c3fTadashi G. Takaoka    public void loadKeyboardView() {
4908b00bc4f3281c229ee830f34a78c0ec287902c3fTadashi G. Takaoka        loadKeyboardViewInternal(mLayoutId, true);
491979f8690967ff5409fe18f5085858ccdb8e0ccf1satok    }
492979f8690967ff5409fe18f5085858ccdb8e0ccf1satok
4938b00bc4f3281c229ee830f34a78c0ec287902c3fTadashi G. Takaoka    private void loadKeyboardViewInternal(int newLayout, boolean forceReset) {
494979f8690967ff5409fe18f5085858ccdb8e0ccf1satok        if (mLayoutId != newLayout || mInputView == null || forceReset) {
495979f8690967ff5409fe18f5085858ccdb8e0ccf1satok            if (mInputView != null) {
496979f8690967ff5409fe18f5085858ccdb8e0ccf1satok                mInputView.closing();
497979f8690967ff5409fe18f5085858ccdb8e0ccf1satok            }
498979f8690967ff5409fe18f5085858ccdb8e0ccf1satok            if (THEMES.length <= newLayout) {
499979f8690967ff5409fe18f5085858ccdb8e0ccf1satok                newLayout = Integer.valueOf(DEFAULT_LAYOUT_ID);
500979f8690967ff5409fe18f5085858ccdb8e0ccf1satok            }
501979f8690967ff5409fe18f5085858ccdb8e0ccf1satok
502979f8690967ff5409fe18f5085858ccdb8e0ccf1satok            LatinIMEUtil.GCUtils.getInstance().reset();
503979f8690967ff5409fe18f5085858ccdb8e0ccf1satok            boolean tryGC = true;
504979f8690967ff5409fe18f5085858ccdb8e0ccf1satok            for (int i = 0; i < LatinIMEUtil.GCUtils.GC_TRY_LOOP_MAX && tryGC; ++i) {
505979f8690967ff5409fe18f5085858ccdb8e0ccf1satok                try {
506979f8690967ff5409fe18f5085858ccdb8e0ccf1satok                    mInputView = (LatinKeyboardView) mInputMethodService.getLayoutInflater(
507979f8690967ff5409fe18f5085858ccdb8e0ccf1satok                            ).inflate(THEMES[newLayout], null);
508979f8690967ff5409fe18f5085858ccdb8e0ccf1satok                    tryGC = false;
509979f8690967ff5409fe18f5085858ccdb8e0ccf1satok                } catch (OutOfMemoryError e) {
510979f8690967ff5409fe18f5085858ccdb8e0ccf1satok                    tryGC = LatinIMEUtil.GCUtils.getInstance().tryGCOrWait(
511979f8690967ff5409fe18f5085858ccdb8e0ccf1satok                            mLayoutId + "," + newLayout, e);
512979f8690967ff5409fe18f5085858ccdb8e0ccf1satok                } catch (InflateException e) {
513979f8690967ff5409fe18f5085858ccdb8e0ccf1satok                    tryGC = LatinIMEUtil.GCUtils.getInstance().tryGCOrWait(
514979f8690967ff5409fe18f5085858ccdb8e0ccf1satok                            mLayoutId + "," + newLayout, e);
515979f8690967ff5409fe18f5085858ccdb8e0ccf1satok                }
516979f8690967ff5409fe18f5085858ccdb8e0ccf1satok            }
517979f8690967ff5409fe18f5085858ccdb8e0ccf1satok            mInputView.setOnKeyboardActionListener(mInputMethodService);
518979f8690967ff5409fe18f5085858ccdb8e0ccf1satok            mLayoutId = newLayout;
519979f8690967ff5409fe18f5085858ccdb8e0ccf1satok        }
520979f8690967ff5409fe18f5085858ccdb8e0ccf1satok        mInputMethodService.mHandler.post(new Runnable() {
521979f8690967ff5409fe18f5085858ccdb8e0ccf1satok            public void run() {
522979f8690967ff5409fe18f5085858ccdb8e0ccf1satok                if (mInputView != null) {
523979f8690967ff5409fe18f5085858ccdb8e0ccf1satok                    mInputMethodService.setInputView(mInputView);
524979f8690967ff5409fe18f5085858ccdb8e0ccf1satok                }
525979f8690967ff5409fe18f5085858ccdb8e0ccf1satok                mInputMethodService.updateInputViewShown();
526979f8690967ff5409fe18f5085858ccdb8e0ccf1satok            }});
527979f8690967ff5409fe18f5085858ccdb8e0ccf1satok    }
528979f8690967ff5409fe18f5085858ccdb8e0ccf1satok
529979f8690967ff5409fe18f5085858ccdb8e0ccf1satok    public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) {
530979f8690967ff5409fe18f5085858ccdb8e0ccf1satok        if (PREF_KEYBOARD_LAYOUT.equals(key)) {
5318b00bc4f3281c229ee830f34a78c0ec287902c3fTadashi G. Takaoka            final int layoutId = Integer.valueOf(
5328b00bc4f3281c229ee830f34a78c0ec287902c3fTadashi G. Takaoka                    sharedPreferences.getString(key, DEFAULT_LAYOUT_ID));
5338b00bc4f3281c229ee830f34a78c0ec287902c3fTadashi G. Takaoka            loadKeyboardViewInternal(layoutId, false);
5341508c0e84f0cd93ab6f5d46fea5026e833f299bcKen Wakasa        } else if (LatinIMESettings.PREF_SETTINGS_KEY.equals(key)) {
5358b00bc4f3281c229ee830f34a78c0ec287902c3fTadashi G. Takaoka            mHasSettingsKey = getSettingsKeyMode(sharedPreferences, mInputMethodService);
5368b00bc4f3281c229ee830f34a78c0ec287902c3fTadashi G. Takaoka            loadKeyboardViewInternal(mLayoutId, true);
537979f8690967ff5409fe18f5085858ccdb8e0ccf1satok        }
538979f8690967ff5409fe18f5085858ccdb8e0ccf1satok    }
539979f8690967ff5409fe18f5085858ccdb8e0ccf1satok
5408b00bc4f3281c229ee830f34a78c0ec287902c3fTadashi G. Takaoka    public boolean isBlackSym() {
5411508c0e84f0cd93ab6f5d46fea5026e833f299bcKen Wakasa        if (mInputView != null && mInputView.getSymbolColorScheme() == 1) {
542979f8690967ff5409fe18f5085858ccdb8e0ccf1satok            return true;
543979f8690967ff5409fe18f5085858ccdb8e0ccf1satok        }
544979f8690967ff5409fe18f5085858ccdb8e0ccf1satok        return false;
545979f8690967ff5409fe18f5085858ccdb8e0ccf1satok    }
546979f8690967ff5409fe18f5085858ccdb8e0ccf1satok
5478b00bc4f3281c229ee830f34a78c0ec287902c3fTadashi G. Takaoka    private boolean isBlackSym(int colorScheme) {
5488b00bc4f3281c229ee830f34a78c0ec287902c3fTadashi G. Takaoka        return colorScheme == CHAR_THEME_COLOR_BLACK;
5498b00bc4f3281c229ee830f34a78c0ec287902c3fTadashi G. Takaoka    }
5508b00bc4f3281c229ee830f34a78c0ec287902c3fTadashi G. Takaoka
5518b00bc4f3281c229ee830f34a78c0ec287902c3fTadashi G. Takaoka    private int getCharColorId() {
552979f8690967ff5409fe18f5085858ccdb8e0ccf1satok        if (isBlackSym()) {
553979f8690967ff5409fe18f5085858ccdb8e0ccf1satok            return CHAR_THEME_COLOR_BLACK;
554979f8690967ff5409fe18f5085858ccdb8e0ccf1satok        } else {
555979f8690967ff5409fe18f5085858ccdb8e0ccf1satok            return CHAR_THEME_COLOR_WHITE;
556979f8690967ff5409fe18f5085858ccdb8e0ccf1satok        }
557979f8690967ff5409fe18f5085858ccdb8e0ccf1satok    }
558979f8690967ff5409fe18f5085858ccdb8e0ccf1satok
55941feaaadb758a8b31d3e436063b4b5faed104d4dsatok    public void onAutoCompletionStateChanged(boolean isAutoCompletion) {
56041feaaadb758a8b31d3e436063b4b5faed104d4dsatok        if (isAutoCompletion != mIsAutoCompletionActive) {
56141feaaadb758a8b31d3e436063b4b5faed104d4dsatok            LatinKeyboardView keyboardView = getInputView();
56241feaaadb758a8b31d3e436063b4b5faed104d4dsatok            mIsAutoCompletionActive = isAutoCompletion;
56341feaaadb758a8b31d3e436063b4b5faed104d4dsatok            keyboardView.invalidateKey(((LatinKeyboard) keyboardView.getKeyboard())
56441feaaadb758a8b31d3e436063b4b5faed104d4dsatok                    .onAutoCompletionStateChanged(isAutoCompletion));
56541feaaadb758a8b31d3e436063b4b5faed104d4dsatok        }
56641feaaadb758a8b31d3e436063b4b5faed104d4dsatok    }
5671508c0e84f0cd93ab6f5d46fea5026e833f299bcKen Wakasa
5688b00bc4f3281c229ee830f34a78c0ec287902c3fTadashi G. Takaoka    private static boolean getSettingsKeyMode(SharedPreferences prefs, Context context) {
5698b00bc4f3281c229ee830f34a78c0ec287902c3fTadashi G. Takaoka        Resources resources = context.getResources();
570503797ae0e55c74068470d237fb47c4da13ec4fbTadashi G. Takaoka        final boolean showSettingsKeyOption = resources.getBoolean(
571503797ae0e55c74068470d237fb47c4da13ec4fbTadashi G. Takaoka                R.bool.config_enable_show_settings_key_option);
57217fcd719de9a0ddcf9fd712481b28038419eec4eKen Wakasa        if (showSettingsKeyOption) {
57317fcd719de9a0ddcf9fd712481b28038419eec4eKen Wakasa            final String settingsKeyMode = prefs.getString(LatinIMESettings.PREF_SETTINGS_KEY,
57417fcd719de9a0ddcf9fd712481b28038419eec4eKen Wakasa                    resources.getString(DEFAULT_SETTINGS_KEY_MODE));
57517fcd719de9a0ddcf9fd712481b28038419eec4eKen Wakasa            // We show the settings key when 1) SETTINGS_KEY_MODE_ALWAYS_SHOW or
57617fcd719de9a0ddcf9fd712481b28038419eec4eKen Wakasa            // 2) SETTINGS_KEY_MODE_AUTO and there are two or more enabled IMEs on the system
57717fcd719de9a0ddcf9fd712481b28038419eec4eKen Wakasa            if (settingsKeyMode.equals(resources.getString(SETTINGS_KEY_MODE_ALWAYS_SHOW))
57817fcd719de9a0ddcf9fd712481b28038419eec4eKen Wakasa                    || (settingsKeyMode.equals(resources.getString(SETTINGS_KEY_MODE_AUTO))
5798b00bc4f3281c229ee830f34a78c0ec287902c3fTadashi G. Takaoka                            && LatinIMEUtil.hasMultipleEnabledIMEs(context))) {
5808b00bc4f3281c229ee830f34a78c0ec287902c3fTadashi G. Takaoka                return true;
58117fcd719de9a0ddcf9fd712481b28038419eec4eKen Wakasa            }
5821508c0e84f0cd93ab6f5d46fea5026e833f299bcKen Wakasa        }
5838b00bc4f3281c229ee830f34a78c0ec287902c3fTadashi G. Takaoka        return false;
5841508c0e84f0cd93ab6f5d46fea5026e833f299bcKen Wakasa    }
585923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project}
586