blob: a3df29199fb780bf72dfa4e4a4aeec34c816cea8 [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;
24import android.os.Handler;
25import android.os.SystemClock;
Jim Miller281a80d2010-02-18 19:54:22 -080026import android.os.Vibrator;
Jim Miller280b6022010-02-09 19:05:02 -080027import android.provider.Settings;
Jim Miller281a80d2010-02-18 19:54:22 -080028import android.util.Log;
Jim Milleraef555b2011-10-12 16:41:30 -070029import android.view.HapticFeedbackConstants;
Jim Miller0b319702010-02-05 18:51:59 -080030import android.view.KeyCharacterMap;
31import android.view.KeyEvent;
32import android.view.View;
Jim Miller79a02b12011-07-29 18:07:32 -070033import android.view.ViewGroup;
Jim Miller3af630c2012-09-26 14:29:18 -070034import android.view.ViewGroup.LayoutParams;
Dianne Hackborn6dd005b2011-07-18 13:22:50 -070035import android.view.ViewRootImpl;
Jim Miller0b319702010-02-05 18:51:59 -080036import com.android.internal.R;
37
38public class PasswordEntryKeyboardHelper implements OnKeyboardActionListener {
39
40 public static final int KEYBOARD_MODE_ALPHA = 0;
41 public static final int KEYBOARD_MODE_NUMERIC = 1;
42 private static final int KEYBOARD_STATE_NORMAL = 0;
43 private static final int KEYBOARD_STATE_SHIFTED = 1;
44 private static final int KEYBOARD_STATE_CAPSLOCK = 2;
Jim Miller281a80d2010-02-18 19:54:22 -080045 private static final String TAG = "PasswordEntryKeyboardHelper";
Jim Miller0b319702010-02-05 18:51:59 -080046 private int mKeyboardMode = KEYBOARD_MODE_ALPHA;
47 private int mKeyboardState = KEYBOARD_STATE_NORMAL;
48 private PasswordEntryKeyboard mQwertyKeyboard;
49 private PasswordEntryKeyboard mQwertyKeyboardShifted;
50 private PasswordEntryKeyboard mSymbolsKeyboard;
51 private PasswordEntryKeyboard mSymbolsKeyboardShifted;
52 private PasswordEntryKeyboard mNumericKeyboard;
Ben Komalo51ea88a2011-10-03 10:53:26 -070053 private final Context mContext;
54 private final View mTargetView;
55 private final KeyboardView mKeyboardView;
Jim Miller281a80d2010-02-18 19:54:22 -080056 private long[] mVibratePattern;
Jim Milleraef555b2011-10-12 16:41:30 -070057 private boolean mEnableHaptics = false;
Jim Miller0b319702010-02-05 18:51:59 -080058
Jim Miller3af630c2012-09-26 14:29:18 -070059 private static final int NUMERIC = 0;
60 private static final int QWERTY = 1;
61 private static final int QWERTY_SHIFTED = 2;
62 private static final int SYMBOLS = 3;
63 private static final int SYMBOLS_SHIFTED = 4;
64
65 int mLayouts[] = new int[] {
66 R.xml.password_kbd_numeric,
67 R.xml.password_kbd_qwerty,
68 R.xml.password_kbd_qwerty_shifted,
69 R.xml.password_kbd_symbols,
70 R.xml.password_kbd_symbols_shift
71 };
72
73 private boolean mUsingScreenWidth;
74
Jim Miller0b319702010-02-05 18:51:59 -080075 public PasswordEntryKeyboardHelper(Context context, KeyboardView keyboardView, View targetView) {
Jim Miller3af630c2012-09-26 14:29:18 -070076 this(context, keyboardView, targetView, true, null);
Jae Yong Sung8171b512010-08-05 10:44:27 -070077 }
78
79 public PasswordEntryKeyboardHelper(Context context, KeyboardView keyboardView, View targetView,
80 boolean useFullScreenWidth) {
Jim Miller3af630c2012-09-26 14:29:18 -070081 this(context, keyboardView, targetView, useFullScreenWidth, null);
82 }
83
84 public PasswordEntryKeyboardHelper(Context context, KeyboardView keyboardView, View targetView,
85 boolean useFullScreenWidth, int layouts[]) {
Jim Miller0b319702010-02-05 18:51:59 -080086 mContext = context;
87 mTargetView = targetView;
88 mKeyboardView = keyboardView;
Jim Miller0b319702010-02-05 18:51:59 -080089 mKeyboardView.setOnKeyboardActionListener(this);
Jim Miller3af630c2012-09-26 14:29:18 -070090 mUsingScreenWidth = useFullScreenWidth;
91 if (layouts != null) {
92 if (layouts.length != mLayouts.length) {
93 throw new RuntimeException("Wrong number of layouts");
94 }
95 for (int i = 0; i < mLayouts.length; i++) {
96 mLayouts[i] = layouts[i];
97 }
98 }
99 createKeyboards();
100 }
101
102 public void createKeyboards() {
103 LayoutParams lp = mKeyboardView.getLayoutParams();
104 if (mUsingScreenWidth || lp.width == ViewGroup.LayoutParams.MATCH_PARENT) {
105 createKeyboardsWithDefaultWidth();
106 } else {
107 createKeyboardsWithSpecificSize(lp.width, lp.height);
108 }
Jim Milleraef555b2011-10-12 16:41:30 -0700109 }
110
111 public void setEnableHaptics(boolean enabled) {
112 mEnableHaptics = enabled;
Jim Miller0b319702010-02-05 18:51:59 -0800113 }
114
115 public boolean isAlpha() {
116 return mKeyboardMode == KEYBOARD_MODE_ALPHA;
117 }
118
Jim Miller3af630c2012-09-26 14:29:18 -0700119 private void createKeyboardsWithSpecificSize(int width, int height) {
120 mNumericKeyboard = new PasswordEntryKeyboard(mContext, mLayouts[NUMERIC], width, height);
121 mQwertyKeyboard = new PasswordEntryKeyboard(mContext, mLayouts[QWERTY], R.id.mode_normal,
122 width, height);
Jae Yong Sung8171b512010-08-05 10:44:27 -0700123 mQwertyKeyboard.enableShiftLock();
124
Jim Miller3af630c2012-09-26 14:29:18 -0700125 mQwertyKeyboardShifted = new PasswordEntryKeyboard(mContext, mLayouts[QWERTY_SHIFTED],
126 R.id.mode_normal, width, height);
Jae Yong Sung8171b512010-08-05 10:44:27 -0700127 mQwertyKeyboardShifted.enableShiftLock();
128 mQwertyKeyboardShifted.setShifted(true); // always shifted.
129
Jim Miller3af630c2012-09-26 14:29:18 -0700130 mSymbolsKeyboard = new PasswordEntryKeyboard(mContext, mLayouts[SYMBOLS], width, height);
Jae Yong Sung8171b512010-08-05 10:44:27 -0700131 mSymbolsKeyboard.enableShiftLock();
132
Jim Miller3af630c2012-09-26 14:29:18 -0700133 mSymbolsKeyboardShifted = new PasswordEntryKeyboard(mContext, mLayouts[SYMBOLS_SHIFTED],
134 width, height);
Jae Yong Sung8171b512010-08-05 10:44:27 -0700135 mSymbolsKeyboardShifted.enableShiftLock();
136 mSymbolsKeyboardShifted.setShifted(true); // always shifted
137 }
138
Jim Miller3af630c2012-09-26 14:29:18 -0700139 private void createKeyboardsWithDefaultWidth() {
140 mNumericKeyboard = new PasswordEntryKeyboard(mContext, mLayouts[NUMERIC]);
141 mQwertyKeyboard = new PasswordEntryKeyboard(mContext, mLayouts[QWERTY], R.id.mode_normal);
Jim Miller0b319702010-02-05 18:51:59 -0800142 mQwertyKeyboard.enableShiftLock();
143
Jim Miller3af630c2012-09-26 14:29:18 -0700144 mQwertyKeyboardShifted = new PasswordEntryKeyboard(mContext, mLayouts[QWERTY_SHIFTED],
Jim Miller0b319702010-02-05 18:51:59 -0800145 R.id.mode_normal);
146 mQwertyKeyboardShifted.enableShiftLock();
147 mQwertyKeyboardShifted.setShifted(true); // always shifted.
148
Jim Miller3af630c2012-09-26 14:29:18 -0700149 mSymbolsKeyboard = new PasswordEntryKeyboard(mContext, mLayouts[SYMBOLS]);
Jim Miller0b319702010-02-05 18:51:59 -0800150 mSymbolsKeyboard.enableShiftLock();
151
Jim Miller3af630c2012-09-26 14:29:18 -0700152 mSymbolsKeyboardShifted = new PasswordEntryKeyboard(mContext, mLayouts[SYMBOLS_SHIFTED]);
Jim Miller0b319702010-02-05 18:51:59 -0800153 mSymbolsKeyboardShifted.enableShiftLock();
154 mSymbolsKeyboardShifted.setShifted(true); // always shifted
155 }
156
157 public void setKeyboardMode(int mode) {
158 switch (mode) {
159 case KEYBOARD_MODE_ALPHA:
160 mKeyboardView.setKeyboard(mQwertyKeyboard);
161 mKeyboardState = KEYBOARD_STATE_NORMAL;
Jim Miller280b6022010-02-09 19:05:02 -0800162 final boolean visiblePassword = Settings.System.getInt(
163 mContext.getContentResolver(),
164 Settings.System.TEXT_SHOW_PASSWORD, 1) != 0;
Jim Miller7dd879a2011-01-23 16:18:01 -0800165 final boolean enablePreview = false; // TODO: grab from configuration
166 mKeyboardView.setPreviewEnabled(visiblePassword && enablePreview);
Jim Miller0b319702010-02-05 18:51:59 -0800167 break;
168 case KEYBOARD_MODE_NUMERIC:
169 mKeyboardView.setKeyboard(mNumericKeyboard);
170 mKeyboardState = KEYBOARD_STATE_NORMAL;
Jim Miller280b6022010-02-09 19:05:02 -0800171 mKeyboardView.setPreviewEnabled(false); // never show popup for numeric keypad
Jim Miller0b319702010-02-05 18:51:59 -0800172 break;
173 }
174 mKeyboardMode = mode;
175 }
176
Joe Onorato16537752010-03-17 22:19:51 -0700177 private void sendKeyEventsToTarget(int character) {
Jeff Browna175a5b2012-02-15 19:18:31 -0800178 ViewRootImpl viewRootImpl = mTargetView.getViewRootImpl();
Jeff Brown6b53e8d2010-11-10 16:03:06 -0800179 KeyEvent[] events = KeyCharacterMap.load(KeyCharacterMap.VIRTUAL_KEYBOARD).getEvents(
Joe Onorato16537752010-03-17 22:19:51 -0700180 new char[] { (char) character });
Jim Miller0b319702010-02-05 18:51:59 -0800181 if (events != null) {
Joe Onorato16537752010-03-17 22:19:51 -0700182 final int N = events.length;
183 for (int i=0; i<N; i++) {
184 KeyEvent event = events[i];
185 event = KeyEvent.changeFlags(event, event.getFlags()
186 | KeyEvent.FLAG_SOFT_KEYBOARD | KeyEvent.FLAG_KEEP_TOUCH_MODE);
keunyoung30f420f2013-08-02 14:23:10 -0700187 viewRootImpl.dispatchInputEvent(event);
Jim Miller0b319702010-02-05 18:51:59 -0800188 }
189 }
190 }
191
192 public void sendDownUpKeyEvents(int keyEventCode) {
193 long eventTime = SystemClock.uptimeMillis();
Jeff Browna175a5b2012-02-15 19:18:31 -0800194 ViewRootImpl viewRootImpl = mTargetView.getViewRootImpl();
195 viewRootImpl.dispatchKeyFromIme(
Jeff Brown6b53e8d2010-11-10 16:03:06 -0800196 new KeyEvent(eventTime, eventTime, KeyEvent.ACTION_DOWN, keyEventCode, 0, 0,
197 KeyCharacterMap.VIRTUAL_KEYBOARD, 0,
Jeff Browna175a5b2012-02-15 19:18:31 -0800198 KeyEvent.FLAG_SOFT_KEYBOARD|KeyEvent.FLAG_KEEP_TOUCH_MODE));
199 viewRootImpl.dispatchKeyFromIme(
Jeff Brown6b53e8d2010-11-10 16:03:06 -0800200 new KeyEvent(eventTime, eventTime, KeyEvent.ACTION_UP, keyEventCode, 0, 0,
201 KeyCharacterMap.VIRTUAL_KEYBOARD, 0,
Jeff Browna175a5b2012-02-15 19:18:31 -0800202 KeyEvent.FLAG_SOFT_KEYBOARD|KeyEvent.FLAG_KEEP_TOUCH_MODE));
Jim Miller0b319702010-02-05 18:51:59 -0800203 }
204
205 public void onKey(int primaryCode, int[] keyCodes) {
Jim Miller0b319702010-02-05 18:51:59 -0800206 if (primaryCode == Keyboard.KEYCODE_DELETE) {
207 handleBackspace();
208 } else if (primaryCode == Keyboard.KEYCODE_SHIFT) {
209 handleShift();
210 } else if (primaryCode == Keyboard.KEYCODE_CANCEL) {
211 handleClose();
212 return;
213 } else if (primaryCode == Keyboard.KEYCODE_MODE_CHANGE && mKeyboardView != null) {
214 handleModeChange();
215 } else {
216 handleCharacter(primaryCode, keyCodes);
217 // Switch back to old keyboard if we're not in capslock mode
218 if (mKeyboardState == KEYBOARD_STATE_SHIFTED) {
219 // skip to the unlocked state
220 mKeyboardState = KEYBOARD_STATE_CAPSLOCK;
221 handleShift();
222 }
223 }
224 }
225
Jim Miller281a80d2010-02-18 19:54:22 -0800226 /**
227 * Sets and enables vibrate pattern. If id is 0 (or can't be loaded), vibrate is disabled.
228 * @param id resource id for array containing vibrate pattern.
229 */
230 public void setVibratePattern(int id) {
231 int[] tmpArray = null;
232 try {
233 tmpArray = mContext.getResources().getIntArray(id);
234 } catch (Resources.NotFoundException e) {
235 if (id != 0) {
236 Log.e(TAG, "Vibrate pattern missing", e);
237 }
238 }
239 if (tmpArray == null) {
240 mVibratePattern = null;
241 return;
242 }
243 mVibratePattern = new long[tmpArray.length];
244 for (int i = 0; i < tmpArray.length; i++) {
245 mVibratePattern[i] = tmpArray[i];
246 }
247 }
248
Jim Miller0b319702010-02-05 18:51:59 -0800249 private void handleModeChange() {
250 final Keyboard current = mKeyboardView.getKeyboard();
251 Keyboard next = null;
252 if (current == mQwertyKeyboard || current == mQwertyKeyboardShifted) {
253 next = mSymbolsKeyboard;
254 } else if (current == mSymbolsKeyboard || current == mSymbolsKeyboardShifted) {
255 next = mQwertyKeyboard;
256 }
257 if (next != null) {
258 mKeyboardView.setKeyboard(next);
259 mKeyboardState = KEYBOARD_STATE_NORMAL;
260 }
261 }
262
Ben Komalo51ea88a2011-10-03 10:53:26 -0700263 public void handleBackspace() {
Jim Miller0b319702010-02-05 18:51:59 -0800264 sendDownUpKeyEvents(KeyEvent.KEYCODE_DEL);
Jim Milleraef555b2011-10-12 16:41:30 -0700265 performHapticFeedback();
Jim Miller0b319702010-02-05 18:51:59 -0800266 }
267
268 private void handleShift() {
269 if (mKeyboardView == null) {
270 return;
271 }
272 Keyboard current = mKeyboardView.getKeyboard();
273 PasswordEntryKeyboard next = null;
274 final boolean isAlphaMode = current == mQwertyKeyboard
275 || current == mQwertyKeyboardShifted;
276 if (mKeyboardState == KEYBOARD_STATE_NORMAL) {
277 mKeyboardState = isAlphaMode ? KEYBOARD_STATE_SHIFTED : KEYBOARD_STATE_CAPSLOCK;
278 next = isAlphaMode ? mQwertyKeyboardShifted : mSymbolsKeyboardShifted;
279 } else if (mKeyboardState == KEYBOARD_STATE_SHIFTED) {
280 mKeyboardState = KEYBOARD_STATE_CAPSLOCK;
281 next = isAlphaMode ? mQwertyKeyboardShifted : mSymbolsKeyboardShifted;
282 } else if (mKeyboardState == KEYBOARD_STATE_CAPSLOCK) {
283 mKeyboardState = KEYBOARD_STATE_NORMAL;
284 next = isAlphaMode ? mQwertyKeyboard : mSymbolsKeyboard;
285 }
286 if (next != null) {
287 if (next != current) {
288 mKeyboardView.setKeyboard(next);
289 }
290 next.setShiftLocked(mKeyboardState == KEYBOARD_STATE_CAPSLOCK);
291 mKeyboardView.setShifted(mKeyboardState != KEYBOARD_STATE_NORMAL);
292 }
293 }
294
295 private void handleCharacter(int primaryCode, int[] keyCodes) {
296 // Maybe turn off shift if not in capslock mode.
297 if (mKeyboardView.isShifted() && primaryCode != ' ' && primaryCode != '\n') {
298 primaryCode = Character.toUpperCase(primaryCode);
299 }
300 sendKeyEventsToTarget(primaryCode);
301 }
302
303 private void handleClose() {
304
305 }
306
307 public void onPress(int primaryCode) {
Jim Milleraef555b2011-10-12 16:41:30 -0700308 performHapticFeedback();
309 }
310
311 private void performHapticFeedback() {
312 if (mEnableHaptics) {
313 mKeyboardView.performHapticFeedback(HapticFeedbackConstants.VIRTUAL_KEY,
314 HapticFeedbackConstants.FLAG_IGNORE_VIEW_SETTING
315 | HapticFeedbackConstants.FLAG_IGNORE_GLOBAL_SETTING);
Jim Miller281a80d2010-02-18 19:54:22 -0800316 }
Jim Miller0b319702010-02-05 18:51:59 -0800317 }
318
319 public void onRelease(int primaryCode) {
320
321 }
322
323 public void onText(CharSequence text) {
324
325 }
326
327 public void swipeDown() {
328
329 }
330
331 public void swipeLeft() {
332
333 }
334
335 public void swipeRight() {
336
337 }
338
339 public void swipeUp() {
340
341 }
342};