1 /* 2 * Copyright (C) 2010 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.Widget; 20 import android.content.Context; 21 import android.content.res.Configuration; 22 import android.content.res.TypedArray; 23 import android.graphics.drawable.Drawable; 24 import android.util.AttributeSet; 25 import android.util.Log; 26 import android.view.accessibility.AccessibilityEvent; 27 import android.view.accessibility.AccessibilityNodeInfo; 28 29 import com.android.internal.R; 30 31 import java.text.DateFormat; 32 import java.text.ParseException; 33 import java.text.SimpleDateFormat; 34 import java.util.Calendar; 35 import java.util.Locale; 36 import java.util.TimeZone; 37 38 /** 39 * This class is a calendar widget for displaying and selecting dates. The range 40 * of dates supported by this calendar is configurable. A user can select a date 41 * by taping on it and can scroll and fling the calendar to a desired date. 42 * 43 * @attr ref android.R.styleable#CalendarView_showWeekNumber 44 * @attr ref android.R.styleable#CalendarView_firstDayOfWeek 45 * @attr ref android.R.styleable#CalendarView_minDate 46 * @attr ref android.R.styleable#CalendarView_maxDate 47 * @attr ref android.R.styleable#CalendarView_shownWeekCount 48 * @attr ref android.R.styleable#CalendarView_selectedWeekBackgroundColor 49 * @attr ref android.R.styleable#CalendarView_focusedMonthDateColor 50 * @attr ref android.R.styleable#CalendarView_unfocusedMonthDateColor 51 * @attr ref android.R.styleable#CalendarView_weekNumberColor 52 * @attr ref android.R.styleable#CalendarView_weekSeparatorLineColor 53 * @attr ref android.R.styleable#CalendarView_selectedDateVerticalBar 54 * @attr ref android.R.styleable#CalendarView_weekDayTextAppearance 55 * @attr ref android.R.styleable#CalendarView_dateTextAppearance 56 */ 57 @Widget 58 public class CalendarView extends FrameLayout { 59 private static final String LOG_TAG = "CalendarView"; 60 61 private static final int MODE_HOLO = 0; 62 private static final int MODE_MATERIAL = 1; 63 64 private final CalendarViewDelegate mDelegate; 65 66 /** 67 * The callback used to indicate the user changes the date. 68 */ 69 public interface OnDateChangeListener { 70 71 /** 72 * Called upon change of the selected day. 73 * 74 * @param view The view associated with this listener. 75 * @param year The year that was set. 76 * @param month The month that was set [0-11]. 77 * @param dayOfMonth The day of the month that was set. 78 */ 79 public void onSelectedDayChange(CalendarView view, int year, int month, int dayOfMonth); 80 } 81 82 public CalendarView(Context context) { 83 this(context, null); 84 } 85 86 public CalendarView(Context context, AttributeSet attrs) { 87 this(context, attrs, R.attr.calendarViewStyle); 88 } 89 90 public CalendarView(Context context, AttributeSet attrs, int defStyleAttr) { 91 this(context, attrs, defStyleAttr, 0); 92 } 93 94 public CalendarView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) { 95 super(context, attrs, defStyleAttr, defStyleRes); 96 97 final TypedArray a = context.obtainStyledAttributes( 98 attrs, R.styleable.CalendarView, defStyleAttr, defStyleRes); 99 final int mode = a.getInt(R.styleable.CalendarView_calendarViewMode, MODE_HOLO); 100 a.recycle(); 101 102 switch (mode) { 103 case MODE_HOLO: 104 mDelegate = new CalendarViewLegacyDelegate( 105 this, context, attrs, defStyleAttr, defStyleRes); 106 break; 107 case MODE_MATERIAL: 108 mDelegate = new CalendarViewMaterialDelegate( 109 this, context, attrs, defStyleAttr, defStyleRes); 110 break; 111 default: 112 throw new IllegalArgumentException("invalid calendarViewMode attribute"); 113 } 114 } 115 116 /** 117 * Sets the number of weeks to be shown. 118 * 119 * @param count The shown week count. 120 * 121 * @attr ref android.R.styleable#CalendarView_shownWeekCount 122 */ 123 public void setShownWeekCount(int count) { 124 mDelegate.setShownWeekCount(count); 125 } 126 127 /** 128 * Gets the number of weeks to be shown. 129 * 130 * @return The shown week count. 131 * 132 * @attr ref android.R.styleable#CalendarView_shownWeekCount 133 */ 134 public int getShownWeekCount() { 135 return mDelegate.getShownWeekCount(); 136 } 137 138 /** 139 * Sets the background color for the selected week. 140 * 141 * @param color The week background color. 142 * 143 * @attr ref android.R.styleable#CalendarView_selectedWeekBackgroundColor 144 */ 145 public void setSelectedWeekBackgroundColor(int color) { 146 mDelegate.setSelectedWeekBackgroundColor(color); 147 } 148 149 /** 150 * Gets the background color for the selected week. 151 * 152 * @return The week background color. 153 * 154 * @attr ref android.R.styleable#CalendarView_selectedWeekBackgroundColor 155 */ 156 public int getSelectedWeekBackgroundColor() { 157 return mDelegate.getSelectedWeekBackgroundColor(); 158 } 159 160 /** 161 * Sets the color for the dates of the focused month. 162 * 163 * @param color The focused month date color. 164 * 165 * @attr ref android.R.styleable#CalendarView_focusedMonthDateColor 166 */ 167 public void setFocusedMonthDateColor(int color) { 168 mDelegate.setFocusedMonthDateColor(color); 169 } 170 171 /** 172 * Gets the color for the dates in the focused month. 173 * 174 * @return The focused month date color. 175 * 176 * @attr ref android.R.styleable#CalendarView_focusedMonthDateColor 177 */ 178 public int getFocusedMonthDateColor() { 179 return mDelegate.getFocusedMonthDateColor(); 180 } 181 182 /** 183 * Sets the color for the dates of a not focused month. 184 * 185 * @param color A not focused month date color. 186 * 187 * @attr ref android.R.styleable#CalendarView_unfocusedMonthDateColor 188 */ 189 public void setUnfocusedMonthDateColor(int color) { 190 mDelegate.setUnfocusedMonthDateColor(color); 191 } 192 193 /** 194 * Gets the color for the dates in a not focused month. 195 * 196 * @return A not focused month date color. 197 * 198 * @attr ref android.R.styleable#CalendarView_unfocusedMonthDateColor 199 */ 200 public int getUnfocusedMonthDateColor() { 201 return mDelegate.getUnfocusedMonthDateColor(); 202 } 203 204 /** 205 * Sets the color for the week numbers. 206 * 207 * @param color The week number color. 208 * 209 * @attr ref android.R.styleable#CalendarView_weekNumberColor 210 */ 211 public void setWeekNumberColor(int color) { 212 mDelegate.setWeekNumberColor(color); 213 } 214 215 /** 216 * Gets the color for the week numbers. 217 * 218 * @return The week number color. 219 * 220 * @attr ref android.R.styleable#CalendarView_weekNumberColor 221 */ 222 public int getWeekNumberColor() { 223 return mDelegate.getWeekNumberColor(); 224 } 225 226 /** 227 * Sets the color for the separator line between weeks. 228 * 229 * @param color The week separator color. 230 * 231 * @attr ref android.R.styleable#CalendarView_weekSeparatorLineColor 232 */ 233 public void setWeekSeparatorLineColor(int color) { 234 mDelegate.setWeekSeparatorLineColor(color); 235 } 236 237 /** 238 * Gets the color for the separator line between weeks. 239 * 240 * @return The week separator color. 241 * 242 * @attr ref android.R.styleable#CalendarView_weekSeparatorLineColor 243 */ 244 public int getWeekSeparatorLineColor() { 245 return mDelegate.getWeekSeparatorLineColor(); 246 } 247 248 /** 249 * Sets the drawable for the vertical bar shown at the beginning and at 250 * the end of the selected date. 251 * 252 * @param resourceId The vertical bar drawable resource id. 253 * 254 * @attr ref android.R.styleable#CalendarView_selectedDateVerticalBar 255 */ 256 public void setSelectedDateVerticalBar(int resourceId) { 257 mDelegate.setSelectedDateVerticalBar(resourceId); 258 } 259 260 /** 261 * Sets the drawable for the vertical bar shown at the beginning and at 262 * the end of the selected date. 263 * 264 * @param drawable The vertical bar drawable. 265 * 266 * @attr ref android.R.styleable#CalendarView_selectedDateVerticalBar 267 */ 268 public void setSelectedDateVerticalBar(Drawable drawable) { 269 mDelegate.setSelectedDateVerticalBar(drawable); 270 } 271 272 /** 273 * Gets the drawable for the vertical bar shown at the beginning and at 274 * the end of the selected date. 275 * 276 * @return The vertical bar drawable. 277 */ 278 public Drawable getSelectedDateVerticalBar() { 279 return mDelegate.getSelectedDateVerticalBar(); 280 } 281 282 /** 283 * Sets the text appearance for the week day abbreviation of the calendar header. 284 * 285 * @param resourceId The text appearance resource id. 286 * 287 * @attr ref android.R.styleable#CalendarView_weekDayTextAppearance 288 */ 289 public void setWeekDayTextAppearance(int resourceId) { 290 mDelegate.setWeekDayTextAppearance(resourceId); 291 } 292 293 /** 294 * Gets the text appearance for the week day abbreviation of the calendar header. 295 * 296 * @return The text appearance resource id. 297 * 298 * @attr ref android.R.styleable#CalendarView_weekDayTextAppearance 299 */ 300 public int getWeekDayTextAppearance() { 301 return mDelegate.getWeekDayTextAppearance(); 302 } 303 304 /** 305 * Sets the text appearance for the calendar dates. 306 * 307 * @param resourceId The text appearance resource id. 308 * 309 * @attr ref android.R.styleable#CalendarView_dateTextAppearance 310 */ 311 public void setDateTextAppearance(int resourceId) { 312 mDelegate.setDateTextAppearance(resourceId); 313 } 314 315 /** 316 * Gets the text appearance for the calendar dates. 317 * 318 * @return The text appearance resource id. 319 * 320 * @attr ref android.R.styleable#CalendarView_dateTextAppearance 321 */ 322 public int getDateTextAppearance() { 323 return mDelegate.getDateTextAppearance(); 324 } 325 326 /** 327 * Gets the minimal date supported by this {@link CalendarView} in milliseconds 328 * since January 1, 1970 00:00:00 in {@link TimeZone#getDefault()} time 329 * zone. 330 * <p> 331 * Note: The default minimal date is 01/01/1900. 332 * <p> 333 * 334 * @return The minimal supported date. 335 * 336 * @attr ref android.R.styleable#CalendarView_minDate 337 */ 338 public long getMinDate() { 339 return mDelegate.getMinDate(); 340 } 341 342 /** 343 * Sets the minimal date supported by this {@link CalendarView} in milliseconds 344 * since January 1, 1970 00:00:00 in {@link TimeZone#getDefault()} time 345 * zone. 346 * 347 * @param minDate The minimal supported date. 348 * 349 * @attr ref android.R.styleable#CalendarView_minDate 350 */ 351 public void setMinDate(long minDate) { 352 mDelegate.setMinDate(minDate); 353 } 354 355 /** 356 * Gets the maximal date supported by this {@link CalendarView} in milliseconds 357 * since January 1, 1970 00:00:00 in {@link TimeZone#getDefault()} time 358 * zone. 359 * <p> 360 * Note: The default maximal date is 01/01/2100. 361 * <p> 362 * 363 * @return The maximal supported date. 364 * 365 * @attr ref android.R.styleable#CalendarView_maxDate 366 */ 367 public long getMaxDate() { 368 return mDelegate.getMaxDate(); 369 } 370 371 /** 372 * Sets the maximal date supported by this {@link CalendarView} in milliseconds 373 * since January 1, 1970 00:00:00 in {@link TimeZone#getDefault()} time 374 * zone. 375 * 376 * @param maxDate The maximal supported date. 377 * 378 * @attr ref android.R.styleable#CalendarView_maxDate 379 */ 380 public void setMaxDate(long maxDate) { 381 mDelegate.setMaxDate(maxDate); 382 } 383 384 /** 385 * Sets whether to show the week number. 386 * 387 * @param showWeekNumber True to show the week number. 388 * 389 * @attr ref android.R.styleable#CalendarView_showWeekNumber 390 */ 391 public void setShowWeekNumber(boolean showWeekNumber) { 392 mDelegate.setShowWeekNumber(showWeekNumber); 393 } 394 395 /** 396 * Gets whether to show the week number. 397 * 398 * @return True if showing the week number. 399 * 400 * @attr ref android.R.styleable#CalendarView_showWeekNumber 401 */ 402 public boolean getShowWeekNumber() { 403 return mDelegate.getShowWeekNumber(); 404 } 405 406 /** 407 * Gets the first day of week. 408 * 409 * @return The first day of the week conforming to the {@link CalendarView} 410 * APIs. 411 * @see Calendar#MONDAY 412 * @see Calendar#TUESDAY 413 * @see Calendar#WEDNESDAY 414 * @see Calendar#THURSDAY 415 * @see Calendar#FRIDAY 416 * @see Calendar#SATURDAY 417 * @see Calendar#SUNDAY 418 * 419 * @attr ref android.R.styleable#CalendarView_firstDayOfWeek 420 */ 421 public int getFirstDayOfWeek() { 422 return mDelegate.getFirstDayOfWeek(); 423 } 424 425 /** 426 * Sets the first day of week. 427 * 428 * @param firstDayOfWeek The first day of the week conforming to the 429 * {@link CalendarView} APIs. 430 * @see Calendar#MONDAY 431 * @see Calendar#TUESDAY 432 * @see Calendar#WEDNESDAY 433 * @see Calendar#THURSDAY 434 * @see Calendar#FRIDAY 435 * @see Calendar#SATURDAY 436 * @see Calendar#SUNDAY 437 * 438 * @attr ref android.R.styleable#CalendarView_firstDayOfWeek 439 */ 440 public void setFirstDayOfWeek(int firstDayOfWeek) { 441 mDelegate.setFirstDayOfWeek(firstDayOfWeek); 442 } 443 444 /** 445 * Sets the listener to be notified upon selected date change. 446 * 447 * @param listener The listener to be notified. 448 */ 449 public void setOnDateChangeListener(OnDateChangeListener listener) { 450 mDelegate.setOnDateChangeListener(listener); 451 } 452 453 /** 454 * Gets the selected date in milliseconds since January 1, 1970 00:00:00 in 455 * {@link TimeZone#getDefault()} time zone. 456 * 457 * @return The selected date. 458 */ 459 public long getDate() { 460 return mDelegate.getDate(); 461 } 462 463 /** 464 * Sets the selected date in milliseconds since January 1, 1970 00:00:00 in 465 * {@link TimeZone#getDefault()} time zone. 466 * 467 * @param date The selected date. 468 * 469 * @throws IllegalArgumentException of the provided date is before the 470 * minimal or after the maximal date. 471 * 472 * @see #setDate(long, boolean, boolean) 473 * @see #setMinDate(long) 474 * @see #setMaxDate(long) 475 */ 476 public void setDate(long date) { 477 mDelegate.setDate(date); 478 } 479 480 /** 481 * Sets the selected date in milliseconds since January 1, 1970 00:00:00 in 482 * {@link TimeZone#getDefault()} time zone. 483 * 484 * @param date The date. 485 * @param animate Whether to animate the scroll to the current date. 486 * @param center Whether to center the current date even if it is already visible. 487 * 488 * @throws IllegalArgumentException of the provided date is before the 489 * minimal or after the maximal date. 490 * 491 * @see #setMinDate(long) 492 * @see #setMaxDate(long) 493 */ 494 public void setDate(long date, boolean animate, boolean center) { 495 mDelegate.setDate(date, animate, center); 496 } 497 498 @Override 499 protected void onConfigurationChanged(Configuration newConfig) { 500 super.onConfigurationChanged(newConfig); 501 mDelegate.onConfigurationChanged(newConfig); 502 } 503 504 @Override 505 public void onInitializeAccessibilityEvent(AccessibilityEvent event) { 506 event.setClassName(CalendarView.class.getName()); 507 } 508 509 @Override 510 public void onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo info) { 511 info.setClassName(CalendarView.class.getName()); 512 } 513 514 /** 515 * A delegate interface that defined the public API of the CalendarView. Allows different 516 * CalendarView implementations. This would need to be implemented by the CalendarView delegates 517 * for the real behavior. 518 */ 519 private interface CalendarViewDelegate { 520 void setShownWeekCount(int count); 521 int getShownWeekCount(); 522 523 void setSelectedWeekBackgroundColor(int color); 524 int getSelectedWeekBackgroundColor(); 525 526 void setFocusedMonthDateColor(int color); 527 int getFocusedMonthDateColor(); 528 529 void setUnfocusedMonthDateColor(int color); 530 int getUnfocusedMonthDateColor(); 531 532 void setWeekNumberColor(int color); 533 int getWeekNumberColor(); 534 535 void setWeekSeparatorLineColor(int color); 536 int getWeekSeparatorLineColor(); 537 538 void setSelectedDateVerticalBar(int resourceId); 539 void setSelectedDateVerticalBar(Drawable drawable); 540 Drawable getSelectedDateVerticalBar(); 541 542 void setWeekDayTextAppearance(int resourceId); 543 int getWeekDayTextAppearance(); 544 545 void setDateTextAppearance(int resourceId); 546 int getDateTextAppearance(); 547 548 void setMinDate(long minDate); 549 long getMinDate(); 550 551 void setMaxDate(long maxDate); 552 long getMaxDate(); 553 554 void setShowWeekNumber(boolean showWeekNumber); 555 boolean getShowWeekNumber(); 556 557 void setFirstDayOfWeek(int firstDayOfWeek); 558 int getFirstDayOfWeek(); 559 560 void setDate(long date); 561 void setDate(long date, boolean animate, boolean center); 562 long getDate(); 563 564 void setOnDateChangeListener(OnDateChangeListener listener); 565 566 void onConfigurationChanged(Configuration newConfig); 567 } 568 569 /** 570 * An abstract class which can be used as a start for CalendarView implementations 571 */ 572 abstract static class AbstractCalendarViewDelegate implements CalendarViewDelegate { 573 /** String for parsing dates. */ 574 private static final String DATE_FORMAT = "MM/dd/yyyy"; 575 576 /** The default minimal date. */ 577 protected static final String DEFAULT_MIN_DATE = "01/01/1900"; 578 579 /** The default maximal date. */ 580 protected static final String DEFAULT_MAX_DATE = "01/01/2100"; 581 582 /** Date format for parsing dates. */ 583 protected static final DateFormat DATE_FORMATTER = new SimpleDateFormat(DATE_FORMAT); 584 585 protected CalendarView mDelegator; 586 protected Context mContext; 587 protected Locale mCurrentLocale; 588 589 AbstractCalendarViewDelegate(CalendarView delegator, Context context) { 590 mDelegator = delegator; 591 mContext = context; 592 593 // Initialization based on locale 594 setCurrentLocale(Locale.getDefault()); 595 } 596 597 protected void setCurrentLocale(Locale locale) { 598 if (locale.equals(mCurrentLocale)) { 599 return; 600 } 601 mCurrentLocale = locale; 602 } 603 604 /** 605 * Parses the given <code>date</code> and in case of success sets 606 * the result to the <code>outDate</code>. 607 * 608 * @return True if the date was parsed. 609 */ 610 protected boolean parseDate(String date, Calendar outDate) { 611 try { 612 outDate.setTime(DATE_FORMATTER.parse(date)); 613 return true; 614 } catch (ParseException e) { 615 Log.w(LOG_TAG, "Date: " + date + " not in format: " + DATE_FORMAT); 616 return false; 617 } 618 } 619 } 620 621 } 622