Home | History | Annotate | Download | only in widget
      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 {
     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 
     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
     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 }
    418