• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
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 
17 package android.widget;
18 
19 import android.content.Context;
20 import android.view.KeyEvent;
21 import android.text.Editable;
22 import android.text.InputFilter;
23 import android.text.Selection;
24 import android.text.Spannable;
25 import android.text.Spanned;
26 import android.text.TextWatcher;
27 import android.text.method.DialerKeyListener;
28 import android.text.method.KeyListener;
29 import android.text.method.TextKeyListener;
30 import android.util.AttributeSet;
31 import android.view.View;
32 import android.graphics.Rect;
33 
34 
35 
36 public class DialerFilter extends RelativeLayout
37 {
DialerFilter(Context context)38     public DialerFilter(Context context) {
39         super(context);
40     }
41 
DialerFilter(Context context, AttributeSet attrs)42     public DialerFilter(Context context, AttributeSet attrs) {
43         super(context, attrs);
44     }
45 
46     @Override
onFinishInflate()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 
82         // 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
onFocusChanged(boolean focused, int direction, Rect previouslyFocusedRect)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 
isQwertyKeyboard()100     public boolean isQwertyKeyboard() {
101         return mIsQwerty;
102     }
103 
104     @Override
onKeyDown(int keyCode, KeyEvent event)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
onKeyUp(int keyCode, KeyEvent event)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 
getMode()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      */
setMode(int newMode)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 
makeLettersPrimary()254     private void makeLettersPrimary() {
255         if (mPrimary == mDigits) {
256             swapPrimaryAndHint(true);
257         }
258     }
259 
makeDigitsPrimary()260     private void makeDigitsPrimary() {
261         if (mPrimary == mLetters) {
262             swapPrimaryAndHint(false);
263         }
264     }
265 
swapPrimaryAndHint(boolean makeLettersPrimary)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 
getLetters()296     public CharSequence getLetters() {
297         if (mLetters.getVisibility() == View.VISIBLE) {
298             return mLetters.getText();
299         } else {
300             return "";
301         }
302     }
303 
getDigits()304     public CharSequence getDigits() {
305         if (mDigits.getVisibility() == View.VISIBLE) {
306             return mDigits.getText();
307         } else {
308             return "";
309         }
310     }
311 
getFilterText()312     public CharSequence getFilterText() {
313         if (mMode != DIGITS_ONLY) {
314             return getLetters();
315         } else {
316             return getDigits();
317         }
318     }
319 
append(String text)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      */
clearText()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 
setLettersWatcher(TextWatcher watcher)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 
setDigitsWatcher(TextWatcher watcher)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 
setFilterWatcher(TextWatcher watcher)371     public void setFilterWatcher(TextWatcher watcher) {
372         if (mMode != DIGITS_ONLY) {
373             setLettersWatcher(watcher);
374         } else {
375             setDigitsWatcher(watcher);
376         }
377     }
378 
removeFilterWatcher(TextWatcher watcher)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      */
onModeChange(int oldMode, int newMode)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 }
418