Home | History | Annotate | Download | only in method
      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.text.method;
     18 
     19 import android.view.KeyEvent;
     20 import android.view.View;
     21 import android.text.Editable;
     22 import android.text.InputFilter;
     23 import android.text.Selection;
     24 import android.text.Spannable;
     25 import android.text.SpannableStringBuilder;
     26 import android.text.Spanned;
     27 
     28 /**
     29  * For numeric text entry
     30  * <p></p>
     31  * As for all implementations of {@link KeyListener}, this class is only concerned
     32  * with hardware keyboards.  Software input methods have no obligation to trigger
     33  * the methods in this class.
     34  */
     35 public abstract class NumberKeyListener extends BaseKeyListener
     36     implements InputFilter
     37 {
     38     /**
     39      * You can say which characters you can accept.
     40      */
     41     protected abstract char[] getAcceptedChars();
     42 
     43     protected int lookup(KeyEvent event, Spannable content) {
     44         return event.getMatch(getAcceptedChars(), getMetaState(content, event));
     45     }
     46 
     47     public CharSequence filter(CharSequence source, int start, int end,
     48                                Spanned dest, int dstart, int dend) {
     49         char[] accept = getAcceptedChars();
     50         boolean filter = false;
     51 
     52         int i;
     53         for (i = start; i < end; i++) {
     54             if (!ok(accept, source.charAt(i))) {
     55                 break;
     56             }
     57         }
     58 
     59         if (i == end) {
     60             // It was all OK.
     61             return null;
     62         }
     63 
     64         if (end - start == 1) {
     65             // It was not OK, and there is only one char, so nothing remains.
     66             return "";
     67         }
     68 
     69         SpannableStringBuilder filtered =
     70             new SpannableStringBuilder(source, start, end);
     71         i -= start;
     72         end -= start;
     73 
     74         int len = end - start;
     75         // Only count down to i because the chars before that were all OK.
     76         for (int j = end - 1; j >= i; j--) {
     77             if (!ok(accept, source.charAt(j))) {
     78                 filtered.delete(j, j + 1);
     79             }
     80         }
     81 
     82         return filtered;
     83     }
     84 
     85     protected static boolean ok(char[] accept, char c) {
     86         for (int i = accept.length - 1; i >= 0; i--) {
     87             if (accept[i] == c) {
     88                 return true;
     89             }
     90         }
     91 
     92         return false;
     93     }
     94 
     95     @Override
     96     public boolean onKeyDown(View view, Editable content,
     97                              int keyCode, KeyEvent event) {
     98         int selStart, selEnd;
     99 
    100         {
    101             int a = Selection.getSelectionStart(content);
    102             int b = Selection.getSelectionEnd(content);
    103 
    104             selStart = Math.min(a, b);
    105             selEnd = Math.max(a, b);
    106         }
    107 
    108         if (selStart < 0 || selEnd < 0) {
    109             selStart = selEnd = 0;
    110             Selection.setSelection(content, 0);
    111         }
    112 
    113         int i = event != null ? lookup(event, content) : 0;
    114         int repeatCount = event != null ? event.getRepeatCount() : 0;
    115         if (repeatCount == 0) {
    116             if (i != 0) {
    117                 if (selStart != selEnd) {
    118                     Selection.setSelection(content, selEnd);
    119                 }
    120 
    121                 content.replace(selStart, selEnd, String.valueOf((char) i));
    122 
    123                 adjustMetaAfterKeypress(content);
    124                 return true;
    125             }
    126         } else if (i == '0' && repeatCount == 1) {
    127             // Pretty hackish, it replaces the 0 with the +
    128 
    129             if (selStart == selEnd && selEnd > 0 &&
    130                     content.charAt(selStart - 1) == '0') {
    131                 content.replace(selStart - 1, selEnd, String.valueOf('+'));
    132                 adjustMetaAfterKeypress(content);
    133                 return true;
    134             }
    135         }
    136 
    137         adjustMetaAfterKeypress(content);
    138         return super.onKeyDown(view, content, keyCode, event);
    139     }
    140 }
    141