PasswordEntryKeyboardHelper.java revision 6b53e8daa69cba1a2a5a7c95a01e37ce9c53226c
1/* 2 * Copyright (C) 2010 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.internal.widget; 18 19import android.content.Context; 20import android.content.res.Resources; 21import android.inputmethodservice.Keyboard; 22import android.inputmethodservice.KeyboardView; 23import android.inputmethodservice.KeyboardView.OnKeyboardActionListener; 24import android.os.Handler; 25import android.os.SystemClock; 26import android.os.Vibrator; 27import android.provider.Settings; 28import android.util.Log; 29import android.view.KeyCharacterMap; 30import android.view.KeyEvent; 31import android.view.View; 32import android.view.ViewRoot; 33import com.android.internal.R; 34 35public class PasswordEntryKeyboardHelper implements OnKeyboardActionListener { 36 37 public static final int KEYBOARD_MODE_ALPHA = 0; 38 public static final int KEYBOARD_MODE_NUMERIC = 1; 39 private static final int KEYBOARD_STATE_NORMAL = 0; 40 private static final int KEYBOARD_STATE_SHIFTED = 1; 41 private static final int KEYBOARD_STATE_CAPSLOCK = 2; 42 private static final String TAG = "PasswordEntryKeyboardHelper"; 43 private int mKeyboardMode = KEYBOARD_MODE_ALPHA; 44 private int mKeyboardState = KEYBOARD_STATE_NORMAL; 45 private PasswordEntryKeyboard mQwertyKeyboard; 46 private PasswordEntryKeyboard mQwertyKeyboardShifted; 47 private PasswordEntryKeyboard mSymbolsKeyboard; 48 private PasswordEntryKeyboard mSymbolsKeyboardShifted; 49 private PasswordEntryKeyboard mNumericKeyboard; 50 private Context mContext; 51 private View mTargetView; 52 private KeyboardView mKeyboardView; 53 private long[] mVibratePattern; 54 private Vibrator mVibrator; 55 56 public PasswordEntryKeyboardHelper(Context context, KeyboardView keyboardView, View targetView) { 57 this(context, keyboardView, targetView, true); 58 } 59 60 public PasswordEntryKeyboardHelper(Context context, KeyboardView keyboardView, View targetView, 61 boolean useFullScreenWidth) { 62 mContext = context; 63 mTargetView = targetView; 64 mKeyboardView = keyboardView; 65 if (useFullScreenWidth || mKeyboardView.getLayoutParams().width == -1) { 66 createKeyboards(); 67 } else { 68 createKeyboardsWithSpecificSize(mKeyboardView.getLayoutParams().width, 69 mKeyboardView.getLayoutParams().height); 70 } 71 mKeyboardView.setOnKeyboardActionListener(this); 72 mVibrator = new Vibrator(); 73 } 74 75 public boolean isAlpha() { 76 return mKeyboardMode == KEYBOARD_MODE_ALPHA; 77 } 78 79 private void createKeyboardsWithSpecificSize(int viewWidth, int viewHeight) { 80 mNumericKeyboard = new PasswordEntryKeyboard(mContext, R.xml.password_kbd_numeric, 81 viewWidth, viewHeight); 82 mQwertyKeyboard = new PasswordEntryKeyboard(mContext, 83 R.xml.password_kbd_qwerty, R.id.mode_normal, viewWidth, viewHeight); 84 mQwertyKeyboard.enableShiftLock(); 85 86 mQwertyKeyboardShifted = new PasswordEntryKeyboard(mContext, 87 R.xml.password_kbd_qwerty_shifted, 88 R.id.mode_normal, viewWidth, viewHeight); 89 mQwertyKeyboardShifted.enableShiftLock(); 90 mQwertyKeyboardShifted.setShifted(true); // always shifted. 91 92 mSymbolsKeyboard = new PasswordEntryKeyboard(mContext, R.xml.password_kbd_symbols, 93 viewWidth, viewHeight); 94 mSymbolsKeyboard.enableShiftLock(); 95 96 mSymbolsKeyboardShifted = new PasswordEntryKeyboard(mContext, 97 R.xml.password_kbd_symbols_shift, viewWidth, viewHeight); 98 mSymbolsKeyboardShifted.enableShiftLock(); 99 mSymbolsKeyboardShifted.setShifted(true); // always shifted 100 } 101 102 private void createKeyboards() { 103 mNumericKeyboard = new PasswordEntryKeyboard(mContext, R.xml.password_kbd_numeric); 104 mQwertyKeyboard = new PasswordEntryKeyboard(mContext, 105 R.xml.password_kbd_qwerty, R.id.mode_normal); 106 mQwertyKeyboard.enableShiftLock(); 107 108 mQwertyKeyboardShifted = new PasswordEntryKeyboard(mContext, 109 R.xml.password_kbd_qwerty_shifted, 110 R.id.mode_normal); 111 mQwertyKeyboardShifted.enableShiftLock(); 112 mQwertyKeyboardShifted.setShifted(true); // always shifted. 113 114 mSymbolsKeyboard = new PasswordEntryKeyboard(mContext, R.xml.password_kbd_symbols); 115 mSymbolsKeyboard.enableShiftLock(); 116 117 mSymbolsKeyboardShifted = new PasswordEntryKeyboard(mContext, 118 R.xml.password_kbd_symbols_shift); 119 mSymbolsKeyboardShifted.enableShiftLock(); 120 mSymbolsKeyboardShifted.setShifted(true); // always shifted 121 } 122 123 public void setKeyboardMode(int mode) { 124 switch (mode) { 125 case KEYBOARD_MODE_ALPHA: 126 mKeyboardView.setKeyboard(mQwertyKeyboard); 127 mKeyboardState = KEYBOARD_STATE_NORMAL; 128 final boolean visiblePassword = Settings.System.getInt( 129 mContext.getContentResolver(), 130 Settings.System.TEXT_SHOW_PASSWORD, 1) != 0; 131 mKeyboardView.setPreviewEnabled(visiblePassword); 132 break; 133 case KEYBOARD_MODE_NUMERIC: 134 mKeyboardView.setKeyboard(mNumericKeyboard); 135 mKeyboardState = KEYBOARD_STATE_NORMAL; 136 mKeyboardView.setPreviewEnabled(false); // never show popup for numeric keypad 137 break; 138 } 139 mKeyboardMode = mode; 140 } 141 142 private void sendKeyEventsToTarget(int character) { 143 Handler handler = mTargetView.getHandler(); 144 KeyEvent[] events = KeyCharacterMap.load(KeyCharacterMap.VIRTUAL_KEYBOARD).getEvents( 145 new char[] { (char) character }); 146 if (events != null) { 147 final int N = events.length; 148 for (int i=0; i<N; i++) { 149 KeyEvent event = events[i]; 150 event = KeyEvent.changeFlags(event, event.getFlags() 151 | KeyEvent.FLAG_SOFT_KEYBOARD | KeyEvent.FLAG_KEEP_TOUCH_MODE); 152 handler.sendMessage(handler.obtainMessage(ViewRoot.DISPATCH_KEY, event)); 153 } 154 } 155 } 156 157 public void sendDownUpKeyEvents(int keyEventCode) { 158 long eventTime = SystemClock.uptimeMillis(); 159 Handler handler = mTargetView.getHandler(); 160 handler.sendMessage(handler.obtainMessage(ViewRoot.DISPATCH_KEY_FROM_IME, 161 new KeyEvent(eventTime, eventTime, KeyEvent.ACTION_DOWN, keyEventCode, 0, 0, 162 KeyCharacterMap.VIRTUAL_KEYBOARD, 0, 163 KeyEvent.FLAG_SOFT_KEYBOARD|KeyEvent.FLAG_KEEP_TOUCH_MODE))); 164 handler.sendMessage(handler.obtainMessage(ViewRoot.DISPATCH_KEY_FROM_IME, 165 new KeyEvent(eventTime, eventTime, KeyEvent.ACTION_UP, keyEventCode, 0, 0, 166 KeyCharacterMap.VIRTUAL_KEYBOARD, 0, 167 KeyEvent.FLAG_SOFT_KEYBOARD|KeyEvent.FLAG_KEEP_TOUCH_MODE))); 168 } 169 170 public void onKey(int primaryCode, int[] keyCodes) { 171 if (primaryCode == Keyboard.KEYCODE_DELETE) { 172 handleBackspace(); 173 } else if (primaryCode == Keyboard.KEYCODE_SHIFT) { 174 handleShift(); 175 } else if (primaryCode == Keyboard.KEYCODE_CANCEL) { 176 handleClose(); 177 return; 178 } else if (primaryCode == Keyboard.KEYCODE_MODE_CHANGE && mKeyboardView != null) { 179 handleModeChange(); 180 } else { 181 handleCharacter(primaryCode, keyCodes); 182 // Switch back to old keyboard if we're not in capslock mode 183 if (mKeyboardState == KEYBOARD_STATE_SHIFTED) { 184 // skip to the unlocked state 185 mKeyboardState = KEYBOARD_STATE_CAPSLOCK; 186 handleShift(); 187 } 188 } 189 } 190 191 /** 192 * Sets and enables vibrate pattern. If id is 0 (or can't be loaded), vibrate is disabled. 193 * @param id resource id for array containing vibrate pattern. 194 */ 195 public void setVibratePattern(int id) { 196 int[] tmpArray = null; 197 try { 198 tmpArray = mContext.getResources().getIntArray(id); 199 } catch (Resources.NotFoundException e) { 200 if (id != 0) { 201 Log.e(TAG, "Vibrate pattern missing", e); 202 } 203 } 204 if (tmpArray == null) { 205 mVibratePattern = null; 206 return; 207 } 208 mVibratePattern = new long[tmpArray.length]; 209 for (int i = 0; i < tmpArray.length; i++) { 210 mVibratePattern[i] = tmpArray[i]; 211 } 212 } 213 214 private void handleModeChange() { 215 final Keyboard current = mKeyboardView.getKeyboard(); 216 Keyboard next = null; 217 if (current == mQwertyKeyboard || current == mQwertyKeyboardShifted) { 218 next = mSymbolsKeyboard; 219 } else if (current == mSymbolsKeyboard || current == mSymbolsKeyboardShifted) { 220 next = mQwertyKeyboard; 221 } 222 if (next != null) { 223 mKeyboardView.setKeyboard(next); 224 mKeyboardState = KEYBOARD_STATE_NORMAL; 225 } 226 } 227 228 private void handleBackspace() { 229 sendDownUpKeyEvents(KeyEvent.KEYCODE_DEL); 230 } 231 232 private void handleShift() { 233 if (mKeyboardView == null) { 234 return; 235 } 236 Keyboard current = mKeyboardView.getKeyboard(); 237 PasswordEntryKeyboard next = null; 238 final boolean isAlphaMode = current == mQwertyKeyboard 239 || current == mQwertyKeyboardShifted; 240 if (mKeyboardState == KEYBOARD_STATE_NORMAL) { 241 mKeyboardState = isAlphaMode ? KEYBOARD_STATE_SHIFTED : KEYBOARD_STATE_CAPSLOCK; 242 next = isAlphaMode ? mQwertyKeyboardShifted : mSymbolsKeyboardShifted; 243 } else if (mKeyboardState == KEYBOARD_STATE_SHIFTED) { 244 mKeyboardState = KEYBOARD_STATE_CAPSLOCK; 245 next = isAlphaMode ? mQwertyKeyboardShifted : mSymbolsKeyboardShifted; 246 } else if (mKeyboardState == KEYBOARD_STATE_CAPSLOCK) { 247 mKeyboardState = KEYBOARD_STATE_NORMAL; 248 next = isAlphaMode ? mQwertyKeyboard : mSymbolsKeyboard; 249 } 250 if (next != null) { 251 if (next != current) { 252 mKeyboardView.setKeyboard(next); 253 } 254 next.setShiftLocked(mKeyboardState == KEYBOARD_STATE_CAPSLOCK); 255 mKeyboardView.setShifted(mKeyboardState != KEYBOARD_STATE_NORMAL); 256 } 257 } 258 259 private void handleCharacter(int primaryCode, int[] keyCodes) { 260 // Maybe turn off shift if not in capslock mode. 261 if (mKeyboardView.isShifted() && primaryCode != ' ' && primaryCode != '\n') { 262 primaryCode = Character.toUpperCase(primaryCode); 263 } 264 sendKeyEventsToTarget(primaryCode); 265 } 266 267 private void handleClose() { 268 269 } 270 271 public void onPress(int primaryCode) { 272 if (mVibratePattern != null) { 273 mVibrator.vibrate(mVibratePattern, -1); 274 } 275 } 276 277 public void onRelease(int primaryCode) { 278 279 } 280 281 public void onText(CharSequence text) { 282 283 } 284 285 public void swipeDown() { 286 287 } 288 289 public void swipeLeft() { 290 291 } 292 293 public void swipeRight() { 294 295 } 296 297 public void swipeUp() { 298 299 } 300}; 301