PasswordEntryKeyboardHelper.java revision 6dd005b48138708762bfade0081d031a2a4a3822
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.ViewRootImpl; 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 final boolean enablePreview = false; // TODO: grab from configuration 132 mKeyboardView.setPreviewEnabled(visiblePassword && enablePreview); 133 break; 134 case KEYBOARD_MODE_NUMERIC: 135 mKeyboardView.setKeyboard(mNumericKeyboard); 136 mKeyboardState = KEYBOARD_STATE_NORMAL; 137 mKeyboardView.setPreviewEnabled(false); // never show popup for numeric keypad 138 break; 139 } 140 mKeyboardMode = mode; 141 } 142 143 private void sendKeyEventsToTarget(int character) { 144 Handler handler = mTargetView.getHandler(); 145 KeyEvent[] events = KeyCharacterMap.load(KeyCharacterMap.VIRTUAL_KEYBOARD).getEvents( 146 new char[] { (char) character }); 147 if (events != null) { 148 final int N = events.length; 149 for (int i=0; i<N; i++) { 150 KeyEvent event = events[i]; 151 event = KeyEvent.changeFlags(event, event.getFlags() 152 | KeyEvent.FLAG_SOFT_KEYBOARD | KeyEvent.FLAG_KEEP_TOUCH_MODE); 153 handler.sendMessage(handler.obtainMessage(ViewRootImpl.DISPATCH_KEY, event)); 154 } 155 } 156 } 157 158 public void sendDownUpKeyEvents(int keyEventCode) { 159 long eventTime = SystemClock.uptimeMillis(); 160 Handler handler = mTargetView.getHandler(); 161 handler.sendMessage(handler.obtainMessage(ViewRootImpl.DISPATCH_KEY_FROM_IME, 162 new KeyEvent(eventTime, eventTime, KeyEvent.ACTION_DOWN, keyEventCode, 0, 0, 163 KeyCharacterMap.VIRTUAL_KEYBOARD, 0, 164 KeyEvent.FLAG_SOFT_KEYBOARD|KeyEvent.FLAG_KEEP_TOUCH_MODE))); 165 handler.sendMessage(handler.obtainMessage(ViewRootImpl.DISPATCH_KEY_FROM_IME, 166 new KeyEvent(eventTime, eventTime, KeyEvent.ACTION_UP, keyEventCode, 0, 0, 167 KeyCharacterMap.VIRTUAL_KEYBOARD, 0, 168 KeyEvent.FLAG_SOFT_KEYBOARD|KeyEvent.FLAG_KEEP_TOUCH_MODE))); 169 } 170 171 public void onKey(int primaryCode, int[] keyCodes) { 172 if (primaryCode == Keyboard.KEYCODE_DELETE) { 173 handleBackspace(); 174 } else if (primaryCode == Keyboard.KEYCODE_SHIFT) { 175 handleShift(); 176 } else if (primaryCode == Keyboard.KEYCODE_CANCEL) { 177 handleClose(); 178 return; 179 } else if (primaryCode == Keyboard.KEYCODE_MODE_CHANGE && mKeyboardView != null) { 180 handleModeChange(); 181 } else { 182 handleCharacter(primaryCode, keyCodes); 183 // Switch back to old keyboard if we're not in capslock mode 184 if (mKeyboardState == KEYBOARD_STATE_SHIFTED) { 185 // skip to the unlocked state 186 mKeyboardState = KEYBOARD_STATE_CAPSLOCK; 187 handleShift(); 188 } 189 } 190 } 191 192 /** 193 * Sets and enables vibrate pattern. If id is 0 (or can't be loaded), vibrate is disabled. 194 * @param id resource id for array containing vibrate pattern. 195 */ 196 public void setVibratePattern(int id) { 197 int[] tmpArray = null; 198 try { 199 tmpArray = mContext.getResources().getIntArray(id); 200 } catch (Resources.NotFoundException e) { 201 if (id != 0) { 202 Log.e(TAG, "Vibrate pattern missing", e); 203 } 204 } 205 if (tmpArray == null) { 206 mVibratePattern = null; 207 return; 208 } 209 mVibratePattern = new long[tmpArray.length]; 210 for (int i = 0; i < tmpArray.length; i++) { 211 mVibratePattern[i] = tmpArray[i]; 212 } 213 } 214 215 private void handleModeChange() { 216 final Keyboard current = mKeyboardView.getKeyboard(); 217 Keyboard next = null; 218 if (current == mQwertyKeyboard || current == mQwertyKeyboardShifted) { 219 next = mSymbolsKeyboard; 220 } else if (current == mSymbolsKeyboard || current == mSymbolsKeyboardShifted) { 221 next = mQwertyKeyboard; 222 } 223 if (next != null) { 224 mKeyboardView.setKeyboard(next); 225 mKeyboardState = KEYBOARD_STATE_NORMAL; 226 } 227 } 228 229 private void handleBackspace() { 230 sendDownUpKeyEvents(KeyEvent.KEYCODE_DEL); 231 } 232 233 private void handleShift() { 234 if (mKeyboardView == null) { 235 return; 236 } 237 Keyboard current = mKeyboardView.getKeyboard(); 238 PasswordEntryKeyboard next = null; 239 final boolean isAlphaMode = current == mQwertyKeyboard 240 || current == mQwertyKeyboardShifted; 241 if (mKeyboardState == KEYBOARD_STATE_NORMAL) { 242 mKeyboardState = isAlphaMode ? KEYBOARD_STATE_SHIFTED : KEYBOARD_STATE_CAPSLOCK; 243 next = isAlphaMode ? mQwertyKeyboardShifted : mSymbolsKeyboardShifted; 244 } else if (mKeyboardState == KEYBOARD_STATE_SHIFTED) { 245 mKeyboardState = KEYBOARD_STATE_CAPSLOCK; 246 next = isAlphaMode ? mQwertyKeyboardShifted : mSymbolsKeyboardShifted; 247 } else if (mKeyboardState == KEYBOARD_STATE_CAPSLOCK) { 248 mKeyboardState = KEYBOARD_STATE_NORMAL; 249 next = isAlphaMode ? mQwertyKeyboard : mSymbolsKeyboard; 250 } 251 if (next != null) { 252 if (next != current) { 253 mKeyboardView.setKeyboard(next); 254 } 255 next.setShiftLocked(mKeyboardState == KEYBOARD_STATE_CAPSLOCK); 256 mKeyboardView.setShifted(mKeyboardState != KEYBOARD_STATE_NORMAL); 257 } 258 } 259 260 private void handleCharacter(int primaryCode, int[] keyCodes) { 261 // Maybe turn off shift if not in capslock mode. 262 if (mKeyboardView.isShifted() && primaryCode != ' ' && primaryCode != '\n') { 263 primaryCode = Character.toUpperCase(primaryCode); 264 } 265 sendKeyEventsToTarget(primaryCode); 266 } 267 268 private void handleClose() { 269 270 } 271 272 public void onPress(int primaryCode) { 273 if (mVibratePattern != null) { 274 mVibrator.vibrate(mVibratePattern, -1); 275 } 276 } 277 278 public void onRelease(int primaryCode) { 279 280 } 281 282 public void onText(CharSequence text) { 283 284 } 285 286 public void swipeDown() { 287 288 } 289 290 public void swipeLeft() { 291 292 } 293 294 public void swipeRight() { 295 296 } 297 298 public void swipeUp() { 299 300 } 301}; 302