PasswordEntryKeyboardHelper.java revision 8171b5182f5f07d33c9dfdf2dd8f0f6ae9588039
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.ALPHA).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, 0, 0, 162 KeyEvent.FLAG_SOFT_KEYBOARD|KeyEvent.FLAG_KEEP_TOUCH_MODE))); 163 handler.sendMessage(handler.obtainMessage(ViewRoot.DISPATCH_KEY_FROM_IME, 164 new KeyEvent(eventTime, eventTime, KeyEvent.ACTION_UP, keyEventCode, 0, 0, 0, 0, 165 KeyEvent.FLAG_SOFT_KEYBOARD|KeyEvent.FLAG_KEEP_TOUCH_MODE))); 166 } 167 168 public void onKey(int primaryCode, int[] keyCodes) { 169 if (primaryCode == Keyboard.KEYCODE_DELETE) { 170 handleBackspace(); 171 } else if (primaryCode == Keyboard.KEYCODE_SHIFT) { 172 handleShift(); 173 } else if (primaryCode == Keyboard.KEYCODE_CANCEL) { 174 handleClose(); 175 return; 176 } else if (primaryCode == Keyboard.KEYCODE_MODE_CHANGE && mKeyboardView != null) { 177 handleModeChange(); 178 } else { 179 handleCharacter(primaryCode, keyCodes); 180 // Switch back to old keyboard if we're not in capslock mode 181 if (mKeyboardState == KEYBOARD_STATE_SHIFTED) { 182 // skip to the unlocked state 183 mKeyboardState = KEYBOARD_STATE_CAPSLOCK; 184 handleShift(); 185 } 186 } 187 } 188 189 /** 190 * Sets and enables vibrate pattern. If id is 0 (or can't be loaded), vibrate is disabled. 191 * @param id resource id for array containing vibrate pattern. 192 */ 193 public void setVibratePattern(int id) { 194 int[] tmpArray = null; 195 try { 196 tmpArray = mContext.getResources().getIntArray(id); 197 } catch (Resources.NotFoundException e) { 198 if (id != 0) { 199 Log.e(TAG, "Vibrate pattern missing", e); 200 } 201 } 202 if (tmpArray == null) { 203 mVibratePattern = null; 204 return; 205 } 206 mVibratePattern = new long[tmpArray.length]; 207 for (int i = 0; i < tmpArray.length; i++) { 208 mVibratePattern[i] = tmpArray[i]; 209 } 210 } 211 212 private void handleModeChange() { 213 final Keyboard current = mKeyboardView.getKeyboard(); 214 Keyboard next = null; 215 if (current == mQwertyKeyboard || current == mQwertyKeyboardShifted) { 216 next = mSymbolsKeyboard; 217 } else if (current == mSymbolsKeyboard || current == mSymbolsKeyboardShifted) { 218 next = mQwertyKeyboard; 219 } 220 if (next != null) { 221 mKeyboardView.setKeyboard(next); 222 mKeyboardState = KEYBOARD_STATE_NORMAL; 223 } 224 } 225 226 private void handleBackspace() { 227 sendDownUpKeyEvents(KeyEvent.KEYCODE_DEL); 228 } 229 230 private void handleShift() { 231 if (mKeyboardView == null) { 232 return; 233 } 234 Keyboard current = mKeyboardView.getKeyboard(); 235 PasswordEntryKeyboard next = null; 236 final boolean isAlphaMode = current == mQwertyKeyboard 237 || current == mQwertyKeyboardShifted; 238 if (mKeyboardState == KEYBOARD_STATE_NORMAL) { 239 mKeyboardState = isAlphaMode ? KEYBOARD_STATE_SHIFTED : KEYBOARD_STATE_CAPSLOCK; 240 next = isAlphaMode ? mQwertyKeyboardShifted : mSymbolsKeyboardShifted; 241 } else if (mKeyboardState == KEYBOARD_STATE_SHIFTED) { 242 mKeyboardState = KEYBOARD_STATE_CAPSLOCK; 243 next = isAlphaMode ? mQwertyKeyboardShifted : mSymbolsKeyboardShifted; 244 } else if (mKeyboardState == KEYBOARD_STATE_CAPSLOCK) { 245 mKeyboardState = KEYBOARD_STATE_NORMAL; 246 next = isAlphaMode ? mQwertyKeyboard : mSymbolsKeyboard; 247 } 248 if (next != null) { 249 if (next != current) { 250 mKeyboardView.setKeyboard(next); 251 } 252 next.setShiftLocked(mKeyboardState == KEYBOARD_STATE_CAPSLOCK); 253 mKeyboardView.setShifted(mKeyboardState != KEYBOARD_STATE_NORMAL); 254 } 255 } 256 257 private void handleCharacter(int primaryCode, int[] keyCodes) { 258 // Maybe turn off shift if not in capslock mode. 259 if (mKeyboardView.isShifted() && primaryCode != ' ' && primaryCode != '\n') { 260 primaryCode = Character.toUpperCase(primaryCode); 261 } 262 sendKeyEventsToTarget(primaryCode); 263 } 264 265 private void handleClose() { 266 267 } 268 269 public void onPress(int primaryCode) { 270 if (mVibratePattern != null) { 271 mVibrator.vibrate(mVibratePattern, -1); 272 } 273 } 274 275 public void onRelease(int primaryCode) { 276 277 } 278 279 public void onText(CharSequence text) { 280 281 } 282 283 public void swipeDown() { 284 285 } 286 287 public void swipeLeft() { 288 289 } 290 291 public void swipeRight() { 292 293 } 294 295 public void swipeUp() { 296 297 } 298}; 299