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