Home | History | Annotate | Download | only in wizard
      1 /*
      2  * Copyright (C) 2016 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
      5  * in compliance with the License. You may obtain a copy of the License at
      6  *
      7  * http://www.apache.org/licenses/LICENSE-2.0
      8  *
      9  * Unless required by applicable law or agreed to in writing, software distributed under the License
     10  * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
     11  * or implied. See the License for the specific language governing permissions and limitations under
     12  * the License.
     13  */
     14 
     15 package androidx.leanback.app.wizard;
     16 
     17 import static org.junit.Assert.assertTrue;
     18 
     19 import android.content.Context;
     20 import android.content.Intent;
     21 import android.content.res.Resources;
     22 import android.support.test.InstrumentationRegistry;
     23 import android.support.test.filters.LargeTest;
     24 import android.support.test.rule.ActivityTestRule;
     25 import android.support.test.runner.AndroidJUnit4;
     26 import android.util.Log;
     27 import android.view.KeyEvent;
     28 import android.widget.LinearLayout;
     29 
     30 import androidx.leanback.app.GuidedStepFragment;
     31 import androidx.leanback.test.R;
     32 import androidx.leanback.widget.GuidanceStylist;
     33 import androidx.leanback.widget.GuidedAction;
     34 import androidx.leanback.widget.GuidedDatePickerAction;
     35 import androidx.leanback.widget.VerticalGridView;
     36 import androidx.leanback.widget.picker.DatePicker;
     37 
     38 import org.junit.Before;
     39 import org.junit.Rule;
     40 import org.junit.Test;
     41 import org.junit.runner.RunWith;
     42 
     43 import java.text.SimpleDateFormat;
     44 import java.util.ArrayList;
     45 import java.util.Calendar;
     46 import java.util.Date;
     47 import java.util.List;
     48 
     49 @LargeTest
     50 @RunWith(AndroidJUnit4.class)
     51 public class GuidedDatePickerTest {
     52 
     53     static final long TRANSITION_LENGTH = 1000;
     54     static long VERTICAL_SCROLL_WAIT = 500;
     55     static long HORIZONTAL_SCROLL_WAIT = 500;
     56     static final long FINAL_WAIT = 1000;
     57 
     58     static final String TAG = "GuidedDatePickerTest";
     59 
     60     private static final int DAY_INDEX = 0;
     61     private static final int MONTH_INDEX = 1;
     62     private static final int YEAR_INDEX = 2;
     63 
     64     @Rule
     65     public ActivityTestRule<GuidedStepAttributesTestActivity> activityTestRule =
     66             new ActivityTestRule<>(GuidedStepAttributesTestActivity.class, false, false);
     67 
     68     GuidedStepAttributesTestActivity mActivity;
     69 
     70 
     71     private void initActivity(Intent intent) {
     72         mActivity = activityTestRule.launchActivity(intent);
     73         try {
     74             Thread.sleep(2000);
     75         } catch(InterruptedException e) {
     76             e.printStackTrace();
     77         }
     78 
     79     }
     80 
     81     Context mContext;
     82     @Before
     83     public void setUp() {
     84         mContext = InstrumentationRegistry.getInstrumentation().getTargetContext();;
     85     }
     86 
     87     public static void sendKey(int keyCode) {
     88         InstrumentationRegistry.getInstrumentation().sendKeyDownUpSync(keyCode);
     89     }
     90 
     91     private int getColumnIndexForDateField(int field, int[] columnIndices) {
     92         int mColDayIndex = columnIndices[0];
     93         int mColMonthIndex = columnIndices[1];
     94         int mColYearIndex = columnIndices[2];
     95         int columnIndex = -1;
     96         switch (field) {
     97             case Calendar.DAY_OF_MONTH:
     98                 columnIndex = mColDayIndex;
     99                 break;
    100             case Calendar.MONTH:
    101                 columnIndex = mColMonthIndex;
    102                 break;
    103             case Calendar.YEAR:
    104                 columnIndex = mColYearIndex;
    105         }
    106         return columnIndex;
    107     }
    108 
    109     private void horizontalScrollToDateField(int field, int[] columnIndices,
    110                                              DatePicker pickerView) throws Throwable{
    111         int columnIndex = getColumnIndexForDateField(field, columnIndices);
    112 
    113         LinearLayout columnsLayout = (LinearLayout) pickerView.getChildAt(0);
    114 
    115         int focusedFieldPos = columnsLayout.indexOfChild(columnsLayout.getFocusedChild());
    116         if (focusedFieldPos == -1) {
    117             sendKey(KeyEvent.KEYCODE_DPAD_CENTER);
    118             Thread.sleep(TRANSITION_LENGTH);
    119         }
    120         focusedFieldPos = columnsLayout.indexOfChild(columnsLayout.getFocusedChild());
    121         assertTrue("Date field could not be focused!", (focusedFieldPos != -1));
    122 
    123         // following is to skip the separator fields "/" which are unfocusable but counted as
    124         // children of columnsLayout
    125         switch (focusedFieldPos) {
    126             case 0:
    127                 focusedFieldPos = 0;
    128                 break;
    129             case 2:
    130                 focusedFieldPos = 1;
    131                 break;
    132             case 4:
    133                 focusedFieldPos = 2;
    134         }
    135 
    136         // now scroll right or left to the corresponding date field as indicated by the input field
    137         int horizontalScrollOffset = columnIndex - focusedFieldPos;
    138 
    139         int horizontalScrollDir = KeyEvent.KEYCODE_DPAD_RIGHT;
    140         if (horizontalScrollOffset < 0) {
    141             horizontalScrollOffset = -horizontalScrollOffset;
    142             horizontalScrollDir = KeyEvent.KEYCODE_DPAD_LEFT;
    143         }
    144         for(int i = 0; i < horizontalScrollOffset; i++) {
    145             sendKey(horizontalScrollDir);
    146             Thread.sleep(HORIZONTAL_SCROLL_WAIT);
    147         }
    148 
    149     }
    150 
    151     /**
    152      * Scrolls vertically all the way up or down (depending on the provided scrollDir parameter)
    153      * to fieldValue if it's not equal to -1; otherwise, the scrolling goes all the way to the end.
    154      * @param field The date field over which the scrolling is performed
    155      * @param fieldValue The field value to scroll to or -1 if the scrolling should go all the way.
    156      * @param columnIndices The date field indices corresponding to day, month, and the year
    157      * @param pickerView The DatePicker view.
    158      * @param scrollDir The direction of scrolling to reach the desired field value.
    159      * @throws Throwable
    160      */
    161     private void verticalScrollToFieldValue(int field, int fieldValue, int[] columnIndices,
    162                                                  DatePicker pickerView, int scrollDir)
    163             throws Throwable {
    164 
    165         int columnIndex = getColumnIndexForDateField(field, columnIndices);
    166         int colDayIndex = columnIndices[0];
    167         int colMonthIndex = columnIndices[1];
    168         int colYearIndex = columnIndices[2];
    169 
    170         horizontalScrollToDateField(field, columnIndices, pickerView);
    171 
    172         Calendar currentActionCal = Calendar.getInstance();
    173         currentActionCal.setTimeInMillis(pickerView.getDate());
    174 
    175         Calendar minCal = Calendar.getInstance();
    176         minCal.setTimeInMillis(pickerView.getMinDate());
    177 
    178         Calendar maxCal = Calendar.getInstance();
    179         maxCal.setTimeInMillis(pickerView.getMaxDate());
    180 
    181 
    182         int prevColumnVal = -1;
    183         int currentColumnVal = pickerView.getColumnAt(columnIndex).getCurrentValue();
    184         while( currentColumnVal != prevColumnVal && currentColumnVal != fieldValue){
    185             assertTrue(mContext.getString(R.string.datepicker_test_wrong_day_value),
    186                     pickerView.getColumnAt(colDayIndex).getCurrentValue()
    187                             == currentActionCal.get(Calendar.DAY_OF_MONTH)
    188             );
    189             assertTrue(mContext.getString(R.string.datepicker_test_wrong_month_value),
    190                     pickerView.getColumnAt(colMonthIndex).getCurrentValue()
    191                             == currentActionCal.get(Calendar.MONTH)
    192             );
    193             assertTrue(mContext.getString(R.string.datepicker_test_wrong_year_value),
    194                     pickerView.getColumnAt(colYearIndex).getCurrentValue()
    195                             == currentActionCal.get(Calendar.YEAR)
    196             );
    197 
    198             int offset = scrollDir == KeyEvent.KEYCODE_DPAD_DOWN ? 1 : -1;
    199             addDate(currentActionCal, field, offset, minCal, maxCal);
    200 
    201             sendKey(scrollDir);
    202             Thread.sleep(VERTICAL_SCROLL_WAIT);
    203 
    204             prevColumnVal = currentColumnVal;
    205             currentColumnVal = pickerView.getColumnAt(columnIndex).getCurrentValue();
    206         }
    207     }
    208 
    209     private void addDate(Calendar mCurrentDate, int field, int offset,
    210                          Calendar mMinDate, Calendar mMaxDate) {
    211         int maxOffset = -1;
    212         int actualMinFieldValue, actualMaxFieldValue;
    213 
    214         if ( field == Calendar.YEAR ) {
    215             actualMinFieldValue = mMinDate.get(Calendar.YEAR);
    216             actualMaxFieldValue = mMaxDate.get(Calendar.YEAR);
    217         } else {
    218             actualMinFieldValue = mCurrentDate.getActualMinimum(field);
    219             actualMaxFieldValue = mCurrentDate.getActualMaximum(field);
    220         }
    221 
    222         if ( offset > 0 ) {
    223             maxOffset = Math.min(
    224                     actualMaxFieldValue - mCurrentDate.get(field), offset);
    225             mCurrentDate.add(field, maxOffset);
    226             if (mCurrentDate.after(mMaxDate)) {
    227                 mCurrentDate.setTimeInMillis(mMaxDate.getTimeInMillis());
    228             }
    229         } else {
    230             maxOffset = Math.max(
    231                     actualMinFieldValue - mCurrentDate.get(field), offset);
    232             mCurrentDate.add(field, Math.max(offset, maxOffset));
    233             if (mCurrentDate.before(mMinDate)) {
    234                 mCurrentDate.setTimeInMillis(mMinDate.getTimeInMillis());
    235             }
    236         }
    237     }
    238 
    239     @Test
    240     public void testJanuaryToFebruaryTransitionForLeapYear() throws Throwable {
    241         long startTime = System.currentTimeMillis();
    242         Intent intent = new Intent();
    243 
    244         String title = "Date Picker Transition Test";
    245         String breadcrumb = "Month Transition Test Demo";
    246         String description = "Testing the transition from Jan to Feb (leap year)";
    247         GuidanceStylist.Guidance guidance = new GuidanceStylist.Guidance(title, description,
    248                 breadcrumb, null);
    249 
    250         List<GuidedAction> actionList = new ArrayList<>();
    251 
    252         Calendar cal = Calendar.getInstance();
    253 
    254         cal.set(Calendar.YEAR, 2016);   // 2016 is a leap year
    255         cal.set(Calendar.MONTH, Calendar.JANUARY);
    256         cal.set(Calendar.DAY_OF_MONTH, cal.getActualMaximum(Calendar.DAY_OF_MONTH));
    257         Date initialDate = cal.getTime();
    258 
    259         GuidedDatePickerAction action = new GuidedDatePickerAction.Builder(
    260                 mContext)
    261                 .id(0)
    262                 .title("Date")
    263                 .date(initialDate.getTime())
    264                 .datePickerFormat("DMY")
    265                 .build();
    266 
    267         actionList.add(action);
    268 
    269         GuidedStepAttributesTestFragment.clear();
    270         GuidedStepAttributesTestFragment.GUIDANCE = guidance;
    271         GuidedStepAttributesTestFragment.ACTION_LIST = actionList;
    272 
    273         initActivity(intent);
    274 
    275         DatePicker mPickerView = (DatePicker) mActivity.findViewById(
    276                 R.id.guidedactions_activator_item);
    277 
    278         verticalScrollToFieldValue(Calendar.MONTH, Calendar.FEBRUARY, new int[] {0, 1, 2},
    279                 mPickerView, KeyEvent.KEYCODE_DPAD_DOWN);
    280         long executionTime = System.currentTimeMillis() - startTime;
    281         Log.d(TAG, "testJanuaryToFebruaryTransitionForLeapYear() Execution time: " + executionTime);
    282         Thread.sleep(FINAL_WAIT);
    283     }
    284 
    285     @Test
    286     public void testFebruaryToMarchTransitionForLeapYear() throws Throwable {
    287         long startTime = System.currentTimeMillis();
    288         Intent intent = new Intent();
    289 
    290         String title = "Date Picker Transition Test";
    291         String breadcrumb = "Month Transition Test Demo";
    292         String description = "Testing the transition from Feb to Mar (leap year)";
    293         GuidanceStylist.Guidance guidance = new GuidanceStylist.Guidance(title, description,
    294                 breadcrumb, null);
    295 
    296         List<GuidedAction> actionList = new ArrayList<>();
    297 
    298         Calendar cal = Calendar.getInstance();
    299 
    300         cal.set(Calendar.YEAR, 2016);
    301         cal.set(Calendar.MONTH, Calendar.FEBRUARY);
    302         cal.set(Calendar.DAY_OF_MONTH, cal.getActualMaximum(Calendar.DAY_OF_MONTH));
    303         Date initialDate = cal.getTime();
    304 
    305         GuidedDatePickerAction action = new GuidedDatePickerAction.Builder(
    306                 mContext)
    307                 .id(0)
    308                 .title("Date")
    309                 .date(initialDate.getTime())
    310                 .datePickerFormat("DMY")
    311                 .build();
    312 
    313         actionList.add(action);
    314 
    315         GuidedStepAttributesTestFragment.clear();
    316         GuidedStepAttributesTestFragment.GUIDANCE = guidance;
    317         GuidedStepAttributesTestFragment.ACTION_LIST = actionList;
    318 
    319         initActivity(intent);
    320 
    321         DatePicker mPickerView = (DatePicker) mActivity.findViewById(
    322                 R.id.guidedactions_activator_item);
    323 
    324         verticalScrollToFieldValue(Calendar.MONTH, Calendar.MARCH, new int[] {0, 1, 2},
    325                 mPickerView, KeyEvent.KEYCODE_DPAD_DOWN);
    326         long executionTime = System.currentTimeMillis() - startTime;
    327         Log.d(TAG, "testFebruaryToMarchTransition() Execution time: " + executionTime);
    328         Thread.sleep(FINAL_WAIT);
    329     }
    330 
    331     @Test
    332     public void testJanuaryToFebruaryTransitionForNonLeapYear() throws Throwable {
    333         long startTime = System.currentTimeMillis();
    334         Intent intent = new Intent();
    335 
    336         String title = "Date Picker Transition Test";
    337         String breadcrumb = "Month Transition Test Demo";
    338         String description = "Testing the transition from Jan to Feb (nonleap year)";
    339         GuidanceStylist.Guidance guidance = new GuidanceStylist.Guidance(title, description,
    340                 breadcrumb, null);
    341 
    342         List<GuidedAction> actionList = new ArrayList<>();
    343 
    344         Calendar cal = Calendar.getInstance();
    345 
    346         cal.set(Calendar.YEAR, 2017);   // 2017 is a leap year
    347         cal.set(Calendar.MONTH, Calendar.JANUARY);
    348         cal.set(Calendar.DAY_OF_MONTH, cal.getActualMaximum(Calendar.DAY_OF_MONTH));
    349         Date initialDate = cal.getTime();
    350 
    351         GuidedDatePickerAction action = new GuidedDatePickerAction.Builder(
    352                 mContext)
    353                 .id(0)
    354                 .title("Date")
    355                 .date(initialDate.getTime())
    356                 .datePickerFormat("DMY")
    357                 .build();
    358 
    359         actionList.add(action);
    360 
    361         GuidedStepAttributesTestFragment.clear();
    362         GuidedStepAttributesTestFragment.GUIDANCE = guidance;
    363         GuidedStepAttributesTestFragment.ACTION_LIST = actionList;
    364 
    365         initActivity(intent);
    366 
    367         DatePicker mPickerView = (DatePicker) mActivity.findViewById(
    368                 R.id.guidedactions_activator_item);
    369 
    370         verticalScrollToFieldValue(Calendar.MONTH, Calendar.FEBRUARY, new int[] {0, 1, 2},
    371                 mPickerView, KeyEvent.KEYCODE_DPAD_DOWN);
    372         long executionTime = System.currentTimeMillis() - startTime;
    373         Log.d(TAG, "testJanuaryToFebruaryTransition() Execution time: " + executionTime);
    374         Thread.sleep(FINAL_WAIT);
    375     }
    376 
    377     @Test
    378     public void testFebruaryToMarchTransitionForNonLeapYear() throws Throwable {
    379         long startTime = System.currentTimeMillis();
    380         Intent intent = new Intent();
    381 
    382         String title = "Date Picker Transition Test";
    383         String breadcrumb = "Month Transition Test Demo";
    384         String description = "Testing the transition from Feb to Mar (nonleap year)";
    385         GuidanceStylist.Guidance guidance = new GuidanceStylist.Guidance(title, description,
    386                 breadcrumb, null);
    387 
    388         List<GuidedAction> actionList = new ArrayList<>();
    389 
    390         Calendar cal = Calendar.getInstance();
    391 
    392         cal.set(Calendar.YEAR, 2017);
    393         cal.set(Calendar.MONTH, Calendar.FEBRUARY);
    394         cal.set(Calendar.DAY_OF_MONTH, cal.getActualMaximum(Calendar.DAY_OF_MONTH));
    395         Date initialDate = cal.getTime();
    396 
    397         GuidedDatePickerAction action = new GuidedDatePickerAction.Builder(
    398                 mContext)
    399                 .id(0)
    400                 .title("Date")
    401                 .date(initialDate.getTime())
    402                 .datePickerFormat("DMY")
    403                 .build();
    404 
    405         actionList.add(action);
    406 
    407         GuidedStepAttributesTestFragment.clear();
    408         GuidedStepAttributesTestFragment.GUIDANCE = guidance;
    409         GuidedStepAttributesTestFragment.ACTION_LIST = actionList;
    410 
    411         initActivity(intent);
    412 
    413         DatePicker mPickerView = (DatePicker) mActivity.findViewById(
    414                 R.id.guidedactions_activator_item);
    415 
    416         verticalScrollToFieldValue(Calendar.MONTH, Calendar.MARCH, new int[] {0, 1, 2},
    417                 mPickerView, KeyEvent.KEYCODE_DPAD_DOWN);
    418         long executionTime = System.currentTimeMillis() - startTime;
    419         Log.d(TAG, "testFebruaryToMarchTransition() Execution time: " + executionTime);
    420         Thread.sleep(FINAL_WAIT);
    421     }
    422 
    423     @Test
    424     public void testDecemberToNovemberTransition() throws Throwable {
    425         long startTime = System.currentTimeMillis();
    426         Intent intent = new Intent();
    427 
    428         String title = "Date Picker Transition Test";
    429         String breadcrumb = "Month Transition Test Demo";
    430         String description = "Testing the transition from Dec to Nov";
    431         GuidanceStylist.Guidance guidance = new GuidanceStylist.Guidance(title, description,
    432                 breadcrumb, null);
    433 
    434         List<GuidedAction> actionList = new ArrayList<>();
    435 
    436         Calendar cal = Calendar.getInstance();
    437 
    438         cal.set(Calendar.YEAR, 2016);
    439         cal.set(Calendar.MONTH, Calendar.DECEMBER);
    440         cal.set(Calendar.DAY_OF_MONTH, cal.getActualMaximum(Calendar.DAY_OF_MONTH));
    441         Date initialDate = cal.getTime();
    442 
    443         GuidedDatePickerAction action = new GuidedDatePickerAction.Builder(
    444                 mContext)
    445                 .id(0)
    446                 .title("Date")
    447                 .date(initialDate.getTime())
    448                 .datePickerFormat("DMY")
    449                 .build();
    450 
    451         actionList.add(action);
    452 
    453         GuidedStepAttributesTestFragment.clear();
    454         GuidedStepAttributesTestFragment.GUIDANCE = guidance;
    455         GuidedStepAttributesTestFragment.ACTION_LIST = actionList;
    456 
    457         initActivity(intent);
    458 
    459         DatePicker mPickerView = (DatePicker) mActivity.findViewById(
    460                 R.id.guidedactions_activator_item);
    461 
    462         verticalScrollToFieldValue(Calendar.MONTH, Calendar.NOVEMBER, new int[] {0, 1, 2},
    463                 mPickerView, KeyEvent.KEYCODE_DPAD_UP);
    464         long executionTime = System.currentTimeMillis() - startTime;
    465         Log.d(TAG, "testDecemberToNovember() Execution time: " + executionTime);
    466         Thread.sleep(FINAL_WAIT);
    467     }
    468 
    469     @Test
    470     public void testNovemberToOctoberTransition() throws Throwable {
    471         long startTime = System.currentTimeMillis();
    472         Intent intent = new Intent();
    473 
    474         String title = "Date Picker Transition Test";
    475         String breadcrumb = "Month Transition Test Demo";
    476         String description = "Testing the transition from Nov to Oct";
    477         GuidanceStylist.Guidance guidance = new GuidanceStylist.Guidance(title, description,
    478                 breadcrumb, null);
    479 
    480         List<GuidedAction> actionList = new ArrayList<>();
    481 
    482         Calendar cal = Calendar.getInstance();
    483 
    484         cal.set(Calendar.YEAR, 2016);
    485         cal.set(Calendar.MONTH, Calendar.NOVEMBER);
    486         cal.set(Calendar.DAY_OF_MONTH, cal.getActualMaximum(Calendar.DAY_OF_MONTH));
    487         Date initialDate = cal.getTime();
    488 
    489         GuidedDatePickerAction action = new GuidedDatePickerAction.Builder(
    490                 mContext)
    491                 .id(0)
    492                 .title("Date")
    493                 .date(initialDate.getTime())
    494                 .datePickerFormat("DMY")
    495                 .build();
    496 
    497         actionList.add(action);
    498 
    499         GuidedStepAttributesTestFragment.clear();
    500         GuidedStepAttributesTestFragment.GUIDANCE = guidance;
    501         GuidedStepAttributesTestFragment.ACTION_LIST = actionList;
    502 
    503         initActivity(intent);
    504 
    505         DatePicker mPickerView = (DatePicker) mActivity.findViewById(
    506                 R.id.guidedactions_activator_item);
    507 
    508         verticalScrollToFieldValue(Calendar.MONTH, Calendar.OCTOBER, new int[] {0, 1, 2},
    509                 mPickerView, KeyEvent.KEYCODE_DPAD_UP);
    510         long executionTime = System.currentTimeMillis() - startTime;
    511         Log.d(TAG, "testNovemberToOctober() Execution time: " + executionTime);
    512         Thread.sleep(FINAL_WAIT);
    513     }
    514 
    515     @Test
    516     public void testLeapToNonLeapYearTransition() throws Throwable {
    517         long startTime = System.currentTimeMillis();
    518         Intent intent = new Intent();
    519 
    520         String title = "Date Picker Transition Test";
    521         String breadcrumb = "Leap Year Transition Test Demo";
    522         String description = "Testing Feb transition from leap to nonlneap year";
    523         GuidanceStylist.Guidance guidance = new GuidanceStylist.Guidance(title, description,
    524                 breadcrumb, null);
    525 
    526         List<GuidedAction> actionList = new ArrayList<>();
    527 
    528         Calendar cal = Calendar.getInstance();
    529 
    530         cal.set(Calendar.YEAR, 2016);   // 2016 is a leap year
    531         cal.set(Calendar.MONTH, Calendar.FEBRUARY);
    532         cal.set(Calendar.DAY_OF_MONTH, cal.getActualMaximum(Calendar.DAY_OF_MONTH));
    533         Date initialDate = cal.getTime();
    534 
    535         GuidedDatePickerAction action = new GuidedDatePickerAction.Builder(
    536                 mContext)
    537                 .id(0)
    538                 .title("Date")
    539                 .date(initialDate.getTime())
    540                 .datePickerFormat("DMY")
    541                 .build();
    542 
    543         actionList.add(action);
    544 
    545         GuidedStepAttributesTestFragment.clear();
    546         GuidedStepAttributesTestFragment.GUIDANCE = guidance;
    547         GuidedStepAttributesTestFragment.ACTION_LIST = actionList;
    548 
    549         initActivity(intent);
    550 
    551         DatePicker mPickerView = (DatePicker) mActivity.findViewById(
    552                 R.id.guidedactions_activator_item);
    553 
    554         verticalScrollToFieldValue(Calendar.YEAR, 2017, new int[] {0, 1, 2},
    555                 mPickerView, KeyEvent.KEYCODE_DPAD_DOWN);
    556         long executionTime = System.currentTimeMillis() - startTime;
    557         Log.d(TAG, "testLeapToNonLeapYearTransition() Execution time: " + executionTime);
    558         Thread.sleep(FINAL_WAIT);
    559     }
    560 
    561     @Test
    562     public void testNonLeapToLeapYearTransition() throws Throwable {
    563         long startTime = System.currentTimeMillis();
    564         Intent intent = new Intent();
    565 
    566         String title = "Date Picker Transition Test";
    567         String breadcrumb = "Leap Year Transition Test Demo";
    568         String description = "Testing Feb transition from nonleap to leap year";
    569         GuidanceStylist.Guidance guidance = new GuidanceStylist.Guidance(title, description,
    570                 breadcrumb, null);
    571 
    572         List<GuidedAction> actionList = new ArrayList<>();
    573 
    574         Calendar cal = Calendar.getInstance();
    575 
    576         cal.set(Calendar.YEAR, 2017);   // 2017 is a non-leap year
    577         cal.set(Calendar.MONTH, Calendar.FEBRUARY);
    578         cal.set(Calendar.DAY_OF_MONTH, cal.getActualMaximum(Calendar.DAY_OF_MONTH));
    579         Date initialDate = cal.getTime();
    580 
    581         GuidedDatePickerAction action = new GuidedDatePickerAction.Builder(
    582                 mContext)
    583                 .id(0)
    584                 .title("Date")
    585                 .date(initialDate.getTime())
    586                 .datePickerFormat("DMY")
    587                 .build();
    588 
    589         actionList.add(action);
    590 
    591         GuidedStepAttributesTestFragment.clear();
    592         GuidedStepAttributesTestFragment.GUIDANCE = guidance;
    593         GuidedStepAttributesTestFragment.ACTION_LIST = actionList;
    594 
    595         initActivity(intent);
    596 
    597         DatePicker mPickerView = (DatePicker) mActivity.findViewById(
    598                 R.id.guidedactions_activator_item);
    599 
    600         verticalScrollToFieldValue(Calendar.YEAR, 2016, new int[] {0, 1, 2},
    601                 mPickerView, KeyEvent.KEYCODE_DPAD_UP);
    602         long executionTime = System.currentTimeMillis() - startTime;
    603         Log.d(TAG, "testNonLeapToLeapYearTransition() Execution time: " + executionTime);
    604         Thread.sleep(FINAL_WAIT);
    605     }
    606 
    607     private void traverseMonths(DatePicker mPickerView, GuidedDatePickerAction dateAction)
    608             throws Throwable {
    609 
    610         final GuidedStepFragment mFragment = (GuidedStepFragment)
    611                 mActivity.getGuidedStepTestFragment();
    612 
    613         Calendar currentActionCal = Calendar.getInstance();
    614         currentActionCal.setTimeInMillis(dateAction.getDate());
    615 
    616         sendKey(KeyEvent.KEYCODE_DPAD_CENTER);
    617         Thread.sleep(TRANSITION_LENGTH);
    618 
    619         int prevMonth = -1;
    620         int currentMonth = mPickerView.getColumnAt(MONTH_INDEX).getCurrentValue();
    621         while (currentMonth != prevMonth) {
    622             int prevDayOfMonth = -1;
    623             int currentDayOfMonth = mPickerView.getColumnAt(DAY_INDEX).getCurrentValue();
    624             // scroll down the days till reaching the last day of month
    625             while (currentDayOfMonth != prevDayOfMonth) {
    626                 sendKey(KeyEvent.KEYCODE_DPAD_DOWN);
    627                 Thread.sleep(VERTICAL_SCROLL_WAIT);
    628                 prevDayOfMonth = currentDayOfMonth;
    629                 currentDayOfMonth = mPickerView.getColumnAt(DAY_INDEX).getCurrentValue();
    630             }
    631             int oldDayValue = mPickerView.getColumnAt(DAY_INDEX).getCurrentValue();
    632             int oldMonthValue = mPickerView.getColumnAt(MONTH_INDEX).getCurrentValue();
    633             // increment the month
    634             sendKey(KeyEvent.KEYCODE_DPAD_RIGHT);
    635             Thread.sleep(VERTICAL_SCROLL_WAIT);
    636 
    637             sendKey(KeyEvent.KEYCODE_DPAD_DOWN);
    638             Thread.sleep(TRANSITION_LENGTH);
    639 
    640             int newDayValue = mPickerView.getColumnAt(DAY_INDEX).getCurrentValue();
    641             int newMonthValue = mPickerView.getColumnAt(MONTH_INDEX).getCurrentValue();
    642             verifyMonthTransition(currentActionCal,
    643                     oldDayValue, oldMonthValue, newDayValue, newMonthValue);
    644 
    645             sendKey(KeyEvent.KEYCODE_DPAD_LEFT);
    646             Thread.sleep(TRANSITION_LENGTH);
    647             prevMonth = currentMonth;
    648             currentMonth = newMonthValue;
    649         }
    650 
    651     }
    652 
    653 
    654     private void verifyMonthTransition(Calendar currentCal, int oldDayValue, int oldMonthValue,
    655                                        int newDayValue, int newMonthValue) {
    656 
    657         if (oldMonthValue == newMonthValue)
    658             return;
    659 
    660         currentCal.set(Calendar.DAY_OF_MONTH, 1);
    661         currentCal.set(Calendar.MONTH, oldMonthValue);
    662         int expectedOldDayValue = currentCal.getActualMaximum(Calendar.DAY_OF_MONTH);
    663         currentCal.set(Calendar.MONTH, newMonthValue);
    664         int numDaysInNewMonth = currentCal.getActualMaximum(Calendar.DAY_OF_MONTH);
    665         int expectedNewDayValue = (expectedOldDayValue <= numDaysInNewMonth)
    666                 ? expectedOldDayValue : numDaysInNewMonth;
    667 
    668         assertTrue(mContext.getString(
    669                 R.string.datepicker_test_transition_error1, oldMonthValue),
    670                 oldDayValue == expectedOldDayValue
    671         );
    672         assertTrue(mContext.getString(
    673                 R.string.datepicker_test_transition_error2, newDayValue, newMonthValue),
    674                 newDayValue == expectedNewDayValue
    675         );
    676     }
    677 
    678     @Test
    679     public void testDateRangesMDYFormat() throws Throwable {
    680 
    681         long startTime = System.currentTimeMillis();
    682 
    683         GuidedDatePickerAction[] datePickerActions = setupDateActionsForMinAndMaxRangeTests();
    684 
    685         scrollToMinAndMaxDates(new int[] {1, 0, 2}, datePickerActions[0]);
    686         long executionTime = System.currentTimeMillis() - startTime;
    687         Log.d(TAG, "testDateRangesMDYFormat() Execution time: " + executionTime);
    688         Thread.sleep(FINAL_WAIT);
    689     }
    690 
    691     public void testDateRangesDMYFormat() throws Throwable {
    692 
    693         long startTime = System.currentTimeMillis();
    694 
    695         GuidedDatePickerAction[] datePickerActions = setupDateActionsForMinAndMaxRangeTests();
    696         Log.d(TAG, "setup dateactions complete!");
    697         scrollToMinAndMaxDates(new int[] {0, 1, 2}, datePickerActions[1]);
    698         long executionTime = System.currentTimeMillis() - startTime;
    699         Log.d(TAG, "testDateRangesDMYFormat() Execution time: " + executionTime);
    700         Thread.sleep(FINAL_WAIT);
    701     }
    702 
    703     @Test
    704     public void testDateRangesWithYearEqual() throws Throwable {
    705 
    706         long startTime = System.currentTimeMillis();
    707 
    708         GuidedDatePickerAction[] datePickerActions = setupDateActionsForMinAndMaxRangeTests();
    709 
    710         scrollToMinAndMaxDates(new int[] {0, 1, 2}, datePickerActions[2]);
    711         long executionTime = System.currentTimeMillis() - startTime;
    712         Log.d(TAG, "testDateRangesWithYearEqual() Execution time: " + executionTime);
    713         Thread.sleep(FINAL_WAIT);
    714     }
    715 
    716     @Test
    717     public void testDateRangesWithMonthAndYearEqual() throws Throwable {
    718 
    719         long startTime = System.currentTimeMillis();
    720 
    721         GuidedDatePickerAction[] datePickerActions = setupDateActionsForMinAndMaxRangeTests();
    722 
    723         scrollToMinAndMaxDates(new int[] {0, 1, 2}, datePickerActions[3]);
    724         long executionTime = System.currentTimeMillis() - startTime;
    725         Log.d(TAG, "testDateRangesWithMonthAndYearEqual() Execution time: " + executionTime);
    726         Thread.sleep(FINAL_WAIT);
    727     }
    728 
    729     @Test
    730     public void testDateRangesWithAllFieldsEqual() throws Throwable {
    731 
    732         long startTime = System.currentTimeMillis();
    733 
    734         GuidedDatePickerAction[] datePickerActions = setupDateActionsForMinAndMaxRangeTests();
    735 
    736         scrollToMinAndMaxDates(new int[] {0, 1, 2}, datePickerActions[4]);
    737         long executionTime = System.currentTimeMillis() - startTime;
    738         Log.d(TAG, "testDateRangesWithAllFieldsEqual() Execution time: " + executionTime);
    739         Thread.sleep(FINAL_WAIT);
    740     }
    741 
    742     private GuidedDatePickerAction[] setupDateActionsForMinAndMaxRangeTests() {
    743         Intent intent = new Intent();
    744         Resources res = mContext.getResources();
    745 
    746         SimpleDateFormat dateFormat = new SimpleDateFormat("dd/MM/yyyy");
    747 
    748         Calendar currCal = Calendar.getInstance();
    749         currCal.set(Calendar.YEAR, 2016);
    750         currCal.set(Calendar.MONTH, Calendar.JULY);
    751         currCal.set(Calendar.DAY_OF_MONTH, 15);
    752 
    753         Calendar minCal = Calendar.getInstance();
    754         minCal.set(Calendar.YEAR, 2014);
    755         minCal.set(Calendar.MONTH, Calendar.OCTOBER);
    756         minCal.set(Calendar.DAY_OF_MONTH, 20);
    757 
    758         Calendar maxCal = Calendar.getInstance();
    759         maxCal.set(Calendar.YEAR, 2018);
    760         maxCal.set(Calendar.MONTH, Calendar.FEBRUARY);
    761         maxCal.set(Calendar.DAY_OF_MONTH, 10);
    762 
    763         String title = "Date Picker Range Test";
    764         String breadcrumb = "Date Picker Range Test Demo";
    765         String description = "";
    766         GuidanceStylist.Guidance guidance = new GuidanceStylist.Guidance(title, description,
    767                 breadcrumb, null);
    768 
    769         List<GuidedAction> actionList = new ArrayList<>();
    770 
    771         // testing different date formats and the correctness of range changes as we scroll
    772         GuidedDatePickerAction dateAction1 = new GuidedDatePickerAction.Builder(
    773                 mContext)
    774                 .id(0)
    775                 .title(res.getString(R.string.datepicker_with_range_title,
    776                         dateFormat.format(minCal.getTime()),
    777                         dateFormat.format(maxCal.getTime())))
    778                 .multilineDescription(true)
    779                 .date(currCal.getTimeInMillis())
    780                 .datePickerFormat("MDY")
    781                 .minDate(minCal.getTimeInMillis())
    782                 .maxDate(maxCal.getTimeInMillis())
    783                 .build();
    784 
    785         GuidedDatePickerAction dateAction2 = new GuidedDatePickerAction.Builder(
    786                 mContext)
    787                 .id(1)
    788                 .title(res.getString(R.string.datepicker_with_range_title,
    789                         dateFormat.format(minCal.getTimeInMillis()),
    790                         dateFormat.format(maxCal.getTimeInMillis())))
    791                 .multilineDescription(true)
    792                 .date(currCal.getTimeInMillis())
    793                 .datePickerFormat("DMY")
    794                 .minDate(minCal.getTimeInMillis())
    795                 .maxDate(maxCal.getTimeInMillis())
    796                 .build();
    797 
    798         // testing date ranges when Year is equal
    799         minCal.set(Calendar.YEAR, maxCal.get(Calendar.YEAR));
    800         int minMonth = Math.min(minCal.get(Calendar.MONTH), maxCal.get(Calendar.MONTH));
    801         int maxMonth = Math.max(minCal.get(Calendar.MONTH), maxCal.get(Calendar.MONTH));
    802         minCal.set(Calendar.MONTH, minMonth);
    803         maxCal.set(Calendar.MONTH, maxMonth);
    804 
    805         GuidedDatePickerAction dateAction3 = new GuidedDatePickerAction.Builder(
    806                 mContext)
    807                 .id(2)
    808                 .title(res.getString(R.string.datepicker_with_range_title,
    809                         dateFormat.format(minCal.getTimeInMillis()),
    810                         dateFormat.format(maxCal.getTimeInMillis())))
    811                 .multilineDescription(true)
    812                 .date(currCal.getTimeInMillis())
    813                 .datePickerFormat("DMY")
    814                 .minDate(minCal.getTimeInMillis())
    815                 .maxDate(maxCal.getTimeInMillis())
    816                 .build();
    817 
    818 
    819         // testing date ranges when both Month and Year are equal
    820         minCal.set(Calendar.MONTH, maxCal.get(Calendar.MONTH));
    821         int minDay = Math.min(minCal.get(Calendar.DAY_OF_MONTH), maxCal.get(Calendar.DAY_OF_MONTH));
    822         int maxDay = Math.max(minCal.get(Calendar.DAY_OF_MONTH), maxCal.get(Calendar.DAY_OF_MONTH));
    823         minCal.set(Calendar.DAY_OF_MONTH, minDay);
    824         maxCal.set(Calendar.DAY_OF_MONTH, maxDay);
    825 
    826         GuidedDatePickerAction dateAction4 = new GuidedDatePickerAction.Builder(
    827                 mContext)
    828                 .id(3)
    829                 .title(res.getString(R.string.datepicker_with_range_title,
    830                         dateFormat.format(minCal.getTimeInMillis()),
    831                         dateFormat.format(maxCal.getTimeInMillis())))
    832                 .multilineDescription(true)
    833                 .date(currCal.getTimeInMillis())
    834                 .datePickerFormat("DMY")
    835                 .minDate(minCal.getTimeInMillis())
    836                 .maxDate(maxCal.getTimeInMillis())
    837                 .build();
    838 
    839 
    840         // testing date ranges when all fields are equal
    841         minCal.set(Calendar.DAY_OF_MONTH, maxCal.get(Calendar.DAY_OF_MONTH));
    842 
    843         GuidedDatePickerAction dateAction5 = new GuidedDatePickerAction.Builder(
    844                 mContext)
    845                 .id(4)
    846                 .title(res.getString(R.string.datepicker_with_range_title,
    847                         dateFormat.format(minCal.getTimeInMillis()),
    848                         dateFormat.format(maxCal.getTimeInMillis())))
    849                 .multilineDescription(true)
    850                 .date(currCal.getTimeInMillis())
    851                 .datePickerFormat("DMY")
    852                 .minDate(minCal.getTimeInMillis())
    853                 .maxDate(maxCal.getTimeInMillis())
    854                 .build();
    855 
    856         actionList.add(dateAction1);
    857         actionList.add(dateAction2);
    858         actionList.add(dateAction3);
    859         actionList.add(dateAction4);
    860         actionList.add(dateAction5);
    861 
    862         GuidedStepAttributesTestFragment.clear();
    863         GuidedStepAttributesTestFragment.GUIDANCE = guidance;
    864         GuidedStepAttributesTestFragment.ACTION_LIST = actionList;
    865 
    866         initActivity(intent);
    867         return new GuidedDatePickerAction[] {dateAction1, dateAction2, dateAction3, dateAction4,
    868                 dateAction5};
    869     }
    870 
    871     private void scrollToMinAndMaxDates(int[] columnIndices, GuidedDatePickerAction dateAction)
    872             throws Throwable{
    873 
    874         final GuidedStepFragment mFragment = (GuidedStepFragment)
    875                 mActivity.getGuidedStepTestFragment();
    876 
    877         VerticalGridView guidedActionsList = (VerticalGridView)
    878                 mActivity.findViewById(R.id.guidedactions_list);
    879 
    880         int currSelectedAction = mFragment.getSelectedActionPosition();
    881         // scroll up/down to the requested action
    882         long verticalScrollOffset = dateAction.getId() - currSelectedAction;
    883 
    884         int verticalScrollDir = KeyEvent.KEYCODE_DPAD_DOWN;
    885         if (verticalScrollOffset < 0) {
    886             verticalScrollOffset= -verticalScrollOffset;
    887             verticalScrollDir = KeyEvent.KEYCODE_DPAD_UP;
    888         }
    889         for(int i = 0; i < verticalScrollOffset; i++) {
    890             sendKey(verticalScrollDir);
    891             Thread.sleep(TRANSITION_LENGTH);
    892         }
    893 
    894         assertTrue("The wrong action was selected!", mFragment.getSelectedActionPosition()
    895                 == dateAction.getId());
    896         DatePicker mPickerView = (DatePicker) mFragment.getActionItemView((int) dateAction.getId())
    897                 .findViewById(R.id.guidedactions_activator_item);
    898 
    899         Calendar currentActionCal = Calendar.getInstance();
    900         currentActionCal.setTimeInMillis(dateAction.getDate());
    901 
    902 
    903         // scrolling to the minimum date
    904 
    905         verticalScrollToFieldValue(Calendar.YEAR, -1, columnIndices, mPickerView,
    906                 KeyEvent.KEYCODE_DPAD_UP);
    907         dateAction.setDate(mPickerView.getDate());
    908 
    909         verticalScrollToFieldValue(Calendar.MONTH, -1, columnIndices, mPickerView,
    910                 KeyEvent.KEYCODE_DPAD_UP);
    911         dateAction.setDate(mPickerView.getDate());
    912 
    913         verticalScrollToFieldValue(Calendar.DAY_OF_MONTH, -1, columnIndices, mPickerView,
    914                 KeyEvent.KEYCODE_DPAD_UP);
    915         dateAction.setDate(mPickerView.getDate());
    916 
    917         Thread.sleep(VERTICAL_SCROLL_WAIT);
    918 
    919         // now scrolling to the maximum date
    920 
    921         verticalScrollToFieldValue(Calendar.YEAR, -1, columnIndices, mPickerView,
    922                 KeyEvent.KEYCODE_DPAD_DOWN);
    923         dateAction.setDate(mPickerView.getDate());
    924 
    925         verticalScrollToFieldValue(Calendar.MONTH, -1, columnIndices, mPickerView,
    926                 KeyEvent.KEYCODE_DPAD_DOWN);
    927         dateAction.setDate(mPickerView.getDate());
    928 
    929         verticalScrollToFieldValue(Calendar.DAY_OF_MONTH, -1, columnIndices, mPickerView,
    930                 KeyEvent.KEYCODE_DPAD_DOWN);
    931         dateAction.setDate(mPickerView.getDate());
    932 
    933         sendKey(KeyEvent.KEYCODE_DPAD_CENTER);
    934         Thread.sleep(TRANSITION_LENGTH);
    935     }
    936 
    937 }
    938