1/*
2 * Copyright (C) 2008 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.cts;
18
19import com.android.cts.stub.R;
20
21
22import android.app.Activity;
23import android.app.Instrumentation;
24import android.test.ActivityInstrumentationTestCase2;
25import android.text.Editable;
26import android.text.Selection;
27import android.text.Spannable;
28import android.text.SpannableString;
29import android.text.Spanned;
30import android.text.method.NumberKeyListener;
31import android.view.KeyEvent;
32import android.view.View;
33import android.widget.TextView;
34import android.widget.TextView.BufferType;
35
36
37public class NumberKeyListenerTest extends
38        ActivityInstrumentationTestCase2<KeyListenerStubActivity> {
39
40    private MockNumberKeyListener mNumberKeyListener;
41    private Activity mActivity;
42    private Instrumentation mInstrumentation;
43    private TextView mTextView;
44
45    public NumberKeyListenerTest(){
46        super("com.android.cts.stub", KeyListenerStubActivity.class);
47    }
48
49    @Override
50    protected void setUp() throws Exception {
51        super.setUp();
52        mActivity = getActivity();
53        mInstrumentation = getInstrumentation();
54        mTextView = (TextView) mActivity.findViewById(R.id.keylistener_textview);
55    }
56
57    /**
58     * Check point:
59     * 1. Filter "Android test", return "".
60     * 2. Filter "12345", return null.
61     * 3. Filter "", return null.
62     * 4. Filter "12345 Android", return "12345".
63     * 5. Filter Spanned("12345 Android"), return Spanned("12345") and copy spans.
64     */
65    public void testFilter() {
66        mNumberKeyListener = new MockNumberKeyListener(MockNumberKeyListener.DIGITS);
67        String source = "Android test";
68        SpannableString dest = new SpannableString("012345");
69        assertEquals("", mNumberKeyListener.filter(source, 0, source.length(),
70                dest, 0, dest.length()).toString());
71
72        source = "12345";
73        dest = new SpannableString("012345");
74        assertNull(mNumberKeyListener.filter(source, 0, source.length(), dest, 0, dest.length()));
75
76        source = "";
77        dest = new SpannableString("012345");
78        assertNull(mNumberKeyListener.filter(source, 0, source.length(), dest, 0, dest.length()));
79
80        source = "12345 Android";
81        dest = new SpannableString("012345 Android-test");
82        assertEquals("12345", mNumberKeyListener.filter(source, 0, source.length(),
83                dest, 0, dest.length()).toString());
84
85        Object what = new Object();
86        Spannable spannableSource = new SpannableString("12345 Android");
87        spannableSource.setSpan(what, 0, spannableSource.length(), Spanned.SPAN_POINT_POINT);
88        Spanned filtered = (Spanned) mNumberKeyListener.filter(spannableSource,
89                0, spannableSource.length(), dest, 0, dest.length());
90        assertEquals("12345", filtered.toString());
91        assertEquals(Spanned.SPAN_POINT_POINT, filtered.getSpanFlags(what));
92        assertEquals(0, filtered.getSpanStart(what));
93        assertEquals("12345".length(), filtered.getSpanEnd(what));
94
95        try {
96            mNumberKeyListener.filter(null, 0, 1, dest, 0, dest.length());
97            fail("should throw NullPointerException.");
98        } catch (NullPointerException e) {
99        }
100    }
101
102    /**
103     * Check point:
104     * If one of the chars in the getAcceptedChars() can be generated by the keyCode of this
105     * key event, return the char; otherwise return '\0'.
106     */
107    public void testLookup() {
108        mNumberKeyListener = new MockNumberKeyListener(MockNumberKeyListener.DIGITS);
109        KeyEvent event1 = new KeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_0);
110        SpannableString str = new SpannableString("012345");
111        assertEquals('0', mNumberKeyListener.lookup(event1, str));
112
113        mNumberKeyListener = new MockNumberKeyListener(MockNumberKeyListener.NOTHING);
114        KeyEvent event2 = new KeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_A);
115        str = new SpannableString("ABCD");
116        assertEquals('\0', mNumberKeyListener.lookup(event2, str));
117
118        try {
119            mNumberKeyListener.lookup(null, str);
120            fail("should throw NullPointerException.");
121        } catch (NullPointerException e) {
122            // expected.
123        }
124    }
125
126    public void testOk() {
127        mNumberKeyListener = new MockNumberKeyListener(MockNumberKeyListener.DIGITS);
128
129        assertTrue(mNumberKeyListener.callOk(mNumberKeyListener.getAcceptedChars(), '3'));
130        assertFalse(mNumberKeyListener.callOk(mNumberKeyListener.getAcceptedChars(), 'e'));
131
132        try {
133            mNumberKeyListener.callOk(null, 'm');
134            fail("should throw NullPointerException.");
135        } catch (NullPointerException e) {
136        }
137    }
138
139    /**
140     * Check point:
141     * 1. Press '0' key, '0' will be added to the text.
142     * 2. Press an unaccepted key if it exists, it will not be added.
143     * 3. remove NumberKeyListener and press '0' key, '0' will not be added.
144     */
145    public void testPressKey() {
146        final CharSequence text = "123456";
147        final MockNumberKeyListener numberKeyListener =
148            new MockNumberKeyListener(MockNumberKeyListener.DIGITS);
149
150        mActivity.runOnUiThread(new Runnable() {
151            public void run() {
152                mTextView.setText(text, BufferType.EDITABLE);
153                mTextView.setKeyListener(numberKeyListener);
154                mTextView.requestFocus();
155                Selection.setSelection((Editable) mTextView.getText(), 0, 0);
156            }
157        });
158        mInstrumentation.waitForIdleSync();
159        assertEquals("123456", mTextView.getText().toString());
160        // press '0' key.
161        sendKeys(KeyEvent.KEYCODE_0);
162        assertEquals("0123456", mTextView.getText().toString());
163
164        // an unaccepted key if it exists.
165        int keyCode = TextMethodUtils.getUnacceptedKeyCode(MockNumberKeyListener.DIGITS);
166        if (-1 != keyCode) {
167            sendKeys(keyCode);
168            // text of TextView will not be changed.
169            assertEquals("0123456", mTextView.getText().toString());
170        }
171
172        mActivity.runOnUiThread(new Runnable() {
173            public void run() {
174                mTextView.setKeyListener(null);
175                mTextView.requestFocus();
176            }
177        });
178        mInstrumentation.waitForIdleSync();
179        // press '0' key.
180        sendKeys(KeyEvent.KEYCODE_0);
181        assertEquals("0123456", mTextView.getText().toString());
182    }
183
184    private static class MockNumberKeyListener extends NumberKeyListener {
185
186        static final char[] DIGITS =
187                new char[] {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9'};
188
189        static final char[] NOTHING = new char[0];
190
191        private final char[] mAcceptedChars;
192
193        MockNumberKeyListener(char[] acceptedChars) {
194            this.mAcceptedChars = acceptedChars;
195        }
196
197        @Override
198        protected char[] getAcceptedChars() {
199            return mAcceptedChars;
200        }
201
202        @Override
203        protected int lookup(KeyEvent event, Spannable content) {
204            return super.lookup(event, content);
205        }
206
207        public boolean callOk(char[] accept, char c) {
208            return NumberKeyListener.ok(accept, c);
209        }
210
211        public int getInputType() {
212            return 0;
213        }
214    }
215}
216