Home | History | Annotate | Download | only in cts
      1 /*
      2  * Copyright (C) 2016 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.cts;
     18 
     19 import static org.junit.Assert.assertEquals;
     20 import static org.junit.Assert.assertFalse;
     21 import static org.junit.Assert.assertTrue;
     22 import static org.junit.Assert.fail;
     23 import static org.mockito.Mockito.mock;
     24 import static org.mockito.Mockito.times;
     25 import static org.mockito.Mockito.verify;
     26 import static org.mockito.Mockito.verifyNoMoreInteractions;
     27 import static org.mockito.Mockito.verifyZeroInteractions;
     28 
     29 import android.app.Instrumentation;
     30 import android.graphics.Rect;
     31 import android.view.ViewGroup;
     32 import android.widget.CalendarView;
     33 import android.widget.ScrollView;
     34 import android.widget.cts.util.TestUtils;
     35 
     36 import androidx.annotation.ColorInt;
     37 import androidx.test.InstrumentationRegistry;
     38 import androidx.test.annotation.UiThreadTest;
     39 import androidx.test.filters.MediumTest;
     40 import androidx.test.rule.ActivityTestRule;
     41 import androidx.test.runner.AndroidJUnit4;
     42 
     43 import com.android.compatibility.common.util.CtsTouchUtils;
     44 import com.android.compatibility.common.util.WidgetTestUtils;
     45 
     46 import org.junit.Before;
     47 import org.junit.Rule;
     48 import org.junit.Test;
     49 import org.junit.runner.RunWith;
     50 
     51 import java.util.Calendar;
     52 import java.util.GregorianCalendar;
     53 
     54 @MediumTest
     55 @RunWith(AndroidJUnit4.class)
     56 public class CalendarViewTest {
     57     private Instrumentation mInstrumentation;
     58     private CalendarViewCtsActivity mActivity;
     59     private CalendarView mCalendarViewMaterial;
     60     private CalendarView mCalendarViewHolo;
     61 
     62     @Rule
     63     public ActivityTestRule<CalendarViewCtsActivity> mActivityRule =
     64             new ActivityTestRule<>(CalendarViewCtsActivity.class);
     65 
     66     @UiThreadTest
     67     @Before
     68     public void setup() {
     69         mInstrumentation = InstrumentationRegistry.getInstrumentation();
     70         mActivity = mActivityRule.getActivity();
     71         mCalendarViewMaterial = (CalendarView) mActivity.findViewById(R.id.calendar_view_material);
     72         mCalendarViewHolo = (CalendarView) mActivity.findViewById(R.id.calendar_view_holoyolo);
     73 
     74         // Initialize both calendar views to the current date
     75         final long currentDate = new GregorianCalendar().getTime().getTime();
     76         mCalendarViewMaterial.setDate(currentDate);
     77         mCalendarViewHolo.setDate(currentDate);
     78     }
     79 
     80     @UiThreadTest
     81     @Test
     82     public void testConstructor() {
     83         new CalendarView(mActivity);
     84 
     85         new CalendarView(mActivity, null);
     86 
     87         new CalendarView(mActivity, null, android.R.attr.calendarViewStyle);
     88 
     89         new CalendarView(mActivity, null, 0, android.R.style.Widget_DeviceDefault_CalendarView);
     90 
     91         new CalendarView(mActivity, null, 0,
     92                 android.R.style.Widget_DeviceDefault_Light_CalendarView);
     93 
     94         new CalendarView(mActivity, null, 0, android.R.style.Widget_Material_CalendarView);
     95 
     96         new CalendarView(mActivity, null, 0, android.R.style.Widget_Material_Light_CalendarView);
     97     }
     98 
     99     @UiThreadTest
    100     @Test
    101     public void testAccessDate() {
    102         // Go back one year
    103         final Calendar newCalendar = new GregorianCalendar();
    104         newCalendar.set(Calendar.YEAR, newCalendar.get(Calendar.YEAR) - 1);
    105         final long yearAgoDate = newCalendar.getTime().getTime();
    106 
    107         mCalendarViewMaterial.setDate(yearAgoDate);
    108         assertEquals(yearAgoDate, mCalendarViewMaterial.getDate());
    109 
    110         // Go forward two years (one year from current date in aggregate)
    111         newCalendar.set(Calendar.YEAR, newCalendar.get(Calendar.YEAR) + 2);
    112         final long yearHenceDate = newCalendar.getTime().getTime();
    113 
    114         mCalendarViewMaterial.setDate(yearHenceDate, true, false);
    115         assertEquals(yearHenceDate, mCalendarViewMaterial.getDate());
    116     }
    117 
    118     @UiThreadTest
    119     @Test
    120     public void testAccessMinMaxDate() {
    121         // Use a range of minus/plus one year as min/max dates
    122         final Calendar minCalendar = new GregorianCalendar();
    123         minCalendar.set(Calendar.YEAR, minCalendar.get(Calendar.YEAR) - 1);
    124         final Calendar maxCalendar = new GregorianCalendar();
    125         maxCalendar.set(Calendar.YEAR, maxCalendar.get(Calendar.YEAR) + 1);
    126 
    127         final long minDate = minCalendar.getTime().getTime();
    128         final long maxDate = maxCalendar.getTime().getTime();
    129 
    130         mCalendarViewMaterial.setMinDate(minDate);
    131         mCalendarViewMaterial.setMaxDate(maxDate);
    132 
    133         assertEquals(mCalendarViewMaterial.getMinDate(), minDate);
    134         assertEquals(mCalendarViewMaterial.getMaxDate(), maxDate);
    135     }
    136 
    137     @UiThreadTest
    138     @Test
    139     public void testMinMaxRangeRestrictionsHolo() {
    140         // Use a range of minus/plus one year as min/max dates.
    141         final Calendar minCalendar = new GregorianCalendar();
    142         minCalendar.set(Calendar.YEAR, minCalendar.get(Calendar.YEAR) - 1);
    143         final Calendar maxCalendar = new GregorianCalendar();
    144         maxCalendar.set(Calendar.YEAR, maxCalendar.get(Calendar.YEAR) + 1);
    145         final long minDate = minCalendar.getTime().getTime();
    146         final long maxDate = maxCalendar.getTime().getTime();
    147 
    148         mCalendarViewHolo.setMinDate(minDate);
    149         mCalendarViewHolo.setMaxDate(maxDate);
    150 
    151         try {
    152             mCalendarViewHolo.setDate(minDate - 1);
    153             fail("Should throw IllegalArgumentException, date is before minDate");
    154         } catch (IllegalArgumentException e) {
    155         }
    156 
    157         try {
    158             mCalendarViewHolo.setDate(maxDate + 1);
    159             fail("Should throw IllegalArgumentException, date is after maxDate");
    160         } catch (IllegalArgumentException e) {
    161         }
    162     }
    163 
    164     @UiThreadTest
    165     @Test
    166     public void testMinMaxRangeClampingMaterial() {
    167         // Use a range of minus/plus one year as min/max dates.
    168         final Calendar minCalendar = new GregorianCalendar();
    169         minCalendar.set(Calendar.YEAR, minCalendar.get(Calendar.YEAR) - 1);
    170         final Calendar maxCalendar = new GregorianCalendar();
    171         maxCalendar.set(Calendar.YEAR, maxCalendar.get(Calendar.YEAR) + 1);
    172         final long minDate = minCalendar.getTime().getTime();
    173         final long maxDate = maxCalendar.getTime().getTime();
    174 
    175         mCalendarViewMaterial.setMinDate(minDate);
    176         mCalendarViewMaterial.setMaxDate(maxDate);
    177         mCalendarViewMaterial.setDate(minDate + 1);
    178 
    179         // Expecting to get back the same values because minDate < date < maxDate.
    180         assertEquals(minDate, mCalendarViewMaterial.getMinDate());
    181         assertEquals(maxDate, mCalendarViewMaterial.getMaxDate());
    182         assertEquals(minDate + 1, mCalendarViewMaterial.getDate());
    183 
    184         // Set a new minDate after the current date.
    185         mCalendarViewMaterial.setMinDate(minDate + 20);
    186         assertEquals(minDate + 20, mCalendarViewMaterial.getMinDate());
    187         assertEquals(maxDate, mCalendarViewMaterial.getMaxDate());
    188         // Verify date clamping when calling setMinDate().
    189         assertEquals(minDate + 20, mCalendarViewMaterial.getDate());
    190 
    191         mCalendarViewMaterial.setMinDate(minDate);
    192         // Set a maxDate before the current date.
    193         mCalendarViewMaterial.setMaxDate(minDate + 10);
    194         assertEquals(minDate, mCalendarViewMaterial.getMinDate());
    195         assertEquals(minDate + 10, mCalendarViewMaterial.getMaxDate());
    196         // Verify date clamping when calling setMaxDate().
    197         assertEquals(minDate + 10, mCalendarViewMaterial.getDate());
    198 
    199         // Set a date before minDate.
    200         mCalendarViewMaterial.setDate(mCalendarViewMaterial.getMinDate() - 1);
    201         // Expect date clamped to minDate.
    202         assertEquals(mCalendarViewMaterial.getMinDate(), mCalendarViewMaterial.getDate());
    203 
    204         // Set a date after maxDate.
    205         mCalendarViewMaterial.setDate(mCalendarViewMaterial.getMaxDate() + 1);
    206         // Expect date clamped to maxDate.
    207         assertEquals(mCalendarViewMaterial.getMaxDate(), mCalendarViewMaterial.getDate());
    208     }
    209 
    210     private void verifyOnDateChangeListener(CalendarView calendarView,
    211             boolean onlyAllowOneChangeEvent) throws Throwable {
    212         final CalendarView.OnDateChangeListener mockDateChangeListener =
    213                 mock(CalendarView.OnDateChangeListener.class);
    214         calendarView.setOnDateChangeListener(mockDateChangeListener);
    215 
    216         // Go back to September 2008
    217         final Calendar calendar = new GregorianCalendar();
    218         calendar.set(Calendar.YEAR, 2008);
    219         calendar.set(Calendar.MONTH, Calendar.SEPTEMBER);
    220         calendar.set(Calendar.DAY_OF_MONTH, 16);
    221         WidgetTestUtils.runOnMainAndDrawSync(mActivityRule, calendarView,
    222                 () -> calendarView.setDate(calendar.getTime().getTime(), false, true));
    223 
    224         // Get bounds of 09/07/2008
    225         calendar.set(Calendar.DAY_OF_MONTH, 7);
    226         final Rect dayBounds = new Rect();
    227         final boolean getDayBoundsSuccess = calendarView.getBoundsForDate(
    228                 calendar.getTime().getTime(), dayBounds);
    229         assertTrue(getDayBoundsSuccess);
    230 
    231         if (onlyAllowOneChangeEvent) {
    232             verifyZeroInteractions(mockDateChangeListener);
    233         }
    234 
    235         // Use instrumentation to emulate a tap on 09/07/2008
    236         CtsTouchUtils.emulateTapOnView(mInstrumentation, mActivityRule, calendarView,
    237                 dayBounds.left + dayBounds.width() / 2,
    238                 dayBounds.top + dayBounds.height() / 2);
    239 
    240         verify(mockDateChangeListener, times(1)).onSelectedDayChange(calendarView,
    241                 2008, Calendar.SEPTEMBER, 7);
    242         if (onlyAllowOneChangeEvent) {
    243             verifyNoMoreInteractions(mockDateChangeListener);
    244         }
    245     }
    246 
    247     @Test
    248     public void testOnDateChangeListenerHolo() throws Throwable {
    249         // Scroll the Holo calendar view all the way up so it's fully visible
    250         final ScrollView scroller = (ScrollView) mActivity.findViewById(R.id.scroller);
    251         final ViewGroup container = (ViewGroup) scroller.findViewById(R.id.container);
    252 
    253         mActivityRule.runOnUiThread(() -> scroller.scrollTo(0, container.getHeight()));
    254         // Note that in pre-Material world we are "allowing" the CalendarView to notify
    255         // the date change listener on multiple occasions. This is the old behavior of the widget.
    256         verifyOnDateChangeListener(mCalendarViewHolo, false);
    257     }
    258 
    259     @Test
    260     public void testOnDateChangeListenerMaterial() throws Throwable {
    261         // Note that in Material world only "real" date change events are allowed to be reported
    262         // to our listener. This is the new behavior of the widget.
    263         verifyOnDateChangeListener(mCalendarViewMaterial, true);
    264     }
    265 
    266     @UiThreadTest
    267     @Test
    268     public void testAppearanceMaterial() {
    269         // The logic in this method is performed on a Material-styled CalendarView and
    270         // non-deprecated attributes / visual appearance APIs
    271 
    272         // Test the initial appearance defined in the layout XML
    273         assertEquals(2, mCalendarViewMaterial.getFirstDayOfWeek());
    274         assertEquals(R.style.TextAppearance_WithColor,
    275                 mCalendarViewMaterial.getDateTextAppearance());
    276         assertEquals(R.style.TextAppearance_WithColorGreen,
    277                 mCalendarViewMaterial.getWeekDayTextAppearance());
    278 
    279         // Change the visual appearance of the widget
    280         mCalendarViewMaterial.setFirstDayOfWeek(Calendar.TUESDAY);
    281         mCalendarViewMaterial.setDateTextAppearance(R.style.TextAppearance_WithColorBlue);
    282         mCalendarViewMaterial.setWeekDayTextAppearance(R.style.TextAppearance_WithColorMagenta);
    283 
    284         assertEquals(Calendar.TUESDAY, mCalendarViewMaterial.getFirstDayOfWeek());
    285         assertEquals(R.style.TextAppearance_WithColorBlue,
    286                 mCalendarViewMaterial.getDateTextAppearance());
    287         assertEquals(R.style.TextAppearance_WithColorMagenta,
    288                 mCalendarViewMaterial.getWeekDayTextAppearance());
    289     }
    290 
    291     @UiThreadTest
    292     @Test
    293     public void testAppearanceHolo() {
    294         // All the logic in this method is performed on a Holo-styled CalendarView, as
    295         // under Material design we are ignoring most of these decorative attributes
    296 
    297         // Test the initial appearance defined in the layout XML
    298         assertEquals(3, mCalendarViewHolo.getFirstDayOfWeek());
    299         assertEquals(5, mCalendarViewHolo.getShownWeekCount());
    300         assertFalse(mCalendarViewHolo.getShowWeekNumber());
    301         assertEquals(R.style.TextAppearance_WithColor,
    302                 mCalendarViewHolo.getDateTextAppearance());
    303         assertEquals(R.style.TextAppearance_WithColorGreen,
    304                 mCalendarViewHolo.getWeekDayTextAppearance());
    305         assertEquals(mActivity.getColor(R.color.calendarview_week_background),
    306                 mCalendarViewHolo.getSelectedWeekBackgroundColor());
    307         assertEquals(mActivity.getColor(R.color.calendarview_focusedmonthdate),
    308                 mCalendarViewHolo.getFocusedMonthDateColor());
    309         assertEquals(mActivity.getColor(R.color.calendarview_unfocusedmonthdate),
    310                 mCalendarViewHolo.getUnfocusedMonthDateColor());
    311         TestUtils.assertAllPixelsOfColor("Selected date vertical bar blue",
    312                 mCalendarViewHolo.getSelectedDateVerticalBar(), 40, 40, true, 0xFF0000FF, 1, true);
    313 
    314         // Change the visual appearance of the widget
    315         final @ColorInt int newSelectedWeekBackgroundColor =
    316                 mActivity.getColor(R.color.calendarview_week_background_new);
    317         final @ColorInt int newFocusedMonthDateColor =
    318                 mActivity.getColor(R.color.calendarview_focusedmonthdate_new);
    319         final @ColorInt int newUnfocusedMonthDataColor =
    320                 mActivity.getColor(R.color.calendarview_unfocusedmonthdate_new);
    321         final @ColorInt int newWeekNumberColor =
    322                 mActivity.getColor(R.color.calendarview_week_number_new);
    323         final @ColorInt int newWeekSeparatorLineColor =
    324                 mActivity.getColor(R.color.calendarview_week_separatorline_new);
    325 
    326         mCalendarViewHolo.setFirstDayOfWeek(Calendar.SUNDAY);
    327         mCalendarViewHolo.setShownWeekCount(4);
    328         mCalendarViewHolo.setShowWeekNumber(true);
    329         mCalendarViewHolo.setDateTextAppearance(R.style.TextAppearance_WithColorBlue);
    330         mCalendarViewHolo.setWeekDayTextAppearance(R.style.TextAppearance_WithColorMagenta);
    331         mCalendarViewHolo.setSelectedWeekBackgroundColor(newSelectedWeekBackgroundColor);
    332         mCalendarViewHolo.setFocusedMonthDateColor(newFocusedMonthDateColor);
    333         mCalendarViewHolo.setUnfocusedMonthDateColor(newUnfocusedMonthDataColor);
    334         mCalendarViewHolo.setWeekNumberColor(newWeekNumberColor);
    335         mCalendarViewHolo.setWeekSeparatorLineColor(newWeekSeparatorLineColor);
    336 
    337         assertEquals(Calendar.SUNDAY, mCalendarViewHolo.getFirstDayOfWeek());
    338         assertEquals(4, mCalendarViewHolo.getShownWeekCount());
    339         assertTrue(mCalendarViewHolo.getShowWeekNumber());
    340         assertEquals(R.style.TextAppearance_WithColorBlue,
    341                 mCalendarViewHolo.getDateTextAppearance());
    342         assertEquals(R.style.TextAppearance_WithColorMagenta,
    343                 mCalendarViewHolo.getWeekDayTextAppearance());
    344         assertEquals(newSelectedWeekBackgroundColor,
    345                 mCalendarViewHolo.getSelectedWeekBackgroundColor());
    346         assertEquals(newFocusedMonthDateColor,
    347                 mCalendarViewHolo.getFocusedMonthDateColor());
    348         assertEquals(newUnfocusedMonthDataColor,
    349                 mCalendarViewHolo.getUnfocusedMonthDateColor());
    350         assertEquals(newWeekNumberColor,
    351                 mCalendarViewHolo.getWeekNumberColor());
    352         assertEquals(newWeekSeparatorLineColor,
    353                 mCalendarViewHolo.getWeekSeparatorLineColor());
    354 
    355         mCalendarViewHolo.setSelectedDateVerticalBar(R.drawable.yellow_fill);
    356         TestUtils.assertAllPixelsOfColor("Selected date vertical bar yellow",
    357                 mCalendarViewHolo.getSelectedDateVerticalBar(), 40, 40, true, 0xFFFFFF00, 1, true);
    358 
    359         mCalendarViewHolo.setSelectedDateVerticalBar(
    360                 mActivity.getDrawable(R.drawable.magenta_fill));
    361         TestUtils.assertAllPixelsOfColor("Selected date vertical bar magenta",
    362                 mCalendarViewHolo.getSelectedDateVerticalBar(), 40, 40, true, 0xFFFF00FF, 1, true);
    363     }
    364 }
    365