blob: b2c9dc53da393f33272f2298d6b55f3d36c6d1d1 [file] [log] [blame]
Jim Miller0b319702010-02-05 18:51:59 -08001/*
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;
Jim Miller281a80d2010-02-18 19:54:22 -080020import android.content.res.Resources;
Jim Miller0b319702010-02-05 18:51:59 -080021import android.inputmethodservice.Keyboard;
22import android.inputmethodservice.KeyboardView;
23import android.inputmethodservice.KeyboardView.OnKeyboardActionListener;
Jim Miller0b319702010-02-05 18:51:59 -080024import android.os.SystemClock;
Jim Miller280b6022010-02-09 19:05:02 -080025import android.provider.Settings;
Jim Miller281a80d2010-02-18 19:54:22 -080026import android.util.Log;
Jim Milleraef555b2011-10-12 16:41:30 -070027import android.view.HapticFeedbackConstants;
Jim Miller0b319702010-02-05 18:51:59 -080028import android.view.KeyCharacterMap;
29import android.view.KeyEvent;
30import android.view.View;
Jim Miller79a02b12011-07-29 18:07:32 -070031import android.view.ViewGroup;
Jim Miller3af630c2012-09-26 14:29:18 -070032import android.view.ViewGroup.LayoutParams;
Dianne Hackborn6dd005b2011-07-18 13:22:50 -070033import android.view.ViewRootImpl;
Jim Miller0b319702010-02-05 18:51:59 -080034import com.android.internal.R;
35
36public class PasswordEntryKeyboardHelper implements OnKeyboardActionListener {
37
38 public static final int KEYBOARD_MODE_ALPHA = 0;
39 public static final int KEYBOARD_MODE_NUMERIC = 1;
40 private static final int KEYBOARD_STATE_NORMAL = 0;
41 private static final int KEYBOARD_STATE_SHIFTED = 1;
42 private static final int KEYBOARD_STATE_CAPSLOCK = 2;
Jim Miller281a80d2010-02-18 19:54:22 -080043 private static final String TAG = "PasswordEntryKeyboardHelper";
Jim Miller0b319702010-02-05 18:51:59 -080044 private int mKeyboardMode = KEYBOARD_MODE_ALPHA;
45 private int mKeyboardState = KEYBOARD_STATE_NORMAL;
46 private PasswordEntryKeyboard mQwertyKeyboard;
47 private PasswordEntryKeyboard mQwertyKeyboardShifted;
48 private PasswordEntryKeyboard mSymbolsKeyboard;
49 private PasswordEntryKeyboard mSymbolsKeyboardShifted;
50 private PasswordEntryKeyboard mNumericKeyboard;
Ben Komalo51ea88a2011-10-03 10:53:26 -070051 private final Context mContext;
52 private final View mTargetView;
53 private final KeyboardView mKeyboardView;
Jim Miller281a80d2010-02-18 19:54:22 -080054 private long[] mVibratePattern;
Jim Milleraef555b2011-10-12 16:41:30 -070055 private boolean mEnableHaptics = false;
Jim Miller0b319702010-02-05 18:51:59 -080056
Jim Miller3af630c2012-09-26 14:29:18 -070057 private static final int NUMERIC = 0;
58 private static final int QWERTY = 1;
59 private static final int QWERTY_SHIFTED = 2;
60 private static final int SYMBOLS = 3;
61 private static final int SYMBOLS_SHIFTED = 4;
62
63 int mLayouts[] = new int[] {
64 R.xml.password_kbd_numeric,
65 R.xml.password_kbd_qwerty,
66 R.xml.password_kbd_qwerty_shifted,
67 R.xml.password_kbd_symbols,
68 R.xml.password_kbd_symbols_shift
69 };
70
71 private boolean mUsingScreenWidth;
72
Jim Miller0b319702010-02-05 18:51:59 -080073 public PasswordEntryKeyboardHelper(Context context, KeyboardView keyboardView, View targetView) {
Jim Miller3af630c2012-09-26 14:29:18 -070074 this(context, keyboardView, targetView, true, null);
Jae Yong Sung8171b512010-08-05 10:44:27 -070075 }
76
77 public PasswordEntryKeyboardHelper(Context context, KeyboardView keyboardView, View targetView,
78 boolean useFullScreenWidth) {
Jim Miller3af630c2012-09-26 14:29:18 -070079 this(context, keyboardView, targetView, useFullScreenWidth, null);
80 }
81
82 public PasswordEntryKeyboardHelper(Context context, KeyboardView keyboardView, View targetView,
83 boolean useFullScreenWidth, int layouts[]) {
Jim Miller0b319702010-02-05 18:51:59 -080084 mContext = context;
85 mTargetView = targetView;
86 mKeyboardView = keyboardView;
Jim Miller0b319702010-02-05 18:51:59 -080087 mKeyboardView.setOnKeyboardActionListener(this);
Jim Miller3af630c2012-09-26 14:29:18 -070088 mUsingScreenWidth = useFullScreenWidth;
89 if (layouts != null) {
90 if (layouts.length != mLayouts.length) {
91 throw new RuntimeException("Wrong number of layouts");
92 }
93 for (int i = 0; i < mLayouts.length; i++) {
94 mLayouts[i] = layouts[i];
95 }
96 }
97 createKeyboards();
98 }
99
100 public void createKeyboards() {
101 LayoutParams lp = mKeyboardView.getLayoutParams();
102 if (mUsingScreenWidth || lp.width == ViewGroup.LayoutParams.MATCH_PARENT) {
103 createKeyboardsWithDefaultWidth();
104 } else {
105 createKeyboardsWithSpecificSize(lp.width, lp.height);
106 }
Jim Milleraef555b2011-10-12 16:41:30 -0700107 }
108
109 public void setEnableHaptics(boolean enabled) {
110 mEnableHaptics = enabled;
Jim Miller0b319702010-02-05 18:51:59 -0800111 }
112
113 public boolean isAlpha() {
114 return mKeyboardMode == KEYBOARD_MODE_ALPHA;
115 }
116
Jim Miller3af630c2012-09-26 14:29:18 -0700117 private void createKeyboardsWithSpecificSize(int width, int height) {
118 mNumericKeyboard = new PasswordEntryKeyboard(mContext, mLayouts[NUMERIC], width, height);
119 mQwertyKeyboard = new PasswordEntryKeyboard(mContext, mLayouts[QWERTY], R.id.mode_normal,
120 width, height);
Jae Yong Sung8171b512010-08-05 10:44:27 -0700121 mQwertyKeyboard.enableShiftLock();
122
Jim Miller3af630c2012-09-26 14:29:18 -0700123 mQwertyKeyboardShifted = new PasswordEntryKeyboard(mContext, mLayouts[QWERTY_SHIFTED],
124 R.id.mode_normal, width, height);
Jae Yong Sung8171b512010-08-05 10:44:27 -0700125 mQwertyKeyboardShifted.enableShiftLock();
126 mQwertyKeyboardShifted.setShifted(true); // always shifted.
127
Jim Miller3af630c2012-09-26 14:29:18 -0700128 mSymbolsKeyboard = new PasswordEntryKeyboard(mContext, mLayouts[SYMBOLS], width, height);
Jae Yong Sung8171b512010-08-05 10:44:27 -0700129 mSymbolsKeyboard.enableShiftLock();
130
Jim Miller3af630c2012-09-26 14:29:18 -0700131 mSymbolsKeyboardShifted = new PasswordEntryKeyboard(mContext, mLayouts[SYMBOLS_SHIFTED],
132 width, height);
Jae Yong Sung8171b512010-08-05 10:44:27 -0700133 mSymbolsKeyboardShifted.enableShiftLock();
134 mSymbolsKeyboardShifted.setShifted(true); // always shifted
135 }
136
Jim Miller3af630c2012-09-26 14:29:18 -0700137 private void createKeyboardsWithDefaultWidth() {
138 mNumericKeyboard = new PasswordEntryKeyboard(mContext, mLayouts[NUMERIC]);
139 mQwertyKeyboard = new PasswordEntryKeyboard(mContext, mLayouts[QWERTY], R.id.mode_normal);
Jim Miller0b319702010-02-05 18:51:59 -0800140 mQwertyKeyboard.enableShiftLock();
141
Jim Miller3af630c2012-09-26 14:29:18 -0700142 mQwertyKeyboardShifted = new PasswordEntryKeyboard(mContext, mLayouts[QWERTY_SHIFTED],
Jim Miller0b319702010-02-05 18:51:59 -0800143 R.id.mode_normal);
144 mQwertyKeyboardShifted.enableShiftLock();
145 mQwertyKeyboardShifted.setShifted(true); // always shifted.
146
Jim Miller3af630c2012-09-26 14:29:18 -0700147 mSymbolsKeyboard = new PasswordEntryKeyboard(mContext, mLayouts[SYMBOLS]);
Jim Miller0b319702010-02-05 18:51:59 -0800148 mSymbolsKeyboard.enableShiftLock();
149
Jim Miller3af630c2012-09-26 14:29:18 -0700150 mSymbolsKeyboardShifted = new PasswordEntryKeyboard(mContext, mLayouts[SYMBOLS_SHIFTED]);
Jim Miller0b319702010-02-05 18:51:59 -0800151 mSymbolsKeyboardShifted.enableShiftLock();
152 mSymbolsKeyboardShifted.setShifted(true); // always shifted
153 }
154
155 public void setKeyboardMode(int mode) {
156 switch (mode) {
157 case KEYBOARD_MODE_ALPHA:
158 mKeyboardView.setKeyboard(mQwertyKeyboard);
159 mKeyboardState = KEYBOARD_STATE_NORMAL;
Jim Miller280b6022010-02-09 19:05:02 -0800160 final boolean visiblePassword = Settings.System.getInt(
161 mContext.getContentResolver(),
162 Settings.System.TEXT_SHOW_PASSWORD, 1) != 0;
Jim Miller7dd879a2011-01-23 16:18:01 -0800163 final boolean enablePreview = false; // TODO: grab from configuration
164 mKeyboardView.setPreviewEnabled(visiblePassword && enablePreview);
Jim Miller0b319702010-02-05 18:51:59 -0800165 break;
166 case KEYBOARD_MODE_NUMERIC:
167 mKeyboardView.setKeyboard(mNumericKeyboard);
168 mKeyboardState = KEYBOARD_STATE_NORMAL;
Jim Miller280b6022010-02-09 19:05:02 -0800169 mKeyboardView.setPreviewEnabled(false); // never show popup for numeric keypad
Jim Miller0b319702010-02-05 18:51:59 -0800170 break;
171 }
172 mKeyboardMode = mode;
173 }
174
Joe Onorato16537752010-03-17 22:19:51 -0700175 private void sendKeyEventsToTarget(int character) {
Jeff Browna175a5b2012-02-15 19:18:31 -0800176 ViewRootImpl viewRootImpl = mTargetView.getViewRootImpl();
Jeff Brown6b53e8d2010-11-10 16:03:06 -0800177 KeyEvent[] events = KeyCharacterMap.load(KeyCharacterMap.VIRTUAL_KEYBOARD).getEvents(
Joe Onorato16537752010-03-17 22:19:51 -0700178 new char[] { (char) character });
Jim Miller0b319702010-02-05 18:51:59 -0800179 if (events != null) {
Joe Onorato16537752010-03-17 22:19:51 -0700180 final int N = events.length;
181 for (int i=0; i<N; i++) {
182 KeyEvent event = events[i];
183 event = KeyEvent.changeFlags(event, event.getFlags()
184 | KeyEvent.FLAG_SOFT_KEYBOARD | KeyEvent.FLAG_KEEP_TOUCH_MODE);
keunyoung30f420f2013-08-02 14:23:10 -0700185 viewRootImpl.dispatchInputEvent(event);
Jim Miller0b319702010-02-05 18:51:59 -0800186 }
187 }
188 }
189
190 public void sendDownUpKeyEvents(int keyEventCode) {
191 long eventTime = SystemClock.uptimeMillis();
Jeff Browna175a5b2012-02-15 19:18:31 -0800192 ViewRootImpl viewRootImpl = mTargetView.getViewRootImpl();
193 viewRootImpl.dispatchKeyFromIme(
Jeff Brown6b53e8d2010-11-10 16:03:06 -0800194 new KeyEvent(eventTime, eventTime, KeyEvent.ACTION_DOWN, keyEventCode, 0, 0,
195 KeyCharacterMap.VIRTUAL_KEYBOARD, 0,
Jeff Browna175a5b2012-02-15 19:18:31 -0800196 KeyEvent.FLAG_SOFT_KEYBOARD|KeyEvent.FLAG_KEEP_TOUCH_MODE));
197 viewRootImpl.dispatchKeyFromIme(
Jeff Brown6b53e8d2010-11-10 16:03:06 -0800198 new KeyEvent(eventTime, eventTime, KeyEvent.ACTION_UP, keyEventCode, 0, 0,
199 KeyCharacterMap.VIRTUAL_KEYBOARD, 0,
Jeff Browna175a5b2012-02-15 19:18:31 -0800200 KeyEvent.FLAG_SOFT_KEYBOARD|KeyEvent.FLAG_KEEP_TOUCH_MODE));
Jim Miller0b319702010-02-05 18:51:59 -0800201 }
202
203 public void onKey(int primaryCode, int[] keyCodes) {
Jim Miller0b319702010-02-05 18:51:59 -0800204 if (primaryCode == Keyboard.KEYCODE_DELETE) {
205 handleBackspace();
206 } else if (primaryCode == Keyboard.KEYCODE_SHIFT) {
207 handleShift();
208 } else if (primaryCode == Keyboard.KEYCODE_CANCEL) {
209 handleClose();
210 return;
211 } else if (primaryCode == Keyboard.KEYCODE_MODE_CHANGE && mKeyboardView != null) {
212 handleModeChange();
213 } else {
214 handleCharacter(primaryCode, keyCodes);
215 // Switch back to old keyboard if we're not in capslock mode
216 if (mKeyboardState == KEYBOARD_STATE_SHIFTED) {
217 // skip to the unlocked state
218 mKeyboardState = KEYBOARD_STATE_CAPSLOCK;
219 handleShift();
220 }
221 }
222 }
223
Jim Miller281a80d2010-02-18 19:54:22 -0800224 /**
225 * Sets and enables vibrate pattern. If id is 0 (or can't be loaded), vibrate is disabled.
226 * @param id resource id for array containing vibrate pattern.
227 */
228 public void setVibratePattern(int id) {
229 int[] tmpArray = null;
230 try {
231 tmpArray = mContext.getResources().getIntArray(id);
232 } catch (Resources.NotFoundException e) {
233 if (id != 0) {
234 Log.e(TAG, "Vibrate pattern missing", e);
235 }
236 }
237 if (tmpArray == null) {
238 mVibratePattern = null;
239 return;
240 }
241 mVibratePattern = new long[tmpArray.length];
242 for (int i = 0; i < tmpArray.length; i++) {
243 mVibratePattern[i] = tmpArray[i];
244 }
245 }
246
Jim Miller0b319702010-02-05 18:51:59 -0800247 private void handleModeChange() {
248 final Keyboard current = mKeyboardView.getKeyboard();
249 Keyboard next = null;
250 if (current == mQwertyKeyboard || current == mQwertyKeyboardShifted) {
251 next = mSymbolsKeyboard;
252 } else if (current == mSymbolsKeyboard || current == mSymbolsKeyboardShifted) {
253 next = mQwertyKeyboard;
254 }
255 if (next != null) {
256 mKeyboardView.setKeyboard(next);
257 mKeyboardState = KEYBOARD_STATE_NORMAL;
258 }
259 }
260
Ben Komalo51ea88a2011-10-03 10:53:26 -0700261 public void handleBackspace() {
Jim Miller0b319702010-02-05 18:51:59 -0800262 sendDownUpKeyEvents(KeyEvent.KEYCODE_DEL);
Jim Milleraef555b2011-10-12 16:41:30 -0700263 performHapticFeedback();
Jim Miller0b319702010-02-05 18:51:59 -0800264 }
265
266 private void handleShift() {
267 if (mKeyboardView == null) {
268 return;
269 }
270 Keyboard current = mKeyboardView.getKeyboard();
271 PasswordEntryKeyboard next = null;
272 final boolean isAlphaMode = current == mQwertyKeyboard
273 || current == mQwertyKeyboardShifted;
274 if (mKeyboardState == KEYBOARD_STATE_NORMAL) {
275 mKeyboardState = isAlphaMode ? KEYBOARD_STATE_SHIFTED : KEYBOARD_STATE_CAPSLOCK;
276 next = isAlphaMode ? mQwertyKeyboardShifted : mSymbolsKeyboardShifted;
277 } else if (mKeyboardState == KEYBOARD_STATE_SHIFTED) {
278 mKeyboardState = KEYBOARD_STATE_CAPSLOCK;
279 next = isAlphaMode ? mQwertyKeyboardShifted : mSymbolsKeyboardShifted;
280 } else if (mKeyboardState == KEYBOARD_STATE_CAPSLOCK) {
281 mKeyboardState = KEYBOARD_STATE_NORMAL;
282 next = isAlphaMode ? mQwertyKeyboard : mSymbolsKeyboard;
283 }
284 if (next != null) {
285 if (next != current) {
286 mKeyboardView.setKeyboard(next);
287 }
288 next.setShiftLocked(mKeyboardState == KEYBOARD_STATE_CAPSLOCK);
289 mKeyboardView.setShifted(mKeyboardState != KEYBOARD_STATE_NORMAL);
290 }
291 }
292
293 private void handleCharacter(int primaryCode, int[] keyCodes) {
294 // Maybe turn off shift if not in capslock mode.
295 if (mKeyboardView.isShifted() && primaryCode != ' ' && primaryCode != '\n') {
296 primaryCode = Character.toUpperCase(primaryCode);
297 }
298 sendKeyEventsToTarget(primaryCode);
299 }
300
301 private void handleClose() {
302
303 }
304
305 public void onPress(int primaryCode) {
Jim Milleraef555b2011-10-12 16:41:30 -0700306 performHapticFeedback();
307 }
308
309 private void performHapticFeedback() {
310 if (mEnableHaptics) {
311 mKeyboardView.performHapticFeedback(HapticFeedbackConstants.VIRTUAL_KEY,
312 HapticFeedbackConstants.FLAG_IGNORE_VIEW_SETTING
313 | HapticFeedbackConstants.FLAG_IGNORE_GLOBAL_SETTING);
Jim Miller281a80d2010-02-18 19:54:22 -0800314 }
Jim Miller0b319702010-02-05 18:51:59 -0800315 }
316
317 public void onRelease(int primaryCode) {
318
319 }
320
321 public void onText(CharSequence text) {
322
323 }
324
325 public void swipeDown() {
326
327 }
328
329 public void swipeLeft() {
330
331 }
332
333 public void swipeRight() {
334
335 }
336
337 public void swipeUp() {
338
339 }
340};