blob: 988d566f5a7eecde2e178d8574f6cb2d49816d5f [file] [log] [blame]
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001/*
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
17package android.text.method;
18
19import android.view.KeyEvent;
20import android.view.View;
21import android.text.Editable;
22import android.text.InputFilter;
23import android.text.Selection;
24import android.text.Spannable;
25import android.text.SpannableStringBuilder;
26import android.text.Spanned;
27
28/**
29 * For numeric text entry
Jean Chalard405bc512012-05-29 19:12:34 +090030 * <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.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080034 */
35public 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) {
Jean Chalard8a1597b2013-03-04 18:45:12 -080044 return event.getMatch(getAcceptedChars(), getMetaState(content, event));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080045 }
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}