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 
17 package android.widget;
18 
19 import android.app.Activity;
20 import android.app.Instrumentation;
21 import android.os.SystemClock;
22 import android.test.ActivityInstrumentationTestCase2;
23 import android.view.KeyEvent;
24 import android.view.View;
25 
26 import androidx.test.filters.LargeTest;
27 
28 import com.android.frameworks.coretests.R;
29 
30 /**
31  * Test {@link DatePicker} focus changes.
32  */
33 @LargeTest
34 public class DatePickerFocusTest extends ActivityInstrumentationTestCase2<DatePickerActivity> {
35 
36     private Activity mActivity;
37     private Instrumentation mInstrumentation;
38     private DatePicker mDatePicker;
39 
DatePickerFocusTest()40     public DatePickerFocusTest() {
41         super(DatePickerActivity.class);
42     }
43 
44     @Override
setUp()45     protected void setUp() throws Exception {
46         super.setUp();
47 
48         mActivity = getActivity();
49         mInstrumentation = getInstrumentation();
50 
51         mDatePicker = (DatePicker) mActivity.findViewById(R.id.datePicker);
52     }
53 
54     /**
55      * Tabs (forward and backward) through the DatePicker to ensure the correct
56      * Views gain focus.
57      */
testFocusTravel()58     public void testFocusTravel() throws Throwable {
59         runTestOnUiThread(new Runnable() {
60             @Override
61             public void run() {
62                 assertTrue(mDatePicker.requestFocus());
63             }
64         });
65         assertViewHasFocus(com.android.internal.R.id.date_picker_header_year);
66         sendKey(KeyEvent.KEYCODE_TAB);
67         assertViewHasFocus(com.android.internal.R.id.prev);
68         sendKey(KeyEvent.KEYCODE_TAB);
69         assertViewHasFocus(com.android.internal.R.id.next);
70         sendKey(KeyEvent.KEYCODE_TAB);
71         assertViewHasFocus(com.android.internal.R.id.day_picker_view_pager);
72         sendKey(KeyEvent.KEYCODE_TAB);
73         assertViewHasFocus(R.id.belowPicker);
74         sendShiftKey(KeyEvent.KEYCODE_TAB);
75         assertViewHasFocus(com.android.internal.R.id.day_picker_view_pager);
76         sendShiftKey(KeyEvent.KEYCODE_TAB);
77         assertViewHasFocus(com.android.internal.R.id.next);
78         sendShiftKey(KeyEvent.KEYCODE_TAB);
79         assertViewHasFocus(com.android.internal.R.id.prev);
80         sendShiftKey(KeyEvent.KEYCODE_TAB);
81         assertViewHasFocus(com.android.internal.R.id.date_picker_header_year);
82     }
83 
sendKey(int keycode)84     private void sendKey(int keycode) {
85         mInstrumentation.sendKeyDownUpSync(keycode);
86         mInstrumentation.waitForIdleSync();
87     }
88 
assertViewHasFocus(final int id)89     private void assertViewHasFocus(final int id) throws Throwable {
90         runTestOnUiThread(new Runnable() {
91             @Override
92             public void run() {
93                 View view = mActivity.findViewById(id);
94                 assertTrue(view.hasFocus());
95             }
96         });
97     }
98 
sendShiftKey(int keycode)99     private void sendShiftKey(int keycode) {
100         final KeyEvent shiftDown = new KeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_SHIFT_LEFT);
101         mInstrumentation.sendKeySync(shiftDown);
102 
103         final KeyEvent keyDown = new KeyEvent(SystemClock.uptimeMillis(),
104                 SystemClock.uptimeMillis(), KeyEvent.ACTION_DOWN, keycode, 0,
105                 KeyEvent.META_SHIFT_ON);
106         mInstrumentation.sendKeySync(keyDown);
107 
108         final KeyEvent keyUp = new KeyEvent(SystemClock.uptimeMillis(),
109                 SystemClock.uptimeMillis(), KeyEvent.ACTION_UP, keycode, 0,
110                 KeyEvent.META_SHIFT_ON);
111         mInstrumentation.sendKeySync(keyUp);
112 
113         final KeyEvent shiftUp = new KeyEvent(KeyEvent.ACTION_UP, KeyEvent.KEYCODE_SHIFT_LEFT);
114         mInstrumentation.sendKeySync(shiftUp);
115 
116         mInstrumentation.waitForIdleSync();
117     }
118 
119     /**
120      * Tests to ensure the keyboard can select the current year.
121      */
testYearChoice()122     public void testYearChoice() throws Throwable {
123         setKnownDate();
124         runTestOnUiThread(new Runnable() {
125             @Override
126             public void run() {
127                 View year = mDatePicker.
128                         findViewById(com.android.internal.R.id.date_picker_header_year);
129                 assertTrue(year.requestFocus());
130             }
131         });
132         sendKey(KeyEvent.KEYCODE_ENTER);
133         runTestOnUiThread(new Runnable() {
134             @Override
135             public void run() {
136                 View yearSelect = mDatePicker.
137                         findViewById(com.android.internal.R.id.date_picker_year_picker);
138                 assertEquals(yearSelect, mDatePicker.findFocus());
139             }
140         });
141         sendKey(KeyEvent.KEYCODE_DPAD_UP);
142         sendKey(KeyEvent.KEYCODE_ENTER);
143         runTestOnUiThread(new Runnable() {
144             @Override
145             public void run() {
146                 View yearSelect = mDatePicker.
147                         findViewById(com.android.internal.R.id.date_picker_year_picker);
148                 assertNotSame(View.VISIBLE, yearSelect.getVisibility());
149                 View year = mDatePicker.
150                         findViewById(com.android.internal.R.id.date_picker_header_year);
151                 assertTrue(year.hasFocus());
152                 assertEquals(2014, mDatePicker.getYear());
153             }
154         });
155     }
156 
testArrowThroughDays()157     public void testArrowThroughDays() throws Throwable {
158         setKnownDate();
159         runTestOnUiThread(new Runnable() {
160             @Override
161             public void run() {
162                 View prev = mDatePicker.findViewById(com.android.internal.R.id.next);
163                 prev.requestFocus();
164             }
165         });
166         sendKey(KeyEvent.KEYCODE_TAB);
167         // Should select the current date and the date shouldn't change
168         sendKey(KeyEvent.KEYCODE_ENTER);
169         assertDateIs(12, 31, 2015);
170         // Move right to January 24, 2016
171         sendKey(KeyEvent.KEYCODE_DPAD_RIGHT);
172         sendKey(KeyEvent.KEYCODE_ENTER);
173         assertDateIs(1, 24, 2016);
174         // Move down to January 31, 2016
175         sendKey(KeyEvent.KEYCODE_DPAD_DOWN);
176         sendKey(KeyEvent.KEYCODE_ENTER);
177         assertDateIs(1, 31, 2016);
178         // Move up to January 5, 2016
179         sendKey(KeyEvent.KEYCODE_DPAD_UP);
180         sendKey(KeyEvent.KEYCODE_DPAD_UP);
181         sendKey(KeyEvent.KEYCODE_DPAD_UP);
182         sendKey(KeyEvent.KEYCODE_DPAD_UP);
183         sendKey(KeyEvent.KEYCODE_DPAD_RIGHT);
184         sendKey(KeyEvent.KEYCODE_DPAD_RIGHT);
185         sendKey(KeyEvent.KEYCODE_ENTER);
186         assertDateIs(1, 5, 2016);
187         // Move up to prev arrow key
188         sendKey(KeyEvent.KEYCODE_DPAD_UP);
189         assertViewHasFocus(com.android.internal.R.id.prev);
190         // tab back into the day-selection pager
191         sendKey(KeyEvent.KEYCODE_TAB);
192         sendKey(KeyEvent.KEYCODE_TAB);
193         sendKey(KeyEvent.KEYCODE_ENTER);
194         assertViewHasFocus(com.android.internal.R.id.day_picker_view_pager);
195         assertDateIs(1, 5, 2016);
196 
197         // Move up out again, then down back into the day-selection pager.
198         // It should land right below the prev button (1/3/2016)
199         sendKey(KeyEvent.KEYCODE_DPAD_UP);
200         sendKey(KeyEvent.KEYCODE_DPAD_DOWN);
201         sendKey(KeyEvent.KEYCODE_ENTER);
202         assertViewHasFocus(com.android.internal.R.id.day_picker_view_pager);
203         assertDateIs(1, 3, 2016);
204 
205         // Move left to previous month (12/12/2015)
206         sendKey(KeyEvent.KEYCODE_DPAD_LEFT);
207         sendKey(KeyEvent.KEYCODE_ENTER);
208         assertDateIs(12, 12, 2015);
209         // Now make sure the start of the month works
210         // Move up to 12/5/2015 and right to 1/1/2016
211         sendKey(KeyEvent.KEYCODE_DPAD_UP);
212         sendKey(KeyEvent.KEYCODE_DPAD_RIGHT);
213         sendKey(KeyEvent.KEYCODE_ENTER);
214         assertDateIs(1, 1, 2016);
215         // Now make sure the left key goes back to previous month (12/5/2015)
216         sendKey(KeyEvent.KEYCODE_DPAD_LEFT);
217         sendKey(KeyEvent.KEYCODE_ENTER);
218         assertDateIs(12, 5, 2015);
219         // Now go to a mismatched row (no such row on previous month)
220         // This moves over to 1/31/2016 and then left to 12/31/2015
221         sendKey(KeyEvent.KEYCODE_DPAD_DOWN);
222         sendKey(KeyEvent.KEYCODE_DPAD_DOWN);
223         sendKey(KeyEvent.KEYCODE_DPAD_DOWN);
224         sendKey(KeyEvent.KEYCODE_DPAD_RIGHT);
225         sendKey(KeyEvent.KEYCODE_DPAD_DOWN);
226         sendKey(KeyEvent.KEYCODE_DPAD_DOWN);
227         sendKey(KeyEvent.KEYCODE_DPAD_LEFT);
228         sendKey(KeyEvent.KEYCODE_ENTER);
229         assertDateIs(12, 31, 2015);
230     }
231 
assertDateIs(int month, final int day, final int year)232     private void assertDateIs(int month, final int day, final int year) throws Throwable {
233         final int monthInt = month - 1; // months are 0-based
234         runTestOnUiThread(new Runnable() {
235             @Override
236             public void run() {
237                 assertEquals(day, mDatePicker.getDayOfMonth());
238                 assertEquals(year, mDatePicker.getYear());
239                 assertEquals(monthInt, mDatePicker.getMonth());
240             }
241         });
242     }
243 
setKnownDate()244     private void setKnownDate() throws Throwable {
245         runTestOnUiThread(new Runnable() {
246             @Override
247             public void run() {
248                 mDatePicker.updateDate(2015, 11, 31); // December 31, 2015
249             }
250         });
251         mInstrumentation.waitForIdleSync();
252     }
253 }
254