• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2020 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 com.android.deskclock.timer;
18 
19 import android.content.Context;
20 import android.text.TextUtils;
21 import android.view.View;
22 import android.widget.TextView;
23 
24 import androidx.annotation.IdRes;
25 import androidx.test.internal.runner.junit4.AndroidJUnit4ClassRunner;
26 import androidx.test.platform.app.InstrumentationRegistry;
27 import androidx.test.rule.ActivityTestRule;
28 
29 import com.android.deskclock.DeskClock;
30 import com.android.deskclock.R;
31 import com.android.deskclock.data.DataModel;
32 import com.android.deskclock.data.Timer;
33 import com.android.deskclock.widget.MockFabContainer;
34 
35 import org.junit.After;
36 import org.junit.Before;
37 import org.junit.Rule;
38 import org.junit.Test;
39 import org.junit.runner.RunWith;
40 
41 import java.util.Locale;
42 
43 import static android.text.format.DateUtils.HOUR_IN_MILLIS;
44 import static android.text.format.DateUtils.MINUTE_IN_MILLIS;
45 import static android.text.format.DateUtils.SECOND_IN_MILLIS;
46 import static android.view.View.INVISIBLE;
47 import static android.view.View.VISIBLE;
48 import static org.junit.Assert.assertArrayEquals;
49 import static org.junit.Assert.assertEquals;
50 import static org.junit.Assert.assertFalse;
51 import static org.junit.Assert.assertNotNull;
52 import static org.junit.Assert.assertNull;
53 import static org.junit.Assert.assertTrue;
54 
55 /**
56  * Exercise the user interface that collects new timer lengths.
57  */
58 @RunWith(AndroidJUnit4ClassRunner.class)
59 public class TimerSetupViewTest {
60 
61     private MockFabContainer fabContainer;
62     private TimerSetupView timerSetupView;
63 
64     private TextView timeView;
65     private View deleteView;
66 
67     private Locale defaultLocale;
68 
69     @Rule
70     public ActivityTestRule<DeskClock> rule = new ActivityTestRule<>(DeskClock.class, true);
71 
72     @Before
setUp()73     public void setUp() {
74         defaultLocale = Locale.getDefault();
75         Locale.setDefault(new Locale("en", "US"));
76         Context context = InstrumentationRegistry.getInstrumentation().getTargetContext();
77         final TimerFragment fragment = new TimerFragment();
78         rule.getActivity().getSupportFragmentManager()
79                 .beginTransaction().add(fragment, null).commit();
80         Runnable selectTabRunnable = () -> {
81             fragment.selectTab();
82             fabContainer = new MockFabContainer(fragment, context);
83             fragment.setFabContainer(fabContainer);
84 
85             // Fetch the child views the tests will manipulate.
86             final View view = fragment.getView();
87             assertNotNull(view);
88 
89             timerSetupView = view.findViewById(R.id.timer_setup);
90             assertNotNull(timerSetupView);
91             assertEquals(VISIBLE, timerSetupView.getVisibility());
92 
93             timeView = timerSetupView.findViewById(R.id.timer_setup_time);
94             timeView.setActivated(true);
95             deleteView = timerSetupView.findViewById(R.id.timer_setup_delete);
96         };
97         InstrumentationRegistry.getInstrumentation().runOnMainSync(selectTabRunnable);
98     }
99 
100     @After
tearDown()101     public void tearDown() {
102         fabContainer = null;
103         timerSetupView = null;
104 
105         timeView = null;
106         deleteView = null;
107 
108         Locale.setDefault(defaultLocale);
109     }
110 
validateDefaultState()111     private void validateDefaultState() {
112         assertIsReset();
113     }
114 
115     @Test
validateDefaultState_TimersExist()116     public void validateDefaultState_TimersExist() {
117         Runnable addTimerRunnable = () -> {
118             Timer timer = DataModel.getDataModel().addTimer(5000L, "", false);
119             validateDefaultState();
120             DataModel.getDataModel().removeTimer(timer);
121         };
122         InstrumentationRegistry.getInstrumentation().runOnMainSync(addTimerRunnable);
123     }
124 
125     @Test
validateDefaultState_NoTimersExist()126     public void validateDefaultState_NoTimersExist() {
127         Runnable runnable = () -> {
128             validateDefaultState();
129         };
130         InstrumentationRegistry.getInstrumentation().runOnMainSync(runnable);
131     }
132 
type0InDefaultState()133     private void type0InDefaultState() {
134         performClick(R.id.timer_setup_digit_0);
135         assertIsReset();
136     }
137 
138     @Test
type0InDefaultState_TimersExist()139     public void type0InDefaultState_TimersExist() {
140         Runnable addTimerRunnable = () -> {
141             Timer timer = DataModel.getDataModel().addTimer(5000L, "", false);
142             type0InDefaultState();
143             DataModel.getDataModel().removeTimer(timer);
144         };
145         InstrumentationRegistry.getInstrumentation().runOnMainSync(addTimerRunnable);
146     }
147 
148     @Test
type0InDefaultState_NoTimersExist()149     public void type0InDefaultState_NoTimersExist() {
150         Runnable runnable = () -> {
151             type0InDefaultState();
152         };
153         InstrumentationRegistry.getInstrumentation().runOnMainSync(runnable);
154     }
155 
fillDisplayThenDeleteAll()156     private void fillDisplayThenDeleteAll() {
157         assertIsReset();
158         // Fill the display.
159         performClick(R.id.timer_setup_digit_1);
160         assertHasValue(0, 0, 1);
161         performClick(R.id.timer_setup_digit_2);
162         assertHasValue(0, 0, 12);
163         performClick(R.id.timer_setup_digit_3);
164         assertHasValue(0, 1, 23);
165         performClick(R.id.timer_setup_digit_4);
166         assertHasValue(0, 12, 34);
167         performClick(R.id.timer_setup_digit_5);
168         assertHasValue(1, 23, 45);
169         performClick(R.id.timer_setup_digit_6);
170         assertHasValue(12, 34, 56);
171 
172         // Typing another character is ignored.
173         performClick(R.id.timer_setup_digit_7);
174         assertHasValue(12, 34, 56);
175         performClick(R.id.timer_setup_digit_8);
176         assertHasValue(12, 34, 56);
177 
178         // Delete everything in the display.
179         performClick(R.id.timer_setup_delete);
180         assertHasValue(1, 23, 45);
181         performClick(R.id.timer_setup_delete);
182         assertHasValue(0, 12, 34);
183         performClick(R.id.timer_setup_delete);
184         assertHasValue(0, 1, 23);
185         performClick(R.id.timer_setup_delete);
186         assertHasValue(0, 0, 12);
187         performClick(R.id.timer_setup_delete);
188         assertHasValue(0, 0, 1);
189         performClick(R.id.timer_setup_delete);
190         assertIsReset();
191     }
192 
193     @Test
fillDisplayThenDeleteAll_TimersExist()194     public void fillDisplayThenDeleteAll_TimersExist() {
195         Runnable addTimerRunnable = () -> {
196             Timer timer = DataModel.getDataModel().addTimer(5000L, "", false);
197             fillDisplayThenDeleteAll();
198             DataModel.getDataModel().removeTimer(timer);
199         };
200         InstrumentationRegistry.getInstrumentation().runOnMainSync(addTimerRunnable);
201     }
202 
203     @Test
fillDisplayThenDeleteAll_NoTimersExist()204     public void fillDisplayThenDeleteAll_NoTimersExist() {
205         Runnable runnable = () -> {
206             fillDisplayThenDeleteAll();
207         };
208         InstrumentationRegistry.getInstrumentation().runOnMainSync(runnable);
209     }
210 
fillDisplayWith9s()211     private void fillDisplayWith9s() {
212         performClick(R.id.timer_setup_digit_9);
213         performClick(R.id.timer_setup_digit_9);
214         performClick(R.id.timer_setup_digit_9);
215         performClick(R.id.timer_setup_digit_9);
216         performClick(R.id.timer_setup_digit_9);
217         performClick(R.id.timer_setup_digit_9);
218         assertHasValue(99, 99, 99);
219     }
220 
221     @Test
fillDisplayWith9s_TimersExist()222     public void fillDisplayWith9s_TimersExist() {
223         Runnable addTimerRunnable = () -> {
224             Timer timer = DataModel.getDataModel().addTimer(5000L, "", false);
225             fillDisplayWith9s();
226             DataModel.getDataModel().removeTimer(timer);
227         };
228         InstrumentationRegistry.getInstrumentation().runOnMainSync(addTimerRunnable);
229     }
230 
231     @Test
fillDisplayWith9s_NoTimersExist()232     public void fillDisplayWith9s_NoTimersExist() {
233         Runnable runnable = () -> {
234             fillDisplayWith9s();
235         };
236         InstrumentationRegistry.getInstrumentation().runOnMainSync(runnable);
237     }
238 
assertIsReset()239     private void assertIsReset() {
240         assertStateEquals(0, 0, 0);
241         assertFalse(timerSetupView.hasValidInput());
242         assertEquals(0, timerSetupView.getTimeInMillis());
243 
244         assertTrue(TextUtils.equals("00h 00m 00s", timeView.getText()));
245         assertTrue(TextUtils.equals("0 hours, 0 minutes, 0 seconds",
246                 timeView.getContentDescription()));
247 
248         assertFalse(deleteView.isEnabled());
249         assertTrue(TextUtils.equals("Delete", deleteView.getContentDescription()));
250 
251         final View fab = fabContainer.getFab();
252         final TextView leftButton = fabContainer.getLeftButton();
253         final TextView rightButton = fabContainer.getRightButton();
254 
255         if (DataModel.getDataModel().getTimers().isEmpty()) {
256             assertEquals(INVISIBLE, leftButton.getVisibility());
257         } else {
258             assertEquals(VISIBLE, leftButton.getVisibility());
259             assertTrue(TextUtils.equals("Cancel", leftButton.getText()));
260         }
261 
262         assertNull(fab.getContentDescription());
263         assertEquals(INVISIBLE, fab.getVisibility());
264         assertEquals(INVISIBLE, rightButton.getVisibility());
265     }
266 
assertHasValue(int hours, int minutes, int seconds)267     private void assertHasValue(int hours, int minutes, int seconds) {
268         final long time =
269                 hours * HOUR_IN_MILLIS + minutes * MINUTE_IN_MILLIS + seconds * SECOND_IN_MILLIS;
270         assertStateEquals(hours, minutes, seconds);
271         assertTrue(timerSetupView.hasValidInput());
272         assertEquals(time, timerSetupView.getTimeInMillis());
273 
274         final String timeString =
275                 String.format(Locale.US, "%02dh %02dm %02ds", hours, minutes, seconds);
276         assertTrue(TextUtils.equals(timeString, timeView.getText()));
277 
278         assertTrue(deleteView.isEnabled());
279         assertTrue(TextUtils.equals("Delete " + seconds % 10, deleteView.getContentDescription()));
280 
281         final View fab = fabContainer.getFab();
282         final TextView leftButton = fabContainer.getLeftButton();
283         final TextView rightButton = fabContainer.getRightButton();
284 
285         if (DataModel.getDataModel().getTimers().isEmpty()) {
286             assertEquals(INVISIBLE, leftButton.getVisibility());
287         } else {
288             assertEquals(VISIBLE, leftButton.getVisibility());
289             assertTrue(TextUtils.equals("Cancel", leftButton.getText()));
290         }
291 
292         assertEquals(VISIBLE, fab.getVisibility());
293         assertTrue(TextUtils.equals("Start", fab.getContentDescription()));
294         assertEquals(INVISIBLE, rightButton.getVisibility());
295     }
296 
assertStateEquals(int hours, int minutes, int seconds)297     private void assertStateEquals(int hours, int minutes, int seconds) {
298         final int[] expected = {
299                 seconds % 10, seconds / 10, minutes % 10, minutes / 10, hours % 10, hours / 10
300         };
301         final int[] actual = (int[]) timerSetupView.getState();
302         assertArrayEquals(expected, actual);
303     }
304 
performClick(@dRes int id)305     private void performClick(@IdRes int id) {
306         final View view = timerSetupView.findViewById(id);
307         assertNotNull(view);
308         assertTrue(view.performClick());
309     }
310 }
311