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