blob: 20bc1142320dd262953bea7739bd778222812e8c [file] [log] [blame]
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001/*
2 * Copyright (C) 2006 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of 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,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package android.widget;
18
19import android.content.Context;
20import android.view.KeyEvent;
21import android.text.Editable;
22import android.text.InputFilter;
23import android.text.Selection;
24import android.text.Spannable;
25import android.text.Spanned;
26import android.text.TextWatcher;
27import android.text.method.DialerKeyListener;
28import android.text.method.KeyListener;
29import android.text.method.TextKeyListener;
30import android.util.AttributeSet;
31import android.util.Log;
32import android.view.KeyCharacterMap;
33import android.view.View;
34import android.graphics.Rect;
35
36
37
38public class DialerFilter extends RelativeLayout
39{
40 public DialerFilter(Context context) {
41 super(context);
42 }
43
44 public DialerFilter(Context context, AttributeSet attrs) {
45 super(context, attrs);
46 }
47
48 @Override
49 protected void onFinishInflate() {
50 super.onFinishInflate();
51
52 // Setup the filter view
53 mInputFilters = new InputFilter[] { new InputFilter.AllCaps() };
54
55 mHint = (EditText) findViewById(com.android.internal.R.id.hint);
56 if (mHint == null) {
57 throw new IllegalStateException("DialerFilter must have a child EditText named hint");
58 }
59 mHint.setFilters(mInputFilters);
60
61 mLetters = mHint;
62 mLetters.setKeyListener(TextKeyListener.getInstance());
63 mLetters.setMovementMethod(null);
64 mLetters.setFocusable(false);
65
66 // Setup the digits view
67 mPrimary = (EditText) findViewById(com.android.internal.R.id.primary);
68 if (mPrimary == null) {
69 throw new IllegalStateException("DialerFilter must have a child EditText named primary");
70 }
71 mPrimary.setFilters(mInputFilters);
72
73 mDigits = mPrimary;
74 mDigits.setKeyListener(DialerKeyListener.getInstance());
75 mDigits.setMovementMethod(null);
76 mDigits.setFocusable(false);
77
78 // Look for an icon
79 mIcon = (ImageView) findViewById(com.android.internal.R.id.icon);
80
81 // Setup focus & highlight for this view
82 setFocusable(true);
83
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080084 // XXX Force the mode to QWERTY for now, since 12-key isn't supported
85 mIsQwerty = true;
86 setMode(DIGITS_AND_LETTERS);
87 }
88
89 /**
90 * Only show the icon view when focused, if there is one.
91 */
92 @Override
93 protected void onFocusChanged(boolean focused, int direction, Rect previouslyFocusedRect) {
94 super.onFocusChanged(focused, direction, previouslyFocusedRect);
95
96 if (mIcon != null) {
97 mIcon.setVisibility(focused ? View.VISIBLE : View.GONE);
98 }
99 }
100
101
102 public boolean isQwertyKeyboard() {
103 return mIsQwerty;
104 }
105
106 @Override
107 public boolean onKeyDown(int keyCode, KeyEvent event) {
108 boolean handled = false;
109
110 switch (keyCode) {
111 case KeyEvent.KEYCODE_DPAD_UP:
112 case KeyEvent.KEYCODE_DPAD_DOWN:
113 case KeyEvent.KEYCODE_DPAD_LEFT:
114 case KeyEvent.KEYCODE_DPAD_RIGHT:
115 case KeyEvent.KEYCODE_ENTER:
116 case KeyEvent.KEYCODE_DPAD_CENTER:
117 break;
118
119 case KeyEvent.KEYCODE_DEL:
120 switch (mMode) {
121 case DIGITS_AND_LETTERS:
122 handled = mDigits.onKeyDown(keyCode, event);
123 handled &= mLetters.onKeyDown(keyCode, event);
124 break;
125
126 case DIGITS_AND_LETTERS_NO_DIGITS:
127 handled = mLetters.onKeyDown(keyCode, event);
128 if (mLetters.getText().length() == mDigits.getText().length()) {
129 setMode(DIGITS_AND_LETTERS);
130 }
131 break;
132
133 case DIGITS_AND_LETTERS_NO_LETTERS:
134 if (mDigits.getText().length() == mLetters.getText().length()) {
135 mLetters.onKeyDown(keyCode, event);
136 setMode(DIGITS_AND_LETTERS);
137 }
138 handled = mDigits.onKeyDown(keyCode, event);
139 break;
140
141 case DIGITS_ONLY:
142 handled = mDigits.onKeyDown(keyCode, event);
143 break;
144
145 case LETTERS_ONLY:
146 handled = mLetters.onKeyDown(keyCode, event);
147 break;
148 }
149 break;
150
151 default:
152 //mIsQwerty = msg.getKeyIsQwertyKeyboard();
153
154 switch (mMode) {
155 case DIGITS_AND_LETTERS:
156 handled = mLetters.onKeyDown(keyCode, event);
157
158 // pass this throw so the shift state is correct (for example,
159 // on a standard QWERTY keyboard, * and 8 are on the same key)
160 if (KeyEvent.isModifierKey(keyCode)) {
161 mDigits.onKeyDown(keyCode, event);
162 handled = true;
163 break;
164 }
165
166 // Only check to see if the digit is valid if the key is a printing key
167 // in the TextKeyListener. This prevents us from hiding the digits
168 // line when keys like UP and DOWN are hit.
169 // XXX note that KEYCODE_TAB is special-cased here for
170 // devices that share tab and 0 on a single key.
171 boolean isPrint = event.isPrintingKey();
172 if (isPrint || keyCode == KeyEvent.KEYCODE_SPACE
173 || keyCode == KeyEvent.KEYCODE_TAB) {
174 char c = event.getMatch(DialerKeyListener.CHARACTERS);
175 if (c != 0) {
176 handled &= mDigits.onKeyDown(keyCode, event);
177 } else {
178 setMode(DIGITS_AND_LETTERS_NO_DIGITS);
179 }
180 }
181 break;
182
183 case DIGITS_AND_LETTERS_NO_LETTERS:
184 case DIGITS_ONLY:
185 handled = mDigits.onKeyDown(keyCode, event);
186 break;
187
188 case DIGITS_AND_LETTERS_NO_DIGITS:
189 case LETTERS_ONLY:
190 handled = mLetters.onKeyDown(keyCode, event);
191 break;
192 }
193 }
194
195 if (!handled) {
196 return super.onKeyDown(keyCode, event);
197 } else {
198 return true;
199 }
200 }
201
202 @Override
203 public boolean onKeyUp(int keyCode, KeyEvent event) {
204 boolean a = mLetters.onKeyUp(keyCode, event);
205 boolean b = mDigits.onKeyUp(keyCode, event);
206 return a || b;
207 }
208
209 public int getMode() {
210 return mMode;
211 }
212
213 /**
214 * Change the mode of the widget.
215 *
216 * @param newMode The mode to switch to.
217 */
218 public void setMode(int newMode) {
219 switch (newMode) {
220 case DIGITS_AND_LETTERS:
221 makeDigitsPrimary();
222 mLetters.setVisibility(View.VISIBLE);
223 mDigits.setVisibility(View.VISIBLE);
224 break;
225
226 case DIGITS_ONLY:
227 makeDigitsPrimary();
228 mLetters.setVisibility(View.GONE);
229 mDigits.setVisibility(View.VISIBLE);
230 break;
231
232 case LETTERS_ONLY:
233 makeLettersPrimary();
234 mLetters.setVisibility(View.VISIBLE);
235 mDigits.setVisibility(View.GONE);
236 break;
237
238 case DIGITS_AND_LETTERS_NO_LETTERS:
239 makeDigitsPrimary();
240 mLetters.setVisibility(View.INVISIBLE);
241 mDigits.setVisibility(View.VISIBLE);
242 break;
243
244 case DIGITS_AND_LETTERS_NO_DIGITS:
245 makeLettersPrimary();
246 mLetters.setVisibility(View.VISIBLE);
247 mDigits.setVisibility(View.INVISIBLE);
248 break;
249
250 }
251 int oldMode = mMode;
252 mMode = newMode;
253 onModeChange(oldMode, newMode);
254 }
255
256 private void makeLettersPrimary() {
257 if (mPrimary == mDigits) {
258 swapPrimaryAndHint(true);
259 }
260 }
261
262 private void makeDigitsPrimary() {
263 if (mPrimary == mLetters) {
264 swapPrimaryAndHint(false);
265 }
266 }
267
268 private void swapPrimaryAndHint(boolean makeLettersPrimary) {
269 Editable lettersText = mLetters.getText();
270 Editable digitsText = mDigits.getText();
271 KeyListener lettersInput = mLetters.getKeyListener();
272 KeyListener digitsInput = mDigits.getKeyListener();
273
274 if (makeLettersPrimary) {
275 mLetters = mPrimary;
276 mDigits = mHint;
277 } else {
278 mLetters = mHint;
279 mDigits = mPrimary;
280 }
281
282 mLetters.setKeyListener(lettersInput);
283 mLetters.setText(lettersText);
284 lettersText = mLetters.getText();
285 Selection.setSelection(lettersText, lettersText.length());
286
287 mDigits.setKeyListener(digitsInput);
288 mDigits.setText(digitsText);
289 digitsText = mDigits.getText();
290 Selection.setSelection(digitsText, digitsText.length());
291
292 // Reset the filters
293 mPrimary.setFilters(mInputFilters);
294 mHint.setFilters(mInputFilters);
295 }
296
297
298 public CharSequence getLetters() {
299 if (mLetters.getVisibility() == View.VISIBLE) {
300 return mLetters.getText();
301 } else {
302 return "";
303 }
304 }
305
306 public CharSequence getDigits() {
307 if (mDigits.getVisibility() == View.VISIBLE) {
308 return mDigits.getText();
309 } else {
310 return "";
311 }
312 }
313
314 public CharSequence getFilterText() {
315 if (mMode != DIGITS_ONLY) {
316 return getLetters();
317 } else {
318 return getDigits();
319 }
320 }
321
322 public void append(String text) {
323 switch (mMode) {
324 case DIGITS_AND_LETTERS:
325 mDigits.getText().append(text);
326 mLetters.getText().append(text);
327 break;
328
329 case DIGITS_AND_LETTERS_NO_LETTERS:
330 case DIGITS_ONLY:
331 mDigits.getText().append(text);
332 break;
333
334 case DIGITS_AND_LETTERS_NO_DIGITS:
335 case LETTERS_ONLY:
336 mLetters.getText().append(text);
337 break;
338 }
339 }
340
341 /**
342 * Clears both the digits and the filter text.
343 */
344 public void clearText() {
345 Editable text;
346
347 text = mLetters.getText();
348 text.clear();
349
350 text = mDigits.getText();
351 text.clear();
352
353 // Reset the mode based on the hardware type
354 if (mIsQwerty) {
355 setMode(DIGITS_AND_LETTERS);
356 } else {
357 setMode(DIGITS_ONLY);
358 }
359 }
360
361 public void setLettersWatcher(TextWatcher watcher) {
362 CharSequence text = mLetters.getText();
363 Spannable span = (Spannable)text;
364 span.setSpan(watcher, 0, text.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
365 }
366
367 public void setDigitsWatcher(TextWatcher watcher) {
368 CharSequence text = mDigits.getText();
369 Spannable span = (Spannable)text;
370 span.setSpan(watcher, 0, text.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
371 }
372
373 public void setFilterWatcher(TextWatcher watcher) {
374 if (mMode != DIGITS_ONLY) {
375 setLettersWatcher(watcher);
376 } else {
377 setDigitsWatcher(watcher);
378 }
379 }
380
381 public void removeFilterWatcher(TextWatcher watcher) {
382 Spannable text;
383 if (mMode != DIGITS_ONLY) {
384 text = mLetters.getText();
385 } else {
386 text = mDigits.getText();
387 }
388 text.removeSpan(watcher);
389 }
390
391 /**
392 * Called right after the mode changes to give subclasses the option to
393 * restyle, etc.
394 */
395 protected void onModeChange(int oldMode, int newMode) {
396 }
397
398 /** This mode has both lines */
399 public static final int DIGITS_AND_LETTERS = 1;
400 /** This mode is when after starting in {@link #DIGITS_AND_LETTERS} mode the filter
401 * has removed all possibility of the digits matching, leaving only the letters line */
402 public static final int DIGITS_AND_LETTERS_NO_DIGITS = 2;
403 /** This mode is when after starting in {@link #DIGITS_AND_LETTERS} mode the filter
404 * has removed all possibility of the letters matching, leaving only the digits line */
405 public static final int DIGITS_AND_LETTERS_NO_LETTERS = 3;
406 /** This mode has only the digits line */
407 public static final int DIGITS_ONLY = 4;
408 /** This mode has only the letters line */
409 public static final int LETTERS_ONLY = 5;
410
411 EditText mLetters;
412 EditText mDigits;
413 EditText mPrimary;
414 EditText mHint;
415 InputFilter mInputFilters[];
416 ImageView mIcon;
417 int mMode;
418 private boolean mIsQwerty;
419}