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 com.android.internal.widget.PagerAdapter; 20 21 import android.annotation.IdRes; 22 import android.annotation.LayoutRes; 23 import android.annotation.NonNull; 24 import android.annotation.Nullable; 25 import android.content.Context; 26 import android.content.res.ColorStateList; 27 import android.content.res.TypedArray; 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 java.util.Calendar; 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 DayPickerPagerAdapter(@onNull Context context, @LayoutRes int layoutResId, @IdRes int calendarViewId)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 setRange(@onNull Calendar min, @NonNull Calendar max)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 */ setFirstDayOfWeek(int weekStart)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 getFirstDayOfWeek()107 public int getFirstDayOfWeek() { 108 return mFirstDayOfWeek; 109 } 110 111 /** 112 * Sets the selected day. 113 * 114 * @param day the selected day 115 */ setSelectedDay(@ullable Calendar day)116 public void setSelectedDay(@Nullable Calendar day) { 117 final int oldPosition = getPositionForDay(mSelectedDay); 118 final int newPosition = getPositionForDay(day); 119 120 // Clear the old position if necessary. 121 if (oldPosition != newPosition && oldPosition >= 0) { 122 final ViewHolder oldMonthView = mItems.get(oldPosition, null); 123 if (oldMonthView != null) { 124 oldMonthView.calendar.setSelectedDay(-1); 125 } 126 } 127 128 // Set the new position. 129 if (newPosition >= 0) { 130 final ViewHolder newMonthView = mItems.get(newPosition, null); 131 if (newMonthView != null) { 132 final int dayOfMonth = day.get(Calendar.DAY_OF_MONTH); 133 newMonthView.calendar.setSelectedDay(dayOfMonth); 134 } 135 } 136 137 mSelectedDay = day; 138 } 139 140 /** 141 * Sets the listener to call when the user selects a day. 142 * 143 * @param listener The listener to call. 144 */ setOnDaySelectedListener(OnDaySelectedListener listener)145 public void setOnDaySelectedListener(OnDaySelectedListener listener) { 146 mOnDaySelectedListener = listener; 147 } 148 setCalendarTextColor(ColorStateList calendarTextColor)149 void setCalendarTextColor(ColorStateList calendarTextColor) { 150 mCalendarTextColor = calendarTextColor; 151 } 152 setDaySelectorColor(ColorStateList selectorColor)153 void setDaySelectorColor(ColorStateList selectorColor) { 154 mDaySelectorColor = selectorColor; 155 } 156 setMonthTextAppearance(int resId)157 void setMonthTextAppearance(int resId) { 158 mMonthTextAppearance = resId; 159 } 160 setDayOfWeekTextAppearance(int resId)161 void setDayOfWeekTextAppearance(int resId) { 162 mDayOfWeekTextAppearance = resId; 163 } 164 getDayOfWeekTextAppearance()165 int getDayOfWeekTextAppearance() { 166 return mDayOfWeekTextAppearance; 167 } 168 setDayTextAppearance(int resId)169 void setDayTextAppearance(int resId) { 170 mDayTextAppearance = resId; 171 } 172 getDayTextAppearance()173 int getDayTextAppearance() { 174 return mDayTextAppearance; 175 } 176 177 @Override getCount()178 public int getCount() { 179 return mCount; 180 } 181 182 @Override isViewFromObject(View view, Object object)183 public boolean isViewFromObject(View view, Object object) { 184 final ViewHolder holder = (ViewHolder) object; 185 return view == holder.container; 186 } 187 getMonthForPosition(int position)188 private int getMonthForPosition(int position) { 189 return (position + mMinDate.get(Calendar.MONTH)) % MONTHS_IN_YEAR; 190 } 191 getYearForPosition(int position)192 private int getYearForPosition(int position) { 193 final int yearOffset = (position + mMinDate.get(Calendar.MONTH)) / MONTHS_IN_YEAR; 194 return yearOffset + mMinDate.get(Calendar.YEAR); 195 } 196 getPositionForDay(@ullable Calendar day)197 private int getPositionForDay(@Nullable Calendar day) { 198 if (day == null) { 199 return -1; 200 } 201 202 final int yearOffset = day.get(Calendar.YEAR) - mMinDate.get(Calendar.YEAR); 203 final int monthOffset = day.get(Calendar.MONTH) - mMinDate.get(Calendar.MONTH); 204 final int position = yearOffset * MONTHS_IN_YEAR + monthOffset; 205 return position; 206 } 207 208 @Override instantiateItem(ViewGroup container, int position)209 public Object instantiateItem(ViewGroup container, int position) { 210 final View itemView = mInflater.inflate(mLayoutResId, container, false); 211 212 final SimpleMonthView v = (SimpleMonthView) itemView.findViewById(mCalendarViewId); 213 v.setOnDayClickListener(mOnDayClickListener); 214 v.setMonthTextAppearance(mMonthTextAppearance); 215 v.setDayOfWeekTextAppearance(mDayOfWeekTextAppearance); 216 v.setDayTextAppearance(mDayTextAppearance); 217 218 if (mDaySelectorColor != null) { 219 v.setDaySelectorColor(mDaySelectorColor); 220 } 221 222 if (mDayHighlightColor != null) { 223 v.setDayHighlightColor(mDayHighlightColor); 224 } 225 226 if (mCalendarTextColor != null) { 227 v.setMonthTextColor(mCalendarTextColor); 228 v.setDayOfWeekTextColor(mCalendarTextColor); 229 v.setDayTextColor(mCalendarTextColor); 230 } 231 232 final int month = getMonthForPosition(position); 233 final int year = getYearForPosition(position); 234 235 final int selectedDay; 236 if (mSelectedDay != null && mSelectedDay.get(Calendar.MONTH) == month) { 237 selectedDay = mSelectedDay.get(Calendar.DAY_OF_MONTH); 238 } else { 239 selectedDay = -1; 240 } 241 242 final int enabledDayRangeStart; 243 if (mMinDate.get(Calendar.MONTH) == month && mMinDate.get(Calendar.YEAR) == year) { 244 enabledDayRangeStart = mMinDate.get(Calendar.DAY_OF_MONTH); 245 } else { 246 enabledDayRangeStart = 1; 247 } 248 249 final int enabledDayRangeEnd; 250 if (mMaxDate.get(Calendar.MONTH) == month && mMaxDate.get(Calendar.YEAR) == year) { 251 enabledDayRangeEnd = mMaxDate.get(Calendar.DAY_OF_MONTH); 252 } else { 253 enabledDayRangeEnd = 31; 254 } 255 256 v.setMonthParams(selectedDay, month, year, mFirstDayOfWeek, 257 enabledDayRangeStart, enabledDayRangeEnd); 258 259 final ViewHolder holder = new ViewHolder(position, itemView, v); 260 mItems.put(position, holder); 261 262 container.addView(itemView); 263 264 return holder; 265 } 266 267 @Override destroyItem(ViewGroup container, int position, Object object)268 public void destroyItem(ViewGroup container, int position, Object object) { 269 final ViewHolder holder = (ViewHolder) object; 270 container.removeView(holder.container); 271 272 mItems.remove(position); 273 } 274 275 @Override getItemPosition(Object object)276 public int getItemPosition(Object object) { 277 final ViewHolder holder = (ViewHolder) object; 278 return holder.position; 279 } 280 281 @Override getPageTitle(int position)282 public CharSequence getPageTitle(int position) { 283 final SimpleMonthView v = mItems.get(position).calendar; 284 if (v != null) { 285 return v.getTitle(); 286 } 287 return null; 288 } 289 290 private final OnDayClickListener mOnDayClickListener = new OnDayClickListener() { 291 @Override 292 public void onDayClick(SimpleMonthView view, Calendar day) { 293 if (day != null) { 294 setSelectedDay(day); 295 296 if (mOnDaySelectedListener != null) { 297 mOnDaySelectedListener.onDaySelected(DayPickerPagerAdapter.this, day); 298 } 299 } 300 } 301 }; 302 303 private static class ViewHolder { 304 public final int position; 305 public final View container; 306 public final SimpleMonthView calendar; 307 ViewHolder(int position, View container, SimpleMonthView calendar)308 public ViewHolder(int position, View container, SimpleMonthView calendar) { 309 this.position = position; 310 this.container = container; 311 this.calendar = calendar; 312 } 313 } 314 315 public interface OnDaySelectedListener { onDaySelected(DayPickerPagerAdapter view, Calendar day)316 public void onDaySelected(DayPickerPagerAdapter view, Calendar day); 317 } 318 } 319