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