PasswordEntryKeyboardHelper.java revision 281a80da143a977046e5b9f65afc85c7fb0b6d25
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 mContext = context; 58 mTargetView = targetView; 59 mKeyboardView = keyboardView; 60 createKeyboards(); 61 mKeyboardView.setOnKeyboardActionListener(this); 62 mVibrator = new Vibrator(); 63 } 64 65 public boolean isAlpha() { 66 return mKeyboardMode == KEYBOARD_MODE_ALPHA; 67 } 68 69 private void createKeyboards() { 70 mNumericKeyboard = new PasswordEntryKeyboard(mContext, R.xml.password_kbd_numeric); 71 mQwertyKeyboard = new PasswordEntryKeyboard(mContext, 72 R.xml.password_kbd_qwerty, R.id.mode_normal); 73 mQwertyKeyboard.enableShiftLock(); 74 75 mQwertyKeyboardShifted = new PasswordEntryKeyboard(mContext, 76 R.xml.password_kbd_qwerty_shifted, 77 R.id.mode_normal); 78 mQwertyKeyboardShifted.enableShiftLock(); 79 mQwertyKeyboardShifted.setShifted(true); // always shifted. 80 81 mSymbolsKeyboard = new PasswordEntryKeyboard(mContext, R.xml.password_kbd_symbols); 82 mSymbolsKeyboard.enableShiftLock(); 83 84 mSymbolsKeyboardShifted = new PasswordEntryKeyboard(mContext, 85 R.xml.password_kbd_symbols_shift); 86 mSymbolsKeyboardShifted.enableShiftLock(); 87 mSymbolsKeyboardShifted.setShifted(true); // always shifted 88 } 89 90 public void setKeyboardMode(int mode) { 91 switch (mode) { 92 case KEYBOARD_MODE_ALPHA: 93 mKeyboardView.setKeyboard(mQwertyKeyboard); 94 mKeyboardState = KEYBOARD_STATE_NORMAL; 95 final boolean visiblePassword = Settings.System.getInt( 96 mContext.getContentResolver(), 97 Settings.System.TEXT_SHOW_PASSWORD, 1) != 0; 98 mKeyboardView.setPreviewEnabled(visiblePassword); 99 break; 100 case KEYBOARD_MODE_NUMERIC: 101 mKeyboardView.setKeyboard(mNumericKeyboard); 102 mKeyboardState = KEYBOARD_STATE_NORMAL; 103 mKeyboardView.setPreviewEnabled(false); // never show popup for numeric keypad 104 break; 105 } 106 mKeyboardMode = mode; 107 } 108 109 private void sendKeyEventsToTarget(int keyEventCode) { 110 Handler handler = mTargetView.getHandler(); 111 KeyEvent[] events = KeyCharacterMap.load(KeyCharacterMap.ALPHA).getEvents( 112 new char[] { (char) keyEventCode }); 113 if (events != null) { 114 for (KeyEvent event : events) { 115 handler.sendMessage(handler.obtainMessage(ViewRoot.DISPATCH_KEY, event)); 116 } 117 } 118 } 119 120 public void sendDownUpKeyEvents(int keyEventCode) { 121 long eventTime = SystemClock.uptimeMillis(); 122 Handler handler = mTargetView.getHandler(); 123 handler.sendMessage(handler.obtainMessage(ViewRoot.DISPATCH_KEY_FROM_IME, 124 new KeyEvent(eventTime, eventTime, KeyEvent.ACTION_DOWN, keyEventCode, 0, 0, 0, 0, 125 KeyEvent.FLAG_SOFT_KEYBOARD|KeyEvent.FLAG_KEEP_TOUCH_MODE))); 126 handler.sendMessage(handler.obtainMessage(ViewRoot.DISPATCH_KEY_FROM_IME, 127 new KeyEvent(eventTime, eventTime, KeyEvent.ACTION_UP, keyEventCode, 0, 0, 0, 0, 128 KeyEvent.FLAG_SOFT_KEYBOARD|KeyEvent.FLAG_KEEP_TOUCH_MODE))); 129 } 130 131 public void onKey(int primaryCode, int[] keyCodes) { 132 if (primaryCode == Keyboard.KEYCODE_DELETE) { 133 handleBackspace(); 134 } else if (primaryCode == Keyboard.KEYCODE_SHIFT) { 135 handleShift(); 136 } else if (primaryCode == Keyboard.KEYCODE_CANCEL) { 137 handleClose(); 138 return; 139 } else if (primaryCode == Keyboard.KEYCODE_MODE_CHANGE && mKeyboardView != null) { 140 handleModeChange(); 141 } else { 142 handleCharacter(primaryCode, keyCodes); 143 // Switch back to old keyboard if we're not in capslock mode 144 if (mKeyboardState == KEYBOARD_STATE_SHIFTED) { 145 // skip to the unlocked state 146 mKeyboardState = KEYBOARD_STATE_CAPSLOCK; 147 handleShift(); 148 } 149 } 150 } 151 152 /** 153 * Sets and enables vibrate pattern. If id is 0 (or can't be loaded), vibrate is disabled. 154 * @param id resource id for array containing vibrate pattern. 155 */ 156 public void setVibratePattern(int id) { 157 int[] tmpArray = null; 158 try { 159 tmpArray = mContext.getResources().getIntArray(id); 160 } catch (Resources.NotFoundException e) { 161 if (id != 0) { 162 Log.e(TAG, "Vibrate pattern missing", e); 163 } 164 } 165 if (tmpArray == null) { 166 mVibratePattern = null; 167 return; 168 } 169 mVibratePattern = new long[tmpArray.length]; 170 for (int i = 0; i < tmpArray.length; i++) { 171 mVibratePattern[i] = tmpArray[i]; 172 } 173 } 174 175 private void handleModeChange() { 176 final Keyboard current = mKeyboardView.getKeyboard(); 177 Keyboard next = null; 178 if (current == mQwertyKeyboard || current == mQwertyKeyboardShifted) { 179 next = mSymbolsKeyboard; 180 } else if (current == mSymbolsKeyboard || current == mSymbolsKeyboardShifted) { 181 next = mQwertyKeyboard; 182 } 183 if (next != null) { 184 mKeyboardView.setKeyboard(next); 185 mKeyboardState = KEYBOARD_STATE_NORMAL; 186 } 187 } 188 189 private void handleBackspace() { 190 sendDownUpKeyEvents(KeyEvent.KEYCODE_DEL); 191 } 192 193 private void handleShift() { 194 if (mKeyboardView == null) { 195 return; 196 } 197 Keyboard current = mKeyboardView.getKeyboard(); 198 PasswordEntryKeyboard next = null; 199 final boolean isAlphaMode = current == mQwertyKeyboard 200 || current == mQwertyKeyboardShifted; 201 if (mKeyboardState == KEYBOARD_STATE_NORMAL) { 202 mKeyboardState = isAlphaMode ? KEYBOARD_STATE_SHIFTED : KEYBOARD_STATE_CAPSLOCK; 203 next = isAlphaMode ? mQwertyKeyboardShifted : mSymbolsKeyboardShifted; 204 } else if (mKeyboardState == KEYBOARD_STATE_SHIFTED) { 205 mKeyboardState = KEYBOARD_STATE_CAPSLOCK; 206 next = isAlphaMode ? mQwertyKeyboardShifted : mSymbolsKeyboardShifted; 207 } else if (mKeyboardState == KEYBOARD_STATE_CAPSLOCK) { 208 mKeyboardState = KEYBOARD_STATE_NORMAL; 209 next = isAlphaMode ? mQwertyKeyboard : mSymbolsKeyboard; 210 } 211 if (next != null) { 212 if (next != current) { 213 mKeyboardView.setKeyboard(next); 214 } 215 next.setShiftLocked(mKeyboardState == KEYBOARD_STATE_CAPSLOCK); 216 mKeyboardView.setShifted(mKeyboardState != KEYBOARD_STATE_NORMAL); 217 } 218 } 219 220 private void handleCharacter(int primaryCode, int[] keyCodes) { 221 // Maybe turn off shift if not in capslock mode. 222 if (mKeyboardView.isShifted() && primaryCode != ' ' && primaryCode != '\n') { 223 primaryCode = Character.toUpperCase(primaryCode); 224 } 225 sendKeyEventsToTarget(primaryCode); 226 } 227 228 private void handleClose() { 229 230 } 231 232 public void onPress(int primaryCode) { 233 if (mVibratePattern != null) { 234 mVibrator.vibrate(mVibratePattern, -1); 235 } 236 } 237 238 public void onRelease(int primaryCode) { 239 240 } 241 242 public void onText(CharSequence text) { 243 244 } 245 246 public void swipeDown() { 247 248 } 249 250 public void swipeLeft() { 251 252 } 253 254 public void swipeRight() { 255 256 } 257 258 public void swipeUp() { 259 260 } 261}; 262