Home | History | Annotate | Download | only in widget
      1 /*
      2  * Copyright (C) 2015 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.annotation.IdRes;
     20 import android.annotation.LayoutRes;
     21 import android.annotation.NonNull;
     22 import android.annotation.Nullable;
     23 import android.content.Context;
     24 import android.content.res.ColorStateList;
     25 import android.content.res.TypedArray;
     26 import android.graphics.Rect;
     27 import android.icu.util.Calendar;
     28 import android.util.SparseArray;
     29 import android.view.LayoutInflater;
     30 import android.view.View;
     31 import android.view.ViewGroup;
     32 import android.widget.SimpleMonthView.OnDayClickListener;
     33 
     34 import com.android.internal.widget.PagerAdapter;
     35 
     36 /**
     37  * An adapter for a list of {@link android.widget.SimpleMonthView} items.
     38  */
     39 class DayPickerPagerAdapter extends PagerAdapter {
     40     private static final int MONTHS_IN_YEAR = 12;
     41 
     42     private final Calendar mMinDate = Calendar.getInstance();
     43     private final Calendar mMaxDate = Calendar.getInstance();
     44 
     45     private final SparseArray<ViewHolder> mItems = new SparseArray<>();
     46 
     47     private final LayoutInflater mInflater;
     48     private final int mLayoutResId;
     49     private final int mCalendarViewId;
     50 
     51     private Calendar mSelectedDay = null;
     52 
     53     private int mMonthTextAppearance;
     54     private int mDayOfWeekTextAppearance;
     55     private int mDayTextAppearance;
     56 
     57     private ColorStateList mCalendarTextColor;
     58     private ColorStateList mDaySelectorColor;
     59     private ColorStateList mDayHighlightColor;
     60 
     61     private OnDaySelectedListener mOnDaySelectedListener;
     62 
     63     private int mCount;
     64     private int mFirstDayOfWeek;
     65 
     66     public DayPickerPagerAdapter(@NonNull Context context, @LayoutRes int layoutResId,
     67             @IdRes int calendarViewId) {
     68         mInflater = LayoutInflater.from(context);
     69         mLayoutResId = layoutResId;
     70         mCalendarViewId = calendarViewId;
     71 
     72         final TypedArray ta = context.obtainStyledAttributes(new int[] {
     73                 com.android.internal.R.attr.colorControlHighlight});
     74         mDayHighlightColor = ta.getColorStateList(0);
     75         ta.recycle();
     76     }
     77 
     78     public void setRange(@NonNull Calendar min, @NonNull Calendar max) {
     79         mMinDate.setTimeInMillis(min.getTimeInMillis());
     80         mMaxDate.setTimeInMillis(max.getTimeInMillis());
     81 
     82         final int diffYear = mMaxDate.get(Calendar.YEAR) - mMinDate.get(Calendar.YEAR);
     83         final int diffMonth = mMaxDate.get(Calendar.MONTH) - mMinDate.get(Calendar.MONTH);
     84         mCount = diffMonth + MONTHS_IN_YEAR * diffYear + 1;
     85 
     86         // Positions are now invalid, clear everything and start over.
     87         notifyDataSetChanged();
     88     }
     89 
     90     /**
     91      * Sets the first day of the week.
     92      *
     93      * @param weekStart which day the week should start on, valid values are
     94      *                  {@link Calendar#SUNDAY} through {@link Calendar#SATURDAY}
     95      */
     96     public void setFirstDayOfWeek(int weekStart) {
     97         mFirstDayOfWeek = weekStart;
     98 
     99         // Update displayed views.
    100         final int count = mItems.size();
    101         for (int i = 0; i < count; i++) {
    102             final SimpleMonthView monthView = mItems.valueAt(i).calendar;
    103             monthView.setFirstDayOfWeek(weekStart);
    104         }
    105     }
    106 
    107     public int getFirstDayOfWeek() {
    108         return mFirstDayOfWeek;
    109     }
    110 
    111     public boolean getBoundsForDate(Calendar day, Rect outBounds) {
    112         final int position = getPositionForDay(day);
    113         final ViewHolder monthView = mItems.get(position, null);
    114         if (monthView == null) {
    115             return false;
    116         } else {
    117             final int dayOfMonth = day.get(Calendar.DAY_OF_MONTH);
    118             return monthView.calendar.getBoundsForDay(dayOfMonth, outBounds);
    119         }
    120     }
    121 
    122     /**
    123      * Sets the selected day.
    124      *
    125      * @param day the selected day
    126      */
    127     public void setSelectedDay(@Nullable Calendar day) {
    128         final int oldPosition = getPositionForDay(mSelectedDay);
    129         final int newPosition = getPositionForDay(day);
    130 
    131         // Clear the old position if necessary.
    132         if (oldPosition != newPosition && oldPosition >= 0) {
    133             final ViewHolder oldMonthView = mItems.get(oldPosition, null);
    134             if (oldMonthView != null) {
    135                 oldMonthView.calendar.setSelectedDay(-1);
    136             }
    137         }
    138 
    139         // Set the new position.
    140         if (newPosition >= 0) {
    141             final ViewHolder newMonthView = mItems.get(newPosition, null);
    142             if (newMonthView != null) {
    143                 final int dayOfMonth = day.get(Calendar.DAY_OF_MONTH);
    144                 newMonthView.calendar.setSelectedDay(dayOfMonth);
    145             }
    146         }
    147 
    148         mSelectedDay = day;
    149     }
    150 
    151     /**
    152      * Sets the listener to call when the user selects a day.
    153      *
    154      * @param listener The listener to call.
    155      */
    156     public void setOnDaySelectedListener(OnDaySelectedListener listener) {
    157         mOnDaySelectedListener = listener;
    158     }
    159 
    160     void setCalendarTextColor(ColorStateList calendarTextColor) {
    161         mCalendarTextColor = calendarTextColor;
    162         notifyDataSetChanged();
    163     }
    164 
    165     void setDaySelectorColor(ColorStateList selectorColor) {
    166         mDaySelectorColor = selectorColor;
    167         notifyDataSetChanged();
    168     }
    169 
    170     void setMonthTextAppearance(int resId) {
    171         mMonthTextAppearance = resId;
    172         notifyDataSetChanged();
    173     }
    174 
    175     void setDayOfWeekTextAppearance(int resId) {
    176         mDayOfWeekTextAppearance = resId;
    177         notifyDataSetChanged();
    178     }
    179 
    180     int getDayOfWeekTextAppearance() {
    181         return mDayOfWeekTextAppearance;
    182     }
    183 
    184     void setDayTextAppearance(int resId) {
    185         mDayTextAppearance = resId;
    186         notifyDataSetChanged();
    187     }
    188 
    189     int getDayTextAppearance() {
    190         return mDayTextAppearance;
    191     }
    192 
    193     @Override
    194     public int getCount() {
    195         return mCount;
    196     }
    197 
    198     @Override
    199     public boolean isViewFromObject(View view, Object object) {
    200         final ViewHolder holder = (ViewHolder) object;
    201         return view == holder.container;
    202     }
    203 
    204     private int getMonthForPosition(int position) {
    205         return (position + mMinDate.get(Calendar.MONTH)) % MONTHS_IN_YEAR;
    206     }
    207 
    208     private int getYearForPosition(int position) {
    209         final int yearOffset = (position + mMinDate.get(Calendar.MONTH)) / MONTHS_IN_YEAR;
    210         return yearOffset + mMinDate.get(Calendar.YEAR);
    211     }
    212 
    213     private int getPositionForDay(@Nullable Calendar day) {
    214         if (day == null) {
    215             return -1;
    216         }
    217 
    218         final int yearOffset = day.get(Calendar.YEAR) - mMinDate.get(Calendar.YEAR);
    219         final int monthOffset = day.get(Calendar.MONTH) - mMinDate.get(Calendar.MONTH);
    220         final int position = yearOffset * MONTHS_IN_YEAR + monthOffset;
    221         return position;
    222     }
    223 
    224     @Override
    225     public Object instantiateItem(ViewGroup container, int position) {
    226         final View itemView = mInflater.inflate(mLayoutResId, container, false);
    227 
    228         final SimpleMonthView v = itemView.findViewById(mCalendarViewId);
    229         v.setOnDayClickListener(mOnDayClickListener);
    230         v.setMonthTextAppearance(mMonthTextAppearance);
    231         v.setDayOfWeekTextAppearance(mDayOfWeekTextAppearance);
    232         v.setDayTextAppearance(mDayTextAppearance);
    233 
    234         if (mDaySelectorColor != null) {
    235             v.setDaySelectorColor(mDaySelectorColor);
    236         }
    237 
    238         if (mDayHighlightColor != null) {
    239             v.setDayHighlightColor(mDayHighlightColor);
    240         }
    241 
    242         if (mCalendarTextColor != null) {
    243             v.setMonthTextColor(mCalendarTextColor);
    244             v.setDayOfWeekTextColor(mCalendarTextColor);
    245             v.setDayTextColor(mCalendarTextColor);
    246         }
    247 
    248         final int month = getMonthForPosition(position);
    249         final int year = getYearForPosition(position);
    250 
    251         final int selectedDay;
    252         if (mSelectedDay != null && mSelectedDay.get(Calendar.MONTH) == month) {
    253             selectedDay = mSelectedDay.get(Calendar.DAY_OF_MONTH);
    254         } else {
    255             selectedDay = -1;
    256         }
    257 
    258         final int enabledDayRangeStart;
    259         if (mMinDate.get(Calendar.MONTH) == month && mMinDate.get(Calendar.YEAR) == year) {
    260             enabledDayRangeStart = mMinDate.get(Calendar.DAY_OF_MONTH);
    261         } else {
    262             enabledDayRangeStart = 1;
    263         }
    264 
    265         final int enabledDayRangeEnd;
    266         if (mMaxDate.get(Calendar.MONTH) == month && mMaxDate.get(Calendar.YEAR) == year) {
    267             enabledDayRangeEnd = mMaxDate.get(Calendar.DAY_OF_MONTH);
    268         } else {
    269             enabledDayRangeEnd = 31;
    270         }
    271 
    272         v.setMonthParams(selectedDay, month, year, mFirstDayOfWeek,
    273                 enabledDayRangeStart, enabledDayRangeEnd);
    274 
    275         final ViewHolder holder = new ViewHolder(position, itemView, v);
    276         mItems.put(position, holder);
    277 
    278         container.addView(itemView);
    279 
    280         return holder;
    281     }
    282 
    283     @Override
    284     public void destroyItem(ViewGroup container, int position, Object object) {
    285         final ViewHolder holder = (ViewHolder) object;
    286         container.removeView(holder.container);
    287 
    288         mItems.remove(position);
    289     }
    290 
    291     @Override
    292     public int getItemPosition(Object object) {
    293         final ViewHolder holder = (ViewHolder) object;
    294         return holder.position;
    295     }
    296 
    297     @Override
    298     public CharSequence getPageTitle(int position) {
    299         final SimpleMonthView v = mItems.get(position).calendar;
    300         if (v != null) {
    301             return v.getMonthYearLabel();
    302         }
    303         return null;
    304     }
    305 
    306     SimpleMonthView getView(Object object) {
    307         if (object == null) {
    308             return null;
    309         }
    310         final ViewHolder holder = (ViewHolder) object;
    311         return holder.calendar;
    312     }
    313 
    314     private final OnDayClickListener mOnDayClickListener = new OnDayClickListener() {
    315         @Override
    316         public void onDayClick(SimpleMonthView view, Calendar day) {
    317             if (day != null) {
    318                 setSelectedDay(day);
    319 
    320                 if (mOnDaySelectedListener != null) {
    321                     mOnDaySelectedListener.onDaySelected(DayPickerPagerAdapter.this, day);
    322                 }
    323             }
    324         }
    325     };
    326 
    327     private static class ViewHolder {
    328         public final int position;
    329         public final View container;
    330         public final SimpleMonthView calendar;
    331 
    332         public ViewHolder(int position, View container, SimpleMonthView calendar) {
    333             this.position = position;
    334             this.container = container;
    335             this.calendar = calendar;
    336         }
    337     }
    338 
    339     public interface OnDaySelectedListener {
    340         public void onDaySelected(DayPickerPagerAdapter view, Calendar day);
    341     }
    342 }
    343