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