KeyboardSwitcher.java revision b19668cfc17ad30afcc3c8c0407d47238ce1a90d
1/*
2 * Copyright (C) 2008 Google Inc.
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License"); you may not
5 * use this file except in compliance with the License. You may obtain a copy of
6 * 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, WITHOUT
12 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
13 * License for the specific language governing permissions and limitations under
14 * the License.
15 */
16
17package com.android.inputmethod.latin;
18
19import java.util.HashMap;
20import java.util.Map;
21
22public class KeyboardSwitcher {
23
24    public static final int MODE_TEXT = 1;
25    public static final int MODE_SYMBOLS = 2;
26    public static final int MODE_PHONE = 3;
27    public static final int MODE_URL = 4;
28    public static final int MODE_EMAIL = 5;
29    public static final int MODE_IM = 6;
30
31    public static final int MODE_TEXT_QWERTY = 0;
32    public static final int MODE_TEXT_ALPHA = 1;
33    public static final int MODE_TEXT_COUNT = 2;
34
35    public static final int KEYBOARDMODE_NORMAL = R.id.mode_normal;
36    public static final int KEYBOARDMODE_URL = R.id.mode_url;
37    public static final int KEYBOARDMODE_EMAIL = R.id.mode_email;
38    public static final int KEYBOARDMODE_IM = R.id.mode_im;
39
40    private static final int SYMBOLS_MODE_STATE_NONE = 0;
41    private static final int SYMBOLS_MODE_STATE_BEGIN = 1;
42    private static final int SYMBOLS_MODE_STATE_SYMBOL = 2;
43
44    LatinKeyboardView mInputView;
45    LatinIME mContext;
46
47    private KeyboardId mSymbolsId;
48    private KeyboardId mSymbolsShiftedId;
49
50    private KeyboardId mCurrentId;
51    private Map<KeyboardId, LatinKeyboard> mKeyboards;
52
53    private int mMode;
54    private int mImeOptions;
55    private int mTextMode = MODE_TEXT_QWERTY;
56    private boolean mIsSymbols;
57    private int mSymbolsModeState = SYMBOLS_MODE_STATE_NONE;
58
59    private int mLastDisplayWidth;
60
61    KeyboardSwitcher(LatinIME context) {
62        mContext = context;
63        mKeyboards = new HashMap<KeyboardId, LatinKeyboard>();
64        mSymbolsId = new KeyboardId(R.xml.kbd_symbols);
65        mSymbolsShiftedId = new KeyboardId(R.xml.kbd_symbols_shift);
66    }
67
68    void setInputView(LatinKeyboardView inputView) {
69        mInputView = inputView;
70    }
71
72    void makeKeyboards() {
73        // Configuration change is coming after the keyboard gets recreated. So don't rely on that.
74        // If keyboards have already been made, check if we have a screen width change and
75        // create the keyboard layouts again at the correct orientation
76        int displayWidth = mContext.getMaxWidth();
77        if (displayWidth == mLastDisplayWidth) return;
78        mLastDisplayWidth = displayWidth;
79        mKeyboards.clear();
80        mSymbolsId = new KeyboardId(R.xml.kbd_symbols);
81        mSymbolsShiftedId = new KeyboardId(R.xml.kbd_symbols_shift);
82    }
83
84    /**
85     * Represents the parameters necessary to construct a new LatinKeyboard,
86     * which also serve as a unique identifier for each keyboard type.
87     */
88    private static class KeyboardId {
89        public int mXml;
90        public int mMode;
91        public boolean mEnableShiftLock;
92
93        public KeyboardId(int xml, int mode, boolean enableShiftLock) {
94            this.mXml = xml;
95            this.mMode = mode;
96            this.mEnableShiftLock = enableShiftLock;
97        }
98
99        public KeyboardId(int xml) {
100            this(xml, 0, false);
101        }
102
103        public boolean equals(Object other) {
104            return other instanceof KeyboardId && equals((KeyboardId) other);
105        }
106
107        public boolean equals(KeyboardId other) {
108            return other.mXml == this.mXml && other.mMode == this.mMode;
109        }
110
111        public int hashCode() {
112            return (mXml + 1) * (mMode + 1) * (mEnableShiftLock ? 2 : 1);
113        }
114    }
115
116    void setKeyboardMode(int mode, int imeOptions) {
117        setKeyboardMode(mode, imeOptions, false);
118    }
119
120    void setKeyboardMode(int mode, int imeOptions, boolean isSymbols) {
121        mMode = mode;
122        mImeOptions = imeOptions;
123        mIsSymbols = isSymbols;
124        mInputView.setPreviewEnabled(true);
125        KeyboardId id = getKeyboardId(mode, imeOptions, isSymbols);
126        LatinKeyboard keyboard = getKeyboard(id);
127
128        if (mode == MODE_PHONE) {
129            mInputView.setPhoneKeyboard(keyboard);
130            mInputView.setPreviewEnabled(false);
131        }
132
133        mCurrentId = id;
134        mInputView.setKeyboard(keyboard);
135        keyboard.setShifted(false);
136        keyboard.setShiftLocked(keyboard.isShiftLocked());
137        keyboard.setImeOptions(mContext.getResources(), mMode, imeOptions);
138
139    }
140
141    private LatinKeyboard getKeyboard(KeyboardId id) {
142        if (!mKeyboards.containsKey(id)) {
143            LatinKeyboard keyboard = new LatinKeyboard(
144                mContext, id.mXml, id.mMode);
145            if (id.mEnableShiftLock) {
146                keyboard.enableShiftLock();
147            }
148            mKeyboards.put(id, keyboard);
149        }
150        return mKeyboards.get(id);
151    }
152
153    private KeyboardId getKeyboardId(int mode, int imeOptions, boolean isSymbols) {
154        if (isSymbols) {
155            return (mode == MODE_PHONE)
156                ? new KeyboardId(R.xml.kbd_phone_symbols) : new KeyboardId(R.xml.kbd_symbols);
157        }
158
159        switch (mode) {
160            case MODE_TEXT:
161                if (mTextMode == MODE_TEXT_QWERTY) {
162                    return new KeyboardId(R.xml.kbd_qwerty, KEYBOARDMODE_NORMAL, true);
163                } else if (mTextMode == MODE_TEXT_ALPHA) {
164                    return new KeyboardId(R.xml.kbd_alpha, KEYBOARDMODE_NORMAL, true);
165                }
166                break;
167            case MODE_SYMBOLS:
168                return new KeyboardId(R.xml.kbd_symbols);
169            case MODE_PHONE:
170                return new KeyboardId(R.xml.kbd_phone);
171            case MODE_URL:
172                return new KeyboardId(R.xml.kbd_qwerty, KEYBOARDMODE_URL, true);
173            case MODE_EMAIL:
174                return new KeyboardId(R.xml.kbd_qwerty, KEYBOARDMODE_EMAIL, true);
175            case MODE_IM:
176                return new KeyboardId(R.xml.kbd_qwerty, KEYBOARDMODE_IM, true);
177        }
178        return null;
179    }
180
181    int getKeyboardMode() {
182        return mMode;
183    }
184
185    boolean isTextMode() {
186        return mMode == MODE_TEXT;
187    }
188
189    int getTextMode() {
190        return mTextMode;
191    }
192
193    void setTextMode(int position) {
194        if (position < MODE_TEXT_COUNT && position >= 0) {
195            mTextMode = position;
196        }
197        if (isTextMode()) {
198            setKeyboardMode(MODE_TEXT, mImeOptions);
199        }
200    }
201
202    int getTextModeCount() {
203        return MODE_TEXT_COUNT;
204    }
205
206    boolean isAlphabetMode() {
207        KeyboardId current = mCurrentId;
208        return current.mMode == KEYBOARDMODE_NORMAL
209            || current.mMode == KEYBOARDMODE_URL
210            || current.mMode == KEYBOARDMODE_EMAIL
211            || current.mMode == KEYBOARDMODE_IM;
212    }
213
214    void toggleShift() {
215        if (mCurrentId.equals(mSymbolsId)) {
216            LatinKeyboard symbolsKeyboard = getKeyboard(mSymbolsId);
217            LatinKeyboard symbolsShiftedKeyboard = getKeyboard(mSymbolsShiftedId);
218            symbolsKeyboard.setShifted(true);
219            mCurrentId = mSymbolsShiftedId;
220            mInputView.setKeyboard(symbolsShiftedKeyboard);
221            symbolsShiftedKeyboard.setShifted(true);
222            symbolsShiftedKeyboard.setImeOptions(mContext.getResources(), mMode, mImeOptions);
223        } else if (mCurrentId.equals(mSymbolsShiftedId)) {
224            LatinKeyboard symbolsKeyboard = getKeyboard(mSymbolsId);
225            LatinKeyboard symbolsShiftedKeyboard = getKeyboard(mSymbolsShiftedId);
226            symbolsShiftedKeyboard.setShifted(false);
227            mCurrentId = mSymbolsId;
228            mInputView.setKeyboard(getKeyboard(mSymbolsId));
229            symbolsKeyboard.setShifted(false);
230            symbolsKeyboard.setImeOptions(mContext.getResources(), mMode, mImeOptions);
231        }
232    }
233
234    void toggleSymbols() {
235        setKeyboardMode(mMode, mImeOptions, !mIsSymbols);
236        if (mIsSymbols) {
237            mSymbolsModeState = SYMBOLS_MODE_STATE_BEGIN;
238        } else {
239            mSymbolsModeState = SYMBOLS_MODE_STATE_NONE;
240        }
241    }
242
243    /**
244     * Updates state machine to figure out when to automatically switch back to alpha mode.
245     * Returns true if the keyboard needs to switch back
246     */
247    boolean onKey(int key) {
248        // Switch back to alpha mode if user types one or more non-space characters followed by
249        // a space.
250        switch (mSymbolsModeState) {
251            case SYMBOLS_MODE_STATE_BEGIN:
252                if (key != ' ' && key > 0) mSymbolsModeState = SYMBOLS_MODE_STATE_SYMBOL;
253                break;
254            case SYMBOLS_MODE_STATE_SYMBOL:
255                if (key == ' ') return true;
256                break;
257        }
258        return false;
259    }
260}
261